[Pkg-owncloud-commits] [owncloud] 126/134: Imported Upstream version 6.0.3~20140418+dfsg

David Prévot taffit at moszumanska.debian.org
Fri Apr 18 21:44:10 UTC 2014


This is an automated email from the git hooks/post-receive script.

taffit pushed a commit to branch master
in repository owncloud.

commit e84bf62665f257ea42a4b1de2b9e0077f2daacdd
Merge: 4863f8b a7bc716
Author: David Prévot <taffit at debian.org>
Date:   Fri Apr 18 10:22:50 2014 -0400

    Imported Upstream version 6.0.3~20140418+dfsg

 apps/calendar/appinfo/app.php                      |     4 -
 apps/calendar/appinfo/remote.php                   |     3 +
 apps/contacts/Changelog                            |     7 +
 apps/contacts/js/app.js                            |    11 +-
 apps/contacts/js/storage.js                        |    31 +-
 apps/contacts/lib/backend/database.php             |     6 +-
 apps/contacts/lib/carddav/backend.php              |     6 +-
 apps/contacts/lib/carddav/plugin.php               |     4 -
 apps/documents/ajax/admin.php                      |    31 +
 apps/documents/ajax/controller.php                 |     1 -
 apps/documents/ajax/documentController.php         |    57 +-
 apps/documents/ajax/otpoll.php                     |    21 +-
 apps/documents/ajax/sessionController.php          |    92 +-
 apps/documents/ajax/userController.php             |    26 +-
 apps/documents/appinfo/app.php                     |     6 +-
 apps/documents/appinfo/database.xml                |    15 +
 apps/documents/appinfo/info.xml                    |     2 +-
 apps/documents/appinfo/routes.php                  |     5 +
 apps/documents/appinfo/update.php                  |     4 +
 apps/documents/appinfo/version                     |     2 +-
 apps/documents/css/3rdparty/webodf/editor.css      |    24 +-
 apps/documents/css/style.css                       |    33 +-
 apps/documents/index.php                           |     2 +-
 apps/documents/js/3rdparty/webodf/editor/Editor.js |    74 +-
 .../js/3rdparty/webodf/editor/EditorSession.js     |    68 +-
 .../js/3rdparty/webodf/editor/MemberListView.js    |     9 +-
 apps/documents/js/3rdparty/webodf/editor/Tools.js  |    16 +-
 .../editor/server/pullbox/OperationRouter.js       |    14 +-
 .../editor/widgets/dialogWidgets/alignmentPane.js  |     5 +-
 .../widgets/dialogWidgets/editHyperlinkPane.html   |    30 +
 .../widgets/dialogWidgets/editHyperlinkPane.js     |   110 +
 .../webodf/editor/widgets/editHyperlinks.js        |   181 +
 .../webodf/editor/widgets/paragraphAlignment.js    |    34 +-
 .../3rdparty/webodf/editor/widgets/simpleStyles.js |    38 +-
 .../3rdparty/webodf/editor/widgets/undoRedoMenu.js |    92 +-
 .../3rdparty/webodf/editor/widgets/zoomSlider.js   |    35 +-
 apps/documents/js/3rdparty/webodf/webodf-debug.js  | 22980 +++++-----
 apps/documents/js/3rdparty/webodf/webodf.js        |  1838 +-
 .../editor/server/owncloud => }/ServerFactory.js   |     5 +-
 apps/documents/js/documents.js                     |   254 +-
 apps/documents/lib/config.php                      |    46 +
 apps/documents/lib/db.php                          |    11 +
 apps/documents/lib/db/member.php                   |    13 +-
 apps/documents/lib/db/op.php                       |    45 +-
 apps/documents/lib/db/session.php                  |    63 +-
 apps/documents/lib/file.php                        |   105 +-
 apps/documents/lib/filter/office.php               |    85 +
 apps/documents/lib/genesis.php                     |     9 +-
 apps/documents/lib/helper.php                      |     7 +
 apps/documents/lib/storage.php                     |    21 +-
 apps/documents/public.php                          |    14 +
 .../src/patches/MemberListView-OCnick.patch        |    10 +
 apps/documents/src/updateWebODF.sh                 |     1 +
 apps/documents/templates/documents.php             |     6 +-
 apps/documents/templates/public.php                |     7 +-
 apps/files/ajax/move.php                           |     2 +-
 apps/files/appinfo/update.php                      |    19 +-
 apps/files/command/scan.php                        |     2 +-
 apps/files/download.php                            |     3 +
 apps/files/js/file-upload.js                       |    36 +-
 apps/files/js/filelist.js                          |     9 +-
 apps/files/js/files.js                             |    26 +-
 apps/files/l10n/pl_PL.php                          |     5 -
 apps/files/templates/part.list.php                 |     8 +-
 apps/files_encryption/lib/helper.php               |    24 +
 apps/files_encryption/lib/proxy.php                |     9 +
 apps/files_encryption/lib/stream.php               |    38 +-
 apps/files_encryption/lib/util.php                 |    34 +-
 apps/files_encryption/tests/proxy.php              |    20 +
 apps/files_encryption/tests/stream.php             |    39 +
 apps/files_encryption/tests/util.php               |    35 +
 apps/files_external/3rdparty/smb4php/smb.php       |    16 +-
 apps/files_external/lib/swift.php                  |     6 +-
 .../3rdparty/pdfjs/compatibility.js                |   139 +-
 .../3rdparty/pdfjs/images/annotation-check.svg     |    11 +-
 .../3rdparty/pdfjs/images/annotation-comment.svg   |    17 +-
 .../3rdparty/pdfjs/images/annotation-help.svg      |    30 +-
 .../3rdparty/pdfjs/images/annotation-insert.svg    |    10 +-
 .../3rdparty/pdfjs/images/annotation-key.svg       |    11 +-
 .../pdfjs/images/annotation-newparagraph.svg       |    11 +-
 .../3rdparty/pdfjs/images/annotation-noicon.svg    |     7 +
 .../3rdparty/pdfjs/images/annotation-note.svg      |    48 +-
 .../3rdparty/pdfjs/images/annotation-paragraph.svg |    17 +-
 .../pdfjs/images/findbarButton-next-rtl.png        |   Bin 371 -> 199 bytes
 .../pdfjs/images/findbarButton-next-rtl at 2x.png     |   Bin 0 -> 304 bytes
 .../3rdparty/pdfjs/images/findbarButton-next.png   |   Bin 381 -> 193 bytes
 .../pdfjs/images/findbarButton-next at 2x.png         |   Bin 0 -> 296 bytes
 .../pdfjs/images/findbarButton-previous-rtl.png    |   Bin 381 -> 193 bytes
 .../pdfjs/images/findbarButton-previous-rtl at 2x.png |   Bin 0 -> 296 bytes
 .../pdfjs/images/findbarButton-previous.png        |   Bin 371 -> 199 bytes
 .../pdfjs/images/findbarButton-previous at 2x.png     |   Bin 0 -> 304 bytes
 .../files_pdfviewer/3rdparty/pdfjs/images/grab.cur |   Bin 0 -> 326 bytes
 .../3rdparty/pdfjs/images/grabbing.cur             |   Bin 0 -> 326 bytes
 .../3rdparty/pdfjs/images/loading-small.png        |   Bin 8944 -> 3612 bytes
 .../secondaryToolbarButton-documentProperties.png  |   Bin 0 -> 403 bytes
 ...econdaryToolbarButton-documentProperties at 2x.png |   Bin 0 -> 933 bytes
 .../images/secondaryToolbarButton-firstPage.png    |   Bin 0 -> 179 bytes
 .../images/secondaryToolbarButton-firstPage at 2x.png |   Bin 0 -> 266 bytes
 .../images/secondaryToolbarButton-handTool.png     |   Bin 0 -> 301 bytes
 .../images/secondaryToolbarButton-handTool at 2x.png  |   Bin 0 -> 583 bytes
 .../images/secondaryToolbarButton-lastPage.png     |   Bin 0 -> 175 bytes
 .../images/secondaryToolbarButton-lastPage at 2x.png  |   Bin 0 -> 276 bytes
 .../images/secondaryToolbarButton-rotateCcw.png    |   Bin 0 -> 360 bytes
 .../images/secondaryToolbarButton-rotateCcw at 2x.png |   Bin 0 -> 731 bytes
 .../images/secondaryToolbarButton-rotateCw.png     |   Bin 0 -> 359 bytes
 .../images/secondaryToolbarButton-rotateCw at 2x.png  |   Bin 0 -> 714 bytes
 .../3rdparty/pdfjs/images/shadow.png               |   Bin 454 -> 290 bytes
 .../3rdparty/pdfjs/images/texture.png              |   Bin 2459 -> 2418 bytes
 .../pdfjs/images/toolbarButton-bookmark.png        |   Bin 244 -> 174 bytes
 .../pdfjs/images/toolbarButton-bookmark at 2x.png     |   Bin 0 -> 260 bytes
 .../pdfjs/images/toolbarButton-download.png        |   Bin 380 -> 259 bytes
 .../pdfjs/images/toolbarButton-download at 2x.png     |   Bin 0 -> 425 bytes
 .../pdfjs/images/toolbarButton-fullscreen.png      |   Bin 491 -> 0 bytes
 .../pdfjs/images/toolbarButton-menuArrows.png      |   Bin 237 -> 108 bytes
 .../pdfjs/images/toolbarButton-menuArrows at 2x.png   |   Bin 0 -> 152 bytes
 .../pdfjs/images/toolbarButton-openFile.png        |   Bin 348 -> 295 bytes
 .../pdfjs/images/toolbarButton-openFile at 2x.png     |   Bin 0 -> 550 bytes
 .../pdfjs/images/toolbarButton-pageDown-rtl.png    |   Bin 538 -> 242 bytes
 .../pdfjs/images/toolbarButton-pageDown-rtl at 2x.png |   Bin 0 -> 398 bytes
 .../pdfjs/images/toolbarButton-pageDown.png        |   Bin 353 -> 238 bytes
 .../pdfjs/images/toolbarButton-pageDown at 2x.png     |   Bin 0 -> 396 bytes
 .../pdfjs/images/toolbarButton-pageUp-rtl.png      |   Bin 377 -> 245 bytes
 .../pdfjs/images/toolbarButton-pageUp-rtl at 2x.png   |   Bin 0 -> 405 bytes
 .../3rdparty/pdfjs/images/toolbarButton-pageUp.png |   Bin 344 -> 246 bytes
 .../pdfjs/images/toolbarButton-pageUp at 2x.png       |   Bin 0 -> 403 bytes
 .../images/toolbarButton-presentationMode.png      |   Bin 0 -> 321 bytes
 .../images/toolbarButton-presentationMode at 2x.png   |   Bin 0 -> 586 bytes
 .../3rdparty/pdfjs/images/toolbarButton-print.png  |   Bin 474 -> 257 bytes
 .../pdfjs/images/toolbarButton-print at 2x.png        |   Bin 0 -> 464 bytes
 .../3rdparty/pdfjs/images/toolbarButton-search.png |   Bin 411 -> 309 bytes
 .../pdfjs/images/toolbarButton-search at 2x.png       |   Bin 0 -> 653 bytes
 .../toolbarButton-secondaryToolbarToggle-rtl.png   |   Bin 0 -> 246 bytes
 ...toolbarButton-secondaryToolbarToggle-rtl at 2x.png |   Bin 0 -> 456 bytes
 .../toolbarButton-secondaryToolbarToggle.png       |   Bin 0 -> 243 bytes
 .../toolbarButton-secondaryToolbarToggle at 2x.png    |   Bin 0 -> 458 bytes
 .../images/toolbarButton-sidebarToggle-rtl.png     |   Bin 0 -> 225 bytes
 .../images/toolbarButton-sidebarToggle-rtl at 2x.png  |   Bin 0 -> 344 bytes
 .../pdfjs/images/toolbarButton-sidebarToggle.png   |   Bin 349 -> 225 bytes
 .../images/toolbarButton-sidebarToggle at 2x.png      |   Bin 0 -> 331 bytes
 .../pdfjs/images/toolbarButton-viewOutline-rtl.png |   Bin 0 -> 177 bytes
 .../images/toolbarButton-viewOutline-rtl at 2x.png    |   Bin 0 -> 394 bytes
 .../pdfjs/images/toolbarButton-viewOutline.png     |   Bin 300 -> 178 bytes
 .../pdfjs/images/toolbarButton-viewOutline at 2x.png  |   Bin 0 -> 331 bytes
 .../pdfjs/images/toolbarButton-viewThumbnail.png   |   Bin 211 -> 185 bytes
 .../images/toolbarButton-viewThumbnail at 2x.png      |   Bin 0 -> 220 bytes
 .../3rdparty/pdfjs/images/toolbarButton-zoomIn.png |   Bin 228 -> 136 bytes
 .../pdfjs/images/toolbarButton-zoomIn at 2x.png       |   Bin 0 -> 160 bytes
 .../pdfjs/images/toolbarButton-zoomOut.png         |   Bin 143 -> 88 bytes
 .../pdfjs/images/toolbarButton-zoomOut at 2x.png      |   Bin 0 -> 109 bytes
 apps/files_pdfviewer/3rdparty/pdfjs/l10n.js        |   266 +-
 .../3rdparty/pdfjs/locale/ar/viewer.properties     |    23 +-
 .../3rdparty/pdfjs/locale/bn-BD/viewer.properties  |   157 +
 .../3rdparty/pdfjs/locale/ca/viewer.properties     |    32 +-
 .../3rdparty/pdfjs/locale/cs/viewer.properties     |   166 +-
 .../3rdparty/pdfjs/locale/cy/viewer.properties     |   134 +
 .../3rdparty/pdfjs/locale/da/viewer.properties     |    55 +-
 .../3rdparty/pdfjs/locale/de/viewer.properties     |    80 +-
 .../3rdparty/pdfjs/locale/el/viewer.properties     |   124 +
 .../3rdparty/pdfjs/locale/en-US/viewer.properties  |    64 +-
 .../3rdparty/pdfjs/locale/es-MX/viewer.properties  |   124 -
 .../3rdparty/pdfjs/locale/es/viewer.properties     |   248 +-
 .../3rdparty/pdfjs/locale/fa/viewer.properties     |   134 +
 .../3rdparty/pdfjs/locale/fi/viewer.properties     |    31 +-
 .../3rdparty/pdfjs/locale/fr/viewer.properties     |   124 +-
 .../3rdparty/pdfjs/locale/he/viewer.properties     |     3 +-
 .../3rdparty/pdfjs/locale/it/viewer.properties     |     9 +-
 .../3rdparty/pdfjs/locale/ja/viewer.properties     |    83 +-
 .../3rdparty/pdfjs/locale/ko/viewer.properties     |   131 +
 .../3rdparty/pdfjs/locale/locale.properties        |    26 +-
 .../3rdparty/pdfjs/locale/lt/viewer.properties     |    31 +-
 .../3rdparty/pdfjs/locale/nl/viewer.properties     |    64 +-
 .../3rdparty/pdfjs/locale/no/viewer.properties     |   134 +
 .../3rdparty/pdfjs/locale/pl/viewer.properties     |    33 +-
 .../3rdparty/pdfjs/locale/pt-BR/viewer.properties  |     3 +-
 .../3rdparty/pdfjs/locale/ro/viewer.properties     |     3 +-
 .../3rdparty/pdfjs/locale/ru/viewer.properties     |     3 +-
 .../3rdparty/pdfjs/locale/sr/viewer.properties     |     3 +-
 .../pdfjs/locale/{sv => sv-SE}/viewer.properties   |    67 +-
 .../3rdparty/pdfjs/locale/tr/viewer.properties     |    31 +-
 .../3rdparty/pdfjs/locale/vi/viewer.properties     |   131 +
 .../3rdparty/pdfjs/locale/zh-CN/viewer.properties  |    45 +-
 .../3rdparty/pdfjs/locale/zh-TW/viewer.properties  |   277 +-
 apps/files_pdfviewer/3rdparty/pdfjs/pdf.js         | 43619 +++----------------
 .../3rdparty/pdfjs/{pdf.js => pdf.worker.js}       | 34411 ++++++++-------
 apps/files_pdfviewer/3rdparty/pdfjs/viewer.css     |  1098 +-
 apps/files_pdfviewer/3rdparty/pdfjs/viewer.js      |  4429 +-
 apps/files_pdfviewer/appinfo/version               |     2 +-
 apps/files_pdfviewer/js/files.php                  |     4 +-
 apps/files_pdfviewer/js/loader.js                  |    21 +-
 apps/files_pdfviewer/templates/pdf.php             |   311 +-
 apps/files_sharing/lib/api.php                     |    43 +-
 apps/files_sharing/lib/cache.php                   |    58 +-
 apps/files_sharing/tests/api.php                   |   340 +-
 apps/files_sharing/tests/cache.php                 |    39 +
 apps/gallery/templates/public.php                  |     2 +-
 apps/updater/ajax/update.php                       |     2 +-
 apps/user_ldap/lib/access.php                      |   117 +-
 apps/user_ldap/lib/configuration.php               |     4 +-
 apps/user_ldap/lib/connection.php                  |     2 +
 apps/user_ldap/lib/helper.php                      |     2 +-
 apps/user_ldap/lib/wizard.php                      |    32 +-
 apps/user_ldap/tests/connection.php                |    54 +
 apps/user_ldap/tests/wizard.php                    |   210 +
 apps/user_ldap/user_ldap.php                       |    36 +-
 core/ajax/share.php                                |    25 +-
 core/command/upgrade.php                           |    26 +
 core/css/apps.css                                  |    22 +-
 core/css/icons.css                                 |    10 +-
 core/css/jquery.ocdialog.css                       |     2 +-
 core/css/styles.css                                |     8 +-
 .../_images/100000000000001D0000001E5C455170.png   |   Bin 1301 -> 0 bytes
 .../_images/10000000000000D2000000F553818155.png   |   Bin 40563 -> 0 bytes
 .../_images/10000000000000F20000003BAA849B42.png   |   Bin 12296 -> 0 bytes
 .../_images/10000000000001E50000018C3AD09A21.png   |   Bin 107117 -> 0 bytes
 .../_images/10000000000001EE00000164642CCA08.png   |   Bin 73614 -> 0 bytes
 .../_images/10000000000001F40000016609A0CFCC.png   |   Bin 55791 -> 0 bytes
 .../_images/100000000000024400000027BEE1E4A9.png   |   Bin 37305 -> 0 bytes
 .../_images/10000000000002650000018CA6A1BE66.png   |   Bin 74341 -> 0 bytes
 .../_images/10000000000002650000018E4285E964.png   |   Bin 92661 -> 0 bytes
 .../_images/10000000000002690000018D3A8C9F17.png   |   Bin 75305 -> 0 bytes
 .../_images/100000000000026A000001DCAF8778F2.png   |   Bin 126167 -> 0 bytes
 .../_images/100000000000026E0000003672ADCB6E.png   |   Bin 59136 -> 0 bytes
 .../_images/100000000000029F000000B8A83D0275.png   |   Bin 131939 -> 0 bytes
 .../_images/10000000000002B30000003A5B960711.png   |   Bin 76501 -> 0 bytes
 .../_images/10000000000002BB000001EABD7E6DF0.png   |   Bin 336801 -> 0 bytes
 .../_images/10000000000002BF000001E5B544E7E7.png   |   Bin 97877 -> 0 bytes
 .../_images/10000000000002C1000001ED5CECCC6D.png   |   Bin 134744 -> 0 bytes
 .../_images/10000000000002C3000001EBBD39E47A.png   |   Bin 113591 -> 0 bytes
 .../_images/10000000000002C700000048F3729BAA.png   |   Bin 67393 -> 0 bytes
 ...000006C954442CE.png => edit_encrypted_file.png} |   Bin
 core/doc/admin/_images/untrusted-domain.png        |   Bin 0 -> 168746 bytes
 .../admin/_sources/apps/activity/Configuration.txt |    15 -
 .../admin/_sources/apps/activity/Introduction.txt  |    22 -
 core/doc/admin/_sources/apps/activity/RSS_Feed.txt |    33 -
 .../_sources/apps/activity/Table_of_Contents.txt   |     4 -
 .../admin/_sources/apps/activity/Utilization.txt   |   136 -
 core/doc/admin/_sources/apps/activity/index.txt    |   176 +-
 .../apps/admin_dependencies_chk/Configuration.txt  |    12 -
 .../apps/admin_dependencies_chk/Introduction.txt   |     6 -
 .../admin_dependencies_chk/Table_of_Contents.txt   |     4 -
 .../apps/admin_dependencies_chk/Utilization.txt    |    17 -
 .../_sources/apps/admin_dependencies_chk/index.txt |    39 +-
 .../apps/files_antivirus/Configuration.txt         |   127 -
 .../_sources/apps/files_antivirus/Introduction.txt |    34 -
 .../apps/files_antivirus/Table_of_Contents.txt     |     4 -
 .../admin/_sources/apps/files_antivirus/index.txt  |   149 +-
 .../apps/files_encryption/Configuration.txt        |    88 -
 .../apps/files_encryption/File_Systems.txt         |    65 -
 .../apps/files_encryption/Introduction.txt         |    57 -
 .../apps/files_encryption/Table_of_Contents.txt    |     4 -
 .../admin/_sources/apps/files_encryption/index.txt |   172 +-
 .../_sources/apps/files_external/Configuration.txt |   875 -
 .../_sources/apps/files_external/Introduction.txt  |    54 -
 .../apps/files_external/Table_of_Contents.txt      |     4 -
 .../admin/_sources/apps/files_external/index.txt   |   647 +-
 .../_sources/apps/files_sharing/Configuration.txt  |    32 -
 .../_sources/apps/files_sharing/Introduction.txt   |     7 -
 .../apps/files_sharing/Retrieving_shared_data.txt  |    46 -
 .../apps/files_sharing/Table_of_Contents.txt       |     4 -
 .../_sources/apps/files_sharing/Utilization.txt    |    96 -
 .../admin/_sources/apps/files_sharing/index.txt    |   187 +-
 .../files_trashbin/Configuration_and_storage_.txt  |    33 -
 .../_sources/apps/files_trashbin/Introduction.txt  |    25 -
 .../apps/files_trashbin/Table_of_Contents.txt      |     8 -
 .../_sources/apps/files_trashbin/Utilization.txt   |   146 -
 .../admin/_sources/apps/files_trashbin/index.txt   |   203 +-
 .../files_versions/Configuration_and_storage.txt   |    52 -
 .../_sources/apps/files_versions/Introduction.txt  |    39 -
 .../_sources/apps/files_versions/Utilization.txt   |   114 -
 .../admin/_sources/apps/files_versions/index.txt   |   195 +-
 .../_sources/apps/firstrunwizard/Configuration.txt |    12 -
 .../_sources/apps/firstrunwizard/Introduction.txt  |     4 -
 .../admin/_sources/apps/firstrunwizard/Links.txt   |    54 -
 .../apps/firstrunwizard/Table_of_Contents.txt      |     4 -
 .../admin/_sources/apps/firstrunwizard/Usage.txt   |    21 -
 .../admin/_sources/apps/firstrunwizard/index.txt   |    99 +-
 core/doc/admin/_sources/apps/index.txt             |    19 +
 .../_sources/apps/user_ldap/CONFIGURATION.txt      |   485 -
 .../admin/_sources/apps/user_ldap/Introduction.txt |    21 -
 .../_sources/apps/user_ldap/Table_of_Contents.txt  |     4 -
 core/doc/admin/_sources/apps/user_ldap/index.txt   |   507 +-
 .../admin/_sources/apps/viewers/Configuration.txt  |    28 -
 .../admin/_sources/apps/viewers/Introduction.txt   |     5 -
 .../admin/_sources/apps/viewers/Utilization.txt    |    23 -
 core/doc/admin/_sources/apps/viewers/index.txt     |    62 +-
 core/doc/admin/_sources/config/Introduction.txt    |    10 -
 .../admin/_sources/config/Table_of_Contents.txt    |     5 -
 core/doc/admin/_sources/config/User_Experience.txt |    35 -
 .../admin/_sources/config/{APPS.txt => apps.txt}   |     2 +-
 .../{Code_Locations.txt => code_locations.txt}     |     0
 ...fault_Parameters.txt => default_parameters.txt} |    11 +
 .../{Deleted_Items.txt => deleted_items.txt}       |     0
 core/doc/admin/_sources/config/index.txt           |    43 +-
 .../_sources/config/{Logging.txt => logging.txt}   |     0
 .../{Mail_Parameters.txt => mail_parameters.txt}   |     9 +-
 .../config/{Maintenance.txt => maintenance.txt}    |     0
 .../{Miscellaneous.txt => miscellaneous.txt}       |     2 +-
 .../_sources/config/{Previews.txt => previews.txt} |     0
 ...ations.txt => reverse_proxy_configurations.txt} |     3 +-
 .../config/{Session_Info.txt => session_info.txt}  |     0
 core/doc/admin/_sources/config/user_experience.txt |    35 +
 .../config/{Verification.txt => verification.txt}  |     3 +-
 .../doc/admin/_sources/configuration/auth_ldap.txt |     4 +-
 .../configuration/configuration_3rdparty.txt       |     4 +-
 .../_sources/configuration/configuration_apps.txt  |     5 +-
 .../configuration/configuration_custom_clients.txt |     4 +-
 .../configuration/configuration_database.txt       |     4 +-
 .../configuration/configuration_encryption.txt     |     4 +-
 .../configuration/configuration_knowledgebase.txt  |    10 +-
 .../configuration/configuration_language.txt       |     4 +-
 .../configuration/configuration_logging.txt        |     5 +-
 .../_sources/configuration/configuration_mail.txt  |     5 +-
 .../configuration/configuration_maintenance.txt    |     7 +-
 .../configuration/configuration_preview.txt        |     8 +-
 .../configuration/configuring_big_file_upload.txt  |    24 +-
 core/doc/admin/_sources/contents.txt               |     2 +
 core/doc/admin/_sources/cron/Introduction.txt      |     5 -
 core/doc/admin/_sources/cron/Usage.txt             |    24 -
 core/doc/admin/_sources/cron/index.txt             |    40 +-
 core/doc/admin/_sources/index.txt                  |    19 +
 .../_sources/installation/installation_linux.txt   |     2 +-
 .../_sources/installation/installation_source.txt  |   409 +-
 core/doc/admin/_sources/issues/index.txt           |     4 +-
 core/doc/admin/_sources/maintenance/update.txt     |     6 +-
 .../_sources/quota/Checking_available_space.txt    |    22 -
 .../admin/_sources/quota/Excluded_from_quota.txt   |    40 -
 core/doc/admin/_sources/quota/Introduction.txt     |    21 -
 core/doc/admin/_sources/quota/Sharing.txt          |    26 -
 .../doc/admin/_sources/quota/Table_of_Contents.txt |     4 -
 core/doc/admin/_sources/quota/index.txt            |   119 +-
 core/doc/admin/_sources/sharing_api/Contents.txt   |     4 -
 .../admin/_sources/sharing_api/Introduction.txt    |    48 -
 ...eate_a_new_Share.txt => create_a_new_share.txt} |    17 +-
 .../{Delete_Share.txt => delete_share.txt}         |     8 +-
 .../{Get_All_Shares.txt => get_all_shares.txt}     |    12 +-
 ...txt => get_information_about_a_known_share.txt} |     7 +-
 ... get_shares_from_a_specific_file_or_folder.txt} |    23 +-
 core/doc/admin/_sources/sharing_api/index.txt      |    67 +-
 .../admin/_sources/sync_client/Advanced_Usage.txt  |   114 -
 .../admin/_sources/sync_client/Introduction.txt    |     9 -
 .../_sources/sync_client/Obtaining_the_Client.txt  |    29 -
 .../_sources/sync_client/Setting_up_an_Account.txt |    54 -
 .../_sources/sync_client/Table_of_Contents.txt     |     7 -
 .../doc/admin/_sources/sync_client/Visual_Tour.txt |   257 -
 core/doc/admin/_sources/sync_client/index.txt      |    11 -
 core/doc/admin/_sources/web_guide/Adding_Data.txt  |   117 -
 .../admin/_sources/web_guide/Initial_Log_In.txt    |    29 -
 core/doc/admin/_sources/web_guide/Introduction.txt |     6 -
 .../_sources/web_guide/Main_ownCloud_screen.txt    |    32 -
 core/doc/admin/_sources/web_guide/Navigation.txt   |    75 -
 .../_sources/web_guide/Personal_Configurations.txt |    84 -
 .../admin/_sources/web_guide/Table_of_Contents.txt |     5 -
 core/doc/admin/_sources/web_guide/index.txt        |    12 -
 core/doc/admin/apps/activity/Configuration.html    |   150 -
 core/doc/admin/apps/activity/Introduction.html     |   153 -
 core/doc/admin/apps/activity/RSS_Feed.html         |   156 -
 .../doc/admin/apps/activity/Table_of_Contents.html |   145 -
 core/doc/admin/apps/activity/Utilization.html      |   205 -
 core/doc/admin/apps/activity/index.html            |   117 +-
 .../apps/admin_dependencies_chk/Configuration.html |   147 -
 .../apps/admin_dependencies_chk/Introduction.html  |   146 -
 .../admin_dependencies_chk/Table_of_Contents.html  |   145 -
 .../apps/admin_dependencies_chk/Utilization.html   |   150 -
 .../admin/apps/admin_dependencies_chk/index.html   |    54 +-
 .../admin/apps/files_antivirus/Configuration.html  |   202 -
 .../admin/apps/files_antivirus/Introduction.html   |   161 -
 .../apps/files_antivirus/Table_of_Contents.html    |   145 -
 core/doc/admin/apps/files_antivirus/index.html     |   126 +-
 .../admin/apps/files_encryption/Configuration.html |   180 -
 .../admin/apps/files_encryption/File_Systems.html  |   160 -
 .../admin/apps/files_encryption/Introduction.html  |   169 -
 .../apps/files_encryption/Table_of_Contents.html   |   145 -
 core/doc/admin/apps/files_encryption/index.html    |   164 +-
 .../admin/apps/files_external/Configuration.html   |   494 -
 .../admin/apps/files_external/Introduction.html    |   165 -
 .../apps/files_external/Table_of_Contents.html     |   145 -
 core/doc/admin/apps/files_external/index.html      |   362 +-
 .../admin/apps/files_sharing/Configuration.html    |   157 -
 .../doc/admin/apps/files_sharing/Introduction.html |   148 -
 .../apps/files_sharing/Retrieving_shared_data.html |   159 -
 .../apps/files_sharing/Table_of_Contents.html      |   145 -
 core/doc/admin/apps/files_sharing/Utilization.html |   194 -
 core/doc/admin/apps/files_sharing/index.html       |   143 +-
 .../files_trashbin/Configuration_and_storage_.html |   159 -
 .../admin/apps/files_trashbin/Introduction.html    |   163 -
 .../apps/files_trashbin/Table_of_Contents.html     |   147 -
 .../doc/admin/apps/files_trashbin/Utilization.html |   221 -
 core/doc/admin/apps/files_trashbin/index.html      |   163 +-
 .../files_versions/Configuration_and_storage.html  |   166 -
 .../admin/apps/files_versions/Introduction.html    |   163 -
 .../doc/admin/apps/files_versions/Utilization.html |   201 -
 core/doc/admin/apps/files_versions/index.html      |   158 +-
 .../admin/apps/firstrunwizard/Configuration.html   |   147 -
 .../admin/apps/firstrunwizard/Introduction.html    |   145 -
 core/doc/admin/apps/firstrunwizard/Links.html      |   165 -
 .../apps/firstrunwizard/Table_of_Contents.html     |   145 -
 core/doc/admin/apps/firstrunwizard/Usage.html      |   149 -
 core/doc/admin/apps/firstrunwizard/index.html      |    83 +-
 core/doc/admin/{sync_client => apps}/index.html    |    53 +-
 core/doc/admin/apps/user_ldap/CONFIGURATION.html   |   484 -
 core/doc/admin/apps/user_ldap/Introduction.html    |   151 -
 .../admin/apps/user_ldap/Table_of_Contents.html    |   145 -
 core/doc/admin/apps/user_ldap/index.html           |   409 +-
 core/doc/admin/apps/viewers/Configuration.html     |   156 -
 core/doc/admin/apps/viewers/Introduction.html      |   146 -
 core/doc/admin/apps/viewers/Utilization.html       |   148 -
 core/doc/admin/apps/viewers/index.html             |    65 +-
 core/doc/admin/config/Introduction.html            |   149 -
 core/doc/admin/config/Mail_Parameters.html         |   145 -
 core/doc/admin/config/Miscellaneous.html           |   145 -
 core/doc/admin/config/Table_of_Contents.html       |   145 -
 core/doc/admin/config/{APPS.html => apps.html}     |    24 +-
 .../{Code_Locations.html => code_locations.html}   |    22 +-
 ...ult_Parameters.html => default_parameters.html} |    34 +-
 .../{Deleted_Items.html => deleted_items.html}     |    22 +-
 core/doc/admin/config/index.html                   |    50 +-
 .../admin/config/{Logging.html => logging.html}    |    22 +-
 core/doc/admin/config/mail_parameters.html         |   239 +
 .../config/{Maintenance.html => maintenance.html}  |    22 +-
 core/doc/admin/config/miscellaneous.html           |   224 +
 .../admin/config/{Previews.html => previews.html}  |    22 +-
 ...ions.html => reverse_proxy_configurations.html} |    25 +-
 .../{Session_Info.html => session_info.html}       |    22 +-
 .../{User_Experience.html => user_experience.html} |    34 +-
 .../{Verification.html => verification.html}       |    25 +-
 core/doc/admin/configuration/auth_ldap.html        |    35 +-
 core/doc/admin/configuration/background_jobs.html  |    33 +-
 .../configuration/configuration_3rdparty.html      |    35 +-
 .../admin/configuration/configuration_apps.html    |    35 +-
 .../configuration/configuration_automation.html    |    41 +-
 .../configuration_custom_clients.html              |    37 +-
 .../configuration/configuration_database.html      |    39 +-
 .../configuration/configuration_encryption.html    |    39 +-
 .../configuration/configuration_knowledgebase.html |    44 +-
 .../configuration/configuration_language.html      |    39 +-
 .../admin/configuration/configuration_logging.html |    39 +-
 .../admin/configuration/configuration_mail.html    |    39 +-
 .../configuration/configuration_maintenance.html   |    39 +-
 .../admin/configuration/configuration_preview.html |    40 +-
 .../configuration/configuration_reverseproxy.html  |    33 +-
 .../admin/configuration/configuration_users.html   |    33 +-
 .../configuration/configuring_big_file_upload.html |    59 +-
 .../admin/configuration/custom_mount_config.html   |    29 +-
 .../configuration/custom_mount_config_gui.html     |    31 +-
 .../admin/configuration/custom_user_backend.html   |    29 +-
 core/doc/admin/configuration/index.html            |    58 +-
 core/doc/admin/configuration/xsendfile.html        |    31 +-
 core/doc/admin/contents.html                       |    98 +-
 core/doc/admin/cron/Introduction.html              |   146 -
 core/doc/admin/cron/Usage.html                     |   154 -
 core/doc/admin/cron/index.html                     |    40 +-
 core/doc/admin/genindex.html                       |     2 +
 core/doc/admin/index.html                          |    46 +-
 core/doc/admin/installation/index.html             |     2 +
 .../admin/installation/installation_appliance.html |     2 +
 .../doc/admin/installation/installation_linux.html |     4 +-
 .../doc/admin/installation/installation_macos.html |     2 +
 .../admin/installation/installation_others.html    |     2 +
 .../admin/installation/installation_source.html    |   373 +-
 core/doc/admin/installation/installation_ucs.html  |     2 +
 .../admin/installation/installation_windows.html   |     2 +
 core/doc/admin/issues/index.html                   |     4 +-
 core/doc/admin/maintenance/backup.html             |     2 +
 core/doc/admin/maintenance/index.html              |     4 +-
 core/doc/admin/maintenance/migrating.html          |     4 +-
 core/doc/admin/maintenance/restore.html            |     2 +
 core/doc/admin/maintenance/update.html             |     8 +-
 core/doc/admin/quota/Checking_available_space.html |   149 -
 core/doc/admin/quota/Excluded_from_quota.html      |   173 -
 core/doc/admin/quota/Introduction.html             |   152 -
 core/doc/admin/quota/Sharing.html                  |   163 -
 core/doc/admin/quota/Table_of_Contents.html        |   145 -
 core/doc/admin/quota/index.html                    |   100 +-
 core/doc/admin/search.html                         |     2 +
 core/doc/admin/sharing_api/Contents.html           |   145 -
 core/doc/admin/sharing_api/Introduction.html       |   188 -
 ...te_a_new_Share.html => create_a_new_share.html} |    16 +-
 .../{Delete_Share.html => delete_share.html}       |     8 +-
 .../{Get_All_Shares.html => get_all_shares.html}   |    10 +-
 ...ml => get_information_about_a_known_share.html} |     7 +-
 ...get_shares_from_a_specific_file_or_folder.html} |    22 +-
 core/doc/admin/sharing_api/index.html              |    98 +-
 core/doc/admin/sync_client/Advanced_Usage.html     |   205 -
 core/doc/admin/sync_client/Introduction.html       |   149 -
 .../admin/sync_client/Obtaining_the_Client.html    |   160 -
 .../admin/sync_client/Setting_up_an_Account.html   |   161 -
 core/doc/admin/sync_client/Table_of_Contents.html  |   146 -
 core/doc/admin/sync_client/Visual_Tour.html        |   261 -
 core/doc/admin/web_guide/Adding_Data.html          |   195 -
 core/doc/admin/web_guide/Initial_Log_In.html       |   154 -
 core/doc/admin/web_guide/Introduction.html         |   147 -
 core/doc/admin/web_guide/Main_ownCloud_screen.html |   156 -
 core/doc/admin/web_guide/Navigation.html           |   178 -
 .../admin/web_guide/Personal_Configurations.html   |   193 -
 core/doc/admin/web_guide/Table_of_Contents.html    |   145 -
 core/doc/admin/web_guide/index.html                |   174 -
 .../_images/1000000000000163000000E9CDA84C92.png   |   Bin
 .../_images/1000000000000175000000FAB2A2B294.png   |   Bin
 .../_images/1000000000000195000000EF7E44082C.png   |   Bin
 .../_images/10000000000001CE000000F2E2084BA1.png   |   Bin
 .../_images/100000000000041D0000003D52225C0D.png   |   Bin
 .../_images/1000000000000453000001BFFCF48776.png   |   Bin
 .../_images/1000000000000467000002B63162E59B.png   |   Bin
 .../_images/10000000000004690000026615360BEB.png   |   Bin
 .../_images/100000000000046D0000015F4B5494A9.png   |   Bin
 .../_images/100000000000046F000000DEA2BFCD9B.png   |   Bin
 .../_images/1000000000000470000001B68AE60DD3.png   |   Bin
 .../_images/10000000000004710000014BBC34499D.png   |   Bin
 .../_images/100000000000047200000129CB014025.png   |   Bin
 .../_images/100000000000047700000219A3013A92.png   |   Bin
 .../_images/1000000000000479000002887E7F48EA.png   |   Bin
 .../_images/100000000000047A000000B727198874.png   |   Bin
 .../_images/100000000000047A000000FB86FF2A9A.png   |   Bin
 .../_images/100000000000047A0000011C6682A254.png   |   Bin
 .../_images/100000000000048100000245268CDB7A.png   |   Bin
 core/doc/user/_sources/files/encryption.txt        |    41 +-
 core/doc/user/_sources/files/files.txt             |     2 +-
 core/doc/user/_sources/files/filesweb.txt          |     2 +-
 core/doc/user/_sources/files/sync.txt              |     2 +-
 core/doc/user/_sources/pim/troubleshooting.txt     |     2 +-
 core/doc/user/_sources/web_guide/index.txt         |   344 +
 core/doc/user/files/encryption.html                |    39 +-
 core/doc/user/files/files.html                     |     2 +-
 core/doc/user/files/filesweb.html                  |     2 +-
 core/doc/user/files/sync.html                      |     2 +-
 core/doc/user/pim/troubleshooting.html             |     2 +-
 core/doc/user/web_guide/index.html                 |   325 +
 core/img/logo-mail.gif                             |   Bin 2196 -> 1191 bytes
 core/js/js.js                                      |    24 +
 core/js/router.js                                  |     4 +
 core/js/share.js                                   |     6 +-
 core/l10n/pl_PL.php                                |     6 -
 core/skeleton/ownCloudUserManual.pdf               |   Bin 1571970 -> 1572014 bytes
 core/templates/mail.php                            |    22 +-
 l10n/pl_PL/core.po                                 |   617 -
 l10n/pl_PL/files.po                                |   322 -
 l10n/pl_PL/files_encryption.po                     |   103 -
 l10n/pl_PL/files_external.po                       |   123 -
 l10n/pl_PL/files_sharing.po                        |    48 -
 l10n/pl_PL/files_trashbin.po                       |    84 -
 l10n/pl_PL/files_versions.po                       |    57 -
 l10n/pl_PL/lib.po                                  |   245 -
 l10n/pl_PL/settings.po                             |   496 -
 l10n/pl_PL/user_ldap.po                            |   419 -
 l10n/pl_PL/user_webdavauth.po                      |    33 -
 lib/base.php                                       |    17 +
 lib/l10n/pl_PL.php                                 |     5 -
 lib/private/api.php                                |    56 +-
 lib/private/appframework/routing/routeconfig.php   |    10 +-
 lib/private/cache/file.php                         |     5 -
 lib/private/config.php                             |     2 +-
 lib/private/connector/sabre/directory.php          |     4 +-
 lib/private/connector/sabre/node.php               |     9 +-
 lib/private/connector/sabre/objecttree.php         |     3 +
 lib/private/connector/sabre/quotaplugin.php        |    11 +
 lib/private/db/statementwrapper.php                |    14 +
 lib/private/defaults.php                           |    14 +
 lib/private/filechunking.php                       |    41 +-
 lib/private/files/cache/cache.php                  |    18 +
 lib/private/files/cache/homecache.php              |     9 +-
 lib/private/files/storage/wrapper/quota.php        |    14 +-
 lib/private/files/view.php                         |    19 +-
 lib/private/group/group.php                        |    12 -
 lib/private/group/manager.php                      |     6 -
 lib/private/helper.php                             |    29 -
 lib/private/mail.php                               |     5 +-
 lib/private/ocsclient.php                          |    16 +-
 lib/private/request.php                            |    78 +-
 lib/private/response.php                           |     4 +
 lib/private/router.php                             |    10 +-
 lib/private/setup.php                              |     4 +
 lib/private/updater.php                            |    11 +-
 lib/private/user/manager.php                       |    14 -
 lib/private/util.php                               |    39 +-
 lib/public/appframework/controller.php             |    22 +-
 lib/public/share.php                               |    21 +-
 lib/public/util.php                                |     7 +-
 ocs/v1.php                                         |     2 +
 settings/js/apps-custom.php                        |     4 +-
 settings/l10n/de.php                               |     2 +-
 settings/l10n/fr.php                               |     2 +-
 settings/l10n/ka_GE.php                            |     2 +-
 settings/l10n/nl.php                               |     2 +-
 settings/l10n/pl_PL.php                            |     6 -
 settings/templates/admin.php                       |     2 -
 version.php                                        |     6 +-
 586 files changed, 53966 insertions(+), 88452 deletions(-)

diff --cc apps/calendar/appinfo/app.php
index b7f6a2b,0000000..26f9795
mode 100644,000000..100644
--- a/apps/calendar/appinfo/app.php
+++ b/apps/calendar/appinfo/app.php
@@@ -1,49 -1,0 +1,45 @@@
 +<?php
 +$l = OCP\Util::getL10N('calendar');
 +OC::$CLASSPATH['OC_Calendar_App'] = 'calendar/lib/app.php';
 +OC::$CLASSPATH['OC_Calendar_Calendar'] = 'calendar/lib/calendar.php';
 +OC::$CLASSPATH['OC_Calendar_Object'] = 'calendar/lib/object.php';
 +OC::$CLASSPATH['OC_Calendar_Hooks'] = 'calendar/lib/hooks.php';
 +OC::$CLASSPATH['OC_Connector_Sabre_CalDAV'] = 'calendar/lib/sabre/backend.php';
 +OC::$CLASSPATH['OC_Connector_Sabre_CalDAV_CalendarRoot'] = 'calendar/lib/sabre/calendarroot.php';
 +OC::$CLASSPATH['OC_Connector_Sabre_CalDAV_UserCalendars'] = 'calendar/lib/sabre/usercalendars.php';
 +OC::$CLASSPATH['OC_Connector_Sabre_CalDAV_Calendar'] = 'calendar/lib/sabre/calendar.php';
 +OC::$CLASSPATH['OC_Connector_Sabre_CalDAV_CalendarObject'] = 'calendar/lib/sabre/object.php';
 +OC::$CLASSPATH['OC_Calendar_Repeat'] = 'calendar/lib/repeat.php';
 +OC::$CLASSPATH['OC_Search_Provider_Calendar'] = 'calendar/lib/search.php';
 +OC::$CLASSPATH['OC_Calendar_Export'] = 'calendar/lib/export.php';
 +OC::$CLASSPATH['OC_Calendar_Import'] = 'calendar/lib/import.php';
 +OC::$CLASSPATH['OC_Share_Backend_Calendar'] = 'calendar/lib/share/calendar.php';
 +OC::$CLASSPATH['OC_Share_Backend_Event'] = 'calendar/lib/share/event.php';
 +//General Hooks
 +OCP\Util::connectHook('OC_User', 'post_createUser', 'OC_Calendar_Hooks', 'createUser');
 +OCP\Util::connectHook('OC_User', 'post_deleteUser', 'OC_Calendar_Hooks', 'deleteUser');
 +//Repeating Events Hooks
 +OCP\Util::connectHook('OC_Calendar', 'addEvent', 'OC_Calendar_Repeat', 'generate');
 +OCP\Util::connectHook('OC_Calendar', 'editEvent', 'OC_Calendar_Repeat', 'update');
 +OCP\Util::connectHook('OC_Calendar', 'deleteEvent', 'OC_Calendar_Repeat', 'clean');
 +OCP\Util::connectHook('OC_Calendar', 'moveEvent', 'OC_Calendar_Repeat', 'update');
 +OCP\Util::connectHook('OC_Calendar', 'deleteCalendar', 'OC_Calendar_Repeat', 'cleanCalendar');
 +
 +OCP\Util::addscript('calendar','loader');
 +OCP\Util::addscript("3rdparty", "chosen/chosen.jquery.min");
 +OCP\Util::addStyle("3rdparty", "chosen/chosen");
 +OCP\Util::addStyle('3rdparty/miniColors', 'jquery.miniColors');
 +OCP\Util::addscript('3rdparty/miniColors', 'jquery.miniColors.min');
 +OCP\App::addNavigationEntry( array(
 +  'id' => 'calendar_index',
 +  'order' => 10,
 +  'href' => OCP\Util::linkTo( 'calendar', 'index.php' ),
 +  'icon' => OCP\Util::imagePath( 'calendar', 'calendar.svg' ),
 +  'name' => $l->t('Calendar')));
 +OC_Search::registerProvider('OC_Search_Provider_Calendar');
 +OCP\Share::registerBackend('calendar', 'OC_Share_Backend_Calendar');
 +OCP\Share::registerBackend('event', 'OC_Share_Backend_Event');
 +
- if(\OCP\App::isEnabled('contacts')) {
- 	\OCP\Share::registerBackend('addressbook', 'OCA\Contacts\Share\Addressbook', 'contact');
- }
- 
 +Sabre\VObject\Property::$classMap['SUMMARY'] = 'OC\VObject\StringProperty';
 +Sabre\VObject\Property::$classMap['DESCRIPTION'] = 'OC\VObject\StringProperty';
 +Sabre\VObject\Property::$classMap['LOCATION'] = 'OC\VObject\StringProperty';
diff --cc apps/calendar/appinfo/remote.php
index a1137521,0000000..139addf
mode 100644,000000..100644
--- a/apps/calendar/appinfo/remote.php
+++ b/apps/calendar/appinfo/remote.php
@@@ -1,48 -1,0 +1,51 @@@
 +<?php
 +/**
 + * Copyright (c) 2011 Jakob Sack <mail at jakobsack.de>
 + * This file is licensed under the Affero General Public License version 3 or
 + * later.
 + * See the COPYING-README file.
 + */
 +OCP\App::checkAppEnabled('calendar');
 +
 +if(substr(OCP\Util::getRequestUri(),0,strlen(OC_App::getAppWebPath('calendar').'/caldav.php')) == OC_App::getAppWebPath('calendar'). '/caldav.php') {
 +	$baseuri = OC_App::getAppWebPath('calendar').'/caldav.php';
 +}
 +
 +// only need authentication apps
 +$RUNTIME_APPTYPES=array('authentication');
 +OC_App::loadApps($RUNTIME_APPTYPES);
++if(\OCP\App::isEnabled('contacts')) {
++	\OCP\Share::registerBackend('addressbook', 'OCA\Contacts\Share\Addressbook', 'contact');
++}
 +
 +// Backends
 +$authBackend = new OC_Connector_Sabre_Auth();
 +$principalBackend = new OC_Connector_Sabre_Principal();
 +$caldavBackend    = new OC_Connector_Sabre_CalDAV();
 +$requestBackend = new OC_Connector_Sabre_Request();
 +
 +// Root nodes
 +$Sabre_CalDAV_Principal_Collection = new Sabre_CalDAV_Principal_Collection($principalBackend);
 +$Sabre_CalDAV_Principal_Collection->disableListing = true; // Disable listening
 +
 +$calendarRoot = new OC_Connector_Sabre_CalDAV_CalendarRoot($principalBackend, $caldavBackend);
 +$calendarRoot->disableListing = true; // Disable listening
 +
 +$nodes = array(
 +	$Sabre_CalDAV_Principal_Collection,
 +	$calendarRoot,
 +	);
 +
 +// Fire up server
 +$server = new Sabre_DAV_Server($nodes);
 +$server->httpRequest = $requestBackend;
 +$server->setBaseUri($baseuri);
 +// Add plugins
 +$server->addPlugin(new Sabre_DAV_Auth_Plugin($authBackend,'ownCloud'));
 +$server->addPlugin(new Sabre_CalDAV_Plugin());
 +$server->addPlugin(new Sabre_DAVACL_Plugin());
 +$server->addPlugin(new Sabre_DAV_Browser_Plugin(false)); // Show something in the Browser, but no upload
 +$server->addPlugin(new Sabre_CalDAV_ICSExportPlugin());
 +
 +// And off we go!
 +$server->exec();
diff --cc apps/contacts/Changelog
index 61d067a,0000000..a5347d4
mode 100644,000000..100644
--- a/apps/contacts/Changelog
+++ b/apps/contacts/Changelog
@@@ -1,59 -1,0 +1,66 @@@
 +ownCloud Contacts Changelog
 +
++6.0.3
++- Some browsers showed the contact photo crop editor in upper-left corner.
++- Added test for functional localStorage.
++- Fixed CardDAV Extended MKCOL.
++- The list item for an open contact disappeared if the user clicked on "New contact".
++- Silenced annoying warning on address book sharing.
++
 +6.0.2
 +- Many improvements for groups both front- and back-end.
 +- Fix unusable app after import of contact with no name.
 +
 +6.0.1
 +- Closed potential XSS issue with group name.
 +
 +6.0
 + - Don't fire a request for every contacts when mass adding to/removing from groups.
 + - Don't have a request for each thumbnail.
 + - Only load default contact photo once.
 + - Added virtual group "Ungrouped".
 + - Groups can now be renamed. contacts#97
 + - Smoother and more failsafe importing.
 + - Rewritten backend to allow for multiple address book sources.
 + - Abstraction layer for address books and contacts.
 + - Partially ported to App Framework.
 + - Use updated app styles.
 + - Select single contacts by Ctrl/Cmd-click, or a range of contacts by Shift-click.
 + - Experimental contacts merge. Might eat kittens!
 + - Regression fixed: Address book rename added again.
 + - Regression fixed: Contacts can be moved between address books again; also with different backends. contacts#57
 +
 +5.0.8
 + - Regression fix: It is again possible to select which address book a new contact should
 +   be saved in.
 + - Regression fix: It is again possible to move contacts between address books.
 + - Fix: When users where deleted, any address books shared with them would also deleted.
 +
 +5.0.7:
 + - Feature: Delete button for single contacts in list. contacts#101
 + - Improvement: Cut ~40% off of initial rendering time.
 + - Fix: Thumbnail was not updated when changing PHOTO via CardDAV. contacts#120
 + - Fix: Drag item only worked on first drag. contacts#33
 + - Fix: The internal client side value for BDAY was malformed after adding a birthday. contacts#104
 + - Fix: URL and EMAIL event handlers reenabled: contacts#109
 + - Fix: Send correct lastModified. contacts#48 contacts#99
 + - Fix: Don't keep attaching event handler for uploaded photo. contacts#24
 + - Fix: Don't recreate default groups after user has deleted them. contacts#47
 + - Fix: Properly format and decode properties on update from 2.1. contacts#54
 + - Fix: When importing into a shared address book, groups were created for the "sharee"
 +   instead of the owner. contacts#39
 + - Fix: If a shared address book was selecting while creating a contacts a new group
 +   with the same name would be created. contacts#39
 + - Fix: Properties are now properly (un)escaped. contacts#42 contacts#7
 + - Fix: Add workaround for stale shares. core#2814 contacts#78
 + - Fix: Cached thumbnail wasn't removed when photo was delete. contacts#77
 +
 +5.0.6:
 + - Improvement: If contacts display name doesn't exists check first for ORG then EMAIL.
 + - Fix: Check for existing address books on migrate->import to avoid duplicate records..
 + - Fix: Older Firefox/Iceweasel didn't show email/tel/url because of missing outerHTML.
 + - Fix: Unescape variables in search results and generated birthday events.
 + - Fix: AddressbookProviders could have duplicate keys.
 + - Feature: Add support for IMPP:SIP aka Internet calls.
 + - Unescape variables in search results and generated birthday events.
 + - AddressbookProviders could have duplicate keys.
diff --cc apps/contacts/js/app.js
index 81443b2,0000000..85ae440
mode 100644,000000..100644
--- a/apps/contacts/js/app.js
+++ b/apps/contacts/js/app.js
@@@ -1,1644 -1,0 +1,1647 @@@
 +Modernizr.load({
 +	test: Modernizr.input.placeholder,
 +	nope: [
 +			OC.filePath('contacts', 'css', 'placeholder_polyfill.min.css'),
 +			OC.filePath('contacts', 'js', 'placeholder_polyfill.jquery.min.combo.js')
 +		]
 +});
 +
 +(function($) {
 +	$.QueryString = (function(a) {
 +		if (a == "") return {};
 +		var b = {};
 +		for (var i = 0; i < a.length; ++i)
 +		{
 +			var p=a[i].split('=');
 +			if (p.length != 2) continue;
 +			b[p[0]] = decodeURIComponent(p[1].replace(/\+/g, " "));
 +		}
 +		return b;
 +	})(window.location.search.substr(1).split('&'))
 +})(jQuery);
 +
 +var utils = {};
 +
 +/**
 + * utils.isArray
 + *
 + * Best guess if object is an array.
 + */
 +utils.isArray = function(obj) {
 +     // do an instanceof check first
 +     if (obj instanceof Array) {
 +         return true;
 +     }
 +     // then check for obvious falses
 +     if (typeof obj !== 'object') {
 +         return false;
 +     }
 +     if (utils.type(obj) === 'array') {
 +         return true;
 +     }
 +     return false;
 +};
 +
 +utils.isInt = function(s) {
 +  return typeof s === 'number' && (s.toString().search(/^-?[0-9]+$/) === 0);
 +};
 +
 +utils.isUInt = function(s) {
 +  return typeof s === 'number' && (s.toString().search(/^[0-9]+$/) === 0);
 +};
 +
 +/**
 + * utils.type
 + *
 + * Attempt to ascertain actual object type.
 + */
 +utils.type = function(obj) {
 +    if (obj === null || typeof obj === 'undefined') {
 +        return String (obj);
 +    }
 +    return Object.prototype.toString.call(obj)
 +        .replace(/\[object ([a-zA-Z]+)\]/, '$1').toLowerCase();
 +};
 +
 +utils.moveCursorToEnd = function(el) {
 +	if (typeof el.selectionStart === 'number') {
 +		el.selectionStart = el.selectionEnd = el.value.length;
 +	} else if (typeof el.createTextRange !== 'undefined') {
 +		el.focus();
 +		var range = el.createTextRange();
 +		range.collapse(false);
 +		range.select();
 +	}
 +};
 +
 +Array.prototype.clone = function() {
 +  return this.slice(0);
 +};
 +
 +Array.prototype.clean = function(deleteValue) {
 +	var arr = this.clone();
 +	for (var i = 0; i < arr.length; i++) {
 +		if (arr[i] == deleteValue) {
 +			arr.splice(i, 1);
 +			i--;
 +		}
 +	}
 +	return arr;
 +};
 +
 +// Keep it DRY ;)
 +var wrongKey = function(event) {
 +	return ((event.type === 'keydown' || event.type === 'keypress') 
 +		&& (event.keyCode !== 32 && event.keyCode !== 13));
 +};
 +
 +/**
 + * Simply notifier
 + * Arguments:
 + * @param string message - The text message to show.
 + * @param int timeout - The timeout in seconds before the notification disappears. Default 10.
 + * @param function timeouthandler - A function to run on timeout.
 + * @param function clickhandler - A function to run on click. If a timeouthandler is given it will be cancelled on click.
 + * @param object data - An object that will be passed as argument to the timeouthandler and clickhandler functions.
 + * @param bool cancel - If set cancel all ongoing timer events and hide the notification.
 + */
 +OC.notify = function(params) {
 +	var self = this;
 +	if(!self.notifier) {
 +		self.notifier = $('#notification');
 +		self.notifier.on('click', function() { $(this).fadeOut();});
 +	}
 +	if(params.cancel) {
 +		self.notifier.off('click');
 +		for(var id in self.notifier.data()) {
 +			if($.isNumeric(id)) {
 +				clearTimeout(parseInt(id));
 +			}
 +		}
 +		self.notifier.text('').fadeOut().removeData();
 +	}
 +	if(params.message) {
 +		self.notifier.text(params.message).fadeIn().css('display', 'inline');
 +	}
 +
 +	var timer = setTimeout(function() {
 +		self.notifier.fadeOut();
 +		if(params.timeouthandler && $.isFunction(params.timeouthandler)) {
 +			params.timeouthandler(self.notifier.data(dataid));
 +			self.notifier.off('click');
 +			self.notifier.removeData(dataid);
 +		}
 +	}, params.timeout && $.isNumeric(params.timeout) ? parseInt(params.timeout)*1000 : 10000);
 +	var dataid = timer.toString();
 +	if(params.data) {
 +		self.notifier.data(dataid, params.data);
 +	}
 +	if(params.clickhandler && $.isFunction(params.clickhandler)) {
 +		self.notifier.on('click', function() {
 +			clearTimeout(timer);
 +			self.notifier.off('click');
 +			params.clickhandler(self.notifier.data(dataid));
 +			self.notifier.removeData(dataid);
 +		});
 +	}
 +};
 +
 +
 +OC.Contacts = OC.Contacts || {
 +	init:function() {
 +		if(oc_debug === true) {
 +			$.error = console.error;
 +		}
 +		var self = this;
 +
 +		this.lastSelectedContacts = [];
 +		this.scrollTimeoutMiliSecs = 100;
 +		this.isScrolling = false;
 +		this.cacheElements();
 +		this.storage = new OC.Contacts.Storage();
 +		this.addressBooks = new OC.Contacts.AddressBookList(
 +			this.storage,
 +			$('#app-settings-content'),
 +			$('#addressBookTemplate')
 +		);
 +		this.contacts = new OC.Contacts.ContactList(
 +			this.storage,
 +			this.addressBooks,
 +			this.$contactList,
 +			this.$contactListItemTemplate,
 +			this.$contactDragItemTemplate,
 +			this.$contactFullTemplate,
 +			this.detailTemplates
 +		);
 +		this.groups = new OC.Contacts.GroupList(
 +			this.storage,
 +			this.$groupList,
 +			this.$groupListItemTemplate
 +		);
 +		self.groups.loadGroups(function() {
 +			self.loading(self.$navigation, false);
 +		});
 +		// Hide the list while populating it.
 +		this.$contactList.hide();
 +		$.when(this.addressBooks.loadAddressBooks()).then(function(addressBooks) {
 +			var num = addressBooks.length;
 +			var deferreds = $(addressBooks).map(function(i, elem) {
 +				return self.contacts.loadContacts(this.getBackend(), this.getId(), this.isActive());
 +			});
 +			// This little beauty is from http://stackoverflow.com/a/6162959/373007 ;)
 +			$.when.apply(null, deferreds.get()).then(function(response) {
 +				self.contacts.setSortOrder(contacts_sortby);
 +				self.$contactList.show();
 +				$(document).trigger('status.contacts.loaded', {
 +					numcontacts: self.contacts.length
 +				});
 +				self.loading(self.$rightContent, false);
 +				// TODO: Move this to event handler
 +				self.groups.selectGroup({id:contacts_lastgroup});
 +				var id = $.QueryString['id']; // Keep for backwards compatible links.
 +				if(!id) {
 +					id = window.location.hash.substr(1);
 +				}
 +				console.log('Groups loaded, id from url:', id);
 +				if(id) {
 +					self.openContact(id);
 +				}
 +				if(!contacts_properties_indexed) {
 +					// Wait a couple of mins then check if contacts are indexed.
 +					setTimeout(function() {
 +							$.when($.post(OC.Router.generate('contacts_index_properties')))
 +								.then(function(response) {
 +									if(!response.isIndexed) {
 +										OC.notify({message:t('contacts', 'Indexing contacts'), timeout:20});
 +									}
 +								});
 +					}, 10000);
 +				} else {
 +					console.log('contacts are indexed.');
 +				}
 +			}).fail(function(response) {
 +				console.warn(response);
 +				self.$rightContent.removeClass('loading');
 +				message = t('contacts', 'Unrecoverable error loading address books: {msg}', {msg:response.message});
 +				OC.dialogs.alert(message, t('contacts', 'Error.'));
 +			});
 +		}).fail(function(response) {
 +			console.log(response.message);
 +			$(document).trigger('status.contacts.error', response);
 +		});
 +		$(OC.Tags).on('change', this.groups.categoriesChanged)
 +		this.bindEvents();
 +		this.$toggleAll.show();
 +		this.hideActions();
 +	},
 +	loading:function(obj, state) {
 +		$(obj).toggleClass('loading', state);
 +	},
 +	/**
 +	 * Show/hide elements in the header
 +	 * @param act An array of actions to show based on class name e.g ['add', 'delete']
 +	 */
 +	hideActions:function() {
 +		this.showActions(false);
 +	},
 +	showActions:function(act) {
 +		console.log('showActions', act);
 +		//console.trace();
 +		this.$headeractions.children().hide();
 +		if(act && act.length > 0) {
 +			this.$contactList.addClass('multiselect');
 +			this.$contactListHeader.find('.actions').show();
 +			this.$contactListHeader.find('.info').hide();
 +			this.$headeractions.children('.'+act.join(',.')).show();
 +		} else {
 +			this.$contactListHeader.find('.actions').hide();
 +			this.$contactListHeader.find('.info').show();
 +			this.$contactList.removeClass('multiselect');
 +		}
 +	},
 +	showAction:function(act, show) {
 +		this.$headeractions.find('.' + act).toggle(show);
 +	},
 +	cacheElements: function() {
 +		var self = this;
 +		this.detailTemplates = {};
 +		// Load templates for contact details.
 +		// The weird double loading is because jquery apparently doesn't
 +		// create a searchable object from a script element.
 +		$.each($($('#contactDetailsTemplate').html()), function(idx, node) {
 +			var $node = $(node);
 +			if($node.is('div')) {
 +				var $tmpl = $(node.innerHTML);
 +				self.detailTemplates[$tmpl.data('element')] = $node;
 +			}
 +		});
 +		this.$groupListItemTemplate = $('#groupListItemTemplate');
 +		this.$contactListItemTemplate = $('#contactListItemTemplate');
 +		this.$contactDragItemTemplate = $('#contactDragItemTemplate');
 +		this.$contactFullTemplate = $('#contactFullTemplate');
 +		this.$contactDetailsTemplate = $('#contactDetailsTemplate');
 +		this.$rightContent = $('#app-content');
 +		this.$navigation = $('#app-navigation');
 +		//this.$header = $('#contactsheader');
 +		this.$groupList = $('#grouplist');
 +		this.$contactList = $('#contactlist');
 +		this.$contactListHeader = $('#contactsHeader');
 +		this.$sortOrder = this.$contactListHeader.find('.action.sort');
 +		this.$sortOrder.val(contacts_sortby||'fn');
 +		this.$headeractions = this.$contactListHeader.find('.actions');
 +		this.$toggleAll = this.$contactListHeader.find('.toggle');
 +		this.$groups = this.$headeractions.find('.groups');
 +		this.$ninjahelp = $('#ninjahelp');
 +		this.$firstRun = $('#firstrun');
 +		this.$settings = $('#app-settings');
 +	},
 +	// Build the select to add/remove from groups.
 +	buildGroupSelect: function() {
 +		// If a contact is open we know which categories it's in
 +		if(this.currentid) {
 +			var contact = this.contacts.findById(this.currentid);
 +			if(contact === null) {
 +				return false;
 +			}
 +			this.$groups.find('optgroup,option:not([value="-1"])').remove();
 +			var addopts = '', rmopts = '';
 +			$.each(this.groups.categories, function(i, category) {
 +				if(contact.inGroup(category.name)) {
 +					rmopts += '<option value="' + category.id + '">' + category.name + '</option>';
 +				} else {
 +					addopts += '<option value="' + category.id + '">' + category.name + '</option>';
 +				}
 +			});
 +			if(addopts.length) {
 +				$(addopts).appendTo(this.$groups)
 +				.wrapAll('<optgroup data-action="add" label="' + t('contacts', 'Add to...') + '"/>');
 +			}
 +			if(rmopts.length) {
 +				$(rmopts).appendTo(this.$groups)
 +				.wrapAll('<optgroup data-action="remove" label="' + t('contacts', 'Remove from...') + '"/>');
 +			}
 +		} else if(this.contacts.getSelectedContacts().length > 0) { // Otherwise add all categories to both add and remove
 +			this.$groups.find('optgroup,option:not([value="-1"])').remove();
 +			var addopts = '', rmopts = '';
 +			$.each(this.groups.categories, function(i, category) {
 +				rmopts += '<option value="' + category.id + '">' + category.name + '</option>';
 +				addopts += '<option value="' + category.id + '">' + category.name + '</option>';
 +			});
 +			$(addopts).appendTo(this.$groups)
 +				.wrapAll('<optgroup data-action="add" label="' + t('contacts', 'Add to...') + '"/>');
 +			$(rmopts).appendTo(this.$groups)
 +				.wrapAll('<optgroup data-action="remove" label="' + t('contacts', 'Remove from...') + '"/>');
 +		} else {
 +			// 3rd option: No contact open, none checked, just show "Add group..."
 +			this.$groups.find('optgroup,option:not([value="-1"])').remove();
 +		}
 +		$('<option value="add">' + t('contacts', 'Add group...') + '</option>').appendTo(this.$groups);
 +		this.$groups.val(-1);
 +	},
 +	bindEvents: function() {
 +		var self = this;
 +
 +		// Should fix Opera check for delayed delete.
 +		$(window).unload(function (){
 +			$(window).trigger('beforeunload');
 +		});
 +
 +		this.hashChange = function() {
 +			console.log('hashchange', window.location.hash)
 +			var id = String(window.location.hash.substr(1));
 +			if(id && id != self.currentid && self.contacts.findById(id) !== null) {
 +				self.openContact(id);
 +			} else if(!id && self.currentid) {
 +				self.closeContact(self.currentid);
 +			}
 +		}
 +
 +		// This apparently get's called on some weird occasions.
 +		//$(window).bind('popstate', this.hashChange);
 +		$(window).bind('hashchange', this.hashChange);
 +		
 +		// App specific events
 +		$(document).bind('status.contact.deleted', function(e, data) {
 +			var id = String(data.id);
 +			if(id == self.currentid) {
 +				delete self.currentid;
 +			}
 +			console.log('contact', data.id, 'deleted');
 +			// update counts on group lists
 +			self.groups.removeFromAll(data.id, true, true);
 +		});
 +
 +		$(document).bind('status.contact.added', function(e, data) {
 +			self.currentid = String(data.id);
 +			self.buildGroupSelect();
 +			self.hideActions();
 +		});
 +
 +		// Keep error messaging at one place to be able to replace it.
 +		$(document).bind('status.contacts.error', function(e, data) {
 +			var message = data.message || data;
 +			console.warn(message);
 +			//console.trace();
 +			OC.notify({message:message});
 +		});
 +
 +		$(document).bind('status.contact.enabled', function(e, enabled) {
 +			console.log('status.contact.enabled', enabled);
 +			/*if(enabled) {
 +				self.showActions(['back', 'download', 'delete', 'groups']);
 +			} else {
 +				self.showActions(['back']);
 +			}*/
 +		});
 +
 +		$(document).bind('status.contacts.count', function(e, response) {
 +			console.log('Num contacts:', response.count);
 +			if(response.count > 0) {
 +				self.$contactList.show();
 +				self.$firstRun.hide();
 +			}
 +		});
 +
 +		$(document).bind('status.contacts.loaded status.contacts.deleted', function(e, response) {
 +			console.log('status.contacts.loaded', response);
 +			if(response.error) {
 +				$(document).trigger('status.contacts.error', response);
 +				console.log('Error loading contacts!');
 +			} else {
 +				if(response.numcontacts === 0) {
 +					self.$contactListHeader.hide();
 +					self.$contactList.hide();
 +					self.$firstRun.show();
 +				} else {
 +					self.$contactListHeader.show();
 +					self.$contactList.show();
 +					self.$firstRun.hide();
 +				$.each(self.addressBooks.addressBooks, function(idx, addressBook) {
 +					console.log('addressBook', addressBook);
 +					if(!addressBook.isActive()) {
 +						self.contacts.showFromAddressbook(addressBook.getId(), false);
 +					}
 +				});
 +				}
 +			}
 +		});
 +
 +		$(document).bind('status.contact.currentlistitem', function(e, result) {
 +			//console.log('status.contact.currentlistitem', result, self.$rightContent.height());
 +			if(self.dontScroll !== true) {
 +				if(result.pos > self.$rightContent.height()) {
 +					self.$rightContent.scrollTop(result.pos - self.$rightContent.height() + result.height);
 +				}
 +				else if(result.pos < self.$rightContent.offset().top) {
 +					self.$rightContent.scrollTop(result.pos);
 +				}
 +			} else {
 +				setTimeout(function() {
 +					self.dontScroll = false;
 +				}, 100);
 +			}
 +			self.currentlistid = result.id;
 +		});
 +
 +		$(document).bind('status.nomorecontacts', function(e, result) {
 +			console.log('status.nomorecontacts', result);
 +			self.$contactList.hide();
 +			self.$firstRun.show();
 +		});
 +
 +		$(document).bind('status.visiblecontacts', function(e, result) {
 +			console.log('status.visiblecontacts', result);
 +			// TODO: To be decided.
 +		});
 +
 +		$(document).bind('request.openurl', function(e, data) {
 +			switch(data.type) {
 +				case 'url':
 +					var regexp = /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!-\/]))?/;
 +					//if(new RegExp("[a-zA-Z0-9]+://([a-zA-Z0-9_]+:[a-zA-Z0-9_]+@)?([a-zA-Z0-9.-]+\\.[A-Za-z]{2,4})(:[0-9]+)?(/.*)?").test(data.url)) {
 +					if(regexp.test(data.url)) {
 +						var newWindow = window.open(data.url,'_blank');
 +						newWindow.focus();
 +					} else {
 +						$(document).trigger('status.contacts.error', {
 +							error: true,
 +							message: t('contacts', 'Invalid URL: "{url}"', {url:data.url})
 +						});
 +					}
 +					break;
 +				case 'email':
 +					var regexp = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;
 +					if(regexp.test(data.url)) {
 +						console.log('success');
 +						try {
 +							window.location = 'mailto:' + data.url;
 +						} catch(e) {
 +							alert(t('contacts', 'There was an error opening a mail composer.'));
 +						}
 +					} else {
 +						$(document).trigger('status.contacts.error', {
 +							error: true,
 +							message: t('contacts', 'Invalid email: "{url}"', {url:data.url})
 +						});
 +					}
 +					break;
 +				case 'adr':
 +					address = data.url.filter(function(n){return n});
 +					var newWindow = window.open('http://open.mapquest.com/?q='+address, '_blank');
 +					newWindow.focus();
 +					break;
 +			}
 +		});
 +
 +		// A contact id was in the request
 +		$(document).bind('request.loadcontact', function(e, result) {
 +			console.log('request.loadcontact', result);
 +			if(self.numcontacts) {
 +				self.openContact(result.id);
 +			} else {
 +				// Contacts are not loaded yet, try again.
 +				console.log('waiting for contacts to load');
 +				setTimeout(function() {
 +					$(document).trigger('request.loadcontact', {
 +						id: result.id
 +					});
 +				}, 1000);
 +			}
 +		});
 +
 +		$(document).bind('request.contact.move', function(e, data) {
 +			console.log('contact', data, 'request.contact.move');
 +			var from = self.addressBooks.find(data.from);
 +			var to = self.addressBooks.find(data.target);
 +			self.addressBooks.moveContact(data.contact, data.from, data.target);
 +		});
 +
 +		$(document).bind('request.contact.setasfavorite', function(e, data) {
 +			console.log('contact', data.id, 'request.contact.setasfavorite');
 +			self.groups.setAsFavorite(data.id, data.state);
 +		});
 +
 +		$(document).bind('request.contact.addtogroup', function(e, data) {
 +			self.groups.addTo(data.id, data.groupid, function(response) {
 +				console.log('contact', data.id, 'request.contact.addtogroup', response);
 +			});
 +		});
 +
 +		$(document).bind('request.contact.removefromgroup', function(e, data) {
 +			console.log('contact', data.id, 'request.contact.removefromgroup');
 +			self.groups.removeFrom(data.id, data.groupid);
 +		});
 +
 +		$(document).bind('request.contact.export', function(e, data) {
 +			console.log('request.contact.export', data);
 +			document.location.href = OC.Router.generate('contacts_contact_export', data);
 +		});
 +
 +		$(document).bind('request.contact.close', function(e, data) {
 +			var id = String(data.id);
 +			console.log('contact', data.id, 'request.contact.close');
 +			self.closeContact(id);
 +		});
 +
 +		$(document).bind('request.contact.open', function(e, data) {
 +			var id = String(data.id);
 +			console.log('contact', data.id, 'request.contact.open');
 +			self.openContact(id);
 +		});
 +
 +		$(document).bind('request.contact.delete', function(e, data) {
 +			var id = String(data.contactId);
 +			console.log('contact', data, 'request.contact.delete');
 +			self.closeContact(id);
 +			self.contacts.delayedDelete(data);
 +			self.$contactList.removeClass('dim');
 +			self.hideActions();
 +		});
 +
 +		$(document).bind('request.contact.merge', function(e, data) {
 +			console.log('contact','request.contact.merge', data);
 +			var merger = self.contacts.findById(data.merger);
 +			var mergees = [];
 +			if(!merger) {
 +				$(document).trigger('status.contacts.error', {
 +					message: t('contacts', 'Merge failed. Cannot find contact: {id}', {id:data.merger})
 +				});
 +				return;
 +			}
 +			$.each(data.mergees, function(idx, id) {
 +				var contact = self.contacts.findById(id);
 +				if(!contact) {
 +					console.warn('cannot find', id, 'by id');
 +				}
 +				mergees.push(contact);
 +			});
 +			if(!merger.merge(mergees)) {
 +				$(document).trigger('status.contacts.error', {
 +					message: t('contacts', 'Merge failed.')
 +				});
 +				return;
 +			}
 +			merger.saveAll(function(response) {
 +				if(response.error) {
 +					$(document).trigger('status.contacts.error', {
 +						message: t('contacts', 'Merge failed. Error saving contact.')
 +					});
 +					return;
 +				} else {
 +					if(data.deleteOther) {
 +						self.contacts.delayedDelete(mergees);
 +					}
 +					console.log('merger', merger);
 +					self.openContact(merger.getId());
 +				}
 +			});
 +		});
 +
 +		$(document).bind('request.select.contactphoto.fromlocal', function(e, metadata) {
 +			console.log('request.select.contactphoto.fromlocal', metadata);
 +			$('#contactphoto_fileupload').trigger('click', metadata);
 +		});
 +
 +		$(document).bind('request.select.contactphoto.fromcloud', function(e, metadata) {
 +			console.log('request.select.contactphoto.fromcloud', metadata);
 +			OC.dialogs.filepicker(t('contacts', 'Select photo'), function(path) {
 +				self.cloudPhotoSelected(metadata, path);
 +			}, false, 'image', true);
 +		});
 +
 +		$(document).bind('request.edit.contactphoto', function(e, metadata) {
 +			console.log('request.edit.contactphoto', metadata);
 +			self.editCurrentPhoto(metadata);
 +		});
 +
 +		$(document).bind('request.groups.reload', function(e, result) {
 +			console.log('request.groups.reload', result);
 +			self.groups.loadGroups(function() {
 +				self.groups.triggerLastGroup();
 +			});
 +		});
 +
 +		$(document).bind('status.group.groupremoved', function(e, result) {
 +			console.log('status.group.groupremoved', result);
 +			if(parseInt(result.groupid) === parseInt(self.currentgroup)) {
 +				self.contacts.showContacts([]);
 +				self.currentgroup = 'all';
 +			}
 +			$.each(result.contacts, function(idx, contactid) {
 +				var contact = self.contacts.findById(contactid);
 +
- 				contact.removeFromGroup(result.groupname);
++				// Test if valid because there could be stale ids in the tag index.
++				if(contact) {
++					contact.removeFromGroup(result.groupname);
++				}
 +			});
 +		});
 +
 +		$(document).bind('status.group.grouprenamed', function(e, result) {
 +			console.log('status.group.grouprenamed', result);
 +			$.each(result.contacts, function(idx, contactid) {
 +				var contact = self.contacts.findById(contactid);
 +				if(!contact) {
 +					console.warn('Couldn\'t find contact', contactid)
 +					return true; // continue
 +				}
 +				contact.renameGroup(result.from, result.to);
 +			});
 +		});
 +
 +		$(document).bind('status.group.contactremoved', function(e, result) {
 +			console.log('status.group.contactremoved', result, self.currentgroup, result.groupid);
 +			var contact = self.contacts.findById(result.contactid);
 +			if(contact) {
 +				if(contact.inGroup(result.groupname)) {
 +					contact.removeFromGroup(result.groupname);
 +				}
 +				if(parseInt(self.currentgroup) === parseInt(result.groupid)) {
 +					console.log('Hiding', contact.getId());
 +					contact.hide();
 +				}
 +			}
 +		});
 +
 +		$(document).bind('status.group.contactadded', function(e, result) {
 +			console.log('status.group.contactadded', result);
 +			var contact = self.contacts.findById(result.contactid);
 +			if(contact) {
 +				if(!contact.inGroup(result.groupname)) {
 +					contact.addToGroup(result.groupname);
 +				}
 +				if(parseInt(self.currentgroup) === parseInt(result.groupid)) {
 +					console.log('Showing', contact.getId());
 +					contact.show();
 +				}
 +				if(self.currentgroup === 'uncategorized') {
 +					console.log('Hiding', contact.getId());
 +					contact.hide();
 +				}
 +			}
 +		});
 +
 +		// Group sorted, save the sort order
 +		$(document).bind('status.groups.sorted', function(e, result) {
 +			console.log('status.groups.sorted', result);
 +			$.when(self.storage.setPreference('groupsort', result.sortorder)).then(function(response) {
 +				if(response.error) {
 +					$(document).trigger('status.contacts.error', {
 +						message: response ? response.message : t('contacts', 'Network or server error. Please inform administrator.')
 +					});
 +				}
 +			})
 +			.fail(function(response) {
 +				console.log(response.message);
 +				$(document).trigger('status.contacts.error', response);
 +				done = true;
 +			});
 +		});
 +		// Group selected, only show contacts from that group
 +		$(document).bind('status.group.selected', function(e, result) {
 +			console.log('status.group.selected', result);
 +			self.currentgroup = result.id;
 +			// Close any open contact.
 +			if(self.currentid) {
 +				var id = self.currentid;
 +				self.closeContact(id);
 +				self.jumpToContact(id);
 +			}
 +			self.$contactList.show();
 +			self.$toggleAll.show();
 +			self.hideActions();
 +			if(result.type === 'category' ||  result.type === 'fav') {
 +				self.contacts.showContacts(result.contacts);
 +			} else if(result.type === 'shared') {
 +				self.contacts.showFromAddressbook(self.currentgroup, true, true);
 +			} else if(result.type === 'uncategorized') {
 +				self.contacts.showUncategorized();
 +			} else {
 +				self.contacts.showContacts(self.currentgroup);
 +			}
 +			$.when(self.storage.setPreference('lastgroup', self.currentgroup)).then(function(response) {
 +				if(response.error) {
 +					$(document).trigger('status.contacts.error', response);
 +				}
 +			})
 +			.fail(function(response) {
 +				console.log(response.message);
 +				$(document).trigger('status.contacts.error', response);
 +				done = true;
 +			});
 +			self.$rightContent.scrollTop(0);
 +		});
 +		// mark items whose title was hid under the top edge as read
 +		/*this.$rightContent.scroll(function() {
 +			// prevent too many scroll requests;
 +			if(!self.isScrolling) {
 +				self.isScrolling = true;
 +				var num = self.$contactList.find('tr').length;
 +				//console.log('num', num);
 +				var offset = self.$contactList.find('tr:eq(' + (num-20) + ')').offset().top;
 +				if(offset < self.$rightContent.height()) {
 +					console.log('load more');
 +					self.contacts.loadContacts(num, function() {
 +						self.isScrolling = false;
 +					});
 +				} else {
 +					setTimeout(function() {
 +						self.isScrolling = false;
 +					}, self.scrollTimeoutMiliSecs);
 +				}
 +				//console.log('scroll, unseen:', offset, self.$rightContent.height());
 +			}
 +		});*/
 +		$('#contactphoto_fileupload').on('click', function(event, metadata) {
 +			var form = $('#file_upload_form');
 +			var url = OC.Router.generate(
 +				'contacts_upload_contact_photo',
 +				{backend: metadata.backend, addressBookId: metadata.addressBookId, contactId: metadata.contactId}
 +			);
 +			form.attr('action', url);
 +		}).on('change', function() {
 +			console.log('#contactphoto_fileupload, change');
 +			self.uploadPhoto(this.files);
 +		});
 +
 +		var target = $('#file_upload_target');
 +		target.load(function() {
 +			var response = $.parseJSON(target.contents().text());
 +			if(response && response.status == 'success') {
 +				console.log('response', response);
 +				self.editPhoto(
 +					response.data.metadata,
 +					response.data.tmp
 +				);
 +				//alert('File: ' + file.tmp + ' ' + file.name + ' ' + file.mime);
 +			} else if(response) {
 +				$(document).trigger('status.contacts.error', response);
 +			}
 +		});
 +
 +		this.$ninjahelp.find('.close').on('click keydown',function(event) {
 +			if(wrongKey(event)) {
 +				return;
 +			}
 +			self.$ninjahelp.hide();
 +		});
 +
 +		this.$toggleAll.on('change', function(event) {
 +			event.stopPropagation();
 +			event.preventDefault();
 +			var isChecked = $(this).is(':checked');
 +			self.setAllChecked(isChecked);
 +			if(self.$groups.find('option').length === 1) {
 +				self.buildGroupSelect();
 +			}
 +			if(isChecked) {
 +				self.showActions(['toggle', 'add', 'download', 'groups', 'delete', 'favorite', 'merge']);
 +			} else {
 +				self.hideActions();
 +			}
 +		});
 +
 +		this.$contactList.on('change', 'input:checkbox', function(event) {
 +			var selected = self.contacts.getSelectedContacts();
 +			var id = String($(this).val());
 +			// Save list of last selected contact to be able to select range
 +			($(this).is(':checked') && self.lastSelectedContacts.indexOf(id) === -1)
 +				? self.lastSelectedContacts.push(id)
 +				: self.lastSelectedContacts.splice(self.lastSelectedContacts.indexOf(id), 1);
 +
 +			if(selected.length > 0 && self.$groups.find('option').length === 1) {
 +				self.buildGroupSelect();
 +			}
 +			if(selected.length === 0) {
 +				self.hideActions();
 +			} else if(selected.length === 1) {
 +				self.showActions(['toggle', 'add', 'download', 'groups', 'delete', 'favorite']);
 +			} else {
 +				self.showActions(['toggle', 'add', 'download', 'groups', 'delete', 'favorite', 'merge']);
 +			}
 +		});
 +
 +		this.$sortOrder.on('change', function() {
 +			$(this).blur().addClass('loading');
 +			contacts_sortby = $(this).val();
 +			self.contacts.setSortOrder();
 +			$(this).removeClass('loading');
 +			self.storage.setPreference('sortby', contacts_sortby);
 +		});
 +
 +		// Add to/remove from group multiple contacts.
 +		this.$groups.on('change', function() {
 +			var $opt = $(this).find('option:selected');
 +			var action = $opt.parent().data('action');
 +			var groupName, groupId, buildnow = false;
 +
 +			var contacts = self.contacts.getSelectedContacts();
 +			var ids = $.map(contacts, function(c) {return c.getId();});
 +
 +			self.setAllChecked(false);
 +			self.$toggleAll.prop('checked', false);
 +			if(!self.currentid) {
 +				self.hideActions();
 +			}
 +
 +			if($opt.val() === 'add') { // Add new group
 +				action = 'add';
 +				console.log('add group...');
 +				self.$groups.val(-1);
 +				self.addGroup(function(response) {
 +					if(!response.error) {
 +						groupId = response.id;
 +						groupName = response.name;
 +						self.groups.addTo(ids, groupId, function(result) {
 +							if(!result.error) {
 +								$.each(ids, function(idx, id) {
 +									// Delay each contact to not trigger too many ajax calls
 +									// at a time.
 +									setTimeout(function() {
 +										var contact = self.contacts.findById(id);
 +										if(contact === null) {
 +											return true;
 +										}
 +										contact.addToGroup(groupName);
 +										// I don't think this is used...
 +										if(buildnow) {
 +											self.buildGroupSelect();
 +										}
 +									}, 1000);
 +								});
 +							} else {
 +								$(document).trigger('status.contacts.error', result);
 +							}
 +						});
 +					} else {
 +						$(document).trigger('status.contacts.error', response);
 +					}
 +				});
 +				return;
 +			}
 +
 +			groupName = $opt.text(), groupId = $opt.val();
 +
 +			if(action === 'add') {
 +				self.groups.addTo(ids, $opt.val(), function(result) {
 +					console.log('after add', result);
 +					if(!result.error) {
 +						$.each(result.ids, function(idx, id) {
 +							// Delay each contact to not trigger too many ajax calls
 +							// at a time.
 +							setTimeout(function() {
 +								console.log('adding', id, 'to', groupName);
 +								var contact = self.contacts.findById(id);
 +								if(contact === null) {
 +									return true;
 +								}
 +								contact.addToGroup(groupName);
 +								// I don't think this is used...
 +								if(buildnow) {
 +									self.buildGroupSelect();
 +								}
 +							}, 1000);
 +						});
 +					} else {
 +						var msg = result.message ? result.message : t('contacts', 'Error adding to group.');
 +						$(document).trigger('status.contacts.error', {message:msg});
 +					}
 +				});
 +				if(!buildnow) {
 +					self.$groups.val(-1).hide().find('optgroup,option:not([value="-1"])').remove();
 +				}
 +			} else if(action === 'remove') {
 +				self.groups.removeFrom(ids, $opt.val(), false, function(result) {
 +					console.log('after remove', result);
 +					if(!result.error) {
 +						var groupname = $opt.text(), groupid = $opt.val();
 +						$.each(result.ids, function(idx, id) {
 +							var contact = self.contacts.findById(id);
 +							if(contact === null) {
 +								return true;
 +							}
 +							contact.removeFromGroup(groupname);
 +							if(buildnow) {
 +								self.buildGroupSelect();
 +							}
 +						});
 +					} else {
 +						var msg = result.message ? result.message : t('contacts', 'Error removing from group.');
 +						$(document).trigger('status.contacts.error', {message:msg});
 +					}
 +				});
 +				if(!buildnow) {
 +					self.$groups.val(-1).hide().find('optgroup,option:not([value="-1"])').remove();
 +				}
 +			} // else something's wrong ;)
 +			self.setAllChecked(false);
 +		});
 +
 +		this.$contactList.on('mouseenter', 'tr.contact', function(event) {
 +			var $td = $(this).find('td').filter(':visible').last();
 +			$('<a />').addClass('svg delete action').appendTo($td);
 +		});
 +
 +		this.$contactList.on('mouseleave', 'tr.contact', function(event) {
 +			$(this).find('a.delete').remove();
 +		});
 +
 +		// Prevent Firefox from selecting the table-cell
 +		this.$contactList.mousedown(function (event) {
 +			if (event.ctrlKey || event.metaKey || event.shiftKey) {
 +				event.preventDefault();
 +			}
 +		});
 +
 +		// Contact list. Either open a contact or perform an action (mailto etc.)
 +		this.$contactList.on('click', 'tr.contact', function(event) {
 +			if($(event.target).is('input')) {
 +				return;
 +			}
 +			// Select a single contact or a range of contacts.
 +			if(event.ctrlKey || event.metaKey || event.shiftKey) {
 +				event.stopPropagation();
 +				event.preventDefault();
 +				self.dontScroll = true;
 +				var $input = $(this).find('input:checkbox');
 +				var index = self.$contactList.find('tr.contact:visible').index($(this));
 +				if(event.shiftKey && self.lastSelectedContacts.length > 0) {
 +					self.contacts.selectRange(
 +						$(this).data('id'),
 +						self.lastSelectedContacts[self.lastSelectedContacts.length-1]
 +					);
 +				} else {
 +					self.contacts.setSelected($(this).data('id'), !$input.prop('checked'));
 +				}
 +				return;
 +			}
 +			if($(event.target).is('a.mailto')) {
 +				$(document).trigger('request.openurl', {
 +					type: 'email',
 +					url: $.trim($(this).find('.email').text())
 +				});
 +				return;
 +			}
 +			if($(event.target).is('a.delete')) {
 +				$(document).trigger('request.contact.delete', {
 +					contactId: $(this).data('id')
 +				});
 +				return;
 +			}
 +			self.openContact(String($(this).data('id')));
 +		});
 +
 +		this.$settings.find('#app-settings-header').on('click keydown',function(event) {
 +			if(wrongKey(event)) {
 +				return;
 +			}
 +			var bodyListener = function(e) {
 +				if(self.$settings.find($(e.target)).length == 0) {
 +					self.$settings.switchClass('open', '');
 +				}
 +			};
 +			if(self.$settings.hasClass('open')) {
 +				self.$settings.switchClass('open', '');
 +				$('body').unbind('click', bodyListener);
 +			} else {
 +				self.$settings.switchClass('', 'open');
 +				$('body').bind('click', bodyListener);
 +			}
 +		});
 +
 +		var addContact = function() {
 +			console.log('add');
 +			self.$toggleAll.hide();
 +			if(self.currentid) {
 +				if(self.currentid === 'new') {
 +					return;
 +				} else {
 +					var contact = self.contacts.findById(self.currentid);
 +					if(contact) {
- 						contact.close();
++						contact.close(true);
 +					}
 +				}
 +			}
 +			self.currentid = 'new';
 +			// Properties that the contact doesn't know
 +			console.log('addContact, groupid', self.currentgroup);
 +			var groupprops = {
 +				favorite: false,
 +				groups: self.groups.categories,
 +				currentgroup: {id:self.currentgroup, name:self.groups.nameById(self.currentgroup)}
 +			};
 +			self.$firstRun.hide();
 +			self.$contactList.show();
 +			self.tmpcontact = self.contacts.addContact(groupprops);
 +			self.tmpcontact.prependTo(self.$contactList.find('tbody')).show().find('.fullname').focus();
 +			self.$rightContent.scrollTop(0);
 +			self.hideActions();
 +		};
 +
 +		this.$firstRun.on('click keydown', '.import', function(event) {
 +			event.preventDefault();
 +			event.stopPropagation();
 +			self.$settings.find('.settings').click();
 +		});
 +
 +		this.$firstRun.on('click keydown', '.add-contact', function(event) {
 +			if(wrongKey(event)) {
 +				return;
 +			}
 +			addContact();
 +		});
 +
 +		this.$groupList.on('click keydown', '.add-contact', function(event) {
 +			if(wrongKey(event)) {
 +				return;
 +			}
 +			addContact();
 +		});
 +
 +		this.$contactListHeader.on('click keydown', '.delete', function(event) {
 +			if(wrongKey(event)) {
 +				return;
 +			}
 +			console.log('delete');
 +			if(self.currentid) {
 +				console.assert(typeof self.currentid === 'string', 'self.currentid is not a string');
 +				contactInfo = self.contacts[self.currentid].metaData();
 +				self.contacts.delayedDelete(contactInfo);
 +			} else {
 +				self.contacts.delayedDelete(self.contacts.getSelectedContacts());
 +			}
 +			self.hideActions();
 +		});
 +
 +		this.$contactListHeader.on('click keydown', '.download', function(event) {
 +			if(wrongKey(event)) {
 +				return;
 +			}
 +
 +			var doDownload = function(contacts) {
 +				// Only get backend, addressbookid and contactid
 +				contacts = $.map(contacts, function(c) {return c.metaData();});
 +				var targets = {};
 +				// Try to shorten request URI
 +				$.each(contacts, function(idx, contact) {
 +					if(!targets[contact.backend]) {
 +						targets[contact.backend] = {};
 +					}
 +					if(!targets[contact.backend][contact.addressBookId]) {
 +						targets[contact.backend][contact.addressBookId] = [];
 +					}
 +					targets[contact.backend][contact.addressBookId].push(contact.contactId);
 +				});
 +				var url = OC.Router.generate('contacts_export_selected', {t:targets});
 +				//console.log('export url', url);
 +				document.location.href = url;
 +			};
 +			var contacts = self.contacts.getSelectedContacts();
 +			console.log('download', contacts.length);
 +
 +			// The 300 is just based on my little testing with Apache2
 +			// Other web servers may fail before.
 +			if(contacts.length > 300) {
 +				OC.notify({
 +					message:t('contacts',"You have selected over 300 contacts.\nThis will most likely fail! Click here to try anyway."),
 +					timeout:5,
 +					clickhandler:function() {
 +						doDownload(contacts);
 +					}
 +				});
 +			} else {
 +				doDownload(contacts);
 +			}
 +		});
 +
 +		this.$contactListHeader.on('click keydown', '.merge', function(event) {
 +			if(wrongKey(event)) {
 +				return;
 +			}
 +			console.log('merge');
 +			self.mergeSelectedContacts();
 +		});
 +
 +		this.$contactListHeader.on('click keydown', '.favorite', function(event) {
 +			if(wrongKey(event)) {
 +				return;
 +			}
 +
 +			var contacts = self.contacts.getSelectedContacts();
 +
 +			self.setAllChecked(false);
 +			self.$toggleAll.prop('checked', false);
 +			if(!self.currentid) {
 +				self.hideActions();
 +			}
 +
 +			$.each(contacts, function(idx, contact) {
 +				if(!self.groups.isFavorite(contact.getId())) {
 +					self.groups.setAsFavorite(contact.getId(), true, function(result) {
 +						if(result.status !== 'success') {
 +							$(document).trigger('status.contacts.error', {message:
 +								t('contacts',
 +									'Error setting {name} as favorite.',
 +									{name:contact.getDisplayName()})
 +							});
 +						}
 +					});
 +				}
 +			});
 +
 +			self.hideActions();
 +		});
 +
 +		this.$contactList.on('mouseenter', 'td.email', function(event) {
 +			if($.trim($(this).text()).length > 3) {
 +				$(this).find('.mailto').css('display', 'inline-block'); //.fadeIn(100);
 +			}
 +		});
 +		this.$contactList.on('mouseleave', 'td.email', function(event) {
 +			$(this).find('.mailto').fadeOut(100);
 +		});
 +
 +		$('body').on('touchmove', function(event) {
 +			event.preventDefault();
 +		});
 +		
 +		$(document).on('keyup', function(event) {
 +			if(!$(event.target).is('body') || event.isPropagationStopped()) {
 +				return;
 +			}
 +			var keyCode = Math.max(event.keyCode, event.which);
 +			// TODO: This should go in separate method
 +			console.log(event, keyCode + ' ' + event.target.nodeName);
 +			/**
 +			* To add:
 +			* Shift-a: add addressbook
 +			* u (85): hide/show leftcontent
 +			* f (70): add field
 +			*/
 +			switch(keyCode) {
 +				case 13: // Enter?
 +					console.log('Enter?');
 +					if(!self.currentid && self.currentlistid) {
 +						self.openContact(self.currentlistid);
 +					}
 +					break;
 +				case 27: // Esc
 +					if(self.$ninjahelp.is(':visible')) {
 +						self.$ninjahelp.hide();
 +					} else if(self.currentid) {
 +						self.closeContact(self.currentid);
 +					}
 +					break;
 +				case 46: // Delete
 +					if(event.shiftKey) {
 +						self.contacts.delayedDelete(self.currentid);
 +					}
 +					break;
 +				case 40: // down
 +				case 74: // j
 +					console.log('next');
 +					if(!self.currentid && self.currentlistid) {
 +						self.contacts.contacts[self.currentlistid].next();
 +					}
 +					break;
 +				case 65: // a
 +					if(event.shiftKey) {
 +						console.log('add group?');
 +						break;
 +					}
 +					self.addContact();
 +					break;
 +				case 38: // up
 +				case 75: // k
 +					console.log('previous');
 +					if(!self.currentid && self.currentlistid) {
 +						self.contacts.contacts[self.currentlistid].prev();
 +					}
 +					break;
 +				case 34: // PageDown
 +				case 78: // n
 +					console.log('page down');
 +					break;
 +				case 79: // o
 +					console.log('open contact?');
 +					break;
 +				case 33: // PageUp
 +				case 80: // p
 +					// prev addressbook
 +					//OC.contacts.contacts.previousAddressbook();
 +					break;
 +				case 82: // r
 +					console.log('refresh - what?');
 +					break;
 +				case 63: // ? German.
 +					if(event.shiftKey) {
 +						self.$ninjahelp.toggle('fast');
 +					}
 +					break;
 +				case 171: // ? Danish
 +				case 191: // ? Standard qwerty
 +					self.$ninjahelp.toggle('fast').position({my: "center",at: "center",of: "#content"});
 +					break;
 +			}
 +
 +		});
 +
 +		// find all with a title attribute and tipsy them
 +		$('.tooltipped.downwards:not(.onfocus)').tipsy({gravity: 'n'});
 +		$('.tooltipped.upwards:not(.onfocus)').tipsy({gravity: 's'});
 +		$('.tooltipped.rightwards:not(.onfocus)').tipsy({gravity: 'w'});
 +		$('.tooltipped.leftwards:not(.onfocus)').tipsy({gravity: 'e'});
 +		$('.tooltipped.downwards.onfocus').tipsy({trigger: 'focus', gravity: 'n'});
 +		$('.tooltipped.rightwards.onfocus').tipsy({trigger: 'focus', gravity: 'w'});
 +	},
 +	mergeSelectedContacts: function() {
 +		var contacts = this.contacts.getSelectedContacts();
 +		var self = this;
 +		this.$rightContent.append('<div id="merge_contacts_dialog"></div>');
 +		if(!this.$mergeContactsTmpl) {
 +			this.$mergeContactsTmpl = $('#mergeContactsTemplate');
 +		}
 +		var $dlg = this.$mergeContactsTmpl.octemplate();
 +		var $liTmpl = $dlg.find('li').detach();
 +		var $mergeList = $dlg.find('.mergelist');
 +		$.each(contacts, function(idx, contact) {
 +			var $li = $liTmpl
 +				.octemplate({idx: idx, id: contact.getId(), displayname: contact.getDisplayName()});
 +			if(!contact.data.thumbnail) {
 +				$li.addClass('thumbnail');
 +			} else {
 +				$li.css('background-image', 'url(data:image/png;base64,' + contact.data.thumbnail + ')');
 +			}
 +			if(idx === 0) {
 +				$li.find('input:radio').prop('checked', true);
 +			}
 +			$mergeList.append($li);
 +		});
 +		$('#merge_contacts_dialog').html($dlg).ocdialog({
 +			modal: true,
 +			closeOnEscape: true,
 +			title:  t('contacts', 'Merge contacts'),
 +			height: 'auto', width: 'auto',
 +			buttons: [
 +				{
 +					text: t('contacts', 'Merge contacts'),
 +					click:function() {
 +						// Do the merging, use $(this) to get dialog
 +						var contactid = $(this).find('input:radio:checked').val();
 +						var others = [];
 +						var deleteOther = $(this).find('#delete_other').prop('checked');
 +						console.log('Selected contact', contactid, 'Delete others', deleteOther);
 +						$.each($(this).find('input:radio:not(:checked)'), function(idx, item) {
 +							others.push($(item).val());
 +						});
 +						console.log('others', others);
 +						$(document).trigger('request.contact.merge', {
 +							merger: contactid,
 +							mergees: others,
 +							deleteOther: deleteOther
 +						});
 +
 +						$(this).ocdialog('close');
 +					},
 +					defaultButton: true
 +				},
 +				{
 +					text: t('contacts', 'Cancel'),
 +					click:function(dlg) {
 +						$(this).ocdialog('close');
 +						return false;
 +					}
 +				}
 +			],
 +			close: function(event, ui) {
 +				$(this).ocdialog('destroy').remove();
 +				$('#add_group_dialog').remove();
 +			},
 +			open: function(event, ui) {
 +				$dlg.find('input').focus();
 +			}
 +		});
 +	},
 +	addGroup: function(cb) {
 +		var self = this;
 +		this.$rightContent.append('<div id="add_group_dialog"></div>');
 +		if(!this.$addGroupTmpl) {
 +			this.$addGroupTmpl = $('#addGroupTemplate');
 +		}
 +		this.$contactList.addClass('dim');
 +		var $dlg = this.$addGroupTmpl.octemplate();
 +		$('#add_group_dialog').html($dlg).ocdialog({
 +			modal: true,
 +			closeOnEscape: true,
 +			title:  t('contacts', 'Add group'),
 +			height: 'auto', width: 'auto',
 +			buttons: [
 +				{
 +					text: t('contacts', 'OK'),
 +					click:function() {
 +						var name = $(this).find('input').val();
 +						if(name.trim() === '') {
 +							return false;
 +						}
 +						self.groups.addGroup(
 +							{name:$dlg.find('input:text').val()},
 +							function(response) {
 +								if(typeof cb === 'function') {
 +									cb(response);
 +								} else {
 +									if(response.error) {
 +										$(document).trigger('status.contacts.error', response);
 +									}
 +								}
 +							});
 +						$(this).ocdialog('close');
 +					},
 +					defaultButton: true
 +				},
 +				{
 +					text: t('contacts', 'Cancel'),
 +					click:function(dlg) {
 +						$(this).ocdialog('close');
 +						return false;
 +					}
 +				}
 +			],
 +			close: function(event, ui) {
 +				$(this).ocdialog('destroy').remove();
 +				$('#add_group_dialog').remove();
 +				self.$contactList.removeClass('dim');
 +			},
 +			open: function(event, ui) {
 +				$dlg.find('input').focus();
 +			}
 +		});
 +	},
 +	setAllChecked: function(checked) {
 +		var selector = checked ? 'input:checkbox:visible:not(checked)' : 'input:checkbox:visible:checked';
 +		$.each(this.$contactList.find(selector), function() {
 +			$(this).prop('checked', checked);
 +		});
 +		this.lastSelectedContacts = [];
 +	},
 +	jumpToContact: function(id) {
 +		this.$rightContent.scrollTop(this.contacts.contactPos(id)-30);
 +	},
 +	closeContact: function(id) {
 +		$(window).unbind('hashchange', this.hashChange);
 +		if(this.currentid === 'new') {
 +			this.tmpcontact.slideUp().remove();
 +			this.$contactList.show();
 +		} else {
 +			var contact = this.contacts.findById(id);
 +			if(contact) {
 +				// Only show the list element if contact is in current group
 +				var showListElement = contact.inGroup(this.groups.nameById(this.currentgroup))
- 					|| this.currentgroup === 'all'
++					|| ['all', 'fav', 'uncategorized'].indexOf(this.currentgroup) !== -1
 +					|| (this.currentgroup === 'uncategorized' && contact.groups().length === 0);
 +				contact.close(showListElement);
 +			}
 +		}
 +		delete this.currentid;
 +		this.hideActions();
 +		this.$groups.find('optgroup,option:not([value="-1"])').remove();
 +		if(this.contacts.length === 0) {
 +			$(document).trigger('status.nomorecontacts');
 +		}
 +		window.location.hash = '';
 +		$(window).bind('hashchange', this.hashChange);
 +	},
 +	openContact: function(id) {
 +		var self = this;
 +		if(typeof id == 'undefined' || id == 'undefined') {
 +			console.warn('id is undefined!');
 +			console.trace();
 +		}
 +		this.hideActions();
 +		if(this.currentid) {
 +			this.closeContact(this.currentid);
 +		}
 +		console.log('Contacts.openContact', id, typeof id);
 +		this.currentid = id;
 +		var contact = this.contacts.findById(this.currentid);
 +		// If opened from search we can't be sure the contact is in currentgroup
 +		if(!contact.inGroup(this.groups.nameById(this.currentgroup))
 +			&& ['all', 'fav', 'uncategorized'].indexOf(this.currentgroup) === -1
 +		) {
 +			this.groups.selectGroup({id:'all'});
 +		}
 +		if(this.currentid && this.currentid !== id) {
 +			this.contacts.closeContact(this.currentid);
 +		}
 +		$(window).unbind('hashchange', this.hashChange);
 +		this.setAllChecked(false);
 +		console.assert(typeof this.currentid === 'string', 'Current ID not string:' + this.currentid);
 +		// Properties that the contact doesn't know
 +		var groupprops = {
 +			favorite: this.groups.isFavorite(this.currentid),
 +			groups: this.groups.categories,
 +			currentgroup: {id:this.currentgroup, name:this.groups.nameById(this.currentgroup)}
 +		};
 +		if(!contact) {
 +			console.warn('Error opening', this.currentid);
 +			$(document).trigger('status.contacts.error', {
 +				message: t('contacts', 'Could not find contact: {id}', {id:this.currentid})
 +			});
 +			this.currentid = null;
 +			return;
 +		}
 +		var $contactelem = contact.renderContact(groupprops);
 +		var $listElement = contact.getListItemElement();
 +		console.log('selected element', $listElement);
 +		window.location.hash = this.currentid;
 +		self.jumpToContact(self.currentid);
 +		$contactelem.insertAfter($listElement).show().find('.fullname').focus();
 +		$listElement.hide();
 +		setTimeout(function() {
 +			$(window).bind('hashchange', self.hashChange);
 +		}, 500);
 +	},
 +	update: function() {
 +		console.log('update');
 +	},
 +	uploadPhoto:function(filelist) {
 +		console.log('uploadPhoto');
 +		var self = this;
 +		if(!filelist) {
 +			$(document).trigger('status.contacts.error', {message:t('contacts','No files selected for upload.')});
 +			return;
 +		}
 +		var file = filelist[0];
 +		var form = $('#file_upload_form');
 +		var totalSize=0;
 +		if(file.size > $('#max_upload').val()) {
 +			$(document).trigger('status.contacts.error', {
 +				message:t(
 +					'contacts',
 +					'The file you are trying to upload exceed the maximum size for file uploads on this server.')
 +			});
 +			return;
 +		} else {
 +			form.submit();
 +		}
 +	},
 +	cloudPhotoSelected:function(metadata, path) {
 +		var self = this;
 +		console.log('cloudPhotoSelected', metadata);
 +		var url = OC.Router.generate(
 +			'contacts_cache_fs_photo',
 +			{backend: metadata.backend, addressBookId: metadata.addressBookId, contactId: metadata.contactId, path: path}
 +		);
 +		var jqXHR = $.getJSON(url, function(response) {
 +			console.log('response', response);
 +			response = self.storage.formatResponse(response, jqXHR);
 +			if(!response.error) {
 +				self.editPhoto(metadata, response.data.tmp);
 +			} else {
 +				$(document).trigger('status.contacts.error', response);
 +			}
 +		});
 +	},
 +	editCurrentPhoto:function(metadata) {
 +		var self = this;
 +		var url = OC.Router.generate(
 +			'contacts_cache_contact_photo',
 +			{backend: metadata.backend, addressBookId: metadata.addressBookId, contactId: metadata.contactId}
 +		);
 +		console.log('url', url);
 +		var jqXHR = $.getJSON(url, function(response) {
 +			response = self.storage.formatResponse(response, jqXHR)
 +			if(!response.error) {
 +				self.editPhoto(metadata, response.data.tmp);
 +			} else {
 +				$(document).trigger('status.contacts.error', response);
 +			}
 +		});
 +	},
 +	editPhoto:function(metadata, tmpkey) {
 +		var $x, $y, $w, $h;
 +		console.log('editPhoto', metadata, tmpkey);
 +		$('.tipsy').remove();
 +		// Simple event handler, called from onChange and onSelect
 +		// event handlers, as per the Jcrop invocation below
 +		var showCoords = function(c) {
 +			$('#x').val(c.x);
 +			$('#y').val(c.y);
 +			$('#w').val(c.w);
 +			$('#h').val(c.h);
 +		};
 +
 +		var clearCoords = function() {
 +			$('#coords input').val('');
 +		};
 +
 +		var self = this;
 +		if(!this.$cropBoxTmpl) {
 +			this.$cropBoxTmpl = $('#cropBoxTemplate');
 +		}
- 		var $container = $('<div />').appendTo($('body'));
++		var $container = $('<div />').appendTo($('#content'));
 +		var url = OC.Router.generate(
 +			'contacts_crop_contact_photo',
 +			{backend: metadata.backend, addressBookId: metadata.addressBookId, contactId: metadata.contactId, key: tmpkey}
 +		);
 +		var $dlg = this.$cropBoxTmpl.octemplate(
 +			{
 +				action: url,
 +				backend: metadata.backend,
 +				addressbookid: metadata.addressbookid,
 +				contactid: metadata.contactid,
 +				tmpkey: tmpkey
 +			}).prependTo($container);
 +
 +		$.when(this.storage.getTempContactPhoto(
 +			metadata.backend,
 +			metadata.addressBookId,
 +			metadata.contactId,
 +			tmpkey
 +		))
 +		.then(function(image) {
 +			var x = 5, y = 5, w = h = Math.min(image.width, image.height);
 +			//$dlg.css({'min-width': w, 'min-height': h});
 +			console.log(x,y,w,h);
 +			$(image).attr('id', 'cropbox').prependTo($dlg).show()
 +			.Jcrop({
 +				onChange:	showCoords,
 +				onSelect:	showCoords,
 +				onRelease:	clearCoords,
 +				//maxSize:	[w, h],
 +				bgColor:	'black',
 +				bgOpacity:	.4,
 +				boxWidth:	400,
 +				boxHeight:	400,
 +				setSelect:	[ x, y, w-10, h-10 ],
 +				aspectRatio: 1
 +			});
 +			$container.ocdialog({
 +				modal: true,
 +				closeOnEscape: true,
 +				title:  t('contacts', 'Edit profile picture'),
 +				height: image.height+100, width: image.width+20,
 +				buttons: [
 +					{
 +						text: t('contacts', 'Crop photo'),
 +						click:function() {
 +							self.savePhoto($(this), function() {
 +								$container.ocdialog('close');
 +							});
 +						},
 +						defaultButton: true
 +					}
 +				],
 +				close: function(event, ui) {
 +					$(this).ocdialog('destroy').remove();
 +					$container.remove();
 +				},
 +				open: function(event, ui) {
 +					showCoords({x:x,y:y,w:w-10,h:h-10});
 +				}
 +			});
 +		})
 +		.fail(function() {
 +			console.warn('Error getting temporary photo');
 +		});
 +	},
 +	savePhoto:function($dlg, cb) {
 +		var $form = $dlg.find('#cropform');
 +		var $target = $dlg.find('#crop_target');
 +		console.log('target', $target);
 +		$target.on('load', function() {
 +			console.log('submitted');
 +			var response = $.parseJSON($target.contents().text());
 +			console.log('response', response);
 +			if(response && response.status == 'success') {
 +				$(document).trigger('status.contact.photoupdated', {
 +					id: response.data.id,
 +					thumbnail: response.data.thumbnail
 +				});
 +			} else {
 +				if(!response) {
 +					$(document).trigger('status.contacts.error', {
 +						message:t('contacts', 'Network or server error. Please inform administrator.')
 +					});
 +				} else {
 +					$(document).trigger('status.contacts.error', response);
 +				}
 +			}
 +			cb();
 +		});
 +		$form.submit();
 +	},
 +};
 +
 +$(document).ready(function() {
 +
 +	OC.Router.registerLoadedCallback(function() {
 +		$.getScript(OC.Router.generate('contacts_jsconfig'))
 +		.done(function() {
 +			OC.Contacts.init();
 +		})
 +		.fail(function(jqxhr, settings, exception) {
 +			console.log('Failed loading settings.', jqxhr, settings, exception);
 +		});
 +	});
 +
 +});
diff --cc apps/contacts/js/storage.js
index 06c08f1,0000000..14d5786
mode 100644,000000..100644
--- a/apps/contacts/js/storage.js
+++ b/apps/contacts/js/storage.js
@@@ -1,634 -1,0 +1,659 @@@
 +OC.Contacts = OC.Contacts || {};
 +
 +(function(window, $, OC) {
 +	'use strict';
 +
 +	var JSONResponse = function(response, jqXHR) {
 +		this.getAllResponseHeaders = jqXHR.getAllResponseHeaders;
 +		this.getResponseHeader = jqXHR.getResponseHeader;
 +		this.statusCode = jqXHR.status;
 +		this.error = false;
 +		// 204 == No content
 +		// 304 == Not modified
 +		if(!response) {
 +			if([204, 304].indexOf(this.statusCode) === -1) {
 +				console.log('jqXHR', jqXHR);
 +				this.error = true;
 +				this.message = jqXHR.statusText;
 +			}
 +		} else {
 +			// We need to allow for both the 'old' success/error status property
 +			// with the body in the data property, and the newer where we rely
 +			// on the status code, and the entire body is used.
 +			if(response.status === 'error'|| this.statusCode >= 400) {
 +				this.error = true;
 +				if(this.statusCode < 500) {
 +					this.message = (response.data && response.data.message)
 +						? response.data.message
 +						: response;
 +				} else {
 +					this.message = t('contacts', 'Server error! Please inform system administator');
 +				}
 +			} else {
 +				this.data = response;
 +			}
 +		}
 +	};
 +
 +	/**
 +	* An object for saving contact data to backends
 +	*
 +	* All methods returns a jQuery.Deferred object which resolves
 +	* to either the requested response or an error object:
 +	* {
 +	*	error: true,
 +	*	message: The error message
 +	* }
 +	*
 +	* @param string user The user to query for. Defaults to current user
 +	*/
 +	var Storage = function(user) {
 +		this.user = user ? user : OC.currentUser;
 +	};
 +
 +	/**
++	 * Test if localStorage is working
++	 *
++	 * @return bool
++	 */
++	Storage.prototype.hasLocalStorage = function(jqXHR) {
++		if (Modernizr) {
++			if (!Modernizr.localStorage) {
++				return false;
++			}
++		}
++		// Some browsers report support but doesn't have it
++		// e.g. Safari in private browsing mode.
++		try {
++			OC.localStorage.setItem('Hello', 'World');
++			OC.localStorage.removeItem('Hello');
++		} catch (e) {
++			return false;
++		}
++		return true;
++	};
++
++	/**
 +	 * When the response isn't returned from requestRoute(), you can
 +	 * wrap it in a JSONResponse so that it's parsable by other objects.
 +	 *
 +	 * @param object response The body of the response
 +	 * @param XMLHTTPRequest http://api.jquery.com/jQuery.ajax/#jqXHR
 +	 */
 +	Storage.prototype.formatResponse = function(response, jqXHR) {
 +		return new JSONResponse(response, jqXHR);
 +	};
 +
 +	/**
 +	 * Get all address books registered for this user.
 +	 *
 +	 * @return An array containing object of address book metadata e.g.:
 +	 * {
 +	 * 	backend:'local',
 +	 * 	id:'1234'
 +	 * 	permissions:31,
 +	 * 	displayname:'Contacts'
 +	 * }
 +	 */
 +	Storage.prototype.getAddressBooksForUser = function() {
 +		return this.requestRoute(
 +			'contacts_address_books_for_user',
 +			'GET',
 +			{}
 +		);
 +	};
 +
 +	/**
 +	 * Add an address book to a specific backend
 +	 *
 +	 * @param string backend - currently defaults to 'local'
 +	 * @param object params An object {displayname:"My contacts", description:""}
 +	 * @return An array containing contact data e.g.:
 +	 * {
 +	 * 	metadata:
 +	 * 		{
 +	 * 		id:'1234'
 +	 * 		permissions:31,
 +	 * 		displayname:'My contacts',
 +	 * 		lastmodified: (unix timestamp),
 +	 * 		owner: 'joye',
 +	 * }
 +	 */
 +	Storage.prototype.addAddressBook = function(backend, parameters) {
 +		console.log('Storage.addAddressBook', backend);
 +		return this.requestRoute(
 +			'contacts_address_book_add',
 +			'POST',
 +			{backend: 'local'},
 +			JSON.stringify(parameters)
 +		);
 +	};
 +
 +	/**
 +	 * Update an address book in a specific backend
 +	 *
 +	 * @param string backend
 +	 * @param string addressBookId Address book ID
 +	 * @param object params An object {displayname:"My contacts", description:""}
 +	 * @return An array containing contact data e.g.:
 +	 * {
 +	 * 	metadata:
 +	 * 		{
 +	 * 		id:'1234'
 +	 * 		permissions:31,
 +	 * 		displayname:'My contacts',
 +	 * 		lastmodified: (unix timestamp),
 +	 * 		owner: 'joye',
 +	 * }
 +	 */
 +	Storage.prototype.updateAddressBook = function(backend, addressBookId, properties) {
 +		console.log('Storage.updateAddressBook', backend);
 +		return this.requestRoute(
 +			'contacts_address_book_update',
 +			'POST',
 +			{backend: backend, addressBookId: addressBookId},
 +			JSON.stringify(properties)
 +		);
 +	};
 +
 +	/**
 +	 * Delete an address book from a specific backend
 +	 *
 +	 * @param string backend
 +	 * @param string addressBookId Address book ID
 +	 */
 +	Storage.prototype.deleteAddressBook = function(backend, addressBookId) {
 +		console.log('Storage.deleteAddressBook', backend, addressBookId);
 +		return this.requestRoute(
 +			'contacts_address_book_delete',
 +			'DELETE',
 +			{backend: backend, addressBookId: addressBookId}
 +		);
 +	};
 +
 +	/**
 +	 * (De)active an address book from a specific backend
 +	 *
 +	 * @param string backend
 +	 * @param string addressBookId Address book ID
 +	 * @param bool state
 +	 */
 +	Storage.prototype.activateAddressBook = function(backend, addressBookId, state) {
 +		console.log('Storage.activateAddressBook', backend, addressBookId, state);
 +		return this.requestRoute(
 +			'contacts_address_book_activate',
 +			'POST',
 +			{backend: backend, addressBookId: addressBookId},
 +			JSON.stringify({state: state})
 +		);
 +	};
 +
 +	/**
 +	 * Get contacts from an address book from a specific backend
 +	 *
 +	 * @param string backend
 +	 * @param string addressBookId Address book ID
 +	 * @return
 +	 * An array containing contact data e.g.:
 +	 * {
 +	 * 	metadata:
 +	 * 		{
 +	 * 		id:'1234'
 +	 * 		permissions:31,
 +	 * 		displayname:'John Q. Public',
 +	 * 		lastmodified: (unix timestamp),
 +	 * 		owner: 'joye',
 +	 * 		parent: (id of the parent address book)
 +	 * 	data: //array of VCard data
 +	 * }
 +	 */
 +	Storage.prototype.getAddressBook = function(backend, addressBookId) {
- 		var headers = {},
++		var self = this,
++			headers = {},
 +			data,
 +			key = 'contacts::' + backend + '::' + addressBookId,
 +			defer = $.Deferred();
 +
- 		if(OC.localStorage.hasItem(key)) {
++		if(this.hasLocalStorage() && OC.localStorage.hasItem(key)) {
 +			data = OC.localStorage.getItem(key);
 +			headers['If-None-Match'] = data.Etag;
 +		}
 +		$.when(this.requestRoute(
 +			'contacts_address_book',
 +			'GET',
 +			{backend: backend, addressBookId: addressBookId},
 +			'',
 +			headers
 +		))
 +		.then(function(response) {
 +			console.log('response', response);
 +			if(response.statusCode === 200) {
 +				console.log('Returning fetched address book');
 +				if(response.data) {
 +					response.data.Etag = response.getResponseHeader('Etag');
- 					OC.localStorage.setItem(key, response.data);
++					if (!self.hasLocalStorage()) {
++						OC.localStorage.setItem(key, response.data);
++					}
 +					defer.resolve(response);
 +				}
 +			} else if(response.statusCode === 304) {
 +				console.log('Returning stored address book');
 +				response.data = data;
 +				defer.resolve(response);
 +			}
 +		})
 +		.fail(function(response) {
 +			console.warn('Request Failed:', response.message);
 +			defer.reject();
 +		});
 +		return defer;
 +	};
 +
 +	/**
 +	 * Add a contact to an address book from a specific backend
 +	 *
 +	 * @param string backend
 +	 * @param string addressBookId Address book ID
 +	 * @return An array containing contact data e.g.:
 +	 * {
 +	 * 	metadata:
 +	 * 		{
 +	 * 		id:'1234'
 +	 * 		permissions:31,
 +	 * 		displayname:'John Q. Public',
 +	 * 		lastmodified: (unix timestamp),
 +	 * 		owner: 'joye',
 +	 * 		parent: (id of the parent address book)
 +	 * 	data: //array of VCard data
 +	 * }
 +	 */
 +	Storage.prototype.addContact = function(backend, addressBookId) {
 +		console.log('Storage.addContact', backend, addressBookId);
 +		return this.requestRoute(
 +			'contacts_address_book_add_contact',
 +			'POST',
 +			{backend: backend, addressBookId: addressBookId}
 +		);
 +	};
 +
 +	/**
 +	 * Delete a contact from an address book from a specific backend
 +	 *
 +	 * @param string backend
 +	 * @param string addressBookId Address book ID
 +	 * @param string contactId Address book ID
 +	 */
 +	Storage.prototype.deleteContact = function(backend, addressBookId, contactId) {
 +		console.log('Storage.deleteContact', backend, addressBookId, contactId);
 +		return this.requestRoute(
 +			'contacts_address_book_delete_contact',
 +			'DELETE',
 +			{backend: backend, addressBookId: addressBookId, contactId: contactId}
 +		);
 +	}
 +
 +	/**
 +	 * Delete a list of contacts from an address book from a specific backend
 +	 *
 +	 * @param string backend
 +	 * @param string addressBookId Address book ID
 +	 * @param array contactIds Address book ID
 +	 */
 +	Storage.prototype.deleteContacts = function(backend, addressBookId, contactIds) {
 +		console.log('Storage.deleteContacts', backend, addressBookId, contactIds);
 +		return this.requestRoute(
 +			'contacts_address_book_delete_contacts',
 +			'POST',
 +			{backend: backend, addressBookId: addressBookId},
 +			JSON.stringify({contacts: contactIds})
 +		);
 +	};
 +
 +	/**
 +	 * Move a contact to an address book from a specific backend
 +	 *
 +	 * @param string backend
 +	 * @param string addressBookId Address book ID
 +	 * @param string contactId Address book ID
 +	 */
 +	Storage.prototype.moveContact = function(backend, addressBookId, contactId, target) {
 +		console.log('Storage.moveContact', backend, addressBookId, contactId, target);
 +		return this.requestRoute(
 +			'contacts_address_book_move_contact',
 +			'POST',
 +			{backend: backend, addressBookId: addressBookId, contactId: contactId},
 +			JSON.stringify(target)
 +		);
 +	};
 +
 +	/**
 +	 * Get Image instance for a contacts profile picture
 +	 *
 +	 * @param string backend
 +	 * @param string addressBookId Address book ID
 +	 * @param string contactId Address book ID
 +	 * @return Image
 +	 */
 +	Storage.prototype.getContactPhoto = function(backend, addressBookId, contactId) {
 +		var photo = new Image();
 +		var url = OC.Router.generate(
 +			'contacts_contact_photo',
 +			{backend: backend, addressBookId: addressBookId, contactId: contactId}
 +		);
 +		var defer = $.Deferred();
 +		var self = this;
 +		$.when(
 +			$(photo).on('load', function() {
 +				defer.resolve(photo);
 +			})
 +			.error(function() {
 +				console.log('Error loading contact photo')
 +				defer.reject();
 +			})
 +			.attr('src', url + '?refresh=' + Math.random())
 +		)
 +		.fail(function(jqxhr, textStatus, error) {
 +			defer.reject();
 +			var err = textStatus + ', ' + error;
 +			console.log( "Request Failed: " + err);
 +			$(document).trigger('status.contact.error', {
 +				message: t('contacts', 'Failed loading photo: {error}', {error:err})
 +			});
 +		});
 +		return defer.promise();
 +	};
 +
 +	/**
 +	 * Get Image instance for a contacts profile picture
 +	 *
 +	 * @param string backend
 +	 * @param string addressBookId Address book ID
 +	 * @param string contactId Address book ID
 +	 * @param string key The key to the cache where the photo is stored.
 +	 * @return Image
 +	 */
 +	Storage.prototype.getTempContactPhoto = function(backend, addressBookId, contactId, key) {
 +		var photo = new Image();
 +		var url = OC.Router.generate(
 +			'contacts_tmp_contact_photo',
 +			{backend: backend, addressBookId: addressBookId, contactId: contactId, key: key, refresh: Math.random()}
 +		);
 +		console.log('url', url);
 +		var defer = $.Deferred();
 +		var self = this;
 +		$.when(
 +			$(photo).on('load', function() {
 +				defer.resolve(photo);
 +			})
 +			.error(function(event) {
 +				console.log('Error loading temporary photo', event)
 +				defer.reject();
 +			})
 +			.attr('src', url)
 +		)
 +		.fail(function(jqxhr, textStatus, error) {
 +			defer.reject();
 +			var err = textStatus + ', ' + error;
 +			console.log( "Request Failed: " + err);
 +			$(document).trigger('status.contact.error', {
 +				message: t('contacts', 'Failed loading photo: {error}', {error:err})
 +			});
 +		});
 +		return defer.promise();
 +	};
 +
 +	/**
 +	 * Get Image instance for default profile picture
 +	 *
 +	 * This method loads the default picture only once and caches it.
 +	 *
 +	 * @return Image
 +	 */
 +	Storage.prototype.getDefaultPhoto = function() {
 +		console.log('Storage.getDefaultPhoto');
 +		if(!this.defaultPhoto) {
 +			var defer = $.Deferred();
 +			var url = OC.imagePath('contacts', 'person_large.png');
 +			this.defaultPhoto = new Image();
 +			var self = this;
 +			$(this.defaultPhoto)
 +				.load(function() {
 +					defer.resolve(this);
 +				}).error(function(event) {
 +					defer.reject();
 +				}).attr('src', url)
 +			return defer.promise();
 +		} else {
 +			return this.defaultPhoto;
 +		}
 +	};
 +
 +	/**
 +	 * Update a contact.
 +	 *
 +	 * @param string backend
 +	 * @param string addressBookId Address book ID
 +	 * @param string contactId Contact ID
 +	 * @param object params An object with the following properties:
 +	 * @param string name The name of the property e.g. EMAIL.
 +	 * @param string|array|null value The of the property
 +	 * @param array parameters Optional parameters for the property
 +	 * @param string checksum For non-singular properties such as email this must contain
 +	 * 	an 8 character md5 checksum of the serialized \Sabre\Property
 +	 */
 +	Storage.prototype.patchContact = function(backend, addressBookId, contactId, params) {
 +		return this.requestRoute(
 +			'contacts_contact_patch',
 +			'PATCH',
 +			{backend: backend, addressBookId: addressBookId, contactId: contactId},
 +			JSON.stringify(params)
 +		);
 +	};
 +
 +	/**
 +	 * Save all properties. Used when merging contacts.
 +	 *
 +	 * @param string backend
 +	 * @param string addressBookId Address book ID
 +	 * @param string contactId Contact ID
 +	 * @param object params An object with the all properties:
 +	 */
 +	Storage.prototype.saveAllProperties = function(backend, addressBookId, contactId, params) {
 +		console.log('Storage.saveAllProperties', params);
 +		return this.requestRoute(
 +			'contacts_contact_save_all',
 +			'POST',
 +			{backend: backend, addressBookId: addressBookId, contactId: contactId},
 +			JSON.stringify(params)
 +		);
 +	};
 +
 +	/**
 +	 * Get all groups for this user.
 +	 *
 +	 * @return An array containing the groups, the favorites, any shared
 +	 * address books, the last selected group and the sort order of the groups.
 +	 * {
 +	 * 	'categories': [{'id':1',Family'}, {...}],
 +	 * 	'favorites': [123,456],
 +	 * 	'shared': [],
 +	 * 	'lastgroup':'1',
 +	 * 	'sortorder':'3,2,4'
 +	 * }
 +	 */
 +	Storage.prototype.getGroupsForUser = function() {
 +		console.log('getGroupsForUser');
 +		return this.requestRoute(
 +			'contacts_categories_list',
 +			'GET',
 +			{}
 +		);
 +	};
 +
 +	/**
 +	 * Add a group
 +	 *
 +	 * @param string name
 +	 * @return A JSON object containing the (maybe sanitized) group name and its ID:
 +	 * {
 +	 * 	'id':1234,
 +	 * 	'name':'My group'
 +	 * }
 +	 */
 +	Storage.prototype.addGroup = function(name) {
 +		console.log('Storage.addGroup', name);
 +		return this.requestRoute(
 +			'contacts_categories_add',
 +			'POST',
 +			{},
 +			JSON.stringify({name: name})
 +		);
 +	};
 +
 +	/**
 +	 * Delete a group
 +	 *
 +	 * @param string name
 +	 */
 +	Storage.prototype.deleteGroup = function(name) {
 +		return this.requestRoute(
 +			'contacts_categories_delete',
 +			'POST',
 +			{},
 +			JSON.stringify({name: name})
 +		);
 +	};
 +
 +	/**
 +	 * Rename a group
 +	 *
 +	 * @param string from
 +	 * @param string to
 +	 */
 +	Storage.prototype.renameGroup = function(from, to) {
 +		return this.requestRoute(
 +			'contacts_categories_rename',
 +			'POST',
 +			{},
 +			JSON.stringify({from: from, to: to})
 +		);
 +	};
 +
 +	/**
 +	 * Add contacts to a group
 +	 *
 +	 * @param array contactIds
 +	 */
 +	Storage.prototype.addToGroup = function(contactIds, categoryId, categoryName) {
 +		console.log('Storage.addToGroup', contactIds, categoryId);
 +		return this.requestRoute(
 +			'contacts_categories_addto',
 +			'POST',
 +			{categoryId: categoryId},
 +			JSON.stringify({contactIds: contactIds, name: categoryName})
 +		);
 +	};
 +
 +	/**
 +	 * Remove contacts from a group
 +	 *
 +	 * @param array contactIds
 +	 */
 +	Storage.prototype.removeFromGroup = function(contactIds, categoryId, categoryName) {
 +		console.log('Storage.removeFromGroup', contactIds, categoryId);
 +		return this.requestRoute(
 +			'contacts_categories_removefrom',
 +			'POST',
 +			{categoryId: categoryId},
 +			JSON.stringify({contactIds: contactIds, name: categoryName})
 +		);
 +	};
 +
 +	/**
 +	 * Set a user preference
 +	 *
 +	 * @param string key
 +	 * @param string value
 +	 */
 +	Storage.prototype.setPreference = function(key, value) {
 +		return this.requestRoute(
 +			'contacts_setpreference',
 +			'POST',
 +			{},
 +			JSON.stringify({key: key, value:value})
 +		);
 +	};
 +
 +	Storage.prototype.prepareImport = function(backend, addressBookId, params) {
 +		console.log('Storage.prepareImport', backend, addressBookId);
 +		return this.requestRoute(
 +			'contacts_import_prepare',
 +			'POST',
 +			{backend: backend, addressBookId: addressBookId},
 +			JSON.stringify(params)
 +		);
 +	};
 +
 +	Storage.prototype.startImport = function(backend, addressBookId, params) {
 +		console.log('Storage.startImport', backend, addressBookId);
 +		return this.requestRoute(
 +			'contacts_import_start',
 +			'POST',
 +			{backend: backend, addressBookId: addressBookId},
 +			JSON.stringify(params)
 +		);
 +	};
 +
 +	Storage.prototype.importStatus = function(backend, addressBookId, params) {
 +		return this.requestRoute(
 +			'contacts_import_status',
 +			'GET',
 +			{backend: backend, addressBookId: addressBookId},
 +			params
 +		);
 +	};
 +
 +	Storage.prototype.requestRoute = function(route, type, routeParams, params, additionalHeaders) {
 +		var isJSON = (typeof params === 'string');
 +		var contentType = isJSON
 +			? (type === 'PATCH' ? 'application/json-merge-patch' : 'application/json')
 +			: 'application/x-www-form-urlencoded';
 +		var processData = !isJSON;
 +		contentType += '; charset=UTF-8';
 +		var self = this;
 +		var url = OC.Router.generate(route, routeParams);
 +		var headers = {
 +			Accept : 'application/json; charset=utf-8',
 +		};
 +		if(typeof additionalHeaders === 'object') {
 +			headers = $.extend(headers, additionalHeaders);
 +		}
 +		var ajaxParams = {
 +			type: type,
 +			url: url,
 +			dataType: 'json',
 +			headers: headers,
 +			contentType: contentType,
 +			processData: processData,
 +			data: params
 +		};
 +
 +		var defer = $.Deferred();
 +
 +		var jqxhr = $.ajax(ajaxParams)
 +			.done(function(response, textStatus, jqXHR) {
 +				defer.resolve(new JSONResponse(response, jqXHR));
 +			})
 +			.fail(function(jqXHR, textStatus, error) {
 +				console.log(jqXHR);
 +				var response = jqXHR.responseText ? $.parseJSON(jqXHR.responseText) : null;
 +				console.log('response', response);
 +				defer.reject(new JSONResponse(response, jqXHR));
 +			});
 +
 +		return defer.promise();
 +	};
 +
 +	OC.Contacts.Storage = Storage;
 +
 +})(window, jQuery, OC);
diff --cc apps/contacts/lib/backend/database.php
index ff88fd0,0000000..a890169
mode 100644,000000..100644
--- a/apps/contacts/lib/backend/database.php
+++ b/apps/contacts/lib/backend/database.php
@@@ -1,812 -1,0 +1,812 @@@
 +<?php
 +/**
 + * ownCloud - Database backend for Contacts
 + *
 + * @author Thomas Tanghus
 + * @copyright 2013 Thomas Tanghus (thomas at tanghus.net)
 + *
 + * This library is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
 + * License as published by the Free Software Foundation; either
 + * version 3 of the License, or any later version.
 + *
 + * This library is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
 + *
 + * You should have received a copy of the GNU Affero General Public
 + * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
 + *
 + */
 +
 +namespace OCA\Contacts\Backend;
 +
 +use OCA\Contacts\Contact,
 +	OCA\Contacts\VObject\VCard,
 +	OCA\Contacts\Utils\Properties,
 +	Sabre\VObject\Reader;
 +
 +/**
 + * Subclass this class for Cantacts backends
 + */
 +
 +class Database extends AbstractBackend {
 +
 +	public $name = 'local';
 +	static private $preparedQueries = array();
 +
 +	/**
 +	* Sets up the backend
 +	*
 +	* @param string $addressBooksTableName
 +	* @param string $cardsTableName
 +	*/
 +	public function __construct(
 +		$userid = null,
 +		$options = array(
 +			'addressBooksTableName' => '*PREFIX*contacts_addressbooks',
 +			'cardsTableName' => '*PREFIX*contacts_cards',
 +			'indexTableName' => '*PREFIX*contacts_cards_properties'
 +		)
 +	) {
 +		$this->userid = $userid ? $userid : \OCP\User::getUser();
 +		$this->addressBooksTableName = $options['addressBooksTableName'];
 +		$this->cardsTableName = $options['cardsTableName'];
 +		$this->indexTableName = $options['indexTableName'];
 +		$this->addressbooks = array();
 +	}
 +
 +	/**
 +	 * Returns the list of addressbooks for a specific user.
 +	 *
 +	 * @see AbstractBackend::getAddressBooksForUser
 +	 * @return array
 +	 */
 +	public function getAddressBooksForUser(array $options = array()) {
 +
 +		try {
 +			if(!isset(self::$preparedQueries['addressbooksforuser'])) {
 +				$sql = 'SELECT `id`, `displayname`, `description`, `ctag` AS `lastmodified`, `userid` AS `owner`, `uri` FROM `'
 +					. $this->addressBooksTableName
 +					. '` WHERE `userid` = ? ORDER BY `displayname`';
 +				self::$preparedQueries['addressbooksforuser'] = \OCP\DB::prepare($sql);
 +			}
 +			$result = self::$preparedQueries['addressbooksforuser']->execute(array($this->userid));
 +			if (\OCP\DB::isError($result)) {
 +				\OCP\Util::writeLog('contacts', __METHOD__. 'DB error: ' . \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
 +				return $this->addressbooks;
 +			}
 +		} catch(\Exception $e) {
 +			\OCP\Util::writeLog('contacts', __METHOD__.' exception: ' . $e->getMessage(), \OCP\Util::ERROR);
 +			return $this->addressbooks;
 +		}
 +
 +		while($row = $result->fetchRow()) {
 +			$row['permissions'] = \OCP\PERMISSION_ALL;
 +			$this->addressbooks[$row['id']] = $row;
 +		}
 +		return $this->addressbooks;
 +	}
 +
 +	public function getAddressBook($addressbookid, array $options = array()) {
 +		//\OCP\Util::writeLog('contacts', __METHOD__.' id: '
 +		//	. $addressbookid, \OCP\Util::DEBUG);
 +		if($this->addressbooks && isset($this->addressbooks[$addressbookid])) {
 +			//print(__METHOD__ . ' ' . __LINE__ .' addressBookInfo: ' . print_r($this->addressbooks[$addressbookid], true));
 +			return $this->addressbooks[$addressbookid];
 +		}
 +		// Hmm, not found. Lets query the db.
 +		try {
 +			$query = 'SELECT `id`, `displayname`, `description`, `userid` AS `owner`, `ctag` AS `lastmodified`, `uri` FROM `'
 +				. $this->addressBooksTableName
- 				. '` WHERE `id` = ?';
++				. '` WHERE `id` = ? AND `userid` = ?';
 +			if(!isset(self::$preparedQueries['getaddressbook'])) {
 +				self::$preparedQueries['getaddressbook'] = \OCP\DB::prepare($query);
 +			}
- 			$result = self::$preparedQueries['getaddressbook']->execute(array($addressbookid));
++			$result = self::$preparedQueries['getaddressbook']->execute(array($addressbookid, $this->userid));
 +			if (\OCP\DB::isError($result)) {
 +				\OCP\Util::writeLog('contacts', __METHOD__. 'DB error: '
 +					. \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
 +				return null;
 +			}
 +			if((int)$result->numRows() === 0) {
- 				throw new \Exception('Address Book not found', 404);
++				return null;
 +			}
 +			$row = $result->fetchRow();
 +			$row['permissions'] = \OCP\PERMISSION_ALL;
 +			$row['backend'] = $this->name;
 +			$this->addressbooks[$addressbookid] = $row;
 +			return $row;
 +		} catch(\Exception $e) {
 +			\OCP\Util::writeLog('contacts', __METHOD__.' exception: '
 +				. $e->getMessage(), \OCP\Util::ERROR);
 +			return null;
 +		}
 +		return null;
 +	}
 +
 +	public function hasAddressBook($addressbookid, array $options = array()) {
 +		// First check if it's already cached
 +		if($this->addressbooks && isset($this->addressbooks[$addressbookid])) {
 +			return true;
 +		}
 +		return count($this->getAddressBook($addressbookid)) > 0;
 +	}
 +
 +	/**
 +	 * Updates an addressbook's properties
 +	 *
 +	 * @param string $addressbookid
 +	 * @param array $changes
 +	 * @return bool
 +	 */
 +	public function updateAddressBook($addressbookid, array $changes, array $options = array()) {
 +		if(count($changes) === 0) {
 +			return false;
 +		}
 +
 +		$query = 'UPDATE `' . $this->addressBooksTableName . '` SET ';
 +
 +		$updates = array();
 +
 +		if(isset($changes['displayname'])) {
 +			$query .= '`displayname` = ?, ';
 +			$updates[] = $changes['displayname'];
 +			if($this->addressbooks && isset($this->addressbooks[$addressbookid])) {
 +				$this->addressbooks[$addressbookid]['displayname'] = $changes['displayname'];
 +			}
 +		}
 +
 +		if(isset($changes['description'])) {
 +			$query .= '`description` = ?, ';
 +			$updates[] = $changes['description'];
 +			if($this->addressbooks && isset($this->addressbooks[$addressbookid])) {
 +				$this->addressbooks[$addressbookid]['description'] = $changes['description'];
 +			}
 +		}
 +
 +		$query .= '`ctag` = ? + 1 WHERE `id` = ?';
 +		$updates[] = time();
 +		$updates[] = $addressbookid;
 +
 +		try {
 +			$stmt = \OCP\DB::prepare($query);
 +			$result = $stmt->execute($updates);
 +			if (\OCP\DB::isError($result)) {
 +				\OCP\Util::writeLog('contacts',
 +					__METHOD__. 'DB error: '
 +					. \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
 +				return false;
 +			}
 +		} catch(\Exception $e) {
 +			\OCP\Util::writeLog('contacts',
 +				__METHOD__ . ', exception: '
 +				. $e->getMessage(), \OCP\Util::ERROR);
 +			return false;
 +		}
 +
 +		return true;
 +	}
 +
 +	/**
 +	 * Creates a new address book
 +	 *
 +	 * Supported properties are 'displayname', 'description' and 'uri'.
 +	 * 'uri' is supported to allow to add from CardDAV requests, and MUST
 +	 * be used for the 'uri' database field if present.
 +	 * 'displayname' MUST be present.
 +	 *
 +	 * @param array $properties
 +	 * @param array $options - Optional (backend specific options)
 +	 * @return string|false The ID if the newly created AddressBook or false on error.
 +	 */
 +	public function createAddressBook(array $properties, array $options = array()) {
 +
 +		if(count($properties) === 0 || !isset($properties['displayname'])) {
 +			return false;
 +		}
 +
 +		$query = 'INSERT INTO `' . $this->addressBooksTableName . '` '
 +			. '(`userid`,`displayname`,`uri`,`description`,`ctag`) VALUES(?,?,?,?,?)';
 +
 +		$updates = array($this->userid, $properties['displayname']);
 +		$updates[] = isset($properties['uri'])
 +			? $properties['uri']
 +			: $this->createAddressBookURI($properties['displayname']);
 +		$updates[] = isset($properties['description']) ? $properties['description'] : '';
 +		$ctag = time();
 +		$updates[] = $ctag;
 +
 +		try {
 +			if(!isset(self::$preparedQueries['createaddressbook'])) {
 +				self::$preparedQueries['createaddressbook'] = \OCP\DB::prepare($query);
 +			}
 +			$result = self::$preparedQueries['createaddressbook']->execute($updates);
 +			if (\OCP\DB::isError($result)) {
 +				\OCP\Util::writeLog('contacts', __METHOD__. 'DB error: ' . \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
 +				return false;
 +			}
 +		} catch(\Exception $e) {
 +			\OCP\Util::writeLog('contacts', __METHOD__ . ', exception: ' . $e->getMessage(), \OCP\Util::ERROR);
 +			return false;
 +		}
 +
 +		$newid = \OCP\DB::insertid($this->addressBooksTableName);
 +		if($this->addressbooks) {
 +			$updates['id'] = $newid;
 +			$updates['ctag'] = $ctag;
 +			$updates['lastmodified'] = $ctag;
 +			$updates['permissions'] = \OCP\PERMISSION_ALL;
 +			$this->addressbooks[$newid] = $updates;
 +		}
 +		return $newid;
 +	}
 +
 +	/**
 +	 * Deletes an entire addressbook and all its contents
 +	 *
 +	 * NOTE: For efficience this method bypasses the cleanup hooks and deletes
 +	 * property indexes and category/group relations by itself.
 +	 *
 +	 * @param string $addressbookid
 +	 * @param array $options - Optional (backend specific options)
 +	 * @return bool
 +	 */
 +	public function deleteAddressBook($addressbookid, array $options = array()) {
 +
 +		// Get all contact ids for this address book
 +		$ids = array();
 +		$result = null;
 +		$stmt = \OCP\DB::prepare('SELECT `id` FROM `' . $this->cardsTableName . '`'
 +					. ' WHERE `addressbookid` = ?');
 +		try {
 +			$result = $stmt->execute(array($addressbookid));
 +			if (\OCP\DB::isError($result)) {
 +				\OCP\Util::writeLog('contacts', __METHOD__. 'DB error: '
 +					. \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
 +				return false;
 +			}
 +		} catch(\Exception $e) {
 +			\OCP\Util::writeLog('contacts', __METHOD__.
 +				', exception: ' . $e->getMessage(), \OCP\Util::ERROR);
 +			return false;
 +		}
 +
 +		if(!is_null($result)) {
 +			while($id = $result->fetchOne()) {
 +				$ids[] = $id;
 +			}
 +		}
 +
 +		\OCP\Util::emitHook('OCA\Contacts', 'pre_deleteAddressBook',
 +			array('addressbookid' => $addressbookid, 'contactids' => $ids)
 +		);
 +
 +		// Delete contacts in address book.
 +		if(!isset(self::$preparedQueries['deleteaddressbookcontacts'])) {
 +			self::$preparedQueries['deleteaddressbookcontacts'] =
 +				\OCP\DB::prepare('DELETE FROM `' . $this->cardsTableName
 +					. '` WHERE `addressbookid` = ?');
 +		}
 +		try {
 +			self::$preparedQueries['deleteaddressbookcontacts']
 +				->execute(array($addressbookid));
 +		} catch(\Exception $e) {
 +			\OCP\Util::writeLog('contacts', __METHOD__.
 +				', exception: ' . $e->getMessage(), \OCP\Util::ERROR);
 +			return false;
 +		}
 +
 +		// Delete the address book.
 +		if(!isset(self::$preparedQueries['deleteaddressbook'])) {
 +			self::$preparedQueries['deleteaddressbook'] =
 +				\OCP\DB::prepare('DELETE FROM `'
 +					. $this->addressBooksTableName . '` WHERE `id` = ?');
 +		}
 +		try {
 +			self::$preparedQueries['deleteaddressbook']
 +				->execute(array($addressbookid));
 +		} catch(\Exception $e) {
 +			\OCP\Util::writeLog('contacts', __METHOD__.
 +				', exception: ' . $e->getMessage(), \OCP\Util::ERROR);
 +			return false;
 +		}
 +
 +		if($this->addressbooks && isset($this->addressbooks[$addressbookid])) {
 +			unset($this->addressbooks[$addressbookid]);
 +		}
 +
 +		return true;
 +	}
 +
 +	/**
 +	 * @brief Updates ctag for addressbook
 +	 * @param integer $id
 +	 * @return boolean
 +	 */
 +	public function setModifiedAddressBook($id) {
 +		$query = 'UPDATE `' . $this->addressBooksTableName
 +			. '` SET `ctag` = ? + 1 WHERE `id` = ?';
 +		if(!isset(self::$preparedQueries['touchaddressbook'])) {
 +			self::$preparedQueries['touchaddressbook'] = \OCP\DB::prepare($query);
 +		}
 +		$ctag = time();
 +		self::$preparedQueries['touchaddressbook']->execute(array($ctag, $id));
 +
 +		return true;
 +	}
 +
 +	public function lastModifiedAddressBook($addressbookid) {
 +		if($this->addressbooks && isset($this->addressbooks[$addressbookid])) {
 +			return $this->addressbooks[$addressbookid]['lastmodified'];
 +		}
 +		$addressBook = $this->getAddressBook($addressbookid);
 +		return $addressBook ? $addressBook['lastmodified'] : null;
 +	}
 +
 +	/**
 +	 * Returns the number of contacts in a specific address book.
 +	 *
 +	 * @param string $addressbookid
 +	 * @param bool $omitdata Don't fetch the entire carddata or vcard.
 +	 * @return array
 +	 */
 +	public function numContacts($addressbookid) {
 +		$query = 'SELECT COUNT(*) AS `count` FROM `' . $this->cardsTableName . '` WHERE '
 +			. '`addressbookid` = ?';
 +
 +		if(!isset(self::$preparedQueries['count'])) {
 +			self::$preparedQueries['count'] = \OCP\DB::prepare($query);
 +		}
 +		$result = self::$preparedQueries['count']->execute(array($addressbookid));
 +		if (\OCP\DB::isError($result)) {
 +			\OCP\Util::writeLog('contacts', __METHOD__. 'DB error: ' . \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
 +			return null;
 +		}
 +		return (int)$result->fetchOne();
 +	}
 +
 +	/**
 +	 * Returns all contacts for a specific addressbook id.
 +	 *
 +	 * @param string $addressbookid
 +	 * @param array $options - Optional (backend specific options)
 +	 * @param bool $omitdata Don't fetch the entire carddata or vcard.
 +	 * @return array
 +	 */
 +	public function getContacts($addressbookid, array $options = array() ) {
 +		//\OCP\Util::writeLog('contacts', __METHOD__.' addressbookid: ' . $addressbookid, \OCP\Util::DEBUG);
 +		$cards = array();
 +		try {
 +			$omitdata = isset($options['omitdata']) ? $options['omitdata'] : false;
 +			$qfields = $omitdata ? '`id`, `fullname` AS `displayname`' : '*';
 +			$query = 'SELECT ' . $qfields . ' FROM `' . $this->cardsTableName
 +				. '` WHERE `addressbookid` = ? ORDER BY `fullname`';
 +			$stmt = \OCP\DB::prepare(
 +				$query,
 +				isset($options['limit']) ? $options['limit'] : null,
 +				isset($options['offset']) ? $options['offset'] : null
 +			);
 +			$result = $stmt->execute(array($addressbookid));
 +			if (\OCP\DB::isError($result)) {
 +				\OCP\Util::writeLog('contacts', __METHOD__. 'DB error: ' . \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
 +				return $cards;
 +			}
 +		} catch(\Exception $e) {
 +			\OCP\Util::writeLog('contacts', __METHOD__.', exception: '.$e->getMessage(), \OCP\Util::ERROR);
 +			return $cards;
 +		}
 +
 +		if(!is_null($result)) {
 +			while($row = $result->fetchRow()) {
 +				$row['permissions'] = \OCP\PERMISSION_ALL;
 +				$cards[] = $row;
 +			}
 +		}
 +
 +		return $cards;
 +	}
 +
 +	/**
 +	 * Returns a specific contact.
 +	 *
 +	 * The $id for Database and Shared backends can be an array containing
 +	 * either 'id' or 'uri' to be able to play seamlessly with the
 +	 * CardDAV backend.
 +	 * FIXME: $addressbookid isn't used in the query, so there's no access control.
 +	 * 	OTOH the groups backend - OC_VCategories - doesn't no about parent collections
 +	 * 	only object IDs. Hmm.
 +	 * 	I could make a hack and add an optional, not documented 'nostrict' argument
 +	 * 	so it doesn't look for addressbookid.
 +	 *
 +	 * @param string $addressbookid
 +	 * @param mixed $id Contact ID
 +	 * @param array $options - Optional (backend specific options)
 +	 * @return array|null
 +	 */
 +	public function getContact($addressbookid, $id, array $options = array()) {
 +		//\OCP\Util::writeLog('contacts', __METHOD__.' identifier: ' . $addressbookid . ' ' . $id['uri'], \OCP\Util::DEBUG);
 +
 +		$noCollection = isset($options['noCollection']) ? $options['noCollection'] : false;
 +
 +		$where_query = '`id` = ?';
 +		if(is_array($id)) {
 +			$where_query = '';
 +			if(isset($id['id'])) {
 +				$id = $id['id'];
 +			} elseif(isset($id['uri'])) {
 +				$where_query = '`uri` = ?';
 +				$id = $id['uri'];
 +			} else {
 +				throw new \Exception(
 +					__METHOD__ . ' If second argument is an array, either \'id\' or \'uri\' has to be set.'
 +				);
 +				return null;
 +			}
 +		}
 +		$ids = array($id);
 +
 +		if(!$noCollection) {
 +			$where_query .= ' AND `addressbookid` = ?';
 +			$ids[] = $addressbookid;
 +		}
 +
 +		try {
 +			$query =  'SELECT `id`, `uri`, `carddata`, `lastmodified`, `addressbookid` AS `parent`, `fullname` AS `displayname` FROM `'
 +				. $this->cardsTableName . '` WHERE ' . $where_query;
 +			$stmt = \OCP\DB::prepare($query);
 +			$result = $stmt->execute($ids);
 +			if (\OCP\DB::isError($result)) {
 +				\OCP\Util::writeLog('contacts', __METHOD__. 'DB error: ' . \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
 +				return null;
 +			}
 +		} catch(\Exception $e) {
 +			\OCP\Util::writeLog('contacts', __METHOD__.', exception: '.$e->getMessage(), \OCP\Util::ERROR);
 +			\OCP\Util::writeLog('contacts', __METHOD__.', id: '. $id, \OCP\Util::DEBUG);
 +			return null;
 +		}
 +
 +		$row = $result->fetchRow();
 +		if(!$row) {
 +			\OCP\Util::writeLog('contacts', __METHOD__.', Not found, id: '. $id, \OCP\Util::DEBUG);
 +			return null;
 +		}
 +		$row['permissions'] = \OCP\PERMISSION_ALL;
 +		return $row;
 +	}
 +
 +	public function hasContact($addressbookid, $id) {
 +		return $this->getContact($addressbookid, $id) !== false;
 +	}
 +
 +	/**
 +	 * Creates a new contact
 +	 *
 +	 * In the Database and Shared backends contact be either a Contact object or a string
 +	 * with carddata to be able to play seamlessly with the CardDAV backend.
 +	 * If this method is called by the CardDAV backend, the carddata is already validated.
 +	 * NOTE: It's assumed that this method is called either from the CardDAV backend, the
 +	 * import script, or from the ownCloud web UI in which case either the uri parameter is
 +	 * set, or the contact has a UID. If neither is set, it will fail.
 +	 *
 +	 * @param string $addressbookid
 +	 * @param VCard|string $contact
 +	 * @param array $options - Optional (backend specific options)
 +	 * @return string|bool The identifier for the new contact or false on error.
 +	 */
 +	public function createContact($addressbookid, $contact, array $options = array()) {
 +
 +		$qname = 'createcontact';
 +		$uri = isset($options['uri']) ? $options['uri'] : null;
 +
 +		if(!$contact instanceof VCard) {
 +			try {
 +				$contact = Reader::read($contact);
 +			} catch(\Exception $e) {
 +				\OCP\Util::writeLog('contacts', __METHOD__.', exception: '.$e->getMessage(), \OCP\Util::ERROR);
 +				return false;
 +			}
 +		}
 +
 +		try {
 +			$contact->validate(VCard::REPAIR|VCard::UPGRADE);
 +		} catch (\Exception $e) {
 +			OCP\Util::writeLog('contacts', __METHOD__ . ' ' .
 +				'Error validating vcard: ' . $e->getMessage(), \OCP\Util::ERROR);
 +			return false;
 +		}
 +
 +		$uri = is_null($uri) ? $this->uniqueURI($addressbookid, $contact->UID . '.vcf') : $uri;
 +		$now = new \DateTime;
 +		$contact->REV = $now->format(\DateTime::W3C);
 +
 +		$appinfo = \OCP\App::getAppInfo('contacts');
 +		$appversion = \OCP\App::getAppVersion('contacts');
 +		$prodid = '-//ownCloud//NONSGML '.$appinfo['name'].' '.$appversion.'//EN';
 +		$contact->PRODID = $prodid;
 +
 +		$data = $contact->serialize();
 +		if(!isset(self::$preparedQueries[$qname])) {
 +		self::$preparedQueries[$qname] = \OCP\DB::prepare('INSERT INTO `'
 +			. $this->cardsTableName
 +			. '` (`addressbookid`,`fullname`,`carddata`,`uri`,`lastmodified`) VALUES(?,?,?,?,?)' );
 +		}
 +		try {
 +			$result = self::$preparedQueries[$qname]
 +				->execute(
 +					array(
 +						$addressbookid,
 +						(string)$contact->FN,
 +						$contact->serialize(),
 +						$uri,
 +						time()
 +					)
 +				);
 +			if (\OCP\DB::isError($result)) {
 +				\OCP\Util::writeLog('contacts', __METHOD__. 'DB error: ' . \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
 +				return false;
 +			}
 +		} catch(\Exception $e) {
 +			\OCP\Util::writeLog('contacts', __METHOD__.', exception: '.$e->getMessage(), \OCP\Util::ERROR);
 +			return false;
 +		}
 +		$newid = \OCP\DB::insertid($this->cardsTableName);
 +
 +		$this->setModifiedAddressBook($addressbookid);
 +		\OCP\Util::emitHook('OCA\Contacts', 'post_createContact',
 +			array('id' => $newid, 'parent' => $addressbookid, 'backend' => $this->name, 'contact' => $contact)
 +		);
 +		return (string)$newid;
 +	}
 +
 +	/**
 +	 * Updates a contact
 +	 *
 +	 * @param string $addressbookid
 +	 * @param mixed $id Contact ID
 +	 * @param VCard|string $contact
 +	 * @param array $options - Optional (backend specific options)
 +	 * @see getContact
 +	 * @return bool
 +	 */
 +	public function updateContact($addressbookid, $id, $contact, array $options = array()) {
 +		$noCollection = isset($options['noCollection']) ? $options['noCollection'] : false;
 +		$isBatch = isset($options['isBatch']) ? $options['isBatch'] : false;
 +		$qname = 'updatecontact';
 +
 +		$updateRevision = true;
 +		$isCardDAV = false;
 +		if(!$contact instanceof VCard) {
 +			try {
 +				$contact = Reader::read($contact);
 +			} catch(\Exception $e) {
 +				\OCP\Util::writeLog('contacts', __METHOD__.', exception: '.$e->getMessage(), \OCP\Util::ERROR);
 +				return false;
 +			}
 +		}
 +
 +		if(is_array($id)) {
 +			$where_query = '';
 +			if(isset($id['id'])) {
 +				$id = $id['id'];
 +			} elseif(isset($id['uri'])) {
 +				$updateRevision = false;
 +				$isCardDAV = true;
 +				$id = $this->getIdFromUri($id['uri']);
 +				if(is_null($id)) {
 +					\OCP\Util::writeLog('contacts', __METHOD__ . ' Couldn\'t find contact', \OCP\Util::ERROR);
 +					return false;
 +				}
 +			} else {
 +				throw new \Exception(
 +					__METHOD__ . ' If second argument is an array, either \'id\' or \'uri\' has to be set.'
 +				);
 +			}
 +		}
 +
 +		if($updateRevision || !isset($contact->REV)) {
 +			$now = new \DateTime;
 +			$contact->REV = $now->format(\DateTime::W3C);
 +		}
 +
 +		$data = $contact->serialize();
 +
 +		if($noCollection) {
 +			$me = $this->getContact(null, $id, $options);
 +			$addressbookid = $me['parent'];
 +		}
 +
 +		$updates = array($contact->FN, $data, time(), $id, $addressbookid);
 +
 +		$query = 'UPDATE `' . $this->cardsTableName
 +				. '` SET `fullname` = ?,`carddata` = ?, `lastmodified` = ? WHERE `id` = ? AND `addressbookid` = ?';
 +		if(!isset(self::$preparedQueries[$qname])) {
 +			self::$preparedQueries[$qname] = \OCP\DB::prepare($query);
 +		}
 +		try {
 +			$result = self::$preparedQueries[$qname]->execute($updates);
 +			if (\OCP\DB::isError($result)) {
 +				\OCP\Util::writeLog('contacts', __METHOD__. 'DB error: ' . \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
 +				return false;
 +			}
 +		} catch(\Exception $e) {
 +			\OCP\Util::writeLog('contacts', __METHOD__.', exception: '
 +				. $e->getMessage(), \OCP\Util::ERROR);
 +			\OCP\Util::writeLog('contacts', __METHOD__.', id' . $id, \OCP\Util::DEBUG);
 +			return false;
 +		}
 +
 +		$this->setModifiedAddressBook($addressbookid);
 +		if(!$isBatch) {
 +			\OCP\Util::emitHook('OCA\Contacts', 'post_updateContact',
 +				array(
 +					'backend' => $this->name,
 +					'addressBookId' => $addressbookid,
 +					'contactId' => $id,
 +					'contact' => $contact,
 +					'carddav' => $isCardDAV
 +				)
 +			);
 +		}
 +		return true;
 +	}
 +
 +	/**
 +	 * Deletes a contact
 +	 *
 +	 * @param string $addressbookid
 +	 * @param string $id
 +	 * @param array $options - Optional (backend specific options)
 +	 * @see getContact
 +	 * @return bool
 +	 */
 +	public function deleteContact($addressbookid, $id, array $options = array()) {
 +		// TODO: pass the uri in $options instead.
 +
 +		$qname = 'deletecontact';
 +		$noCollection = isset($options['noCollection']) ? $options['noCollection'] : false;
 +		$isBatch = isset($options['isBatch']) ? $options['isBatch'] : false;
 +
 +		if(is_array($id)) {
 +			if(isset($id['id'])) {
 +				$id = $id['id'];
 +			} elseif(isset($id['uri'])) {
 +				$id = $this->getIdFromUri($id['uri']);
 +				if(is_null($id)) {
 +					\OCP\Util::writeLog('contacts', __METHOD__ . ' Couldn\'t find contact', \OCP\Util::ERROR);
 +					return false;
 +				}
 +			} else {
 +				throw new Exception(
 +					__METHOD__ . ' If second argument is an array, either \'id\' or \'uri\' has to be set.'
 +				);
 +			}
 +		}
 +
 +		if(!$isBatch) {
 +			\OCP\Util::emitHook('OCA\Contacts', 'pre_deleteContact',
 +				array('id' => $id)
 +			);
 +		}
 +
 +		if($noCollection) {
 +			$me = $this->getContact(null, $id, $options);
 +			$addressbookid = $me['parent'];
 +		}
 +
 +		if(!isset(self::$preparedQueries[$qname])) {
 +			self::$preparedQueries[$qname] = \OCP\DB::prepare('DELETE FROM `'
 +				. $this->cardsTableName
 +				. '` WHERE `id` = ? AND `addressbookid` = ?');
 +		}
 +		\OCP\Util::writeLog('contacts', __METHOD__ . ' updates: ' . $id . '/' . $addressbookid, \OCP\Util::DEBUG);
 +		try {
 +			$result = self::$preparedQueries[$qname]->execute(array($id, $addressbookid));
 +			if (\OCP\DB::isError($result)) {
 +				\OCP\Util::writeLog('contacts', __METHOD__. 'DB error: '
 +					. \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
 +				return false;
 +			}
 +		} catch(\Exception $e) {
 +			\OCP\Util::writeLog('contacts', __METHOD__.
 +				', exception: ' . $e->getMessage(), \OCP\Util::ERROR);
 +			\OCP\Util::writeLog('contacts', __METHOD__.', id: '
 +				. $id, \OCP\Util::DEBUG);
 +			return false;
 +		}
 +		$this->setModifiedAddressBook($addressbookid);
 +		return true;
 +	}
 +
 +	/**
 +	 * @brief Get the last modification time for a contact.
 +	 *
 +	 * Must return a UNIX time stamp or null if the backend
 +	 * doesn't support it.
 +	 *
 +	 * @param string $addressbookid
 +	 * @param mixed $id
 +	 * @returns int | null
 +	 */
 +	public function lastModifiedContact($addressbookid, $id) {
 +		$contact = $this->getContact($addressbookid, $id);
 +		return ($contact ? $contact['lastmodified'] : null);
 +	}
 +
 +	/**
 +	 * @brief Get the contact id from the uri.
 +	 *
 +	 * @param mixed $id
 +	 * @returns int | null
 +	 */
 +	public function getIdFromUri($uri) {
 +		$query =  'SELECT `id` FROM `'. $this->cardsTableName . '` WHERE `uri` = ?';
 +		$stmt = \OCP\DB::prepare($query);
 +		$result = $stmt->execute(array($uri));
 +		if (\OCP\DB::isError($result)) {
 +			\OCP\Util::writeLog('contacts', __METHOD__. 'DB error: ' . \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
 +			return null;
 +		}
 +		$one = $result->fetchOne();
 +		if(!$one) {
 +			\OCP\Util::writeLog('contacts', __METHOD__.', Not found, uri: '. $uri, \OCP\Util::DEBUG);
 +			return null;
 +		}
 +		return $one;
 +	}
 +
 +	private function createAddressBookURI($displayname, $userid = null) {
 +		$userid = $userid ? $userid : \OCP\User::getUser();
 +		$name = str_replace(' ', '_', strtolower($displayname));
 +		try {
 +			$stmt = \OCP\DB::prepare('SELECT `uri` FROM `' . $this->addressBooksTableName . '` WHERE `userid` = ? ');
 +			$result = $stmt->execute(array($userid));
 +			if (\OCP\DB::isError($result)) {
 +				\OCP\Util::writeLog('contacts', __METHOD__. 'DB error: ' . \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
 +				return $name;
 +			}
 +		} catch(\Exception $e) {
 +			\OCP\Util::writeLog('contacts', __METHOD__ . ' exception: ' . $e->getMessage(), \OCP\Util::ERROR);
 +			return $name;
 +		}
 +		$uris = array();
 +		while($row = $result->fetchRow()) {
 +			$uris[] = $row['uri'];
 +		}
 +
 +		$newname = $name;
 +		$i = 1;
 +		while(in_array($newname, $uris)) {
 +			$newname = $name.$i;
 +			$i = $i + 1;
 +		}
 +		return $newname;
 +	}
 +
 +	/**
 +	* @brief Checks if a contact with the same URI already exist in the address book.
 +	* @param string $addressBookId Address book ID.
 +	* @param string $uri
 +	* @returns string Unique URI
 +	*/
 +	protected function uniqueURI($addressBookId, $uri) {
 +		$stmt = \OCP\DB::prepare( 'SELECT * FROM `' . $this->cardsTableName . '` WHERE `addressbookid` = ? AND `uri` = ?' );
 +
 +		$result = $stmt->execute(array($addressBookId, $uri));
 +
 +		if($result->numRows() > 0) {
 +			while(true) {
 +				$uri = Properties::generateUID() . '.vcf';
 +				$result = $stmt->execute(array($addressBookId, $uri));
 +				if($result->numRows() > 0) {
 +					continue;
 +				} else {
 +					return $uri;
 +				}
 +			}
 +		} else {
 +			return $uri;
 +		}
 +	}
 +}
diff --cc apps/contacts/lib/carddav/backend.php
index 7d26812,0000000..7b0155b
mode 100644,000000..100644
--- a/apps/contacts/lib/carddav/backend.php
+++ b/apps/contacts/lib/carddav/backend.php
@@@ -1,275 -1,0 +1,277 @@@
 +<?php
 +/**
 + * ownCloud - Addressbook
 + *
 + * @author Jakob Sack
 + * @copyright 2011 Jakob Sack mail at jakobsack.de
 + *
 + * This library is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
 + * License as published by the Free Software Foundation; either
 + * version 3 of the License, or any later version.
 + *
 + * This library is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
 + *
 + * You should have received a copy of the GNU Affero General Public
 + * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
 + *
 + */
 +
 +namespace OCA\Contacts\CardDAV;
 +
 +use OCA\Contacts;
 +
 +class Backend extends \Sabre_CardDAV_Backend_Abstract {
 +
 +	public function __construct($backends) {
 +		$this->backends = $backends;
 +	}
 +
 +	/**
 +	 * Returns the list of addressbooks for a specific user.
 +	 *
 +	 * @param string $principaluri
 +	 * @return array
 +	 */
 +	public function getAddressBooksForUser($principaluri) {
 +
 +		$app = new Contacts\App();
 +		$userAddressBooks = array();
 +		foreach($this->backends as $backendName) {
 +			$backend = $app->getBackend($backendName);
 +			$addressBooks = $backend->getAddressBooksForUser();
 +			
 +			if (is_array($addressBooks)) {
 +				foreach($addressBooks as $addressBook) {
 +					if($addressBook['owner'] != \OCP\USER::getUser()) {
 +						$addressBook['uri'] = $addressBook['uri'] . '_shared_by_' . $addressBook['owner'];
 +						$addressBook['displayname'] = $addressBook['displayname'];
 +					}
 +					$userAddressBooks[] = array(
 +						'id'  => $backend->name . '::' . $addressBook['id'],
 +						'uri' => $addressBook['uri'],
 +						'principaluri' => 'principals/'.$addressBook['owner'],
 +						'{DAV:}displayname' => $addressBook['displayname'],
 +						'{' . \Sabre_CardDAV_Plugin::NS_CARDDAV . '}addressbook-description'
 +								=> $addressBook['description'],
 +						'{http://calendarserver.org/ns/}getctag' => $addressBook['lastmodified'],
 +						'{' . \Sabre_CardDAV_Plugin::NS_CARDDAV . '}supported-address-data' =>
 +							new \Sabre_CardDAV_Property_SupportedAddressData(),
 +					);
 +				}
 +			}
 +		}
 +
 +		return $userAddressBooks;
 +	}
 +
 +
 +	/**
 +	 * Updates an addressbook's properties
 +	 *
 +	 * See Sabre_DAV_IProperties for a description of the mutations array, as
 +	 * well as the return value.
 +	 *
 +	 * @param mixed $addressbookid
 +	 * @param array $mutations
 +	 * @see Sabre_DAV_IProperties::updateProperties
 +	 * @return bool|array
 +	 */
 +	public function updateAddressBook($addressbookid, array $mutations) {
 +		$changes = array();
 +
 +		foreach($mutations as $property=>$newvalue) {
 +			switch($property) {
 +				case '{DAV:}displayname' :
 +					$changes['displayname'] = $newvalue;
 +					break;
 +				case '{' . \Sabre_CardDAV_Plugin::NS_CARDDAV
 +						. '}addressbook-description' :
 +					$changes['description'] = $newvalue;
 +					break;
 +				default :
 +					// If any unsupported values were being updated, we must
 +					// let the entire request fail.
 +					return false;
 +			}
 +		}
 +
 +		list($id, $backend) = $this->getBackendForAddressBook($addressbookid);
 +		return $backend->updateAddressBook($id, $changes);
 +
 +	}
 +
 +	/**
 +	 * Creates a new address book
 +	 *
 +	 * @param string $principaluri
 +	 * @param string $uri Just the 'basename' of the url.
 +	 * @param array $properties
 +	 * @return void
 +	 */
 +	public function createAddressBook($principaluri, $uri, array $properties) {
 +
 +		foreach($properties as $property => $newvalue) {
 +			switch($property) {
 +				case '{DAV:}displayname' :
 +					$properties['displayname'] = $newvalue;
 +					break;
 +				case '{' . \Sabre_CardDAV_Plugin::NS_CARDDAV
 +						. '}addressbook-description' :
 +					$properties['description'] = $newvalue;
 +					break;
 +				default :
 +					throw new \Sabre_DAV_Exception_BadRequest('Unknown property: '
 +						. $property);
 +			}
 +
 +		}
 +
 +		$properties['uri'] = $uri;
 +
- 		list(,$backend) = $this->getBackendForAddressBook($addressbookid);
- 		$backend->createAddressBook($properties, $userid);
++		$app = new Contacts\App();
++		$backend = $app->getBackend('local');
++
++		$backend->createAddressBook($properties);
 +	}
 +
 +	/**
 +	 * Deletes an entire addressbook and all its contents
 +	 *
 +	 * @param mixed $addressbookid
 +	 * @return void
 +	 */
 +	public function deleteAddressBook($addressbookid) {
 +		list($id, $backend) = $this->getBackendForAddressBook($addressbookid);
 +		$backend->deleteAddressBook($id);
 +	}
 +
 +	/**
 +	 * Returns the last modified date if the backend supports it.
 +	 *
 +	 * @param mixed $addressbookid
 +	 * @return void
 +	 */
 +	public function lastModifiedAddressBook($addressbookid) {
 +		list($id, $backend) = $this->getBackendForAddressBook($addressbookid);
 +		return $backend->lastModifiedAddressBook($id);
 +	}
 +
 +	/**
 +	 * Returns all cards for a specific addressbook id.
 +	 *
 +	 * @param mixed $addressbookid
 +	 * @return array
 +	 */
 +	public function getCards($addressbookid) {
 +		list($id, $backend) = $this->getBackendForAddressBook($addressbookid);
 +		$contacts = $backend->getContacts($id);
 +
 +		$cards = array();
 +		foreach($contacts as $contact) {
 +			$cards[] = array(
 +				'id' => $contact['id'],
 +				//'carddata' => $i['carddata'],
 +				'size' => strlen($contact['carddata']),
 +				'etag' => '"' . md5($contact['carddata']) . '"',
 +				'uri' => urlencode($contact['uri']),
 +				'lastmodified' => $contact['lastmodified'] );
 +		}
 +
 +		return $cards;
 +	}
 +
 +	/**
 +	 * Returns a specfic card
 +	 *
 +	 * @param mixed $addressbookid
 +	 * @param string $carduri
 +	 * @return array
 +	 */
 +	public function getCard($addressbookid, $carduri) {
 +		list($id, $backend) = $this->getBackendForAddressBook($addressbookid);
 +		try {
 +			$contact = $backend->getContact($id, array('uri' => urldecode($carduri)));
 +			if(is_array($contact) ) {
 +				$contact['etag'] = '"' . md5($contact['carddata']) . '"';
 +				return $contact;
 +			}
 +		} catch(\Exception $e) {
 +			//throw new \Sabre_DAV_Exception_NotFound($e->getMessage());
 +			\OCP\Util::writeLog('contacts', __METHOD__.', Exception: '. $e->getMessage(), \OCP\Util::DEBUG);
 +			return false;
 +		}
 +		return false;
 +	}
 +
 +	/**
 +	 * Creates a new card
 +	 *
 +	 * We don't return an Etag as the carddata can have been modified
 +	 * by Plugin::validate()
 +	 *
 +	 * @see Plugin::validate()
 +	 * @param mixed $addressbookid
 +	 * @param string $carduri
 +	 * @param string $carddata
 +	 * @return string|null
 +	 */
 +	public function createCard($addressbookid, $carduri, $carddata) {
 +		list($id, $backend) = $this->getBackendForAddressBook($addressbookid);
 +		$backend->createContact($id, $carddata, array('uri' => $carduri));
 +	}
 +
 +	/**
 +	 * Updates a card
 +	 *
 +	 * @param mixed $addressbookid
 +	 * @param string $carduri
 +	 * @param string $carddata
 +	 * @return null
 +	 */
 +	public function updateCard($addressbookid, $carduri, $carddata) {
 +		list($id, $backend) = $this->getBackendForAddressBook($addressbookid);
 +		$backend->updateContact($id, array('uri' => $carduri,), $carddata);
 +	}
 +
 +	/**
 +	 * Deletes a card
 +	 *
 +	 * @param mixed $addressbookid
 +	 * @param string $carduri
 +	 * @return bool
 +	 */
 +	public function deleteCard($addressbookid, $carduri) {
 +		list($id, $backend) = $this->getBackendForAddressBook($addressbookid);
 +		return $backend->deleteContact($id, array('uri' => $carduri));
 +	}
 +
 +	/**
 +	 * @brief gets the userid from a principal path
 +	 * @param string $principaluri
 +	 * @return string
 +	 */
 +	public function userIDByPrincipal($principaluri) {
 +		list(, $userid) = \Sabre_DAV_URLUtil::splitPath($principaluri);
 +		return $userid;
 +	}
 +
 +	/**
 +	 * Get the backend for an address book
 +	 *
 +	 * @param mixed $addressbookid
 +	 * @return array(string, \OCA\Contacts\Backend\AbstractBackend)
 +	 */
 +	public function getBackendForAddressBook($addressbookid) {
 +		list($backendName, $id) = explode('::', $addressbookid);
 +		$app = new Contacts\App();
 +		$backend = $app->getBackend($backendName);
 +		if($backend->name === $backendName && $backend->hasAddressBook($id)) {
 +			return array($id, $backend);
 +		}
 +		throw new \Sabre_DAV_Exception_NotFound('Backend not found: ' . $addressbookid);
 +	}
 +}
diff --cc apps/contacts/lib/carddav/plugin.php
index 60c9deb,0000000..45aa5da
mode 100644,000000..100644
--- a/apps/contacts/lib/carddav/plugin.php
+++ b/apps/contacts/lib/carddav/plugin.php
@@@ -1,69 -1,0 +1,65 @@@
 +<?php
 +/**
 + * ownCloud - CardDAV plugin
 + *
 + * The CardDAV plugin adds CardDAV functionality to the WebDAV server
 + *
 + * @author Thomas Tanghus
 + * @copyright 2013 Thomas Tanghus (thomas at tanghus.net)
 + *
 + * This library is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
 + * License as published by the Free Software Foundation; either
 + * version 3 of the License, or any later version.
 + *
 + * This library is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
 + *
 + * You should have received a copy of the GNU Affero General Public
 + * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
 + *
 + */
 +
 +namespace OCA\Contacts\CardDAV;
 +
 +use Sabre\VObject;
 +use OCA\Contacts\VObject\VCard;
 +
 +/**
 + * This class overrides Sabre_CardDAV_Plugin::validateVCard() to be able
 + * to import partially invalid vCards by ignoring invalid lines and to
 + * validate and upgrade using \OCA\Contacts\VCard.
 +*/
 +class Plugin extends \Sabre_CardDAV_Plugin {
 +
 +	/**
 +	* Checks if the submitted vCard data is in fact, valid.
 +	*
 +	* An exception is thrown if it's not.
 +	*
 +	* @param resource|string $data
 +	* @return void
 +	*/
 +	protected function validateVCard(&$data) {
 +
 +		// If it's a stream, we convert it to a string first.
 +		if (is_resource($data)) {
 +			$data = stream_get_contents($data);
 +		}
 +
- 		// Converting the data to unicode, if needed.
- 		$data = \Sabre_DAV_StringUtil::ensureUTF8($data);
- 		//\OCP\Util::writeLog('contacts', __METHOD__ . "\n".$data, \OCP\Util::DEBUG);
- 
 +		try {
 +			$vobj = VObject\Reader::read($data, VObject\Reader::OPTION_IGNORE_INVALID_LINES);
 +		} catch (VObject\ParseException $e) {
 +			throw new \Sabre_DAV_Exception_UnsupportedMediaType('This resource only supports valid vcard data. Parse error: ' . $e->getMessage());
 +		}
 +
 +		if ($vobj->name !== 'VCARD') {
 +			throw new \Sabre_DAV_Exception_UnsupportedMediaType('This collection can only support vcard objects.');
 +		}
 +
 +		$vobj->validate(VCard::REPAIR|VCard::UPGRADE);
 +		$data = $vobj->serialize();
 +	}
 +}
diff --cc apps/documents/ajax/admin.php
index 0000000,0000000..086ffee
new file mode 100644
--- /dev/null
+++ b/apps/documents/ajax/admin.php
@@@ -1,0 -1,0 +1,31 @@@
++<?php
++
++namespace OCA\Documents;
++
++\OCP\JSON::callCheck();
++\OCP\JSON::checkAdminUser();
++
++$converter = isset($_POST['converter']) ? $_POST['converter'] : null;
++$url = isset($_POST['url']) ? $_POST['url'] : null;
++try {
++	if (!is_null($converter)){
++		Config::setConverter($converter);
++	}
++	
++	if (!is_null($url)){
++		Config::setConverterUrl($url);
++	}
++	
++	if (Config::getConverter()!='local'){
++		if (!Converter::checkConnection()){
++			Helper::warnLog('Bad response from Format Filter Server');
++			\OCP\JSON::error(array('message' => Config::getL10n()->t('Format filter server is down or misconfigured') ));
++			exit();
++		}
++	}
++	
++	\OCP\JSON::success();
++} catch (\Exception $e){
++	\OCP\JSON::error();
++}
++exit();
diff --cc apps/documents/ajax/controller.php
index 39d6663,0000000..348e699
mode 100644,000000..100644
--- a/apps/documents/ajax/controller.php
+++ b/apps/documents/ajax/controller.php
@@@ -1,43 -1,0 +1,42 @@@
 +<?php
 +
 +/**
 + * ownCloud - Documents App
 + *
 + * @author Victor Dubiniuk
 + * @copyright 2013 Victor Dubiniuk victor.dubiniuk at gmail.com
 + *
 + * This file is licensed under the Affero General Public License version 3 or
 + * later.
 + */
 +
 +namespace OCA\Documents;
 +
 +class Controller {
 +
 +	/**
 +	 * Do security precheck
 +	 * @param bool callcheck - whether security token check is needed
 +	 * @return string userId of the currently logged in user
 +	 */
 +	public static function preDispatch($callcheck = true){
 +		if ($callcheck){
 +			\OCP\JSON::callCheck();
 +		}
 +		\OCP\JSON::checkAppEnabled('documents');
 +		\OCP\JSON::checkLoggedIn();
 +		return \OCP\User::getUser();
 +	}
 +	
 +	/**
 +	 * Do security precheck for not logged in users
 +	 * @param bool callcheck - whether security token check is needed
 +	 */
 +	public static function preDispatchGuest($callcheck = true){
 +		if ($callcheck){
 +			\OCP\JSON::callCheck();
 +		}
 +		\OCP\JSON::checkAppEnabled('documents');
- 		return '(guest)';
 +	}
 +
 +}
diff --cc apps/documents/ajax/documentController.php
index f6cc2b6,0000000..b5eb322
mode 100644,000000..100644
--- a/apps/documents/ajax/documentController.php
+++ b/apps/documents/ajax/documentController.php
@@@ -1,111 -1,0 +1,122 @@@
 +<?php
 +
 +/**
 + * ownCloud - Documents App
 + *
 + * @author Victor Dubiniuk
 + * @copyright 2013 Victor Dubiniuk victor.dubiniuk at gmail.com
 + *
 + * This file is licensed under the Affero General Public License version 3 or
 + * later.
 + */
 +
 +namespace OCA\Documents;
 +
 +class DocumentController extends Controller{
 +	const ODT_TEMPLATE = 'UEsDBBQAAAgAAC6aLENexjIMJwAAACcAAAAIAAAAbWltZXR5cGVhcHBsaWNhdGlvbi92bmQub2FzaXMub3BlbmRvY3VtZW50LnRleHRQSwMEFAAACAAALposQ9dwh9LYAgAA2AIAABgAAABUaHVtYm5haWxzL3RodW1ibmFpbC5wbmeJUE5HDQoaCgAAAA1JSERSAAAAxgAAAQAIAgAAAGc/nhcAAAKfSURBVHic7dKxCQAwDMCwDvn/5fQJQ6FIF3jw7O6BzrwO4DeWImYpYpYiZililiJmKWKWImYpYpYiZililiJmKWKWImYpYpYiZililiJmKWKWImYpYpYiZililiJmKWKWImYpYpYiZililiJmKWKWImYpYpYiZililiJmKWKWImYpYpYiZililiJmKWKWImYpYpYiZililiJmKWKWImYpYpYiZililiJmKWKWImYpYpYiZililiJm [...]
 +	
 +	public static function create($args){
 +		$uid = self::preDispatch();
 +		
 +		$view = new \OC\Files\View('/' . $uid . '/files');
 +		
 +		$dir = \OCP\Config::getUserValue(\OCP\User::getUser(), 'documents', 'save_path', '/');
++		if (!$view->is_dir($dir)){
++			$dir = '/';
++		}
 +		$path = Helper::getNewFileName($view, $dir . '/New Document.odt');
 +		
 +		$content = base64_decode(self::ODT_TEMPLATE);
 +		if (class_exists('\OC\Files\Type\TemplateManager')){
 +			$manager = \OC_Helper::getFileTemplateManager();
 +			$templateContent = $manager->getTemplate(Storage::MIMETYPE_LIBREOFFICE_WORDPROCESSOR);
 +			if ($templateContent){
 +				$content = $templateContent;
 +			}
 +		}
 +		
- 		$view->file_put_contents($path, $content);
++		if ($view->file_put_contents($path, $content)){
++			$info = $view->getFileInfo($path);
++			\OCP\JSON::success(array ('fileid' => $info['fileid']) );
++		} else {
++			\OCP\JSON::error(
++					array ('message' => Config::getL10n()->t('Can\'t create document'))
++			);
++		}
 +	}
 +
 +
 +	/**
 +	 * Process partial/complete file download
 +	 * @param array $args - array containing session id as an element with a key es_id 
 +	 */
 +	public static function serve($args){
 +		$session = new Db_Session();
- 		$sessionData = $session->load(@$args['es_id'])->getData();
++		$session->load(@$args['es_id']);
 +			
- 		$file = new File(@$sessionData['file_id']);
- 		if (!$file->isPublicShare()){
- 			self::preDispatch(false);
- 		} else {
- 			self::preDispatchGuest(false);
- 		}
++		self::preDispatchGuest();
 +		
- 		$filename = isset($sessionData['genesis_url']) ? $sessionData['genesis_url'] : '';
- 		$download = new Download($sessionData['owner'], $filename);
++		$filename = $session->getGenesisUrl() ? $session->getGenesisUrl() : '';
++		$download = new Download($session->getOwner(), $filename);
 +		$download->sendResponse();
 +	}
 +	
 +
 +	public static function rename($args){
- 		$fileId = intval(@$args['file_id']);
- 		$name = @$_POST['name'];
- 		$file = new File($fileId);
- 		$l = new \OC_L10n('documents');
++		$uid = self::preDispatch();
++		
++		$fileId = intval(Helper::getArrayValueByKey($args, 'file_id', 0));
++		$name = Helper::getArrayValueByKey($_POST, 'name');
++
++		$view = \OC\Files\Filesystem::getView();
++		$path = $view->getPath($fileId);
 +
- 		if (isset($name) && $file->getPermissions() & \OCP\PERMISSION_UPDATE) {
- 			if ($file->renameTo($name)) {
- 				// TODO: propagate to other clients
++		if (isset($name) && $view->is_file($path) && $view->isUpdatable($path)) {
++			$newPath = dirname($path) . '/' . $name;
++			if ($view->rename($path, $newPath)) {
 +				\OCP\JSON::success();
 +				return;
 +			}
 +		}
 +		\OCP\JSON::error(array(
- 			'message' => $l->t('You don\'t have permission to rename this document')
++			'message' => Config::getL10n()->t('You don\'t have permission to rename this document')
 +		));
 +	}
 +
 +	/**
 +	 * lists the documents the user has access to (including shared files, once the code in core has been fixed)
 +	 * also adds session and member info for these files
 +	 */
 +	public static function listAll(){
 +		self::preDispatch();
 +		
- 		$documents = Storage::getDocuments();
++		$found = Storage::getDocuments();
 +
 +		$fileIds = array();
- 		
- 		//$previewAvailable = \OCP\Preview::show($file);
- 		foreach ($documents as $key=>$document) {
- 			//\OCP\Preview::show($document['path']);
++		$documents = array();
++		foreach ($found as $key=>$document) {
++			if (is_object($document)){
++				$documents[] = $document->getData();
++			} else {
++				$documents[$key] = $document;
++			}
 +			$documents[$key]['icon'] = preg_replace('/\.png$/', '.svg', \OC_Helper::mimetypeIcon($document['mimetype']));
 +			$fileIds[] = $document['fileid'];
 +		}
 +
 +		usort($documents, function($a, $b){
 +			return @$b['mtime']-@$a['mtime'];
 +		});
 +		
 +		$session = new Db_Session();
 +		$sessions = $session->getCollectionBy('file_id', $fileIds);
 +
 +		$members = array();
 +		$member = new Db_Member();
 +		foreach ($sessions as $session) {			
 +			$members[$session['es_id']] = $member->getActiveCollection($session['es_id']);
 +		}
 +
 +		\OCP\JSON::success(array('documents' => $documents,'sessions' => $sessions,'members' => $members));
 +	}
 +}
diff --cc apps/documents/ajax/otpoll.php
index 6a83f82,0000000..bb3e30e
mode 100644,000000..100644
--- a/apps/documents/ajax/otpoll.php
+++ b/apps/documents/ajax/otpoll.php
@@@ -1,116 -1,0 +1,119 @@@
 +<?php
 +
 +/**
 + * ownCloud - Documents App
 + *
 + * @author Victor Dubiniuk
 + * @copyright 2013 Victor Dubiniuk victor.dubiniuk at gmail.com
 + *
 + * This file is licensed under the Affero General Public License version 3 or
 + * later.
 + */
 +
 +namespace OCA\Documents;
 +
 +class BadRequestException extends \Exception {
 +
 +	protected $body = "";
 +
 +	public function setBody($body){
 +		$this->body = $body;
 +	}
 +
 +	public function getBody(){
 +		return $this->body;
 +	}
 +}
 +
 +$response = array();
 +
 +try{
 +	$request = new Request();
 +	$esId = $request->getParam('args/es_id');
 +	
 +	$session = new Db_Session();
- 	$sessionData = $session->load($esId)->getData();
++	$session->load($esId);
++	
++	$memberId = $request->getParam('args/member_id');
++	$member = new Db_Member();
++	$member->load($memberId);
++	
++	if ($member->getIsGuest() || is_null($member->getIsGuest())){
++		Controller::preDispatchGuest(false);
++	} else {
++		Controller::preDispatch(false);
++	}
 +
 +	try {
- 		$file = new File(@$sessionData['file_id']);
++		$file = new File($session->getFileId());
 +	} catch (\Exception $e){
 +		Helper::warnLog('Error. Session no longer exists. ' . $e->getMessage());
 +		$ex = new BadRequestException();
 +		$ex->setBody($request->getRawRequest());
 +		throw $ex;
 +	}
- 	if (!$file->isPublicShare()){
- 		Controller::preDispatch(false);
- 	} else {
- 		Controller::preDispatchGuest(false);
- 	}
 +	
 +	$command = $request->getParam('command');
 +	switch ($command){
 +		case 'sync_ops':
 +			$seqHead = (string) $request->getParam('args/seq_head');
 +			if (!is_null($seqHead)){
- 				$memberId = $request->getParam('args/member_id');
 +				$ops = $request->getParam('args/client_ops');
 +				$hasOps = is_array($ops) && count($ops)>0;
 +
 +				$op = new Db_Op();
 +				$currentHead = $op->getHeadSeq($esId);
 +				
- 				$member = new Db_Member();
 +				try {
 +					$member->updateActivity($memberId);
 +				} catch (\Exception $e){
 +				}
 +
 +				// TODO handle the case ($currentHead == "") && ($seqHead != "")
 +				if ($seqHead == $currentHead) {
 +					// matching heads
 +					if ($hasOps) {
 +						// incoming ops without conflict
 +						// Add incoming ops, respond with a new head
 +						$newHead = Db_Op::addOpsArray($esId, $memberId, $ops);
 +						$response["result"] = 'added';
 +						$response["head_seq"] = $newHead ? $newHead : $currentHead;
 +					} else {
 +						// no incoming ops (just checking for new ops...)
 +						$response["result"] = 'new_ops';
 +						$response["ops"] = array();
 +						$response["head_seq"] = $currentHead;
 +					}
 +				} else { // HEADs do not match
 +					$response["ops"] = $op->getOpsAfterJson($esId, $seqHead);
 +					$response["head_seq"] = $currentHead;
 +					$response["result"] = $hasOps ? 'conflict' : 'new_ops';
 +				}
 +				
 +				$inactiveMembers = $member->updateByTimeout($esId);
 +				foreach ($inactiveMembers as $inactive){
 +					$op->removeCursor($esId, $inactive);
 +					$op->removeMember($esId, $inactive);
 +				}
 +			
 +			} else {
 +				// Error - no seq_head passed
 +				throw new BadRequestException();
 +			}
 +
 +			break;
 +		default:
 +			$ex = new BadRequestException();
 +			$ex->setBody($request->getRawRequest());
 +			throw $ex;
 +			break;
 +	}
 +
 +	\OCP\JSON::success($response);
 +} catch (BadRequestException $e){
 +	header('HTTP/1.1 400: BAD REQUEST');
 +	\OCP\JSON::error( array(
 +		'err' => 'bad request:[' . $e->getBody() . ']',
 +	));
 +}
 +exit();
diff --cc apps/documents/ajax/sessionController.php
index fee50ad,0000000..6750116
mode 100644,000000..100644
--- a/apps/documents/ajax/sessionController.php
+++ b/apps/documents/ajax/sessionController.php
@@@ -1,189 -1,0 +1,201 @@@
 +<?php
 +
 +/**
 + * ownCloud - Documents App
 + *
 + * @author Victor Dubiniuk
 + * @copyright 2013 Victor Dubiniuk victor.dubiniuk at gmail.com
 + *
 + * This file is licensed under the Affero General Public License version 3 or
 + * later.
 + */
 +
 +namespace OCA\Documents;
 +
 +class SessionController extends Controller{
 +	
 +	public static function joinAsGuest($args){
- 		$uid = self::preDispatchGuest();
- 		$uid = substr(@$_POST['name'], 0, 16) .' '. $uid;
- 		$token = @$args['token'];
++		self::preDispatchGuest();
++		
++		$uid = Helper::getArrayValueByKey($_POST, 'name');
++		$guestUid = substr($uid, 0, 16);
++		
 +		try {
++			$token = Helper::getArrayValueByKey($args, 'token');
 +			$file = File::getByShareToken($token);
- 			self::join($uid, $file);
++			$session = Db_Session::start($uid, $file, true);
++			\OCP\JSON::success($session);
 +		} catch (\Exception $e){
 +			Helper::warnLog('Starting a session failed. Reason: ' . $e->getMessage());
 +			\OCP\JSON::error();
 +			exit();
 +		}
 +	}
 +
 +	public static function joinAsUser($args){
 +		$uid = self::preDispatch();
- 		$fileId = intval(@$args['file_id']);
++		$fileId = Helper::getArrayValueByKey($args, 'file_id');
 +		
 +		try {
- 			$file = new File($fileId);
- 		
- 			if ($file->getPermissions() & \OCP\PERMISSION_UPDATE) {
- 				self::join($uid, $file);	
++			$view = \OC\Files\Filesystem::getView();
++			$path = $view->getPath($fileId);
++			
++			if ($view->isUpdatable($path)) {
++				$file = new File($fileId);
++				$session = Db_Session::start($uid, $file);
++				\OCP\JSON::success($session);
 +			} else {
++				$info = $view->getFileInfo();
 +				\OCP\JSON::success(array(
- 					'permissions' => $file->getPermissions(),
++					'permissions' => $info['permissions'],
 +					'id' => $fileId
 +				));
 +			}
 +			exit();
 +		} catch (\Exception $e){
 +			Helper::warnLog('Starting a session failed. Reason: ' . $e->getMessage());
 +			\OCP\JSON::error();
 +			exit();
 +		}
 +	}
 +	
- 	protected static function join($uid, $file){
- 			$session = Db_Session::start($uid, $file);
- 			\OCP\JSON::success($session);
- 			exit();
- 	}
 +
 +	/**
 +	 * Store the document content to its origin
 +	 */
 +	public static function save(){
 +		try {
 +			$esId = @$_SERVER['HTTP_WEBODF_SESSION_ID'];
 +			if (!$esId){
 +				throw new \Exception('Session id can not be empty');
 +			}
 +			
 +			$memberId = @$_SERVER['HTTP_WEBODF_MEMBER_ID'];
++			$currentMember = new Db_Member();
++			$currentMember->load($memberId);
++			if (is_null($currentMember->getIsGuest()) || $currentMember->getIsGuest()){
++				$uid = self::preDispatchGuest();
++			} else {
++				self::preDispatch();
++			}
++			
++			//check if member belongs to the session
++			if ($esId != $currentMember->getEsId()){
++				throw new \Exception($memberId . ' does not belong to session ' . $esId);
++			}
++			
 +			$sessionRevision = @$_SERVER['HTTP_WEBODF_SESSION_REVISION'];
 +			
 +			$stream = fopen('php://input','r');
 +			if (!$stream){
 +				throw new \Exception('New content missing');
 +			}
 +			$content = stream_get_contents($stream);
 +
 +			$session = new Db_Session();
 +			$session->load($esId);
 +			
- 			if (!$session->hasData()){
++			if (!$session->getEsId()){
 +				throw new \Exception('Session does not exist');
 +			}
- 			$sessionData = $session->getData();
- 			$file = new File($sessionData['file_id']);
- 			if (!$file->isPublicShare()){
- 				self::preDispatch();
- 			} else {
- 				self::preDispatchGuest();
- 			}
- 			
- 			list($view, $path) = $file->getOwnerViewAndPath();
 +
- 			$isWritable = ($view->file_exists($path) && $view->isUpdatable($path)) || $view->isCreatable($path);
- 			if (!$isWritable){
- 				throw new \Exception($path . ' does not exist or is not writable for user ' . $uid);
++			try {
++				if ($currentMember->getIsGuest()){
++					$file = File::getByShareToken($currentMember->getToken());
++				} else {
++					$file = new File($session->getFileId());
++				}
++				
++				list($view, $path) = $file->getOwnerViewAndPath();
++			} catch (\Exception $e){
++				//File was deleted or unshared. We need to save content as new file anyway
++				//Sorry, but for guests it would be lost :(
++				$view = new \OC\Files\View('/' . $uid . '/files');
++		
++				$dir = \OCP\Config::getUserValue(\OCP\User::getUser(), 'documents', 'save_path', '');
++				$path = Helper::getNewFileName($view, $dir . 'New Document.odt');
 +			}
 +			
 +			$member = new Db_Member();
 +			$members = $member->getActiveCollection($esId);
 +			$memberIds = array_map(
 +				function($x){
 +					return ($x['member_id']);
 +				},
 +				$members
 +			);
- 				
- 			//check if member belongs to the session
- 			if (!in_array($memberId, $memberIds)){
- 				throw new \Exception($memberId . ' does not belong to session ' . $esId);
- 			}
 +			
 +			// Active users except current user
 +			$memberCount = count($memberIds) - 1;
 +			
- 			if ($view->file_exists($path)){		
- 				
++			if ($view->file_exists($path)){
 +				$proxyStatus = \OC_FileProxy::$enabled;
 +				\OC_FileProxy::$enabled = false;	
 +				$currentHash = sha1($view->file_get_contents($path));
 +				\OC_FileProxy::$enabled = $proxyStatus;
 +				
- 				if (!Helper::isVersionsEnabled() && $currentHash !== $sessionData['genesis_hash']){
++				if (!Helper::isVersionsEnabled() && $currentHash !== $session->getGenesisHash()){
 +					// Original file was modified externally. Save to a new one
 +					$path = Helper::getNewFileName($view, $path, '-conflict');
 +				}
 +				
 +				$mimetype = $view->getMimeType($path);
 +			} else {
 +				$mimetype = Storage::MIMETYPE_LIBREOFFICE_WORDPROCESSOR;
 +			}
 +			
 +			$data = Filter::write($content, $mimetype);
 +			
 +			if ($view->file_put_contents($path, $data['content'])){
 +				// Not a last user
 +				if ($memberCount>0){
 +					// Update genesis hash to prevent conflicts
 +					Helper::debugLog('Update hash');
- 					
 +					$session->updateGenesisHash($esId, sha1($data['content']));
 +				} else {
 +					// Last user. Kill session data
 +					Db_Session::cleanUp($esId);
 +				}
 +				
 +				$view->touch($path);
 +			}
 +			\OCP\JSON::success();
- 			exit();
 +		} catch (\Exception $e){
 +			Helper::warnLog('Saving failed. Reason:' . $e->getMessage());
- 			\OCP\JSON::error(array('message'=>$e->getMessage()));
- 			exit();
++			//\OCP\JSON::error(array('message'=>$e->getMessage()));
++			\OC_Response::setStatus(500);
 +		}
++		exit();
 +	}
 +	
 +	public static function info(){
 +		self::preDispatch();
 +		$items = @$_POST['items'];
 +		$info = array();
 +
 +		if (is_array($items)){
 +			$session = new Db_Session();
 +			$info = $session->getInfoByFileId($items);
 +		}
 +
 +		\OCP\JSON::success(array(
 +			"info" => $info
 +		));
 +	}
 +	
 +	public static function listAll(){
 +		self::preDispatch();
 +		$session = new Db_Session();
 +		$sessions = $session->getCollection();
 +
 +		$preparedSessions = array_map(
 +				function($x){
 +					return ($x['es_id']);
 +				}, $sessions
 +		);
 +		\OCP\JSON::success(array(
 +			"session_list" => $preparedSessions
 +		));
 +	}
 +
 +}
diff --cc apps/documents/ajax/userController.php
index fa4f0bd,0000000..e47d2a3
mode 100644,000000..100644
--- a/apps/documents/ajax/userController.php
+++ b/apps/documents/ajax/userController.php
@@@ -1,53 -1,0 +1,75 @@@
 +<?php
 +
 +/**
 + * ownCloud - Documents App
 + *
 + * @author Victor Dubiniuk
 + * @copyright 2013 Victor Dubiniuk victor.dubiniuk at gmail.com
 + *
 + * This file is licensed under the Affero General Public License version 3 or
 + * later.
 + */
 +
 +namespace OCA\Documents;
 +
 +class UserController extends Controller{
 +	
 +	public static function disconnectUser($args){
 +		$uid = self::preDispatch();
 +		 self::disconnect($args, $uid);
 +	}
 +	
 +	public static function disconnectGuest($args){
 +		 self::preDispatchGuest();
 +		 self::disconnect($args, false);
 +	}
 +	
 +	protected static function disconnect($args, $uid){
 +		$esId = @$_POST['esId'];
 +		$member = new Db_Member();
 +		$member->loadBy('member_id', $args['member_id']);
 +		if ($esId && $member->hasData()){
- 			$memberData = $member->getData();
- 			if ($memberData['es_id']===$esId && $memberData['status']==Db_Member::MEMBER_STATUS_ACTIVE){
++			if ($member->getEsId() === $esId && $member->getStatus() == Db_Member::MEMBER_STATUS_ACTIVE){
 +				$member->deactivate(array($args['member_id']));
 +				$op = new Db_Op();
 +				$op->removeMember($esId, $args['member_id']);
 +			}
 +		}
 +		\OCP\JSON::success();
 +	}
 +	
++	public static function rename($args){
++		self::preDispatchGuest();
++		
++		$memberId = Helper::getArrayValueByKey($args, 'member_id');
++		$name = Helper::getArrayValueByKey($_POST, 'name');
++		$member = new Db_Member();
++		$member->load($memberId);
++
++		if ($member->getEsId()
++				&& $member->getStatus() == Db_Member::MEMBER_STATUS_ACTIVE 
++				&& $member->getIsGuest()
++		){
++			$guestMark = Db_Member::getGuestPostfix();
++			if (substr($name, -strlen($guestMark)) !== $guestMark){
++				$name = $name . ' ' . $guestMark;
++			}
++			
++			$op = new Db_Op();
++			$op->changeNick($member->getEsId(), $memberId, $name);
++		}
++		\OCP\JSON::success();
++	}
++	
 +	
 +	/**
 +	 * Stub - sends a generic avatar
 +	 */
 +	public static function sendAvatar(){
 +		$uid = self::preDispatch(false);
 +		$image = new \OC_Image('iVBORw0KGgoAAAANSUhEUgAAADAAAAAwEAYAAAAHkiXEAAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAABIAAAASABGyWs+AAAACXZwQWcAAAAwAAAAMADO7oxXAAAUWUlEQVR42u1beXBUVfb+3tZLOp21u0nSHbIRQkJYk5QwIhGNLMKAiDiCqGXpaKFSY2mpVTqOC9aUOo4zMjWihcoUboUysqqMDG6MJMAYooQtJJB962ydTi/v9Vt+f1zv73U3aQibOjOcKji5r1/fd9/3nXvuOefeBi7LZbksl+Wy/K8K81MP4GxiNptMDJOQkJ7ucDBMYaHdnprKsnl5RqPRCMTHGwyCAJjNoihJgM83MDA4qGnt7V1dbreq1tW53b29mnbypKZpGqCqP/X7RMvPhoC0NIeDZceNmznziisE4c47y8omTzaZFi9OS0tLS0kZPTo52WYrLJSkl [...]
 +		\OC_Util::obEnd();
 +
 +		echo $image->show();
 +	}
 +}
diff --cc apps/documents/appinfo/app.php
index d2b5136,0000000..e45a8ac
mode 100644,000000..100644
--- a/apps/documents/appinfo/app.php
+++ b/apps/documents/appinfo/app.php
@@@ -1,52 -1,0 +1,50 @@@
 +<?php
 +
 +/**
 + * ownCloud - Documents App
 + *
 + * @author Frank Karlitschek
-  * @copyright 2011 Frank Karlitschek karlitschek at kde.org
++ * @copyright 2013-2014 Frank Karlitschek karlitschek at kde.org
 + * 
 + * This library is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
 + * License as published by the Free Software Foundation; either 
 + * version 3 of the License, or any later version.
 + * 
 + * This library is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
 + *  
 + * You should have received a copy of the GNU Lesser General Public 
 + * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
 + * 
 + */
 +
 +OCP\App::register(array('order' => 70, 'id' => 'documents', 'name' => 'Documents'));
 +//OCP\App::registerAdmin('documents', 'settings');
 +OCP\App::registerPersonal('documents', 'personal');
 +
- $l10n = \OCP\Util::getL10N('documents');
- 
 +OCP\App::addNavigationEntry(array(
 +	'id' => 'documents_index', 
 +	'order' => 2,
 +	'href' => OCP\Util::linkTo('documents', 'index.php'), 
 +	'icon' => OCP\Util::imagePath('documents', 'documents.svg'),
- 	'name' => $l10n->t('Documents'))
++	'name' => OCA\Documents\Config::getL10n()->t('Documents'))
 +);
 +
 +OC::$CLASSPATH['OCA\Documents\Controller'] = 'documents/ajax/controller.php';
 +OC::$CLASSPATH['OCA\Documents\DocumentController'] = 'documents/ajax/documentController.php';
 +OC::$CLASSPATH['OCA\Documents\SessionController'] = 'documents/ajax/sessionController.php';
 +OC::$CLASSPATH['OCA\Documents\UserController'] = 'documents/ajax/userController.php';
 +OC::$CLASSPATH['OCA\Documents\Download_Simple'] = 'documents/lib/download/simple.php';
 +OC::$CLASSPATH['OCA\Documents\Download_Range'] = 'documents/lib/download/range.php';
 +OC::$CLASSPATH['OCA\Documents\Db_Session'] = 'documents/lib/db/session.php';
 +OC::$CLASSPATH['OCA\Documents\Db_Member'] = 'documents/lib/db/member.php';
 +OC::$CLASSPATH['OCA\Documents\Db_Op'] = 'documents/lib/db/op.php';
 +
 +//Script for registering file actions
 +OCP\Util::addScript('documents', 'viewer/viewer');
 +
 +//Listen to delete file signal
 +OCP\Util::connectHook('OC_Filesystem', 'delete', "OCA\Documents\Storage", "onDelete");
diff --cc apps/documents/appinfo/database.xml
index 8d4433e,0000000..acd0d3c
mode 100644,000000..100644
--- a/apps/documents/appinfo/database.xml
+++ b/apps/documents/appinfo/database.xml
@@@ -1,238 -1,0 +1,253 @@@
 +<?xml version="1.0" encoding="ISO-8859-1" ?>
 +<database>
 +	<name>*dbname*</name>
 +	<create>true</create>
 +	<overwrite>false</overwrite>
 +	<charset>utf8</charset>
 +	<table>
 +		<name>*dbprefix*documents_session</name>
 +		<declaration>
 +			
 +			<field>
 +				<name>es_id</name>
 +				<type>text</type>
 +				<notnull>true</notnull>
 +				<length>64</length>
 +			</field>
 +			<field>
 +				<name>genesis_url</name>
 +				<type>text</type>
 +				<length>512</length>
 +			</field>
 +			<field>
 +				<name>genesis_hash</name>
 +				<type>text</type>
 +				<length>128</length>
 +				<notnull>true</notnull>
 +			</field>
 +			<field>
 +				<name>file_id</name>
 +				<type>text</type>
 +				<length>512</length>
 +			</field>
 +			<field>
 +				<name>owner</name>
 +				<type>text</type>
 +				<notnull>true</notnull>
 +				<length>64</length>
 +			</field>
 +			
 +			<index>
 +				<name>documents_session_ei_idx</name>
 +				<primary>true</primary>
 +				<unique>true</unique>
 +				<field>
 +					<name>es_id</name>
 +					<sorting>ascending</sorting>
 +				</field>
 +			</index>
 +			
 +		</declaration>
 +	</table>
 +	
 +	<table>
 +		<name>*dbprefix*documents_member</name>
 +		<declaration>
 +			
 +			<field>
 +				<name>member_id</name>
 +				<type>integer</type>
 +				<notnull>true</notnull>
 +				<autoincrement>1</autoincrement>
 +				<unsigned>true</unsigned>
 +				<length>4</length>
 +			</field>
 +			<field>
 +				<name>es_id</name>
 +				<type>text</type>
 +				<notnull>true</notnull>
 +				<length>64</length>
 +			</field>
 +			<field>
 +				<name>uid</name>
 +				<type>text</type>
 +				<length>64</length>
 +			</field>
 +			<field>
 +				<name>color</name>
 +				<type>text</type>
 +				<length>32</length>
 +			</field>
 +			<field>
 +				<name>last_activity</name>
 +				<type>integer</type>
 +				<unsigned>true</unsigned>
 +				<length>4</length>
 +			</field>
 +			<field>
++				<name>is_guest</name>
++				<type>integer</type>
++				<default>0</default>
++				<notnull>true</notnull>
++				<unsigned>true</unsigned>
++				<length>1</length>
++			</field>
++			<field>
++				<name>token</name>
++				<type>text</type>
++				<default></default>
++				<notnull>false</notnull>
++				<length>32</length>
++			</field>
++			<field>
 +				<name>status</name>
 +				<type>integer</type>
 +				<default>1</default>
 +				<notnull>true</notnull>
 +				<unsigned>true</unsigned>
 +				<length>1</length>
 +			</field>
 +			
 +		</declaration>
 +	</table>
 +		
 +	<table>
 +		<name>*dbprefix*documents_op</name>
 +		<declaration>
 +			
 +			<field>
 +				<name>seq</name>
 +				<type>integer</type>
 +				<notnull>true</notnull>
 +				<autoincrement>1</autoincrement>
 +				<unsigned>true</unsigned>
 +				<length>4</length>
 +			</field>
 +			<field>
 +				<name>es_id</name>
 +				<type>text</type>
 +				<notnull>true</notnull>
 +				<length>64</length>
 +			</field>
 +			<field>
 +				<name>member</name>
 +				<type>integer</type>
 +				<default>1</default>
 +				<notnull>true</notnull>
 +				<unsigned>true</unsigned>
 +				<length>4</length>
 +			</field>
 +			<field>
 +				<name>opspec</name>
 +				<type>clob</type>
 +				<notnull>false</notnull>
 +			</field>
 +			
 +			<index>
 +				<name>seq_pKey</name>
 +				<primary>true</primary>
 +				<field>
 +					<name>seq</name>
 +					<sorting>ascending</sorting>
 +				</field>
 +			</index>
 +			<index>
 +				<name>documents_op_eis_idx</name>
 +				<unique>true</unique>
 +				<field>
 +					<name>es_id</name>
 +					<sorting>ascending</sorting>
 +				</field>
 +				<field>
 +					<name>seq</name>
 +					<sorting>ascending</sorting>
 +				</field>
 +			</index>
 +			
 +		</declaration>
 +	</table>
 +	<table>
 +		<name>*dbprefix*documents_invite</name>
 +		<declaration>
 +			
 +			<field>
 +				<name>es_id</name>
 +				<type>text</type>
 +				<notnull>true</notnull>
 +				<length>64</length>
 +			</field>
 +			<field>
 +				<name>uid</name>
 +				<type>text</type>
 +				<length>64</length>
 +			</field>
 +			<field>
 +				<name>status</name>
 +				<type>integer</type>
 +				<default>0</default>
 +				<length>2</length>
 +			</field>
 +			<field>
 +				<name>sent_on</name>
 +				<type>integer</type>
 +				<default></default>
 +				<notnull>false</notnull>
 +				<unsigned>true</unsigned>
 +				<length>4</length>
 +			</field>
 +			
 +		</declaration>
 +	</table>
 +	<table>
 +		<name>*dbprefix*documents_revisions</name>
 +		<declaration>
 +			
 +			<field>
 +				<name>es_id</name>
 +				<type>text</type>
 +				<notnull>true</notnull>
 +				<length>64</length>
 +			</field>
 +			<field>
 +				<name>seq_head</name>
 +				<type>integer</type>
 +				<notnull>true</notnull>
 +				<unsigned>true</unsigned>
 +				<length>4</length>
 +			</field>
 +			<field>
 +				<name>member_id</name>
 +				<type>integer</type>
 +				<notnull>true</notnull>
 +				<unsigned>true</unsigned>
 +				<length>4</length>
 +			</field>
 +			<field>
 +				<name>file_id</name>
 +				<type>text</type>
 +				<length>512</length>
 +			</field>
 +			<field>
 +				<name>save_hash</name>
 +				<type>text</type>
 +				<length>128</length>
 +				<notnull>true</notnull>
 +			</field>
 +			
 +			<index>
 +				<name>documents_rev_eis_idx</name>
 +				<unique>true</unique>
 +				<field>
 +					<name>es_id</name>
 +					<sorting>ascending</sorting>
 +				</field>
 +				<field>
 +					<name>seq_head</name>
 +					<sorting>ascending</sorting>
 +				</field>
 +			</index>
 +			
 +		</declaration>
 +	</table>
 +	
 +</database>
diff --cc apps/documents/appinfo/info.xml
index e51570d,0000000..9c191ca
mode 100644,000000..100644
--- a/apps/documents/appinfo/info.xml
+++ b/apps/documents/appinfo/info.xml
@@@ -1,14 -1,0 +1,14 @@@
 +<?xml version="1.0"?>
 +<info>
 +	<id>documents</id>
 +	<name>Documents</name>
 +	<description>An ownCloud app to work with office documents</description>
 +	<licence>AGPL</licence>
 +	<author>Frank Karlitschek</author>
- 	<require>5.0.19</require>
++	<require>6.0</require>
 +	<shipped>true</shipped>
 +	<default_enable/>
 +	<public>
 +		<documents>public.php</documents>
 +	</public>
 +</info>
diff --cc apps/documents/appinfo/routes.php
index 3a41ffe,0000000..d8a81cc
mode 100644,000000..100644
--- a/apps/documents/appinfo/routes.php
+++ b/apps/documents/appinfo/routes.php
@@@ -1,93 -1,0 +1,98 @@@
 +<?php
 +/**
 + * ownCloud - Documents App
 + *
 + * @author Victor Dubiniuk
 + * @copyright 2013 Victor Dubiniuk victor.dubiniuk at gmail.com
 + *
 + * This file is licensed under the Affero General Public License version 3 or
 + * later.
 + */
 +
 +/**
 + * Document routes
 + */
 +
 +$this->create('documents_documents_create', 'ajax/documents/create')
 +	->post()
 +	->action('\OCA\Documents\DocumentController', 'create')
 +;
 +$this->create('documents_genesis', 'ajax/genesis/{es_id}')
 +	->post()
 +	->action('\OCA\Documents\DocumentController', 'serve')
 +;
 +$this->create('documents_rename', 'ajax/documents/rename/{file_id}')
 +	->post()
 +	->action('\OCA\Documents\DocumentController', 'rename')
 +;
 +$this->create('documents_genesis', 'ajax/genesis/{es_id}')
 +	->get()
 +	->action('\OCA\Documents\DocumentController', 'serve')
 +;
 +
 +$this->create('documents_documents_list', 'ajax/documents/list')
 +	->get()
 +	->action('\OCA\Documents\DocumentController', 'listAll')
 +;
 +
 +/**
 + * Session routes
 + */
 +$this->create('documents_session_list', 'ajax/session/list')
 +	->get()
 +	->action('\OCA\Documents\SessionController', 'listAll')
 +;
 +$this->create('documents_session_list', 'ajax/session/list')
 +	->post()
 +	->action('\OCA\Documents\SessionController', 'listAll')
 +;
 +
 +$this->create('documents_session_info', 'ajax/session/info')
 +	->post()
 +	->action('\OCA\Documents\SessionController', 'info')
 +;
 +
 +$this->create('documents_session_joinasuser', 'ajax/session/joinasuser/{file_id}')
 +	->get()
 +	->action('\OCA\Documents\SessionController', 'joinAsUser')
 +;
 +$this->create('documents_session_joinasuser', 'ajax/session/joinasuser/{file_id}')
 +	->post()
 +	->action('\OCA\Documents\SessionController', 'joinAsUser')
 +;
 +$this->create('documents_session_joinasguest', 'ajax/session/joinasguest/{token}')
 +	->get()
 +	->action('\OCA\Documents\SessionController', 'joinAsGuest')
 +;
 +$this->create('documents_session_joinasguest', 'ajax/session/joinasguest/{token}')
 +	->post()
 +	->action('\OCA\Documents\SessionController', 'joinAsGuest')
 +;
 +
 +$this->create('documents_session_save', 'ajax/session/save')
 +	->post()
 +	->action('\OCA\Documents\SessionController', 'save')
 +;
 +
 +/**
 + * User routes
 + */
 +$this->create('documents_user_avatar', 'ajax/user/avatar')
 +	->get()
 +	->action('\OCA\Documents\UserController', 'sendAvatar')
 +;
 +
++$this->create('documents_user_rename', 'ajax/user/rename/{member_id}')
++	->post()
++	->action('\OCA\Documents\UserController', 'rename')
++;
++
 +$this->create('documents_user_disconnect', 'ajax/user/disconnect/{member_id}')
 +	->post()
 +	->action('\OCA\Documents\UserController', 'disconnectUser')
 +;
 +
 +$this->create('documents_user_disconnectGuest', 'ajax/user/disconnectGuest/{member_id}')
 +	->post()
 +	->action('\OCA\Documents\UserController', 'disconnectGuest')
 +;
diff --cc apps/documents/appinfo/update.php
index 18ed655,0000000..7a5274f
mode 100644,000000..100644
--- a/apps/documents/appinfo/update.php
+++ b/apps/documents/appinfo/update.php
@@@ -1,31 -1,0 +1,35 @@@
 +<?php
 +/**
 + * ownCloud - Documents App
 + *
 + * @author Victor Dubiniuk
 + * @copyright 2013 Victor Dubiniuk victor.dubiniuk at gmail.com
 + *
 + * This file is licensed under the Affero General Public License version 3 or
 + * later.
 + */
 +
 +$installedVersion = \OCP\Config::getAppValue('documents', 'installed_version');
 +
 +$cleanup = \OC_DB::prepare('DELETE FROM `*PREFIX*documents_member` WHERE `last_activity`=0 or `last_activity` is NULL');
 +$cleanup->execute();
 +
 +if (version_compare($installedVersion, '0.7', '<=')) {
 +	\OCP\Config::setAppValue('documents', 'unstable', 'false');
 +	$session = new \OCA\Documents\Db_Session();
 +	
 +	$query = \OC_DB::prepare('UPDATE `*PREFIX*documents_session` SET `genesis_url`=? WHERE `es_id`=?');
 +
 +	foreach ($session->getCollection() as $sessionData){
 +		$sessionData['genesis_url'] = \OCA\Documents\Genesis::DOCUMENTS_DIRNAME . $sessionData['genesis_url'];
 +		$query->execute(array(
 +			$sessionData['genesis_url'],
 +			$sessionData['es_id']
 +		));
 +		
 +	}
++}
++if (version_compare($installedVersion, '0.8', '<')) {
++	$query = \OC_DB::prepare('UPDATE `*PREFIX*documents_member` SET `is_guest`=1 WHERE `uid` LIKE \'%(guest)\' ');
++	$query->execute(array());
 +}
diff --cc apps/documents/appinfo/version
index d5cc44d,0000000..c18d72b
mode 100644,000000..100644
--- a/apps/documents/appinfo/version
+++ b/apps/documents/appinfo/version
@@@ -1,1 -1,0 +1,1 @@@
- 0.7.2
++0.8.1
diff --cc apps/documents/css/3rdparty/webodf/editor.css
index 23f86ee,0000000..6f23a0c
mode 100644,000000..100644
--- a/apps/documents/css/3rdparty/webodf/editor.css
+++ b/apps/documents/css/3rdparty/webodf/editor.css
@@@ -1,288 -1,0 +1,300 @@@
 +body.claro, #mainContainer {
 +    width: 100%;
 +    height: 100%;
 +    margin: 0;
 +    font-family: sans-serif;
 +    font-size: 10pt;
 +    padding: 0px;
 +}
 +
 +#mainContainer {
 +    background-color: gray;
 +}
 +
 +#editor *:focus {
 +    outline: none;
 +}
 +
 +#editor {
 +    border: none;
 +    box-shadow: 0px 0px 14px #555;
 +    overflow: hidden;
 +    padding: 0px !important;
 +    z-index: 4;
 +}
 +
 +#toolbar {
 +    overflow: hidden;
++    top: 0;
++    left: 0;
++    right: 0;
++    position: absolute;
++    z-index: 5;
++    box-shadow: 0 1px 5px rgba(0, 0, 0, 0.25);
 +}
 +
 +#container {
 +    text-align: center;
 +    background-color: #ddd;
 +    overflow: auto;
- 
 +    position: absolute;
 +    top: 30px;
 +    bottom: 0;
 +    left: 0;
 +    right: 0;
 +}
 +
 +#canvas {
-     box-shadow: 0px 0px 20px #aaa;
 +    margin-top: 30px;
 +    margin-left: 10px;
 +    margin-right: 10px;
 +    margin-bottom: 30px;
 +
 +    transform-origin: top center;
 +    -webkit-transform-origin: top center;
 +    -moz-transform-origin: top center;
 +    -o-transform-origin: top center;
-     overflow: hidden;
++    overflow: visible;
++}
 +
++/* Add shadow to the sizer and not the canvas,
++ * so that it will follow the smooth zooming
++ * of the slider and not have to be updated
++ * every time a gesture ends
++ */
++#canvas > div {
++    box-shadow: 0px 0px 20px #aaa;
 +    border: 1px solid #ccc;
 +}
 +
 +#collaboration {
 +    width: 20%;
 +    border-top-left-radius: 5px;
 +    border-top-right-radius: 5px;
 +
 +    box-shadow: 0 0 3px #888;
 +
 +    border: none;
 +}
 +
 +#collaboration > .dojoxExpandoTitle {
 +    border-top-left-radius: 5px;
 +    border-top-right-radius: 5px;
 +    border: none;
 +    background-color: rgb(243, 243, 243);
 +}
 +
 +#collaboration > .dojoxExpandoWrapper {
 +    width: 100%;
 +    background-color: rgb(243, 243, 243);
 +    border: 1px solid #769DC0;
 +    border: none;
 +
 +}
 +
 +#members {
 +    width: 70px;  
 +    padding: 2px;
 +    text-align: center;
 +    background-color: gray;
 +    border: none;
 +}
 +
 +#inviteButton {
 +    display: none;
 +
 +    color: white;
 +    margin-top: 5px;
 +    padding: 3px;
 +    word-wrap: break-word;
 +    text-align: center justify;
 +    margin-left: auto;
 +    margin-right: auto;
 +    border-radius: 5px;
 +    text-align: center;
 +    background-color: black;
 +    box-shadow: 0px 0px 5px rgb(90, 90, 90);
 +    border: 1px solid black;
 +    cursor: pointer;
 +}
 +#inviteButton:hover {
 +    color: yellow;
 +    box-shadow: 0px 0px 5px red;
 +}
 +#inviteButton:active {
 +    box-shadow: 0px 0px 15px red;
 +}
 +
 +#members > #nameInfo {
 +    padding-top: 3px;
 +    padding-bottom: 3px;
 +    width: 100%;
 +    background-color: #eef;
 +}
 +
 +#memberList .memberListButton {
 +    margin-top: 5px;
 +    padding-top: 3px;
 +    margin-left: auto;
 +    margin-right: auto;
 +    width: 68px;
 +    border-radius: 5px;
 +    text-align: center;
 +    background-color: black;
 +    box-shadow: 0px 0px 5px rgb(90, 90, 90);
 +    border: 1px solid black;
 +    cursor: pointer;
 +}
 +
 +#memberList .memberListLabel {
 +    color: white;
 +    border-radius: 5px;
 +    padding: 2px;
 +    font-size: 8pt;
 +    word-wrap: break-word;
 +    text-align: center justify;
 +}
 +div.memberListLabel[fullname]:before {
 +    content: attr(fullname) "";
 +}
 +
 +#memberList img {
 +    box-shadow: 0px 0px 5px rgb(90, 90, 90) inset;
 +    background-color: rgb(200, 200, 200);
 +    border-radius: 5px;
 +    border: 2px solid;
 +    height: 60px;
 +    width: 60px;
 +    display: block;
 +    margin: auto;
 +}
 +
 +#memberList img:hover {
 +    opacity: 0.9;
 +}
 +
 +.dijitDialog {
 +    border: none !important;
 +    box-shadow: 0 1px 50px rgba(0, 0, 0, 0.25) !important;
 +    -moz-box-shadow: 0 1px 50px rgba(0, 0, 0, 0.25) !important;
 +    -o-box-shadow: 0 1px 50px rgba(0, 0, 0, 0.25) !important;
 +    -webkit-box-shadow: 0 1px 50px rgba(0, 0, 0, 0.25) !important;
 +    -ms-box-shadow: 0 1px 50px rgba(0, 0, 0, 0.25) !important;
 +}
 +
 +.dijitDialogTitle {
 +    color: #333 !important;
 +    font-size: 14pt !important;
 +}
 +
 +.dijitDialogPaneContent {
 +    border: none !important;
 +    overflow: hidden !important;
 +    height: 510px !important;
 +    width: 450px !important;
 +}
 +
 +.dijitDialogPaneContent h3 {
 +    font-weight: normal;
 +    color: #333;
 +    font-size: 12pt;
 +    padding: 0px;
 +    width: 80%;
 +    border-bottom: 1px solid #eee;
 +}
 +
 +.dijitTabPaneWrapper {
 +    border: none !important;
 +}
 +.dijitDialogTitleBar {
 +    border: none !important;
 +    background-color: #fff !important;
 +}
 +
 +.dijitDialogPaneActionBar {
 +    margin: 0 !important;
 +}
 +
 +.dijitDialogUnderlay {
 +    background: radial-gradient(center, transparent, #333) !important;
 +    background: -webkit-radial-gradient(center, transparent , #333) !important;
 +    background: -moz-radial-gradient(center, transparent , #333) !important;
 +    background: -o-radial-gradient(center, transparent , #333) !important;
 +    background: -ms-radial-gradient(center, transparent , #333) !important;
 +}
 +
 +.labeledSelect > table {
 +    margin-left: 10px;
 +}
 +
 +.dijitSpinner {
 +    width: 50px !important;
 +}
 +
 +.dijitRadio {
 +    margin-top: 3px !important;
 +    margin-bottom: 3px !important;
 +}
 +
 +.dijitCheckBox {
 +    margin-top: 3px !important;
 +    margin-bottom: 7px !important;
 +}
 +.dojoxColorPicker {
 +    background-color: transparent !important;
 +    border: none !important;
 +}
 +
 +.dialogPreviewBox {
 +    height: 100px;
 +    width: 100%;
 +    border: 1px solid gray;
 +    background-color: white;
 +    text-align: center;
 +}
 +
- cursor div {
++cursor .handle {
 +    margin-top: 5px;
 +    padding-top: 3px;
 +    margin-left: auto;
 +    margin-right: auto;
 +    width: 64px !important;
 +    height: 68px !important;
 +    border-radius: 5px;
 +    text-align: center;
 +    background-color: black !important;
 +    box-shadow: 0px 0px 5px rgb(90, 90, 90);
 +    border: 1px solid black;
 +
 +    top: -85px !important;
 +    left: -34px !important;
 +}
 +
 +cursor img {
 +    box-shadow: 0px 0px 5px rgb(90, 90, 90) inset;
 +    background-color: rgb(200, 200, 200);
 +    border-radius: 5px;
 +    border: 2px solid;
 +    height: 60px !important;
 +    width: 60px !important;
 +    display: block;
 +    margin: auto;
 +}
 +
- cursor div.active {
++cursor .handle.active {
 +    opacity: 0.8;
 +}
 +
- cursor div:after {
++cursor .handle:after {
 +    content: ' ';
 +    position: absolute;
 +    width: 0px;
 +    height: 0px;
 +    border-style: solid;
 +    border-width: 8.7px 5px 0 5px;
 +    border-color: black transparent transparent transparent;
 +
 +    top: 100%;
 +    left: 43%;
 +}
 +
diff --cc apps/documents/css/style.css
index 13c3686,0000000..203d202
mode 100644,000000..100644
--- a/apps/documents/css/style.css
+++ b/apps/documents/css/style.css
@@@ -1,290 -1,0 +1,317 @@@
 +#editor ::-webkit-scrollbar-thumb {
 +	background-color: #fff;
 +}
 +
 +.documentslist { padding:5px; }
 +
 +.documentslist .document, 
 +.documentslist .progress,
 +.documentslist .add-document{
 +	display: inline-block;
 +	height: 200px;
 +	width: 200px;
 +	float: left;
 +	background-color: #e8e8e8;
 +	margin: 14px;
 +	vertical-align: top;
 +	border-radius: 5px;
 +}
 +
 +.add-document a {
 +	display: inline-block;
 +	position: relative;
 +	height: 100px;
 +	width: 200px;
 +	background-repeat: no-repeat;
 +	background-size: 32px;
 +	background-position: 50%;
 +}
 +
 +
 +.add-document a.add {
 +	border-bottom: 1px solid #fff;
 +}
 +.add-document .add,
 +.add-document .upload {
 +	opacity: .7;
 +}
 +.add-document .add:hover,
 +.add-document .add:focus,
 +.add-document #upload:hover .upload,
 +.add-document .upload:focus {
 +	opacity: 1;
 +}
 +
 +.add-document label {
 +	position: absolute;
 +	bottom: 10px;
 +	width: 100%;
 +	font-weight: normal;
 +	text-align: center;
 +}
 +
 +.documentslist .progress{
 +	position:absolute;
 +	left:232px;
 +	z-index:5;
 +	background-color: #e8e8e8;
 +}
 +
 +.documentslist .progress div{
 +	margin-top: 144px;
 +	text-align: center;
 +}
 +
 +.documentslist .document:hover,
 +.documentslist .document a:focus {
 +	background-color: #ddd;
 +}
 +
 +.documentslist .session-active {
 +	position: relative;
 +	margin-left: 128px;
 +	margin-top: 128px;
 +	width: 32px;
 +}
 +.document a {
 +	display: block;
 +	position: relative;
 +	height: 200px;
 +	width: 200px;
 +	background-repeat: no-repeat;
 +	background-size: 64px;
 +	background-position: 68px;
 +}
 +.document label {
 +	position: absolute;
 +	bottom: 5px;
 +	width: 100%;
 +	font-weight: normal;
 +	text-overflow: ellipsis;
 +	overflow: hidden;
 +	text-align: center;
 +	padding: 0 8px;
 +	-webkit-box-sizing: border-box;
 +	-moz-box-sizing: border-box;
 +	box-sizing: border-box;
 +	white-space: nowrap;
 +}
 +
 +#odf-toolbar{
 +	text-align: left;
 +	position: absolute;
 +	width: 100%;
 +	padding:0;
 +	z-index: 500;
 +}
 +
 +#odf-toolbar #dropdown{
 +	right:auto;
 +}
 +
 +#document-title{
 +/*	position: absolute;
 +	top: 9px;
 +	left:50%;
 +	margin:0; */
 +	padding: 4px 0 5px;
 +	border-bottom: 1px solid #E9E9E9;
 +
 +	text-align: center;
 +	font-weight: bold;
++	color:#fff;
++	background-color:#1d2d44;
 +}
++
++#document-title div.logo-wide{
++	float:left;
++	height: 24px;
++	width: 80px;
++	background-size:80px 24px;
++}
++
 +#document-title div{
 +	position: relative;
 +	/*margin-left:-50%;*/
 +}
 +#document-title>input {
- 	height:9px;
++	height:14px;
 +	margin: 0;
- 	padding-top:4px;
++	padding:3px 6px;
 +	width: 300px;
++	font-size: 12px;
++	color:#000;
 +}
 +
 +#odf-close{
++	margin-top:0;
 +	float: right;
 +}
 +
 +#odf-invite{
++	margin-top:0;
 +	float: left;
 +}
 +
 +#mainContainer{
 +	position:absolute;
 +	z-index:500;
 +}
 +
 +#documents-overlay,  #documents-overlay-below{
 +    position: fixed;
 +    top: 0;
 +    left: 0;
 +    width: 100%;
 +    height: 100%;
 +    filter:alpha(opacity=30);
 +    opacity: .3;
 +    z-index: 1000;
 +	background-color: #111;
 +}
 +
 +#documents-overlay-below{
 +	left:0;
 +	top:0;
 +    filter:alpha(opacity=100);
 +    opacity: 1;
 +	background:#f0f0f0;
 +	z-index: 999;
 +}
 +
 +#file_upload_start{
 +	display: block;
 +	position:relative;
 +	left:0; top:0; width:200px; height:100px; 
 +	margin-bottom: -110px;padding:0;
 +	cursor:pointer; overflow:hidden;
 +	font-size:1em;
 +	-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; filter:alpha(opacity=0); opacity:0;
 +	z-index:20; 
 +}
 +
 +#saving-document{
 +	float:right;
 +	display:none;
 +}
 +
 +#warning-connection-lost{
 +	padding: 6px 0;
 +	text-align: center;
 +	color: #ffffff;
 +	background-color: #CE7070;
 +	font-size: 16px;
 +	font-weight: bold;
 +}
 +
 +#warning-connection-lost img {
 +	margin-right: 4px;
 +	float: right;
 +	height: 20px;
 +}
 +
 +#connection-lost{
 +	right: 5px;
 +	background: #fff;
 +	width: 95%;
 +	position: absolute;
 +	top: 87px;
 +}
 +
 +
 +/* override WebODF styling here */
 +
 +#mainContainer #collaboration{
 +	float:right;position: relative;z-index: 1;
 +	width: 70px;padding:5px;
 +}
 +
 +#members{
 +	padding-top: 69px !important;
 +}
 +
 +.memberListButton span{
 +	display: block;
 +    box-shadow: 0px 0px 5px rgb(90, 90, 90) inset;
 +    background-color: rgb(200, 200, 200);
 +    border-radius: 5px;
 +    border: 2px solid;
 +    display: block;
 +    margin: auto;
 +}
 +
 +.memberListButton img{
 +    border: 0 none !important;
 +}
 +
++.memberListButton input{
++	width:46px;
++}
++
 +#toolbar {
++	top:30px !important;
 +	border-bottom: none !important;
 +	padding: 5px 0 0 !important;
 +}
 +
 +#toolbar > .dijit{
 +	margin-left:3px;
 +}
 +#toolbar > span.dijit{
 +	margin-left: 0;
 +}
 +
 +#container {
 +	top: 38px !important;
 +}
 +
 +cursor > div {
 +	padding-bottom: 0 !important;
 +}
 +
 +editinfo > div.editInfoMarker {
 +	width: 4px;
 +	border-radius: 0;
 +	box-shadow: 0 0 0 #fff;
 +	background-clip:content-box;
 +	padding: 0 5px;
 +}
 +
 +editinfo > div.editInfoMarker:hover {
 +}
 +
 +.dijitToolbar .dijitDropDownButton {
 +	padding-top: 2px;
 +}
 +
 +.dijitSpinner .dijitSpinnerButtonContainer .dijitArrowButton {
 +margin-top:-1px;
 +}
 +
 +.claro .dijitTextBox .dijitInputInner,
 +.claro .dijitSpinner .dijitSpinnerButtonInner {
 +	margin: 0;
 +}
 +
 +/* part of dojo.css */
 +.dojoTabular {border-collapse: collapse; border-spacing: 0; border: 1px solid #ccc; margin: 0 1.5em;}
 +.dojoTabular th {text-align: center; font-weight: bold;}
 +.dojoTabular thead,.dojoTabular tfoot {background-color: #efefef; border: 1px solid #ccc; border-width: 1px 0;}
 +.dojoTabular th,.dojoTabular td {padding: 0.25em 0.5em;}
 +
 +/* raise notification z-index above the documents app */
 +#odf-toolbar + #notification-container {
 +	z-index: 501;
 +}
 +
 +document p{
 +	cursor:auto;
- }
++}
++
++
++/* backward compatibility */
++#document-title .logo-wide {
++	background-image: url(../../../../core/img/logo-wide.svg);
++	width: 147px;
++	height: 32px;
++}
diff --cc apps/documents/index.php
index 235192b,0000000..5ad1060
mode 100644,000000..100644
--- a/apps/documents/index.php
+++ b/apps/documents/index.php
@@@ -1,55 -1,0 +1,55 @@@
 +<?php
 +
 +/**
 + * ownCloud - Documents App
 + *
 + * @author Frank Karlitschek
-  * @copyright 2011 Frank Karlitschek karlitschek at kde.org
++ * @copyright 2013-2014 Frank Karlitschek karlitschek at kde.org
 + * 
 + * This library is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
 + * License as published by the Free Software Foundation; either 
 + * version 3 of the License, or any later version.
 + * 
 + * This library is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
 + *  
 + * You should have received a copy of the GNU Lesser General Public 
 + * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
 + * 
 + */
 +
 +
 +namespace OCA\Documents;
 +
 +\OCP\User::checkLoggedIn();
 +\OCP\JSON::checkAppEnabled('documents');
 +\OCP\App::setActiveNavigationEntry( 'documents_index' );
 +
 +\OCP\Util::addStyle( 'documents', 'style' );
 +\OCP\Util::addStyle( 'documents', '3rdparty/webodf/dojo-app');
 +\OCP\Util::addStyle( 'documents', '3rdparty/webodf/editor');
 +
 +\OCP\Util::addScript('documents', 'documents');
 +
 +\OCP\Util::addScript('files', 'file-upload');
 +\OCP\Util::addScript('files', 'jquery.iframe-transport');
 +\OCP\Util::addScript('files', 'jquery.fileupload');
 +
 +
 +$tmpl = new \OCP\Template('documents', 'documents', 'user');
 +
 +$unstable = \OCP\Config::getAppValue('documents', 'unstable', 'false');
 +$maxUploadFilesize = \OCP\Util::maxUploadFilesize("/");
 +$savePath = \OCP\Config::getUserValue(\OCP\User::getUser(), 'documents', 'save_path', '/');
 +
 +
 +$tmpl->assign('useUnstable', $unstable);
 +$tmpl->assign('uploadMaxFilesize', $maxUploadFilesize);
 +$tmpl->assign('uploadMaxHumanFilesize', \OCP\Util::humanFileSize($maxUploadFilesize));
 +$tmpl->assign('savePath', $savePath);
 +$tmpl->assign("allowShareWithLink", \OC_Appconfig::getValue('core', 'shareapi_allow_links', 'yes'));
 +
 +$tmpl->printPage();
diff --cc apps/documents/js/3rdparty/webodf/editor/Editor.js
index 86840e2,0000000..ce2d1b9
mode 100644,000000..100644
--- a/apps/documents/js/3rdparty/webodf/editor/Editor.js
+++ b/apps/documents/js/3rdparty/webodf/editor/Editor.js
@@@ -1,534 -1,0 +1,586 @@@
 +/**
 + * @license
 + * Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
 + *
 + * @licstart
 + * The JavaScript code in this page is free software: you can redistribute it
 + * and/or modify it under the terms of the GNU Affero General Public License
 + * (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + * the License, or (at your option) any later version.  The code is distributed
 + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 + *
 + * You should have received a copy of the GNU Affero General Public License
 + * along with this code.  If not, see <http://www.gnu.org/licenses/>.
 + *
 + * As additional permission under GNU AGPL version 3 section 7, you
 + * may distribute non-source (e.g., minimized or compacted) forms of
 + * that code without the copy of the GNU GPL normally required by
 + * section 4, provided you include this license notice and a URL
 + * through which recipients can access the Corresponding Source.
 + *
 + * As a special exception to the AGPL, any HTML file which merely makes function
 + * calls to this code, and for that purpose includes it by reference shall be
 + * deemed a separate work for copyright law purposes. In addition, the copyright
 + * holders of this code give you permission to combine this code with free
 + * software libraries that are released under the GNU LGPL. You may copy and
 + * distribute such a system following the terms of the GNU AGPL for this code
 + * and the LGPL for the libraries. If you modify this code, you may extend this
 + * exception to your version of the code, but you are not obligated to do so.
 + * If you do not wish to do so, delete this exception statement from your
 + * version.
 + *
 + * This license applies to this entire compilation.
 + * @licend
 + * @source: http://www.webodf.org/
 + * @source: https://github.com/kogmbh/WebODF/
 + */
 +
 +/*global runtime, define, document, odf, ops, window, gui, alert, saveAs, Blob */
 +
 +define("webodf/editor/Editor", [
 +    "webodf/editor/EditorSession",
 +    "webodf/editor/MemberListView",
 +    "dijit/layout/BorderContainer",
 +    "dijit/layout/ContentPane",
 +    "webodf/editor/Tools"],
 +
 +    function (EditorSession,
 +        MemberListView,
 +        BorderContainer,
 +        ContentPane,
 +        Tools) {
 +        "use strict";
 +
 +        runtime.loadClass('odf.OdfCanvas');
 +
 +        /**
 +         * @constructor
 +         * @param {{unstableFeaturesEnabled:boolean,
 +         *          loadCallback:function(),
 +         *          saveCallback:function(),
 +         *          closeCallback:function()}}
 +         * param {!ops.Server=} server
 +         * @param {!ServerFactory=} serverFactory
 +         */
 +        function Editor(args, server, serverFactory) {
 +
 +            var self = this,
 +                // Private
 +                session,
 +                editorSession,
 +                mainContainer,
 +                memberListView,
 +                tools,
 +                loadOdtFile = args.loadCallback,
 +                saveOdtFile = args.saveCallback,
 +                close = args.closeCallback,
 +                odfCanvas,
 +                eventNotifier = new core.EventNotifier([
 +                    Editor.EVENT_ERROR,
 +                    Editor.EVENT_BEFORESAVETOFILE,
 +                    Editor.EVENT_SAVEDTOFILE,
 +                    Editor.EVENT_HASLOCALUNSYNCEDOPERATIONSCHANGED,
 +                    Editor.EVENT_HASSESSIONHOSTCONNECTIONCHANGED
 +                ]),
 +                pendingMemberId,
 +                pendingEditorReadyCallback;
 +
 +            /**
 +             * @param {!string} eventid
 +             * @param {*} args
 +             * @return {undefined}
 +             */
 +            function fireEvent(eventid, args) {
 +                eventNotifier.emit(eventid, args);
 +            }
 +
 +            function getFileBlob(cbSuccess, cbError) {
 +                var odfContainer = odfCanvas.odfContainer();
 +
 +                if (odfContainer) {
 +                    odfContainer.createByteArray(cbSuccess, cbError);
 +                } else {
 +                    cbError("No odfContainer!");
 +                }
 +            }
 +
 +            /**
 +             * prepare all gui elements and load the given document.
 +             * after loading is completed, the given callback is called.
 +             * the caller still has to call editorSession.startEditing
 +             * which will insert the the cursor.
 +             *
 +             * @param {!string} initialDocumentUrl
 +             * @param {!string} memberId
 +             * @param {!function()} editorReadyCallback
 +             * @return {undefined}
 +             */
 +            function initDocLoading(initialDocumentUrl, memberId, editorReadyCallback) {
 +                runtime.assert(initialDocumentUrl, "document should be defined here.");
 +                runtime.assert(memberId !== undefined, "memberId should be defined here.");
 +                runtime.assert(!pendingEditorReadyCallback, "pendingEditorReadyCallback should not exist here.");
 +                runtime.assert(!editorSession, "editorSession should not exist here.");
 +                runtime.assert(!session, "session should not exist here.");
 +
 +                pendingMemberId = memberId;
 +                pendingEditorReadyCallback = editorReadyCallback;
 +
 +                odfCanvas.load(initialDocumentUrl);
 +            }
 +
 +
 +            /**
 +             * open the document,
 +             * call editorReadyCallback once everything is done.
 +             *
 +             * @param {!string} docUrl
 +             * @param {!string} memberId
 +             * @param {!function()} editorReadyCallback
 +             * @return {undefined}
 +             */
 +            this.openDocument = function (docUrl, memberId, editorReadyCallback) {
 +                initDocLoading(docUrl, memberId, function () {
 +                    runtime.loadClass("ops.OpAddMember");
 +                    var op = new ops.OpAddMember();
 +                    op.init({
 +                        memberid: memberId,
 +                        setProperties: {
 +                            fullName: runtime.tr("Unknown Author"),
 +                            color: "black",
 +                            imageUrl: "avatar-joe.png"
 +                        }
 +                    });
 +                    session.enqueue([op]);
 +                    editorReadyCallback();
 +                });
 +            };
 +
 +            /**
 +             * Closes a single-user document, and does cleanup.
 +             * @param {!function(!Object=)} callback, passing an error object in case of error
 +             * @return undefined;
 +             */
 +            this.closeDocument = function (callback) {
 +                runtime.assert(session, "session should exist here.");
 +                runtime.loadClass("ops.OpRemoveMember");
 +
 +                var op = new ops.OpRemoveMember();
 +                op.init({
 +                    memberid: editorSession.sessionController.getInputMemberId()
 +                });
 +                session.enqueue([op]);
 +
 +                session.close(function (err) {
 +                    if (err) {
 +                        callback(err);
 +                    } else {
 +                        editorSession.destroy(function (err) {
 +                            if (err) {
 +                                callback(err);
 +                            } else {
 +                                editorSession = undefined;
 +                                session.destroy(function (err) {
 +                                    if (err) {
 +                                        callback(err);
 +                                    } else {
 +                                        session = undefined;
 +                                        callback();
 +                                    }
 +                                });
 +                            }
 +                        });
 +                    }
 +                });
 +            };
 +
 +            /**
 +             * @param {!string} filename
 +             * @param {?function()} callback
 +             * @return {undefined}
 +             */
 +            this.saveDocument = function (filename, callback) {
 +                function onsuccess(data) {
 +                    var mimebase = "application/vnd.oasis.opendocument.",
 +                        mimetype = mimebase + "text",
 +                        blob;
 +                    filename = filename || "doc.odt";
 +                    if (filename.substr(-4) === ".odp") {
 +                        mimetype = mimebase + "presentation";
 +                    } else if (filename.substr(-4) === ".ods") {
 +                        mimetype = mimebase + "spreadsheet";
 +                    }
 +                    blob = new Blob([data.buffer], {type: mimetype});
 +                    saveAs(blob, filename);
 +                    //TODO: add callback as event handler to saveAs
 +                    fireEvent(Editor.EVENT_SAVEDTOFILE, null);
 +                }
 +                function onerror(error) {
 +                    // TODO: use callback for that
 +                    alert(error);
 +                }
 +
 +                fireEvent(Editor.EVENT_BEFORESAVETOFILE, null);
 +                getFileBlob(onsuccess, onerror);
 +            };
 +
 +            /**
 +             * @param {!Object} error
 +             * @return {undefined}
 +             */
 +            function handleOperationRouterErrors(error) {
 +                // TODO: translate error into Editor ids or at least document the possible values
 +                fireEvent(Editor.EVENT_ERROR, error);
 +            }
 +
 +            /**
 +             * open the initial document of an editing-session,
 +             * request a replay of previous operations, call
 +             * editorReadyCallback once everything is done.
 +             *
 +             * @param {!string} sessionId
 +             * @param {!string} memberId
 +             * @param {!function()} editorReadyCallback
 +             * @return {undefined}
 +             */
 +            this.openSession = function (sessionId, memberId, editorReadyCallback) {
 +                initDocLoading(server.getGenesisUrl(sessionId), memberId, function () {
 +                    // overwrite router 
 +                    // TODO: serverFactory should be a backendFactory,
 +                    // and there should be a backendFactory for local editing
 +                    var opRouter = serverFactory.createOperationRouter(sessionId, memberId, server, odfCanvas.odfContainer(), handleOperationRouterErrors);
 +                    session.setOperationRouter(opRouter);
 +                    // forward events
 +                    // TODO: relying here on that opRouter uses the same id strings ATM, those should be defined at OperationRouter interface
 +                    opRouter.subscribe(Editor.EVENT_HASLOCALUNSYNCEDOPERATIONSCHANGED, function (hasUnsyncedOps) {
 +                        fireEvent(Editor.EVENT_HASLOCALUNSYNCEDOPERATIONSCHANGED, hasUnsyncedOps);
 +                    });
 +                    opRouter.subscribe(Editor.EVENT_HASSESSIONHOSTCONNECTIONCHANGED, function (hasSessionHostConnection) {
 +                        fireEvent(Editor.EVENT_HASSESSIONHOSTCONNECTIONCHANGED, hasSessionHostConnection);
 +                    });
 +                    opRouter.subscribe(Editor.EVENT_BEFORESAVETOFILE, function () {
 +                        fireEvent(Editor.EVENT_BEFORESAVETOFILE, null);
 +                    });
 +                    opRouter.subscribe(Editor.EVENT_SAVEDTOFILE, function () {
 +                        fireEvent(Editor.EVENT_SAVEDTOFILE, null);
 +                    });
 +
 +                    // now get existing ops and after that let the user edit
 +                    opRouter.requestReplay(function done() {
 +                        editorReadyCallback();
 +                    });
 +
 +                });
 +            };
 +
 +            /**
 +             * Closes the current editing running editing (polling-timer),
 +             * cleanup.
 +             * @param {!function(!Object=)} callback, passing an error object in case of error
 +             * @return {undefined}
 +             */
 +            this.closeSession = function (callback) {
 +                runtime.assert(session, "session should exist here.");
 +                // TODO: there is a better pattern for this instead of unrolling
 +                session.close(function(err) {
 +                    if (err) {
 +                        callback(err);
 +                    } else {
 +                        // now also destroy session, will not be reused for new document
 +                        memberListView.setEditorSession(undefined);
 +                        editorSession.destroy(function(err) {
 +                            if (err) {
 +                                callback(err);
 +                            } else {
 +                                editorSession = undefined;
 +                                session.destroy(function(err) {
 +                                    if (err) {
 +                                        callback(err);
 +                                    } else {
 +                                        session = undefined;
 +                                        callback();
 +                                    }
 +                                });
 +                            }
 +                        });
 +                    }
 +                });
 +            };
 +
 +            /**
 +             * Adds a cursor and enables the tools and allows modifications.
 +             * Should be called inside/after editorReadyCallback.
 +             * TODO: turn this and endEditing() into readonly switch
 +             * @return {undefined}
 +             */
 +            this.startEditing = function () {
 +                runtime.assert(editorSession, "editorSession should exist here.");
 +
 +                tools.setEditorSession(editorSession);
++                editorSession.sessionController.insertLocalCursor();
 +                editorSession.sessionController.startEditing();
 +            };
 +
 +            /**
 +             * Removes the cursor and disables the tools and allows modifications.
 +             * Should be called before closeDocument, if startEditing was called before
 +             * @return {undefined}
 +             */
 +            this.endEditing = function () {
 +                runtime.assert(editorSession, "editorSession should exist here.");
 +
 +                tools.setEditorSession(undefined);
 +                editorSession.sessionController.endEditing();
++                editorSession.sessionController.removeLocalCursor();
 +            };
 +
 +            /**
 +             * Allows to register listeners for certain events. Currently
 +             * available events are, with the type of the argument passed to the callback:
 +             * Editor.EVENT_BEFORESAVETOFILE - no argument
 +             * Editor.EVENT_SAVEDTOFILE - no argument
 +             * Editor.EVENT_HASLOCALUNSYNCEDOPERATIONSCHANGED - boolean, reflecting new hasLocalUnsyncedOperations state
 +             * Editor.EVENT_HASSESSIONHOSTCONNECTIONCHANGED - boolean, reflecting new hasSessionhostConnection state
 +             * Editor.EVENT_ERROR - string, one of these errorcodes:
 +             *   "notMemberOfSession"
 +             *   "opExecutionFailure"
 +             *   "sessionDoesNotExist"
 +             *   "unknownOpReceived"
 +             *   "unknownServerReply"
 +             *   "unresolvableConflictingOps"
 +             *
 +             * @param {!string} eventid
 +             * @param {!Function} listener
 +             * @return {undefined}
 +             */
 +            this.addEventListener = function (eventid, listener) {
 +                eventNotifier.subscribe(eventid, listener);
 +            };
 +
 +            /**
 +             * @param {!string} eventid
 +             * @param {!Function} listener
 +             * @return {undefined}
 +             */
 +            this.removeEventListener = function (eventid, listener) {
 +                eventNotifier.unsubscribe(eventid, listener);
 +            };
 +
 +            /**
++             * Applies a CSS transformation to the toolbar
++             * to ensure that if there is a body-scroll,
++             * the toolbar remains visible at the top of
++             * the screen.
++             * The bodyscroll quirk has been observed on
++             * iOS, generally when the keyboard appears.
++             * But this workaround should function on
++             * other platforms that exhibit this behaviour
++             * as well.
++             * @return {undefined}
++             */
++            function translateToolbar() {
++                var bar = document.getElementById('toolbar'),
++                    y = document.body.scrollTop;
++
++                bar.style.WebkitTransformOrigin = "center top";
++                bar.style.WebkitTransform = 'translateY(' + y + 'px)';
++            }
++
++            /**
++             * FIXME: At the moment both the toolbar and the canvas
++             * container are absolutely positioned. Changing them to
++             * relative positioning to ensure that they do not overlap
++             * causes scrollbars *within* the container to disappear.
++             * Not sure why this happens, and a proper CSS fix has not
++             * been found yet, so for now we need to reposition
++             * the container using Js.
++             * @return {undefined}
++             */
++            function repositionContainer() {
++                document.getElementById('container').style.top = document.getElementById('toolbar').getBoundingClientRect().height + 'px';
++            }
++
++            /**
 +             * @param {!function(!Object=)} callback, passing an error object in case of error
 +             * @return {undefined}
 +             */
 +            this.destroy = function (callback) {
 +                var destroyMemberListView = memberListView ? memberListView.destroy : function(cb) { cb(); };
 +
++                window.removeEventListener('scroll', translateToolbar);
++                window.removeEventListener('focusout', translateToolbar);
++                window.removeEventListener('touchmove', translateToolbar);
++                window.removeEventListener('resize', repositionContainer);
++
 +                // TODO: decide if some forced close should be done here instead of enforcing proper API usage
 +                runtime.assert(!session, "session should not exist here.");
 +
 +                // TODO: investigate what else needs to be done
 +                mainContainer.destroyRecursive(true);
 +
 +                destroyMemberListView(function(err) {
 +                    if (err) {
 +                        callback(err);
 +                    } else {
 +                        tools.destroy(function(err) {
 +                            if (err) {
 +                                callback(err);
 +                            } else {
 +                                odfCanvas.destroy(function(err) {
 +                                    if (err) {
 +                                        callback(err);
 +                                    } else {
 +                                        callback();
 +                                    }
 +                                });
 +                            }
 +                        });
 +                    }
 +                });
 +            };
 +
 +            function setFocusToOdfCanvas() {
 +                editorSession.sessionController.getEventManager().focus();
 +            }
 +
 +            // init
 +            function init() {
 +                var editorPane, memberListPane,
 +                    inviteButton,
 +                    canvasElement = document.getElementById("canvas"),
++                    container = document.getElementById('container'),
 +                    memberListElement = document.getElementById('memberList'),
 +                    collabEditing = Boolean(server),
 +                    directParagraphStylingEnabled = (! collabEditing) || args.unstableFeaturesEnabled,
 +                    imageInsertingEnabled = (! collabEditing) || args.unstableFeaturesEnabled,
++                    hyperlinkEditingEnabled = (! collabEditing) || args.unstableFeaturesEnabled,
 +                    // annotations not yet properly supported for OT
 +                    annotationsEnabled = (! collabEditing) || args.unstableFeaturesEnabled,
 +                     // undo manager is not yet integrated with collaboration
 +                    undoRedoEnabled = (! collabEditing),
 +                    closeCallback;
 +
 +                // Extend runtime with a convenient translation function
 +                runtime.translateContent = function (node) {
 +                    var i,
 +                        element,
 +                        tag,
 +                        placeholder,
 +                        translatable = node.querySelectorAll("*[text-i18n]");
 +
 +                    for (i = 0; i < translatable.length; i += 1) {
 +                        element = translatable[i];
 +                        tag = element.localName;
 +                        placeholder = element.getAttribute('text-i18n');
 +                        if (tag === "label"
 +                                || tag === "span"
 +                                || /h\d/i.test(tag)) {
 +                            element.textContent = runtime.tr(placeholder);
 +                        }
 +                    }
 +                };
 +
 +                if (collabEditing) {
 +                    runtime.assert(memberListElement, 'missing "memberList" div in HTML');
 +                }
 +
 +                runtime.assert(canvasElement, 'missing "canvas" div in HTML');
 +
 +                // App Widgets
 +                mainContainer = new BorderContainer({}, 'mainContainer');
 +
 +                editorPane = new ContentPane({
 +                    region: 'center'
 +                }, 'editor');
 +                mainContainer.addChild(editorPane);
 +
 +                if (collabEditing) {
 +                    memberListPane = new ContentPane({
 +                        region: 'right',
 +                        title: runtime.tr("Members")
 +                    }, 'members');
 +                    mainContainer.addChild(memberListPane);
 +                    memberListView = new MemberListView(memberListElement);
 +                }
 +
 +                mainContainer.startup();
 +
 +                if (window.inviteButtonProxy) {
 +                    inviteButton = document.getElementById('inviteButton');
 +                    runtime.assert(inviteButton, 'missing "inviteButton" div in HTML');
 +                    inviteButton.innerText = runtime.tr("Invite Members");
 +                    inviteButton.style.display = "block";
 +                    inviteButton.onclick = window.inviteButtonProxy.clicked;
 +                }
 +
 +                tools = new Tools({
-                         onToolDone: setFocusToOdfCanvas,
-                         loadOdtFile: loadOdtFile,
-                         saveOdtFile: saveOdtFile,
-                         close: close,
-                         directParagraphStylingEnabled: directParagraphStylingEnabled,
-                         imageInsertingEnabled: imageInsertingEnabled,
-                         annotationsEnabled: annotationsEnabled,
-                         undoRedoEnabled: undoRedoEnabled
-                     });
++                    onToolDone: setFocusToOdfCanvas,
++                    loadOdtFile: loadOdtFile,
++                    saveOdtFile: saveOdtFile,
++                    close: close,
++                    directParagraphStylingEnabled: directParagraphStylingEnabled,
++                    imageInsertingEnabled: imageInsertingEnabled,
++                    hyperlinkEditingEnabled: hyperlinkEditingEnabled,
++                    annotationsEnabled: annotationsEnabled,
++                    undoRedoEnabled: undoRedoEnabled
++                });
 +
 +                odfCanvas = new odf.OdfCanvas(canvasElement);
-                 odfCanvas.enableAnnotations(annotationsEnabled);
++                odfCanvas.enableAnnotations(annotationsEnabled, true);
 +
 +                odfCanvas.addListener("statereadychange", function () {
 +                    var viewOptions = {
 +                            editInfoMarkersInitiallyVisible: collabEditing,
 +                            caretAvatarsInitiallyVisible: false,
 +                            caretBlinksOnRangeSelect: true
 +                        };
 +
 +                    // create session around loaded document
 +                    session = new ops.Session(odfCanvas);
 +                    editorSession = new EditorSession(session, pendingMemberId, {
 +                        viewOptions: viewOptions,
 +                        directParagraphStylingEnabled: directParagraphStylingEnabled,
-                         imageInsertingEnabled: imageInsertingEnabled
++                        imageInsertingEnabled: imageInsertingEnabled,
++                        hyperlinkEditingEnabled: hyperlinkEditingEnabled
 +                    });
 +                    if (undoRedoEnabled) {
 +                        editorSession.sessionController.setUndoManager(new gui.TrivialUndoManager());
 +                    }
 +
 +                    if (memberListView) {
 +                        memberListView.setEditorSession(editorSession);
 +                    }
 +
 +                    // and report back to caller
 +                    pendingEditorReadyCallback();
 +                    // reset
 +                    pendingEditorReadyCallback = null;
 +                    pendingMemberId = null;
 +                });
++
++                repositionContainer();
++
++                window.addEventListener('scroll', translateToolbar);
++                window.addEventListener('focusout', translateToolbar);
++                window.addEventListener('touchmove', translateToolbar);
++                window.addEventListener('resize', repositionContainer);
 +            }
 +
 +            init();
 +        }
 +
 +        /**@const @type {!string}*/
 +        Editor.EVENT_ERROR =                             "error";
 +        /**@const @type {!string}*/
 +        Editor.EVENT_BEFORESAVETOFILE =                  "beforeSaveToFile";
 +        /**@const @type {!string}*/
 +        Editor.EVENT_SAVEDTOFILE =                       "savedToFile";
 +        /**@const @type {!string}*/
 +        Editor.EVENT_HASLOCALUNSYNCEDOPERATIONSCHANGED = "hasLocalUnsyncedOperationsChanged";
 +        /**@const @type {!string}*/
 +        Editor.EVENT_HASSESSIONHOSTCONNECTIONCHANGED =   "hasSessionHostConnectionChanged";
 +
 +        return Editor;
 +    });
 +
 +// vim:expandtab
diff --cc apps/documents/js/3rdparty/webodf/editor/EditorSession.js
index 91d28b4,0000000..5c33e5a
mode 100644,000000..100644
--- a/apps/documents/js/3rdparty/webodf/editor/EditorSession.js
+++ b/apps/documents/js/3rdparty/webodf/editor/EditorSession.js
@@@ -1,660 -1,0 +1,666 @@@
 +/**
 + * @license
 + * Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
 + *
 + * @licstart
 + * The JavaScript code in this page is free software: you can redistribute it
 + * and/or modify it under the terms of the GNU Affero General Public License
 + * (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + * the License, or (at your option) any later version.  The code is distributed
 + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 + *
 + * You should have received a copy of the GNU Affero General Public License
 + * along with this code.  If not, see <http://www.gnu.org/licenses/>.
 + *
 + * As additional permission under GNU AGPL version 3 section 7, you
 + * may distribute non-source (e.g., minimized or compacted) forms of
 + * that code without the copy of the GNU GPL normally required by
 + * section 4, provided you include this license notice and a URL
 + * through which recipients can access the Corresponding Source.
 + *
 + * As a special exception to the AGPL, any HTML file which merely makes function
 + * calls to this code, and for that purpose includes it by reference shall be
 + * deemed a separate work for copyright law purposes. In addition, the copyright
 + * holders of this code give you permission to combine this code with free
 + * software libraries that are released under the GNU LGPL. You may copy and
 + * distribute such a system following the terms of the GNU AGPL for this code
 + * and the LGPL for the libraries. If you modify this code, you may extend this
 + * exception to your version of the code, but you are not obligated to do so.
 + * If you do not wish to do so, delete this exception statement from your
 + * version.
 + *
 + * This license applies to this entire compilation.
 + * @licend
 + * @source: http://www.webodf.org/
 + * @source: https://github.com/kogmbh/WebODF/
 + */
 +
 +/*global define, runtime, core, gui, ops, document */
 +
 +define("webodf/editor/EditorSession", [
 +    "dojo/text!" + OC.filePath('documents', 'css', 'fonts.css')
 +], function (fontsCSS) { // fontsCSS is retrieved as a string, using dojo's text retrieval AMD plugin
 +    "use strict";
 +
-     runtime.libraryPaths = function () {
-         return [ "../../webodf/lib" ];
-     };
- 
 +    runtime.loadClass("core.DomUtils");
 +    runtime.loadClass("odf.OdfUtils");
 +    runtime.loadClass("ops.OdtDocument");
 +    runtime.loadClass("ops.StepsTranslator");
 +    runtime.loadClass("ops.Session");
 +    runtime.loadClass("odf.Namespaces");
 +    runtime.loadClass("odf.OdfCanvas");
++    runtime.loadClass("odf.OdfUtils");
 +    runtime.loadClass("gui.CaretManager");
 +    runtime.loadClass("gui.Caret");
 +    runtime.loadClass("gui.SessionController");
 +    runtime.loadClass("gui.SessionView");
 +    runtime.loadClass("gui.TrivialUndoManager");
++    runtime.loadClass("gui.SvgSelectionView");
 +    runtime.loadClass("gui.SelectionViewManager");
 +    runtime.loadClass("core.EventNotifier");
 +    runtime.loadClass("gui.ShadowCursor");
 +
 +    /**
 +     * Instantiate a new editor session attached to an existing operation session
 +     * @param {!ops.Session} session
 +     * @param {!string} localMemberId
 +     * @param {{viewOptions:gui.SessionViewOptions,directParagraphStylingEnabled:boolean}} config
 +     * @constructor
 +     */
 +    var EditorSession = function EditorSession(session, localMemberId, config) {
 +        var self = this,
 +            currentParagraphNode = null,
 +            currentCommonStyleName = null,
 +            currentStyleName = null,
 +            caretManager,
 +            selectionViewManager,
 +            odtDocument = session.getOdtDocument(),
 +            textns = odf.Namespaces.textns,
 +            fontStyles = document.createElement('style'),
 +            formatting = odtDocument.getFormatting(),
 +            domUtils = new core.DomUtils(),
 +            odfUtils = new odf.OdfUtils(),
 +            eventNotifier = new core.EventNotifier([
 +                EditorSession.signalMemberAdded,
 +                EditorSession.signalMemberUpdated,
 +                EditorSession.signalMemberRemoved,
 +                EditorSession.signalCursorAdded,
 +                EditorSession.signalCursorMoved,
 +                EditorSession.signalCursorRemoved,
 +                EditorSession.signalParagraphChanged,
 +                EditorSession.signalCommonStyleCreated,
 +                EditorSession.signalCommonStyleDeleted,
 +                EditorSession.signalParagraphStyleModified,
 +                EditorSession.signalUndoStackChanged]),
 +            shadowCursor = new gui.ShadowCursor(odtDocument);
 +
 +        /**
 +         * @return {Array.<!string>}
 +         */
 +        function getAvailableFonts() {
 +            var availableFonts, regex, matches;
 +
 +            availableFonts = {};
 +
 +            regex =  /font-family *: *(?:\'([^']*)\'|\"([^"]*)\")/gm;
 +            matches = regex.exec(fontsCSS);
 +
 +            while (matches) {
 +                availableFonts[matches[1] || matches[2]] = 1;
 +                matches = regex.exec(fontsCSS);
 +            }
 +            availableFonts = Object.keys(availableFonts);
 +
 +            return availableFonts;
 +        }
 +
 +        function checkParagraphStyleName() {
 +            var newStyleName,
 +                newCommonStyleName;
 +
 +            newStyleName = currentParagraphNode.getAttributeNS(textns, 'style-name');
 +
 +            if (newStyleName !== currentStyleName) {
 +                currentStyleName = newStyleName;
 +                // check if common style is still the same
 +                newCommonStyleName = formatting.getFirstCommonParentStyleNameOrSelf(newStyleName);
 +                if (!newCommonStyleName) {
 +                    // Default style, empty-string name
 +                    currentCommonStyleName = newStyleName = currentStyleName = "";
 +                    self.emit(EditorSession.signalParagraphChanged, {
 +                        type: 'style',
 +                        node: currentParagraphNode,
 +                        styleName: currentCommonStyleName
 +                    });
 +                    return;
 +                }
 +                // a common style
 +                if (newCommonStyleName !== currentCommonStyleName) {
 +                    currentCommonStyleName = newCommonStyleName;
 +                    self.emit(EditorSession.signalParagraphChanged, {
 +                        type: 'style',
 +                        node: currentParagraphNode,
 +                        styleName: currentCommonStyleName
 +                    });
 +                }
 +            }
 +        }
 +        /**
 +         * Creates a NCName from the passed string
 +         * @param {!string} name
 +         * @return {!string}
 +         */
 +        function createNCName(name) {
 +            var letter,
 +                result = "",
 +                i;
 +
 +            // encode
 +            for (i = 0; i < name.length; i++) {
 +                letter = name[i];
 +                // simple approach, can be improved to not skip other allowed chars
 +                if (letter.match(/[a-zA-Z0-9.-_]/) !== null) {
 +                    result += letter;
 +                } else {
 +                    result += "_" + letter.charCodeAt(0).toString(16) + "_";
 +                }
 +            }
 +            // ensure leading char is from proper range
 +            if (result.match(/^[a-zA-Z_]/) === null) {
 +                result = "_" + result;
 +            }
 +
 +            return result;
 +        }
 +
 +        function uniqueParagraphStyleNCName(name) {
 +            var result,
 +                i = 0,
 +                ncMemberId = createNCName(localMemberId),
 +                ncName = createNCName(name);
 +
 +            // create default paragraph style
 +            // localMemberId is used to avoid id conflicts with ids created by other members
 +            result = ncName + "_" + ncMemberId;
 +            // then loop until result is really unique
 +            while (formatting.hasParagraphStyle(result)) {
 +                result = ncName + "_" + i + "_" + ncMemberId;
 +                i++;
 +            }
 +
 +            return result;
 +        }
 +
 +        function trackCursor(cursor) {
 +            var node;
 +
 +            node = odtDocument.getParagraphElement(cursor.getNode());
 +            if (!node) {
 +                return;
 +            }
 +            currentParagraphNode = node;
 +            checkParagraphStyleName();
 +        }
 +
 +        function trackCurrentParagraph(info) {
 +            var cursor = odtDocument.getCursor(localMemberId),
 +                range = cursor && cursor.getSelectedRange(),
-                 paragraphRange = odtDocument.getDOM().createRange();
++                paragraphRange = odtDocument.getDOMDocument().createRange();
 +            paragraphRange.selectNode(info.paragraphElement);
 +            if ((range && domUtils.rangesIntersect(range, paragraphRange)) || info.paragraphElement === currentParagraphNode) {
 +                self.emit(EditorSession.signalParagraphChanged, info);
 +                checkParagraphStyleName();
 +            }
 +            paragraphRange.detach();
 +        }
 +
 +        function onMemberAdded(member) {
 +            self.emit(EditorSession.signalMemberAdded, member.getMemberId());
 +        }
 +
 +        function onMemberUpdated(member) {
 +            self.emit(EditorSession.signalMemberUpdated, member.getMemberId());
 +        }
 +
 +        function onMemberRemoved(memberId) {
 +            self.emit(EditorSession.signalMemberRemoved, memberId);
 +        }
 +
 +        function onCursorAdded(cursor) {
 +            self.emit(EditorSession.signalCursorAdded, cursor.getMemberId());
 +            trackCursor(cursor);
 +        }
 +
 +        function onCursorRemoved(memberId) {
 +            self.emit(EditorSession.signalCursorRemoved, memberId);
 +        }
 +
 +        function onCursorMoved(cursor) {
 +            // Emit 'cursorMoved' only when *I* am moving the cursor, not the other users
 +            if (cursor.getMemberId() === localMemberId) {
 +                self.emit(EditorSession.signalCursorMoved, cursor);
 +                trackCursor(cursor);
 +            }
 +        }
 +
 +        function onStyleCreated(newStyleName) {
 +            self.emit(EditorSession.signalCommonStyleCreated, newStyleName);
 +        }
 +
 +        function onStyleDeleted(styleName) {
 +            self.emit(EditorSession.signalCommonStyleDeleted, styleName);
 +        }
 +
 +        function onParagraphStyleModified(styleName) {
 +            self.emit(EditorSession.signalParagraphStyleModified, styleName);
 +        }
 +
 +        /**
 +         * Call all subscribers for the given event with the specified argument
 +         * @param {!string} eventid
 +         * @param {Object} args
 +         */
 +        this.emit = function (eventid, args) {
 +            eventNotifier.emit(eventid, args);
 +        };
 +
 +        /**
 +         * Subscribe to a given event with a callback
 +         * @param {!string} eventid
 +         * @param {!Function} cb
 +         */
 +        this.subscribe = function (eventid, cb) {
 +            eventNotifier.subscribe(eventid, cb);
 +        };
 +
 +        /**
 +         * @param {!string} eventid
 +         * @param {!Function} cb
 +         * @return {undefined}
 +         */
 +        this.unsubscribe = function (eventid, cb) {
 +            eventNotifier.unsubscribe(eventid, cb);
 +        };
 +
 +        this.getCursorPosition = function () {
 +            return odtDocument.getCursorPosition(localMemberId);
 +        };
 +
 +        this.getCursorSelection = function () {
 +            return odtDocument.getCursorSelection(localMemberId);
 +        };
 +
 +        this.getOdfCanvas = function () {
 +            return odtDocument.getOdfCanvas();
 +        };
 +
 +        this.getCurrentParagraph = function () {
 +            return currentParagraphNode;
 +        };
 +
 +        this.getAvailableParagraphStyles = function () {
 +            return formatting.getAvailableParagraphStyles();
 +        };
 +
 +        this.getCurrentParagraphStyle = function () {
 +            return currentCommonStyleName;
 +        };
 +
 +        /**
 +         * Round the step up to the next step
 +         * @param {!number} step
-          * @returns {!boolean}
++         * @return {!boolean}
 +         */
 +        function roundUp(step) {
 +            return step === ops.StepsTranslator.NEXT_STEP;
 +        }
 +
 +        /**
 +         * Applies the paragraph style with the given
 +         * style name to all the paragraphs within
 +         * the cursor selection.
 +         * @param {!string} styleName
 +         * @return {undefined}
 +         */
 +        this.setCurrentParagraphStyle = function (styleName) {
 +            var range = odtDocument.getCursor(localMemberId).getSelectedRange(),
 +                paragraphs = odfUtils.getParagraphElements(range),
 +                opQueue = [];
 +
 +            paragraphs.forEach(function (paragraph) {
 +                var paragraphStartPoint = odtDocument.convertDomPointToCursorStep(paragraph, 0, roundUp),
 +                    paragraphStyleName = paragraph.getAttributeNS(odf.Namespaces.textns, "style-name"),
 +                    opSetParagraphStyle;
 +
 +                if (paragraphStyleName !== styleName) {
 +                    opSetParagraphStyle = new ops.OpSetParagraphStyle();
 +                    opSetParagraphStyle.init({
 +                        memberid: localMemberId,
 +                        styleName: styleName,
 +                        position: paragraphStartPoint
 +                    });
 +                    opQueue.push(opSetParagraphStyle);
 +                }
 +            });
 +
 +            if (opQueue.length > 0) {
 +                session.enqueue(opQueue);
 +            }
 +        };
 +
 +        this.insertTable = function (initialRows, initialColumns, tableStyleName, tableColumnStyleName, tableCellStyleMatrix) {
 +            var op = new ops.OpInsertTable();
 +            op.init({
 +                memberid: localMemberId,
 +                position: self.getCursorPosition(),
 +                initialRows: initialRows,
 +                initialColumns: initialColumns,
 +                tableStyleName: tableStyleName,
 +                tableColumnStyleName: tableColumnStyleName,
 +                tableCellStyleMatrix: tableCellStyleMatrix
 +            });
 +            session.enqueue([op]);
 +        };
 +
 +        /**
 +         * Takes a style name and returns the corresponding paragraph style
 +         * element. If the style name is an empty string, the default style
 +         * is returned.
 +         * @param {!string} styleName
 +         * @return {Element}
 +         */
 +        this.getParagraphStyleElement = function (styleName) {
 +            return (styleName === "")
 +                ? formatting.getDefaultStyleElement('paragraph')
 +                : odtDocument.getParagraphStyleElement(styleName);
 +        };
 +
 +        /**
 +         * Returns if the style is used anywhere in the document
 +         * @param {!Element} styleElement
 +         * @return {boolean}
 +         */
 +        this.isStyleUsed = function (styleElement) {
 +            return formatting.isStyleUsed(styleElement);
 +        };
 +
-         function getDefaultParagraphStyleAttributes () {
++        function getDefaultParagraphStyleAttributes() {
 +            var styleNode = formatting.getDefaultStyleElement('paragraph');
 +            if (styleNode) {
 +                return formatting.getInheritedStyleAttributes(styleNode);
 +            }
 +
 +            return null;
-         };
++        }
 +
 +        /**
 +         * Returns the attributes of a given paragraph style name
 +         * (with inheritance). If the name is an empty string,
 +         * the attributes of the default style are returned.
 +         * @param {!string} styleName
 +         * @return {Object}
 +         */
 +        this.getParagraphStyleAttributes = function (styleName) {
 +            return (styleName === "")
 +                ? getDefaultParagraphStyleAttributes()
 +                : odtDocument.getParagraphStyleAttributes(styleName);
 +        };
 +
 +        /**
 +         * Creates and enqueues a paragraph-style cloning operation.
 +         * Returns the created id for the new style.
 +         * @param {!string} styleName  id of the style to update
 +         * @param {!{paragraphProperties,textProperties}} setProperties  properties which are set
 +         * @param {!{paragraphPropertyNames,textPropertyNames}=} removedProperties  properties which are removed
 +         * @return {undefined}
 +         */
 +        this.updateParagraphStyle = function (styleName, setProperties, removedProperties) {
 +            var op;
 +            op = new ops.OpUpdateParagraphStyle();
 +            op.init({
 +                memberid: localMemberId,
 +                styleName: styleName,
 +                setProperties: setProperties,
 +                removedProperties: (!removedProperties) ? {} : removedProperties
 +            });
 +            session.enqueue([op]);
 +        };
 +
 +        /**
 +         * Creates and enqueues a paragraph-style cloning operation.
 +         * Returns the created id for the new style.
 +         * @param {!string} styleName id of the style to clone
 +         * @param {!string} newStyleDisplayName display name of the new style
 +         * @return {!string}
 +         */
 +        this.cloneParagraphStyle = function (styleName, newStyleDisplayName) {
 +            var newStyleName = uniqueParagraphStyleNCName(newStyleDisplayName),
 +                styleNode = self.getParagraphStyleElement(styleName),
 +                formatting = odtDocument.getFormatting(),
 +                op, setProperties, attributes, i;
 +
 +            setProperties = formatting.getStyleAttributes(styleNode);
 +            // copy any attributes directly on the style
 +            attributes = styleNode.attributes;
 +            for (i = 0; i < attributes.length; i += 1) {
 +                // skip...
 +                // * style:display-name -> not copied, set to new string below
 +                // * style:name         -> not copied, set from op by styleName property
 +                // * style:family       -> "paragraph" always, set by op
 +                if (!/^(style:display-name|style:name|style:family)/.test(attributes[i].name)) {
 +                    setProperties[attributes[i].name] = attributes[i].value;
 +                }
 +            }
 +
 +            setProperties['style:display-name'] = newStyleDisplayName;
 +
 +            op = new ops.OpAddStyle();
 +            op.init({
 +                memberid: localMemberId,
 +                styleName: newStyleName,
 +                styleFamily: 'paragraph',
 +                setProperties: setProperties
 +            });
 +            session.enqueue([op]);
 +
 +            return newStyleName;
 +        };
 +
 +        this.deleteStyle = function (styleName) {
 +            var op;
 +            op = new ops.OpRemoveStyle();
 +            op.init({
 +                memberid: localMemberId,
 +                styleName: styleName,
 +                styleFamily: 'paragraph'
 +            });
 +            session.enqueue([op]);
 +        };
 +
 +        /**
 +         * Returns an array of the declared fonts in the ODF document,
 +         * with 'duplicates' like Arial1, Arial2, etc removed. The alphabetically
 +         * first font name for any given family is kept.
 +         * The elements of the array are objects containing the font's name and
 +         * the family.
 +         * @return {Array.<!Object>}
 +         */
 +        this.getDeclaredFonts = function () {
 +            var fontMap = formatting.getFontMap(),
 +                usedFamilies = [],
 +                array = [],
 +                sortedNames,
 +                key,
 +                value,
 +                i;
 +
 +            // Sort all the keys in the font map alphabetically
 +            sortedNames = Object.keys(fontMap);
 +            sortedNames.sort();
 +
 +            for (i = 0; i < sortedNames.length; i += 1) {
 +                key = sortedNames[i];
 +                value = fontMap[key];
 +
 +                // Use the font declaration only if the family is not already used.
 +                // Therefore we are able to discard the alphabetic successors of the first
 +                // font name.
 +                if (usedFamilies.indexOf(value) === -1) {
 +                    array.push({
 +                        name: key,
 +                        family: value
 +                    });
 +                    if (value) {
 +                        usedFamilies.push(value);
 +                    }
 +                }
 +            }
 +
 +            return array;
 +        };
 +
++        this.getSelectedHyperlinks = function () {
++            var cursor = odtDocument.getCursor(localMemberId);
++            // no own cursor yet/currently added?
++            if (!cursor) {
++                return [];
++            }
++            return odfUtils.getHyperlinkElements(cursor.getSelectedRange());
++        };
++
++        this.getSelectedRange = function () {
++            var cursor = odtDocument.getCursor(localMemberId);
++            return cursor && cursor.getSelectedRange();
++        };
++
 +        function undoStackModified(e) {
 +            self.emit(EditorSession.signalUndoStackChanged, e);
 +        }
 +
-         this.hasUndoManager = function () {
-             return Boolean(self.sessionController.getUndoManager());
-         };
- 
 +        this.undo = function () {
-             var undoManager = self.sessionController.getUndoManager();
-             undoManager.moveBackward(1);
++            self.sessionController.undo();
 +        };
 +
 +        this.redo = function () {
-             var undoManager = self.sessionController.getUndoManager();
-             undoManager.moveForward(1);
++            self.sessionController.redo();
 +        };
 +
 +        /**
 +         *
 +         * @param {!string} mimetype
 +         * @param {!string} content base64 encoded string
 +         * @param {!number} width
 +         * @param {!number} height
 +         */
 +        this.insertImage = function (mimetype, content, width, height) {
-             self.sessionController.getTextManipulator().removeCurrentSelection();
-             self.sessionController.getImageManager().insertImage(mimetype, content, width, height);
++            self.sessionController.getTextController().removeCurrentSelection();
++            self.sessionController.getImageController().insertImage(mimetype, content, width, height);
 +        };
 +
 +        /**
 +         * @param {!string} memberId
 +         * @return {?ops.Member}
 +         */
 +        this.getMember = function (memberId) {
 +            return odtDocument.getMember(memberId);
 +        };
 +
 +        /**
 +         * @param {!function(!Object=)} callback, passing an error object in case of error
 +         * @return {undefined}
 +         */
 +        this.destroy = function(callback) {
 +            var head = document.getElementsByTagName('head')[0];
 +
 +            head.removeChild(fontStyles);
 +
-             odtDocument.unsubscribe(ops.OdtDocument.signalMemberAdded, onMemberAdded);
-             odtDocument.unsubscribe(ops.OdtDocument.signalMemberUpdated, onMemberUpdated);
-             odtDocument.unsubscribe(ops.OdtDocument.signalMemberRemoved, onMemberRemoved);
-             odtDocument.unsubscribe(ops.OdtDocument.signalCursorAdded, onCursorAdded);
-             odtDocument.unsubscribe(ops.OdtDocument.signalCursorRemoved, onCursorRemoved);
-             odtDocument.unsubscribe(ops.OdtDocument.signalCursorMoved, onCursorMoved);
++            odtDocument.unsubscribe(ops.Document.signalMemberAdded, onMemberAdded);
++            odtDocument.unsubscribe(ops.Document.signalMemberUpdated, onMemberUpdated);
++            odtDocument.unsubscribe(ops.Document.signalMemberRemoved, onMemberRemoved);
++            odtDocument.unsubscribe(ops.Document.signalCursorAdded, onCursorAdded);
++            odtDocument.unsubscribe(ops.Document.signalCursorRemoved, onCursorRemoved);
++            odtDocument.unsubscribe(ops.Document.signalCursorMoved, onCursorMoved);
 +            odtDocument.unsubscribe(ops.OdtDocument.signalCommonStyleCreated, onStyleCreated);
 +            odtDocument.unsubscribe(ops.OdtDocument.signalCommonStyleDeleted, onStyleDeleted);
 +            odtDocument.unsubscribe(ops.OdtDocument.signalParagraphStyleModified, onParagraphStyleModified);
 +            odtDocument.unsubscribe(ops.OdtDocument.signalParagraphChanged, trackCurrentParagraph);
 +            odtDocument.unsubscribe(ops.OdtDocument.signalUndoStackChanged, undoStackModified);
 +
 +            self.sessionView.destroy(function(err) {
 +                if (err) {
 +                    callback(err);
 +                } else {
 +                    delete self.sessionView;
 +                    caretManager.destroy(function(err) {
 +                        if (err) {
 +                            callback(err);
 +                        } else {
 +                            selectionViewManager.destroy(function(err) {
 +                                if (err) {
 +                                    callback(err);
 +                                } else {
 +                                    self.sessionController.destroy(function(err) {
 +                                        if (err) {
 +                                            callback(err);
 +                                        } else {
 +                                            delete self.sessionController;
 +                                            callback();
 +                                        }
 +                                    });
 +                                }
 +                            });
 +                        }
 +                    });
 +                }
 +            });
 +        };
 +
 +        function init() {
 +            var head = document.getElementsByTagName('head')[0];
 +
 +            // TODO: fonts.css should be rather done by odfCanvas, or?
 +            fontStyles.type = 'text/css';
 +            fontStyles.media = 'screen, print, handheld, projection';
 +            fontStyles.appendChild(document.createTextNode(fontsCSS));
 +            head.appendChild(fontStyles);
 +
 +            self.sessionController = new gui.SessionController(session, localMemberId, shadowCursor, {
 +                directParagraphStylingEnabled: config.directParagraphStylingEnabled
 +            });
 +            caretManager = new gui.CaretManager(self.sessionController);
-             selectionViewManager = new gui.SelectionViewManager();
++            selectionViewManager = new gui.SelectionViewManager(gui.SvgSelectionView);
 +            self.sessionView = new gui.SessionView(config.viewOptions, localMemberId, session, caretManager, selectionViewManager);
 +            self.availableFonts = getAvailableFonts();
 +            selectionViewManager.registerCursor(shadowCursor, true);
 +            // Custom signals, that make sense in the Editor context. We do not want to expose webodf's ops signals to random bits of the editor UI.
-             odtDocument.subscribe(ops.OdtDocument.signalMemberAdded, onMemberAdded);
-             odtDocument.subscribe(ops.OdtDocument.signalMemberUpdated, onMemberUpdated);
-             odtDocument.subscribe(ops.OdtDocument.signalMemberRemoved, onMemberRemoved);
-             odtDocument.subscribe(ops.OdtDocument.signalCursorAdded, onCursorAdded);
-             odtDocument.subscribe(ops.OdtDocument.signalCursorRemoved, onCursorRemoved);
-             odtDocument.subscribe(ops.OdtDocument.signalCursorMoved, onCursorMoved);
++            odtDocument.subscribe(ops.Document.signalMemberAdded, onMemberAdded);
++            odtDocument.subscribe(ops.Document.signalMemberUpdated, onMemberUpdated);
++            odtDocument.subscribe(ops.Document.signalMemberRemoved, onMemberRemoved);
++            odtDocument.subscribe(ops.Document.signalCursorAdded, onCursorAdded);
++            odtDocument.subscribe(ops.Document.signalCursorRemoved, onCursorRemoved);
++            odtDocument.subscribe(ops.Document.signalCursorMoved, onCursorMoved);
 +            odtDocument.subscribe(ops.OdtDocument.signalCommonStyleCreated, onStyleCreated);
 +            odtDocument.subscribe(ops.OdtDocument.signalCommonStyleDeleted, onStyleDeleted);
 +            odtDocument.subscribe(ops.OdtDocument.signalParagraphStyleModified, onParagraphStyleModified);
 +            odtDocument.subscribe(ops.OdtDocument.signalParagraphChanged, trackCurrentParagraph);
 +            odtDocument.subscribe(ops.OdtDocument.signalUndoStackChanged, undoStackModified);
 +        }
 +
 +        init();
 +    };
 +
 +    /**@const*/EditorSession.signalMemberAdded =            "memberAdded";
 +    /**@const*/EditorSession.signalMemberUpdated =          "memberUpdated";
 +    /**@const*/EditorSession.signalMemberRemoved =          "memberRemoved";
 +    /**@const*/EditorSession.signalCursorAdded =            "cursorAdded";
 +    /**@const*/EditorSession.signalCursorRemoved =          "cursorRemoved";
 +    /**@const*/EditorSession.signalCursorMoved =            "cursorMoved";
 +    /**@const*/EditorSession.signalParagraphChanged =       "paragraphChanged";
 +    /**@const*/EditorSession.signalCommonStyleCreated =     "styleCreated";
 +    /**@const*/EditorSession.signalCommonStyleDeleted =     "styleDeleted";
 +    /**@const*/EditorSession.signalParagraphStyleModified = "paragraphStyleModified";
 +    /**@const*/EditorSession.signalUndoStackChanged =       "signalUndoStackChanged";
 +
 +    return EditorSession;
 +});
diff --cc apps/documents/js/3rdparty/webodf/editor/MemberListView.js
index 9f604c7,0000000..c8f347b
mode 100644,000000..100644
--- a/apps/documents/js/3rdparty/webodf/editor/MemberListView.js
+++ b/apps/documents/js/3rdparty/webodf/editor/MemberListView.js
@@@ -1,214 -1,0 +1,221 @@@
 +/**
 + * @license
 + * Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
 + *
 + * @licstart
 + * The JavaScript code in this page is free software: you can redistribute it
 + * and/or modify it under the terms of the GNU Affero General Public License
 + * (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + * the License, or (at your option) any later version.  The code is distributed
 + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 + *
 + * You should have received a copy of the GNU Affero General Public License
 + * along with this code.  If not, see <http://www.gnu.org/licenses/>.
 + *
 + * As additional permission under GNU AGPL version 3 section 7, you
 + * may distribute non-source (e.g., minimized or compacted) forms of
 + * that code without the copy of the GNU GPL normally required by
 + * section 4, provided you include this license notice and a URL
 + * through which recipients can access the Corresponding Source.
 + *
 + * As a special exception to the AGPL, any HTML file which merely makes function
 + * calls to this code, and for that purpose includes it by reference shall be
 + * deemed a separate work for copyright law purposes. In addition, the copyright
 + * holders of this code give you permission to combine this code with free
 + * software libraries that are released under the GNU LGPL. You may copy and
 + * distribute such a system following the terms of the GNU AGPL for this code
 + * and the LGPL for the libraries. If you modify this code, you may extend this
 + * exception to your version of the code, but you are not obligated to do so.
 + * If you do not wish to do so, delete this exception statement from your
 + * version.
 + *
 + * This license applies to this entire compilation.
 + * @licend
 + * @source: http://www.webodf.org/
 + * @source: https://github.com/kogmbh/WebODF/
 + */
 +
 +/*global define,runtime */
 +
 +define("webodf/editor/MemberListView",
 +       ["webodf/editor/EditorSession"],
 +
 +  function (EditorSession) {
 +    "use strict";
 +
 +    /**
 +     * @param {!Element} memberListDiv
 +     * @constructor
 +     */
 +    return function MemberListView(memberListDiv) {
 +        var editorSession = null;
 +
 +        runtime.assert(memberListDiv, "memberListDiv unavailable");
 +
 +        /**
 +         * @param {!string} memberId
 +         * @return {undefined}
 +         */
 +        function updateAvatarButton(memberId, memberDetails) {
 +            var node = memberListDiv.firstChild;
 +
 +           // this takes care of incorrectly implemented MemberModels,
 +           // which might end up returning undefined member data
 +           if (!memberDetails) {
 +                runtime.log("MemberModel sent undefined data for member \"" + memberId + "\".");
 +                return;
 +            }
 +
 +            while (node) {
 +                if (node.memberId === memberId) {
 +                    node = node.firstChild;
 +                    while (node) {
 +                        if (node.localName === "img") {
 +                            // update avatar image
 +                            node.src = memberDetails.imageUrl;
 +                            // update border color
 +                            node.style.borderColor = memberDetails.color;
 +						} else if (node.localName === "span" && memberDetails.imageUrl){
 +							try {
 +								$(node).avatar(memberDetails.imageUrl, 60);
 +							} catch (e){}
 +							node.style.borderColor = memberDetails.color;
 +                        } else if (node.localName === "div") {
 +                            node.setAttribute('fullname', memberDetails.fullName);
 +                        }
 +                        node = node.nextSibling;
 +                    }
 +                    return;
 +                }
 +                node = node.nextSibling;
 +            }
 +        }
 +
 +        /**
 +         * @param {!string} memberId
 +         * @return {undefined}
 +         */
 +        function createAvatarButton(memberId) {
 +            var doc = memberListDiv.ownerDocument,
 +                htmlns = doc.documentElement.namespaceURI,
 +                avatarDiv = doc.createElementNS(htmlns, "div"),
 +                imageElement = doc.createElement("span"),
 +                fullnameNode = doc.createElement("div");
 +
 +            avatarDiv.className = "memberListButton";
 +            fullnameNode.className = "memberListLabel";
 +            avatarDiv.appendChild(imageElement);
 +            avatarDiv.appendChild(fullnameNode);
 +            avatarDiv.memberId = memberId; // TODO: namespace?
 +
 +            avatarDiv.onmouseover = function () {
 +                //avatar.getCaret().showHandle();
 +            };
 +            avatarDiv.onmouseout = function () {
 +                //avatar.getCaret().hideHandle();
 +            };
 +            avatarDiv.onclick = function () {
++                if (memberId === editorSession.sessionController.getInputMemberId()){
++                    documentsMain.onNickChange(memberId, fullnameNode);
++                }
 +                var caret = editorSession.sessionView.getCaret(memberId);
 +                if (caret) {
 +                    //caret.toggleHandleVisibility();
 +                }
 +            };
-             memberListDiv.appendChild(avatarDiv);
++            if (memberId === editorSession.sessionController.getInputMemberId()){
++                memberListDiv.insertBefore(avatarDiv, memberListDiv.firstChild);
++            } else {
++                memberListDiv.appendChild(avatarDiv);
++            }
 +        }
 +
 +        /**
 +         * @param {!string} memberId
 +         * @return {undefined}
 +         */
 +        function removeAvatarButton(memberId) {
 +            var node = memberListDiv.firstChild;
 +            while (node) {
 +                if (node.memberId === memberId) {
 +                    memberListDiv.removeChild(node);
 +                    return;
 +                }
 +                node = node.nextSibling;
 +            }
 +        }
 +
 +        /**
 +         * @param {!string} memberId
 +         * @return {undefined}
 +         */
 +        function addMember(memberId) {
 +            var member = editorSession.getMember(memberId),
 +                properties = member.getProperties();
 +            createAvatarButton(memberId);
 +            updateAvatarButton(memberId, properties);
 +        }
 +
 +        /**
 +         * @param {!string} memberId
 +         * @return {undefined}
 +         */
 +        function updateMember(memberId) {
 +            var member = editorSession.getMember(memberId),
 +                properties = member.getProperties();
 +
 +            updateAvatarButton(memberId, properties);
 +        }
 +
 +        /**
 +         * @param {!string} memberId
 +         * @return {undefined}
 +         */
 +        function removeMember(memberId) {
 +            removeAvatarButton(memberId);
 +        }
 +
 +        function disconnectFromEditorSession() {
 +            var node, nextNode;
 +
 +            if (editorSession) {
 +                // unsubscribe from editorSession
 +                editorSession.unsubscribe(EditorSession.signalMemberAdded, addMember);
 +                editorSession.unsubscribe(EditorSession.signalMemberUpdated, updateMember);
 +                editorSession.unsubscribe(EditorSession.signalMemberRemoved, removeMember);
 +                // remove all current avatars
 +                node = memberListDiv.firstChild;
 +                while (node) {
 +                    nextNode = node.nextSibling;
 +                    memberListDiv.removeChild(node);
 +                    node = nextNode;
 +                }
 +            }
 +        }
 +
 +        /**
 +         * @param {!EditorSession} session
 +         * @return {undefined}
 +         */
 +        this.setEditorSession = function(session) {
 +            disconnectFromEditorSession();
 +
 +            editorSession = session;
 +            if (editorSession) {
 +                editorSession.subscribe(EditorSession.signalMemberAdded, addMember);
 +                editorSession.subscribe(EditorSession.signalMemberUpdated, updateMember);
 +                editorSession.subscribe(EditorSession.signalMemberRemoved, removeMember);
 +            }
 +        };
 +
 +        /**
 +         * @param {!function(!Object=)} callback, passing an error object in case of error
 +         * @return {undefined}
 +         */
 +        this.destroy = function (callback) {
 +            disconnectFromEditorSession();
 +            callback();
 +        };
 +    };
 +});
diff --cc apps/documents/js/3rdparty/webodf/editor/Tools.js
index 8ab50b2,0000000..c0aa4da
mode 100644,000000..100644
--- a/apps/documents/js/3rdparty/webodf/editor/Tools.js
+++ b/apps/documents/js/3rdparty/webodf/editor/Tools.js
@@@ -1,267 -1,0 +1,279 @@@
 +/**
 + * Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
 + *
 + * @licstart
 + * The JavaScript code in this page is free software: you can redistribute it
 + * and/or modify it under the terms of the GNU Affero General Public License
 + * (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + * the License, or (at your option) any later version.  The code is distributed
 + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 + *
 + * You should have received a copy of the GNU Affero General Public License
 + * along with this code.  If not, see <http://www.gnu.org/licenses/>.
 + *
 + * As additional permission under GNU AGPL version 3 section 7, you
 + * may distribute non-source (e.g., minimized or compacted) forms of
 + * that code without the copy of the GNU GPL normally required by
 + * section 4, provided you include this license notice and a URL
 + * through which recipients can access the Corresponding Source.
 + *
 + * As a special exception to the AGPL, any HTML file which merely makes function
 + * calls to this code, and for that purpose includes it by reference shall be
 + * deemed a separate work for copyright law purposes. In addition, the copyright
 + * holders of this code give you permission to combine this code with free
 + * software libraries that are released under the GNU LGPL. You may copy and
 + * distribute such a system following the terms of the GNU AGPL for this code
 + * and the LGPL for the libraries. If you modify this code, you may extend this
 + * exception to your version of the code, but you are not obligated to do so.
 + * If you do not wish to do so, delete this exception statement from your
 + * version.
 + *
 + * This license applies to this entire compilation.
 + * @licend
 + * @source: http://www.webodf.org/
 + * @source: https://github.com/kogmbh/WebODF/
 + */
 +
 +/*global define,document,require,ops */
 +
 +define("webodf/editor/Tools", [
 +    "dojo/ready",
 +    "dijit/MenuItem",
 +    "dijit/DropDownMenu",
 +    "dijit/form/Button",
 +    "dijit/form/DropDownButton",
 +    "dijit/Toolbar",
 +    "webodf/editor/widgets/paragraphAlignment",
 +    "webodf/editor/widgets/simpleStyles",
 +    "webodf/editor/widgets/undoRedoMenu",
 +    "webodf/editor/widgets/toolbarWidgets/currentStyle",
 +    "webodf/editor/widgets/annotation",
-     "webodf/editor/widgets/paragraphStylesDialog",
++    "webodf/editor/widgets/editHyperlinks",
 +    "webodf/editor/widgets/imageInserter",
++    "webodf/editor/widgets/paragraphStylesDialog",
 +    "webodf/editor/widgets/zoomSlider",
 +    "webodf/editor/EditorSession"],
-     function (ready, MenuItem, DropDownMenu, Button, DropDownButton, Toolbar, ParagraphAlignment, SimpleStyles, UndoRedoMenu, CurrentStyle, AnnotationControl, ParagraphStylesDialog, ImageInserter, ZoomSlider, EditorSession) {
++    function (ready, MenuItem, DropDownMenu, Button, DropDownButton, Toolbar, ParagraphAlignment, SimpleStyles, UndoRedoMenu, CurrentStyle, AnnotationControl, EditHyperlinks, ImageInserter, ParagraphStylesDialog, ZoomSlider, EditorSession) {
 +        "use strict";
 +
 +        return function Tools(args) {
 +            var tr = runtime.tr,
 +                onToolDone = args.onToolDone,
 +                loadOdtFile = args.loadOdtFile,
 +                saveOdtFile = args.saveOdtFile,
 +                close = args.close,
 +                toolbar,
 +                loadButton, saveButton, closeButton,
 +                formatDropDownMenu, formatMenuButton,
 +                paragraphStylesMenuItem, paragraphStylesDialog, simpleStyles, currentStyle,
 +                zoomSlider,
 +                undoRedoMenu,
 +                editorSession,
 +                paragraphAlignment,
 +                imageInserter,
 +                annotationControl,
++                editHyperlinks,
 +                sessionSubscribers = [];
 +
 +            function handleCursorMoved(cursor) {
 +                var disabled = cursor.getSelectionType() === ops.OdtCursor.RegionSelection;
 +                if (formatMenuButton) {
 +                    formatMenuButton.setAttribute('disabled', disabled);
 +                }
 +            }
 +
 +            function setEditorSession(session) {
 +                if (editorSession) {
 +                    editorSession.unsubscribe(EditorSession.signalCursorMoved, handleCursorMoved);
 +                }
 +                editorSession = session;
 +                if (editorSession) {
 +                    editorSession.subscribe(EditorSession.signalCursorMoved, handleCursorMoved);
 +                }
 +
 +                sessionSubscribers.forEach(function (subscriber) {
 +                    subscriber.setEditorSession(editorSession);
 +                });
 +            }
 +
 +            this.setEditorSession = setEditorSession;
 +
 +            /**
 +             * @param {!function(!Object=)} callback, passing an error object in case of error
 +             * @return {undefined}
 +             */
 +            this.destroy = function (callback) {
 +                // TODO:
 +                // 1. We don't want to use `document`
 +                // 2. We would like to avoid deleting all widgets
 +                // under document.body because this might interfere with
 +                // other apps that use the editor not-in-an-iframe,
 +                // but dojo always puts its dialogs below the body,
 +                // so this works for now. Perhaps will be obsoleted
 +                // once we move to a better widget toolkit
 +                var widgets = dijit.findWidgets(document.body);
 +                dojo.forEach(widgets, function(w) {
 +                    w.destroyRecursive(false);
 +                });
 +                callback();
 +            };
 +
 +            // init
 +            ready(function () {
 +                toolbar = new Toolbar({}, "toolbar");
 +
 +                // Undo/Redo
 +                if (args.undoRedoEnabled) {
 +                    undoRedoMenu = new UndoRedoMenu(function (widget) {
 +                        widget.placeAt(toolbar);
 +                        widget.startup();
 +                    });
 +                    sessionSubscribers.push(undoRedoMenu);
++                    undoRedoMenu.onToolDone = onToolDone;
 +                }
 +
 +                // Add annotation
 +                if (args.annotationsEnabled) {
 +                    annotationControl = new AnnotationControl(function (widget) {
 +                        widget.placeAt(toolbar);
 +                        widget.startup();
 +                    });
 +                    sessionSubscribers.push(annotationControl);
 +                    annotationControl.onToolDone = onToolDone;
 +                }
 +
 +                // Simple Style Selector [B, I, U, S]
 +                simpleStyles = new SimpleStyles(function (widget) {
 +                    widget.placeAt(toolbar);
 +                    widget.startup();
 +                });
 +                sessionSubscribers.push(simpleStyles);
 +                simpleStyles.onToolDone = onToolDone;
 +
 +                // Paragraph direct alignment buttons
 +                if (args.directParagraphStylingEnabled) {
 +                    paragraphAlignment = new ParagraphAlignment(function (widget) {
 +                        widget.placeAt(toolbar);
 +                        widget.startup();
 +                    });
 +                    sessionSubscribers.push(paragraphAlignment);
 +                    paragraphAlignment.onToolDone = onToolDone;
 +                }
 +
 +
 +                // Paragraph Style Selector
 +                currentStyle = new CurrentStyle(function (widget) {
 +                    widget.placeAt(toolbar);
 +                    widget.startup();
 +                });
 +                sessionSubscribers.push(currentStyle);
 +                currentStyle.onToolDone = onToolDone;
 +
 +                // Zoom Level Selector
 +                zoomSlider = new ZoomSlider(function (widget) {
 +                    widget.placeAt(toolbar);
 +                    widget.startup();
 +                });
 +                sessionSubscribers.push(zoomSlider);
 +                zoomSlider.onToolDone = onToolDone;
 +
 +                // Load
 +                if (loadOdtFile) {
 +                    loadButton = new Button({
 +                        label: tr('Open'),
 +                        showLabel: false,
 +                        iconClass: 'dijitIcon dijitIconFolderOpen',
 +                        style: {
 +                            float: 'left'
 +                        },
 +                        onClick: function () {
 +                            loadOdtFile();
 +                        }
 +                    });
 +                    loadButton.placeAt(toolbar);
 +                }
 +
 +                // Save
 +                if (saveOdtFile) {
 +                    saveButton = new Button({
 +                        label: tr('Save'),
 +                        showLabel: false,
 +                        iconClass: 'dijitEditorIcon dijitEditorIconSave',
 +                        style: {
 +                            float: 'left'
 +                        },
 +                        onClick: function () {
 +                            saveOdtFile();
 +                            onToolDone();
 +                        }
 +                    });
 +                    saveButton.placeAt(toolbar);
 +                }
 +
 +                // Format menu
 +                formatDropDownMenu = new DropDownMenu({});
 +                paragraphStylesMenuItem = new MenuItem({
 +                    label: tr("Paragraph...")
 +                });
 +                formatDropDownMenu.addChild(paragraphStylesMenuItem);
 +
 +                paragraphStylesDialog = new ParagraphStylesDialog(function (dialog) {
 +                    paragraphStylesMenuItem.onClick = function () {
 +                        if (editorSession) {
 +                            dialog.startup();
 +                            dialog.show();
 +                        }
 +                    };
 +                });
 +                sessionSubscribers.push(paragraphStylesDialog);
 +                paragraphStylesDialog.onToolDone = onToolDone;
 +
++                if (args.hyperlinkEditingEnabled) {
++                    editHyperlinks = new EditHyperlinks(function (widget) {
++                        widget.placeAt(toolbar);
++                        widget.startup();
++                    });
++                    sessionSubscribers.push(editHyperlinks);
++                    editHyperlinks.onToolDone = onToolDone;
++                }
++
 +                formatMenuButton = new DropDownButton({
 +                    dropDown: formatDropDownMenu,
 +                    label: tr('Format'),
 +                    iconClass: "dijitIconEditTask",
 +                    style: {
 +                        float: 'left'
 +                    }
 +                });
 +                formatMenuButton.placeAt(toolbar);
 +
 +                if (args.imageInsertingEnabled) {
 +                    imageInserter = new ImageInserter(function (widget) {
 +                        widget.placeAt(toolbar);
 +                        widget.startup();
 +                    });
 +                    sessionSubscribers.push(imageInserter);
 +                    imageInserter.onToolDone = onToolDone;
 +                }
 +
 +                if (close) {
 +                    closeButton = new Button({
 +                        label: tr('Close'),
 +                        showLabel: false,
 +                        iconClass: 'dijitEditorIcon dijitEditorIconCancel',
 +                        style: {
 +                            float: 'right'
 +                        },
 +                        onClick: function () {
 +                            close();
 +                        }
 +                    });
 +                    closeButton.placeAt(toolbar);
 +                }
 +
 +                setEditorSession(editorSession);
 +            });
 +        };
 +
 +    });
diff --cc apps/documents/js/3rdparty/webodf/editor/server/pullbox/OperationRouter.js
index a6cf8d6,0000000..de24b50
mode 100644,000000..100644
--- a/apps/documents/js/3rdparty/webodf/editor/server/pullbox/OperationRouter.js
+++ b/apps/documents/js/3rdparty/webodf/editor/server/pullbox/OperationRouter.js
@@@ -1,590 -1,0 +1,602 @@@
 +/**
 + * @license
 + * Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
 + *
 + * @licstart
 + * This file is part of WebODF.
 + *
 + * WebODF is free software: you can redistribute it and/or modify it
 + * under the terms of the GNU Affero General Public License (GNU AGPL)
 + * as published by the Free Software Foundation, either version 3 of
 + * the License, or (at your option) any later version.
 + *
 + * WebODF is distributed in the hope that it will be useful, but
 + * WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU Affero General Public License for more details.
 + *
 + * You should have received a copy of the GNU Affero General Public License
 + * along with WebODF.  If not, see <http://www.gnu.org/licenses/>.
 + * @licend
 + *
 + * @source: http://www.webodf.org/
 + * @source: https://github.com/kogmbh/WebODF/
 + */
 +
 +/*global runtime, ops*/
 +
 +define("webodf/editor/server/pullbox/OperationRouter", [], function () {
 +    "use strict";
 +
 +    // TODO: these eventid strings should be defined at OperationRouter interface
 +    var /**@const @type {!string}*/
 +        EVENT_BEFORESAVETOFILE =                  "beforeSaveToFile",
 +        /**@const @type {!string}*/
 +        EVENT_SAVEDTOFILE =                       "savedToFile",
 +        /**@const @type {!string}*/
 +        EVENT_HASLOCALUNSYNCEDOPERATIONSCHANGED = "hasLocalUnsyncedOperationsChanged",
 +        /**@const @type {!string}*/
 +        EVENT_HASSESSIONHOSTCONNECTIONCHANGED =   "hasSessionHostConnectionChanged";
 +
 +    runtime.loadClass("ops.OperationTransformer");
 +    runtime.loadClass("core.EventNotifier");
 +
 +    /**
 +     * route operations in a networked collaborative manner.
 +     *
 +     * incoming operations (from controller) are sent to a server,
 +     * who will distribute them.
 +     *
 +     * incoming operations (from the server are played on the DOM.
 +     */
 +
 +    /**
 +     * @constructor
 +     * @implements ops.OperationRouter
 +     */
 +    return function PullBoxOperationRouter(sessionId, memberId, server, odfContainer, errorCallback) {
 +        "use strict";
 +
 +        var operationFactory,
 +            /**@type{function(!ops.Operation):boolean}*/
 +            playbackFunction,
 +            idleTimeout = null,
 +            syncOpsTimeout = null,
 +            /**@type{!boolean}*/
 +            isInstantSyncRequested = false,
 +            /**@type{!boolean}*/
 +            isPlayingUnplayedServerOpSpecs = false,
 +            /**@type{!boolean}*/
 +            isSyncCallRunning = false,
 +            /**@type{!boolean}*/
 +            hasError = false,
 +            /**@type{!boolean}*/
 +            syncingBlocked = false,
 +            /** @type {!string} id of latest op stack state known on the server */
 +            lastServerSeq = "",
 +            /** @type {!Array.<!Function>} sync request callbacks created since the last sync call to the server */
 +            syncRequestCallbacksQueue = [],
 +            /** @type {!Array.<!Object>} ops created since the last sync call to the server */
 +            unsyncedClientOpspecQueue = [],
 +            /** @type {!Array.<!Object>} ops already received from the server but not yet applied */
 +            unplayedServerOpspecQueue = [],
 +            /** @type {!Array.<!Function>} sync request callbacks which should be called after the received ops have been applied server */
 +            uncalledSyncRequestCallbacksQueue = [],
 +            /** @type {!Array.<!function(!boolean):undefined>} ops created since the last sync call to the server */
 +            hasLocalUnsyncedOpsStateSubscribers = [],
 +            /**@type{!boolean}*/
 +            hasLocalUnsyncedOps = false,
 +            /** @type {!Array.<!function(!boolean):undefined>} */
 +            hasSessionHostConnectionStateSubscribers = [],
 +            /**@type{!boolean}*/
 +            hasSessionHostConnection = true,
 +            eventNotifier = new core.EventNotifier([
 +                EVENT_BEFORESAVETOFILE,
 +                EVENT_SAVEDTOFILE,
 +                EVENT_HASLOCALUNSYNCEDOPERATIONSCHANGED,
-                 EVENT_HASSESSIONHOSTCONNECTIONCHANGED
++                EVENT_HASSESSIONHOSTCONNECTIONCHANGED,
++                ops.OperationRouter.signalProcessingBatchStart,
++                ops.OperationRouter.signalProcessingBatchEnd
 +            ]),
 +            /**@type{!boolean} tells if any local ops have been modifying ops */
 +            hasPushedModificationOps = false,
 +            operationTransformer = new ops.OperationTransformer(),
 +            /**@const*/replayTime = 500,
 +            /**@const*/syncOpsDelay = 3000,
 +            /**@const*/idleDelay = 5000;
 +
 +        /**
 +         * @return {undefined}
 +         */
 +        function updateHasLocalUnsyncedOpsState() {
 +            var i,
 +                hasLocalUnsyncedOpsNow = (unsyncedClientOpspecQueue.length > 0);
 +
 +            // no change?
 +            if (hasLocalUnsyncedOps === hasLocalUnsyncedOpsNow) {
 +                return;
 +            }
 +
 +            hasLocalUnsyncedOps = hasLocalUnsyncedOpsNow;
 +            eventNotifier.emit(EVENT_HASLOCALUNSYNCEDOPERATIONSCHANGED, hasLocalUnsyncedOps);
 +        }
 +
 +        /**
 +         * @param {!boolean} hasConnection
 +         * @return {undefined}
 +         */
 +        function updateHasSessionHostConnectionState(hasConnection) {
 +            var i;
 +
 +            // no change?
 +            if (hasSessionHostConnection === hasConnection) {
 +                return;
 +            }
 +
 +            hasSessionHostConnection = hasConnection;
 +            eventNotifier.emit(EVENT_HASSESSIONHOSTCONNECTIONCHANGED, hasSessionHostConnection);
 +        }
 +
 +        /**
 +         * @return {undefined}
 +         */
 +        function playUnplayedServerOpSpecs() {
 +            /**
 +             * @return {undefined}
 +             */
 +            function doPlayUnplayedServerOpSpecs() {
 +                var opspec, op, startTime, i;
 +
 +                isPlayingUnplayedServerOpSpecs = false;
 +
 +                // take start time
 +                startTime = (new Date()).getTime();
 +
++                eventNotifier.emit(ops.OperationRouter.signalProcessingBatchStart, {});
++
 +                // apply as much as possible in the given time
 +                while (unplayedServerOpspecQueue.length > 0) {
 +                    // time over?
 +                    if ((new Date().getTime()) - startTime > replayTime) {
 +                        break;
 +                    }
 +
 +                    opspec = unplayedServerOpspecQueue.shift();
 +
 +                    // use factory to create an instance, and playback!
 +                    op = operationFactory.create(opspec);
 +                    runtime.log(" op in: "+runtime.toJson(opspec));
 +                    if (op !== null) {
 +                        if (!playbackFunction(op)) {
++                            eventNotifier.emit(ops.OperationRouter.signalProcessingBatchEnd, {});
 +                            hasError = true;
 +                            errorCallback("opExecutionFailure");
 +                            return;
 +                        }
 +                    } else {
++                        eventNotifier.emit(ops.OperationRouter.signalProcessingBatchEnd, {});
 +                        hasError = true;
 +                        runtime.log("ignoring invalid incoming opspec: " + opspec);
 +                        errorCallback("unknownOpReceived");
 +                        return;
 +                    }
 +                }
 +
++                eventNotifier.emit(ops.OperationRouter.signalProcessingBatchEnd, {});
++
 +                // still unplayed opspecs?
 +                if (unplayedServerOpspecQueue.length > 0) {
 +                    // let other events be handled. then continue
 +                    isPlayingUnplayedServerOpSpecs = true;
 +                    runtime.getWindow().setTimeout(doPlayUnplayedServerOpSpecs, 1);
 +                } else {
 +                    // finally call all the callbacks waiting for that sync!
 +                    for (i = 0; i < uncalledSyncRequestCallbacksQueue.length; i += 1) {
 +                        uncalledSyncRequestCallbacksQueue[i]();
 +                    }
 +
 +                    uncalledSyncRequestCallbacksQueue = [];
 +                }
 +            }
 +
 +            if (isPlayingUnplayedServerOpSpecs) {
 +                return;
 +            }
 +            doPlayUnplayedServerOpSpecs();
 +        }
 +
 +        /**
 +         * @param {Array.<!Object>} opspecs
 +         * @param {Array.<!Function>} callbacks
 +         * @return {undefined}
 +         */
 +        function receiveOpSpecsFromNetwork(opspecs, callbacks) {
 +            // append to existing unplayed
 +            unplayedServerOpspecQueue = unplayedServerOpspecQueue.concat(opspecs);
 +            uncalledSyncRequestCallbacksQueue = uncalledSyncRequestCallbacksQueue.concat(callbacks);
 +        }
 +
 +        /**
 +         * Transforms the unsynced client ops and the server ops,
 +         * applies the server ops after transformation
 +         * @param {Array.<!Object>} serverOpspecs
 +         * @return {!boolean}
 +         */
 +        function handleOpsSyncConflict(serverOpspecs) {
 +            var i,
 +                transformResult;
 +
 +            if (! serverOpspecs) {
 +                // TODO: proper error message, stop working
 +                runtime.assert(false, "no opspecs received!");
 +                return false;
 +            } // TODO: more checking of proper content in serverOpspecs
 +
 +            transformResult = operationTransformer.transform(unsyncedClientOpspecQueue, /**@type{!Array.<!Object>}*/(serverOpspecs));
 +
 +            if (!transformResult) {
 +                return false;
 +            }
 +
 +            // store transformed server ops
 +            for (i = 0; i < transformResult.opsB.length; i += 1) {
 +                unplayedServerOpspecQueue.push(transformResult.opsB[i].spec());
 +            }
 +
 +            // store opspecs of all transformed client opspecs
 +            unsyncedClientOpspecQueue = [];
 +            for (i = 0; i < transformResult.opsA.length; i += 1) {
 +                unsyncedClientOpspecQueue.push(transformResult.opsA[i].spec());
 +            }
 +
 +            return true;
 +        }
 +
 +        /**
 +         * @return {undefined}
 +         */
 +        function syncOps() {
 +            var syncedClientOpspecs,
 +                syncRequestCallbacksArray;
 +
 +            /**
 +             * @return {undefined}
 +             */
 +            function startSyncOpsTimeout() {
 +                idleTimeout = null;
 +                syncOpsTimeout = runtime.getWindow().setTimeout(function() {
 +                    syncOpsTimeout = null;
 +                    syncOps();
 +                }, syncOpsDelay);
 +            }
 +
 +            if (isSyncCallRunning || hasError) {
 +                return;
 +            }
 +            // TODO: hack, remove
 +            if (syncingBlocked) {
 +                return;
 +            }
 +
 +runtime.log("OperationRouter: sending sync_ops call");
 +            // no more instant pull request in any case
 +            isInstantSyncRequested = false;
 +            // set lock
 +            isSyncCallRunning = true;
 +
 +            // take specs from queue, if any
 +            syncedClientOpspecs = unsyncedClientOpspecQueue;
 +            unsyncedClientOpspecQueue = [];
 +            syncRequestCallbacksArray = syncRequestCallbacksQueue;
 +            syncRequestCallbacksQueue = [];
 +
 +            server.call({
 +                command: 'sync_ops',
 +                args: {
 +                    es_id: sessionId,
 +                    member_id: memberId,
 +                    seq_head: String(lastServerSeq),
 +                    client_ops: syncedClientOpspecs
 +                }
 +            }, function(responseData) {
 +                var response,
 +                    /**@type{!boolean}*/
 +                    hasUnresolvableConflict = false;
 +
 +                updateHasSessionHostConnectionState(true);
 +
 +                if (syncingBlocked) {
 +                    return;
 +                }
 +
 +                try {
 +                    response = /** @type{{result:string, head_seq:string, ops:Array.<!Object>}} */(runtime.fromJson(responseData));
 +                } catch (e) {
 +                    hasError = true;
 +                    runtime.log("Could not parse reply: "+responseData);
 +                    errorCallback("unknownServerReply");
 +                    return;
 +                }
 +                // TODO: hack, remove
 +                runtime.log("sync_ops reply: " + responseData);
 +
 +                // just new ops?
 +                if (response.result === "new_ops") {
 +                    if (response.ops.length > 0) {
 +                        // no new locally in the meantime?
 +                        if (unsyncedClientOpspecQueue.length === 0) {
 +                            receiveOpSpecsFromNetwork(response.ops, syncRequestCallbacksArray);
 +                        } else {
 +                            // transform server ops against new local ones and apply,
 +                            // transform and send new local ops to server
 +                            runtime.log("meh, have new ops locally meanwhile, have to do transformations.");
 +                            hasUnresolvableConflict = !handleOpsSyncConflict(response.ops);
 +                            syncRequestCallbacksQueue = syncRequestCallbacksArray.concat(syncRequestCallbacksQueue);
 +                       }
 +                        // and note server state
 +                        lastServerSeq = response.head_seq;
 +                    } else {
 +                        receiveOpSpecsFromNetwork([], syncRequestCallbacksArray);
 +                    }
 +                } else if (response.result === "added") {
 +                    runtime.log("All added to server");
 +                    receiveOpSpecsFromNetwork([], syncRequestCallbacksArray);
 +                    // note server state
 +                    lastServerSeq = response.head_seq;
 +                    updateHasLocalUnsyncedOpsState();
 +                } else if (response.result === "conflict") {
 +                    // put the send ops back into the outgoing queue
 +                    unsyncedClientOpspecQueue = syncedClientOpspecs.concat(unsyncedClientOpspecQueue);
 +                    syncRequestCallbacksQueue = syncRequestCallbacksArray.concat(syncRequestCallbacksQueue);
 +                    // transform server ops against new local ones and apply,
 +                    // transform and request new send new local ops to server
 +                    runtime.log("meh, server has new ops meanwhile, have to do transformations.");
 +                    hasUnresolvableConflict = !handleOpsSyncConflict(response.ops);
 +                    // and note server state
 +                    lastServerSeq = response.head_seq;
 +                    // try again instantly
 +                    if (!hasUnresolvableConflict) {
 +                        isInstantSyncRequested = true;
 +                    }
 +                } else if (response.result === "error") {
 +                    runtime.log("server reports an error: "+response.error);
 +                    hasError = true;
 +                    errorCallback(
 +                        response.error === "ENOSESSION" ? "sessionDoesNotExist":
 +                        response.error === "ENOMEMBER" ?  "notMemberOfSession":
 +                                                          "unknownServerReply"
 +                    );
 +                    return;
 +                } else {
 +                    hasError = true;
 +                    runtime.log("Unexpected result on sync-ops call: "+response.result);
 +                    errorCallback("unknownServerReply");
 +                    return;
 +                }
 +
 +                // unlock
 +                isSyncCallRunning = false;
 +
 +                if (hasUnresolvableConflict) {
 +                    hasError = true;
 +                    errorCallback("unresolvableConflictingOps");
 +                } else {
 +                    // prepare next sync
 +                    if (isInstantSyncRequested) {
 +                        syncOps();
 +                    } else {
 +                        // nothing on client to sync?
 +                        if (unsyncedClientOpspecQueue.length === 0) {
 +                            idleTimeout = runtime.getWindow().setTimeout(startSyncOpsTimeout, idleDelay);
 +                        } else {
 +                            startSyncOpsTimeout();
 +                        }
 +                    }
 +                    playUnplayedServerOpSpecs();
 +                }
 +            }, function() {
 +                runtime.log("meh, server cannot be reached ATM.");
 +                // signal connection problem, but do not give up for now
 +                updateHasSessionHostConnectionState(false);
 +                // put the (not) send ops back into the outgoing queue
 +                unsyncedClientOpspecQueue = syncedClientOpspecs.concat(unsyncedClientOpspecQueue);
 +                syncRequestCallbacksQueue = syncRequestCallbacksArray.concat(syncRequestCallbacksQueue);
 +                // unlock
 +                isSyncCallRunning = false;
 +                // nothing on client to sync?
 +                if (unsyncedClientOpspecQueue.length === 0) {
 +                    idleTimeout = runtime.getWindow().setTimeout(startSyncOpsTimeout, idleDelay);
 +                } else {
 +                    startSyncOpsTimeout();
 +                }
 +                playUnplayedServerOpSpecs();
 +            });
 +        }
 +
 +        function triggerPushingOps() {
 +            // disable any idle timeout
 +            if (idleTimeout) {
 +                runtime.clearTimeout(idleTimeout);
 +                idleTimeout = null;
 +            }
 +
 +            // enable syncOps timeout, if needed
 +            if (!syncOpsTimeout && !isSyncCallRunning) {
 +runtime.log("OperationRouter: opsSync requested for pushing");
 +                syncOpsTimeout = runtime.getWindow().setTimeout(function() {
 +                    syncOpsTimeout = null;
 +                    syncOps();
 +                }, syncOpsDelay);
 +            }
 +        }
 +
 +        /**
 +         * @param {!Funtion} cb
 +         * @return {undefined}
 +         */
 +        function requestInstantOpsSync(cb) {
 +            // register callback
 +            syncRequestCallbacksQueue.push(cb);
 +
 +            // disable any idle timeout
 +            if (idleTimeout) {
 +                runtime.clearTimeout(idleTimeout);
 +                idleTimeout = null;
 +            }
 +
 +            // disable any syncOps timeout
 +            if (syncOpsTimeout) {
 +                runtime.clearTimeout(syncOpsTimeout);
 +                syncOpsTimeout = null;
 +            }
 +
 +runtime.log("OperationRouter: instant opsSync requested");
 +            isInstantSyncRequested = true;
 +            syncOps();
 +        };
 +
 +        this.requestReplay = function (done_cb) {
 +            requestInstantOpsSync(done_cb);
 +        };
 +
 +        /**
 +         * Sets the factory to use to create operation instances from operation specs.
 +         *
 +         * @param {!ops.OperationFactory} f
 +         * @return {undefined}
 +         */
 +        this.setOperationFactory = function (f) {
 +            operationFactory = f;
 +            operationTransformer.setOperationFactory(f);
 +        };
 +
 +        /**
 +         * Sets the method which should be called to apply operations.
 +         *
 +         * @param {!function(!ops.Operation):boolean} playback_func
 +         * @return {undefined}
 +         */
 +        this.setPlaybackFunction = function (playback_func) {
 +            playbackFunction = playback_func;
 +        };
 +
 +        /**
 +         * Brings the locally created operations into the game.
 +         *
 +         * @param {!Array.<!ops.Operation>} operations
 +         * @return {undefined}
 +         */
 +        this.push = function (operations) {
 +            var i, op, opspec,
 +                timestamp = (new Date()).getTime();
 +
 +            if (hasError) {
 +                return;
 +            }
 +            // TODO: should be an assert in the future
 +            // there needs to be a flag telling that processing is happening,
 +            // and thus any input should be dropped in the sessioncontroller
 +            // ideally also have some UI element showing the processing state
 +            if (unplayedServerOpspecQueue.length > 0) {
 +                return;
 +            }
 +
++            eventNotifier.emit(ops.OperationRouter.signalProcessingBatchStart, {});
++
 +            for (i = 0; i < operations.length; i += 1) {
 +                op = operations[i];
 +                opspec = op.spec();
 +
 +                // note if any local ops modified 
 +                hasPushedModificationOps = hasPushedModificationOps || op.isEdit;
 +
 +                // add timestamp TODO: improve the useless recreation of the op
 +                opspec.timestamp = timestamp;
 +                op = operationFactory.create(opspec);
 +
 +                // apply locally
 +                if (!playbackFunction(op)) {
 +                    hasError = true;
 +                    errorCallback("opExecutionFailure");
 +                    return;
 +                }
 +
 +                // send to server
 +                unsyncedClientOpspecQueue.push(opspec);
 +            }
 +
 +            triggerPushingOps();
 +
 +            updateHasLocalUnsyncedOpsState();
++
++            eventNotifier.emit(ops.OperationRouter.signalProcessingBatchEnd, {});
 +        };
 +
 +        /**
 +         * Requests a gracefull shutdown of the Operation Router.
 +         * Buffered operations shall be sent to the server.
 +         * A callback is called on success.
 +         */
 +        this.close = function (cb) {
 +            function cbDoneSaving(err) {
 +                eventNotifier.emit(EVENT_SAVEDTOFILE, null);
 +                cb(err);
 +            }
 +
 +            function cbSuccess(fileData) {
 +                server.writeSessionStateToFile(sessionId, memberId, lastServerSeq, fileData, cbDoneSaving);
 +            }
 +
 +            function doClose() {
 +                syncingBlocked = true;
 +                if (hasPushedModificationOps) {
 +                    eventNotifier.emit(EVENT_BEFORESAVETOFILE, null);
 +
 +                    odfContainer.createByteArray(cbSuccess, cbDoneSaving);
 +                } else {
 +                    cb();
 +                }
 +            }
 +
 +            if (hasError) {
 +                cb();
 +            } else if (hasLocalUnsyncedOps) {
 +                requestInstantOpsSync(doClose);
 +            } else {
 +                doClose();
 +            }
 +        };
 +
 +        /**
 +         * @param {!string} eventId
 +         * @param {!Function} cb
 +         * @return {undefined}
 +         */
 +        this.subscribe = function (eventId, cb) {
 +            eventNotifier.subscribe(eventId, cb);
 +        };
 +
 +        /**
 +         * @param {!string} eventId
 +         * @param {!Function} cb
 +         * @return {undefined}
 +         */
 +        this.unsubscribe = function (eventId, cb) {
 +            eventNotifier.unsubscribe(eventId, cb);
 +        };
 +
 +        /**
 +         * @return {!boolean}
 +         */
 +        this.hasLocalUnsyncedOps = function () {
 +            return hasLocalUnsyncedOps;
 +        };
 +
 +        /**
 +         * @return {!boolean}
 +         */
 +        this.hasSessionHostConnection = function () {
 +            return hasSessionHostConnection;
 +        };
 +    };
 +});
diff --cc apps/documents/js/3rdparty/webodf/editor/widgets/dialogWidgets/alignmentPane.js
index 9e9a149,0000000..24136f0
mode 100644,000000..100644
--- a/apps/documents/js/3rdparty/webodf/editor/widgets/dialogWidgets/alignmentPane.js
+++ b/apps/documents/js/3rdparty/webodf/editor/widgets/dialogWidgets/alignmentPane.js
@@@ -1,128 -1,0 +1,129 @@@
 +/**
 + * @license
 + * Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
 + *
 + * @licstart
 + * The JavaScript code in this page is free software: you can redistribute it
 + * and/or modify it under the terms of the GNU Affero General Public License
 + * (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + * the License, or (at your option) any later version.  The code is distributed
 + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 + *
 + * You should have received a copy of the GNU Affero General Public License
 + * along with this code.  If not, see <http://www.gnu.org/licenses/>.
 + *
 + * As additional permission under GNU AGPL version 3 section 7, you
 + * may distribute non-source (e.g., minimized or compacted) forms of
 + * that code without the copy of the GNU GPL normally required by
 + * section 4, provided you include this license notice and a URL
 + * through which recipients can access the Corresponding Source.
 + *
 + * As a special exception to the AGPL, any HTML file which merely makes function
 + * calls to this code, and for that purpose includes it by reference shall be
 + * deemed a separate work for copyright law purposes. In addition, the copyright
 + * holders of this code give you permission to combine this code with free
 + * software libraries that are released under the GNU LGPL. You may copy and
 + * distribute such a system following the terms of the GNU AGPL for this code
 + * and the LGPL for the libraries. If you modify this code, you may extend this
 + * exception to your version of the code, but you are not obligated to do so.
 + * If you do not wish to do so, delete this exception statement from your
 + * version.
 + *
 + * This license applies to this entire compilation.
 + * @licend
 + * @source: http://www.webodf.org/
 + * @source: https://github.com/kogmbh/WebODF/
 + */
 +
 +/*global runtime,core,define,require,dijit */
 +
- runtime.loadClass("core.CSSUnits");
- 
 +define("webodf/editor/widgets/dialogWidgets/alignmentPane", [], function () {
 +    "use strict";
++
++    runtime.loadClass("core.CSSUnits");
++
 +    var AlignmentPane = function (callback) {
 +        var self = this,
 +            editorSession,
 +            contentPane,
 +            form;
 +
 +        this.widget = function () {
 +            return contentPane;
 +        };
 +
 +        this.value = function () {
 +            return form.get('value');
 +        };
 +
 +        this.setStyle = function (styleName) {
 +            var style = editorSession.getParagraphStyleAttributes(styleName)['style:paragraph-properties'],
 +                cssUnits = new core.CSSUnits(),
 +                s_topMargin,
 +                s_bottomMargin,
 +                s_leftMargin,
 +                s_rightMargin,
 +                s_textAlign;
 +
 +            if (style !== undefined) {
 +                s_topMargin = parseFloat(cssUnits.convertMeasure(style['fo:margin-top'], 'mm'));
 +                s_leftMargin = parseFloat(cssUnits.convertMeasure(style['fo:margin-left'], 'mm'));
 +                s_rightMargin = parseFloat(cssUnits.convertMeasure(style['fo:margin-right'], 'mm'));
 +                s_bottomMargin = parseFloat(cssUnits.convertMeasure(style['fo:margin-bottom'], 'mm'));
 +                s_textAlign = style['fo:text-align'];
 +
 +                form.attr('value', {
 +                    topMargin: isNaN(s_topMargin) ? 0 : s_topMargin,
 +                    bottomMargin: isNaN(s_bottomMargin) ? 0 : s_bottomMargin,
 +                    leftMargin: isNaN(s_leftMargin) ? 0 : s_leftMargin,
 +                    rightMargin: isNaN(s_rightMargin) ? 0 : s_rightMargin,
 +                    textAlign: s_textAlign && s_textAlign.length ? s_textAlign : 'left'
 +                });
 +            } else {
 +                form.attr('value', {
 +                    topMargin: 0,
 +                    bottomMargin: 0,
 +                    leftMargin: 0,
 +                    rightMargin: 0,
 +                    textAlign: 'left'
 +                });
 +            }
 +        };
 +
 +        this.setEditorSession = function(session) {
 +            editorSession = session;
 +        };
 +
 +        function init(cb) {
 +            require([
 +                "dojo",
 +                "dojo/ready",
 +                "dojo/dom-construct",
 +                "dijit/layout/ContentPane"],
 +                function (dojo, ready, domConstruct, ContentPane) {
 +                    var editorBase = dojo.config && dojo.config.paths &&
 +                            dojo.config.paths['webodf/editor'];
 +                runtime.assert(editorBase, "webodf/editor path not defined in dojoConfig");
 +                ready(function () {
 +                    contentPane = new ContentPane({
 +                        title: runtime.tr("Alignment"),
 +                        href: editorBase+"/widgets/dialogWidgets/alignmentPane.html",
 +                        preload: true
 +                    });
 +                    contentPane.onLoad = function () {
 +                        form = dijit.byId('alignmentPaneForm');
 +                        runtime.translateContent(form.domNode);
 +                    };
 +                    return cb();
 +                });
 +            });
 +        }
 +
 +        init(function () {
 +            return callback(self);
 +        });
 +    };
 +
 +    return AlignmentPane;
 +});
diff --cc apps/documents/js/3rdparty/webodf/editor/widgets/dialogWidgets/editHyperlinkPane.html
index 0000000,0000000..ad6b5a1
new file mode 100644
--- /dev/null
+++ b/apps/documents/js/3rdparty/webodf/editor/widgets/dialogWidgets/editHyperlinkPane.html
@@@ -1,0 -1,0 +1,30 @@@
++<html>
++    <head></head>
++    <body>
++        <div data-dojo-type="dijit/form/Form" id="editHyperlinkPaneForm" data-dojo-id="editHyperlinkPaneForm">
++            <div>
++                <label text-i18n="Display Text" for="linkDisplayText"></label><br/>
++                <input data-dojo-type="dijit/form/TextBox" id="linkDisplayText"
++                       value=""
++                       data-dojo-props="trim:true"
++                       name="linkDisplayText" />
++                <input data-dojo-type="dijit/form/TextBox" id="isReadOnlyText"
++                       type ="hidden"
++                       value=""
++                       data-dojo-props="trim:true"
++                       name="isReadOnlyText" />
++            </div>
++            <div>
++                <label text-i18n="URL" for="linkUrl"></label><br/>
++                <input data-dojo-type="dijit/form/TextBox" id="linkUrl"
++                value="http://"
++                data-dojo-props="trim:true"
++                name="linkUrl" />
++            </div>
++            <div>
++                <button data-dojo-type="dijit/form/Button" id="saveHyperlinkChangeButton" type="submit">Ok</button>
++                <button data-dojo-type="dijit/form/Button" id="cancelHyperlinkChangeButton" data-dojo-id="cancelHyperlinkChangeButton">Cancel</button>
++            </div>
++        </div>
++    </body>
++</html> 
diff --cc apps/documents/js/3rdparty/webodf/editor/widgets/dialogWidgets/editHyperlinkPane.js
index 0000000,0000000..d696e78
new file mode 100644
--- /dev/null
+++ b/apps/documents/js/3rdparty/webodf/editor/widgets/dialogWidgets/editHyperlinkPane.js
@@@ -1,0 -1,0 +1,110 @@@
++/**
++ * @license
++ * Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
++ *
++ * @licstart
++ * The JavaScript code in this page is free software: you can redistribute it
++ * and/or modify it under the terms of the GNU Affero General Public License
++ * (GNU AGPL) as published by the Free Software Foundation, either version 3 of
++ * the License, or (at your option) any later version.  The code is distributed
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
++ *
++ * You should have received a copy of the GNU Affero General Public License
++ * along with this code.  If not, see <http://www.gnu.org/licenses/>.
++ *
++ * As additional permission under GNU AGPL version 3 section 7, you
++ * may distribute non-source (e.g., minimized or compacted) forms of
++ * that code without the copy of the GNU GPL normally required by
++ * section 4, provided you include this license notice and a URL
++ * through which recipients can access the Corresponding Source.
++ *
++ * As a special exception to the AGPL, any HTML file which merely makes function
++ * calls to this code, and for that purpose includes it by reference shall be
++ * deemed a separate work for copyright law purposes. In addition, the copyright
++ * holders of this code give you permission to combine this code with free
++ * software libraries that are released under the GNU LGPL. You may copy and
++ * distribute such a system following the terms of the GNU AGPL for this code
++ * and the LGPL for the libraries. If you modify this code, you may extend this
++ * exception to your version of the code, but you are not obligated to do so.
++ * If you do not wish to do so, delete this exception statement from your
++ * version.
++ *
++ * This license applies to this entire compilation.
++ * @licend
++ * @source: http://www.webodf.org/
++ * @source: https://github.com/kogmbh/WebODF/
++ */
++
++/*global runtime,core,define,require,document,dijit */
++
++define("webodf/editor/widgets/dialogWidgets/editHyperlinkPane", [
++    "dojo",
++    "dijit/layout/ContentPane"],
++
++    function (dojo, ContentPane) {
++        "use strict";
++
++        runtime.loadClass("core.CSSUnits");
++
++        var EditHyperlinkPane = function () {
++            var self = this,
++                editorBase = dojo.config && dojo.config.paths && dojo.config.paths['webodf/editor'],
++                contentPane,
++                form,
++                displayTextField,
++                initialValue;
++
++            runtime.assert(editorBase, "webodf/editor path not defined in dojoConfig");
++
++            function onSave() {
++                if (self.onSave) {
++                    self.onSave();
++                }
++                return false;
++            }
++
++            function onCancel() {
++                form.set('value', initialValue);
++                if (self.onCancel) {
++                    self.onCancel();
++                }
++            }
++
++            contentPane = new ContentPane({
++                title: runtime.tr("editLink"),
++                href: editorBase+"/widgets/dialogWidgets/editHyperlinkPane.html",
++                preload: true,
++                onLoad : function () {
++                    form = dijit.byId('editHyperlinkPaneForm');
++                    form.onSubmit = onSave;
++                    dijit.byId('cancelHyperlinkChangeButton').onClick = onCancel;
++                    displayTextField = dijit.byId('linkDisplayText');
++                    runtime.translateContent(form.domNode);
++                    if (initialValue) {
++                        form.set('value', initialValue);
++                        displayTextField.set('disabled', initialValue.isReadOnlyText);
++                        initialValue = undefined;
++                    }
++                }
++            });
++
++            this.widget = function () {
++                return contentPane;
++            };
++
++            this.value = function () {
++                return form && form.get('value');
++            };
++
++            this.set = function (value) {
++                initialValue = value;
++                if (form) {
++                    form.set('value', value);
++                    displayTextField.set('disabled', value.isReadOnlyText);
++                }
++            };
++        };
++
++        return EditHyperlinkPane;
++});
diff --cc apps/documents/js/3rdparty/webodf/editor/widgets/editHyperlinks.js
index 0000000,0000000..c1fc840
new file mode 100644
--- /dev/null
+++ b/apps/documents/js/3rdparty/webodf/editor/widgets/editHyperlinks.js
@@@ -1,0 -1,0 +1,181 @@@
++/**
++ * @license
++ * Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
++ *
++ * @licstart
++ * The JavaScript code in this page is free software: you can redistribute it
++ * and/or modify it under the terms of the GNU Affero General Public License
++ * (GNU AGPL) as published by the Free Software Foundation, either version 3 of
++ * the License, or (at your option) any later version.  The code is distributed
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
++ *
++ * You should have received a copy of the GNU Affero General Public License
++ * along with this code.  If not, see <http://www.gnu.org/licenses/>.
++ *
++ * As additional permission under GNU AGPL version 3 section 7, you
++ * may distribute non-source (e.g., minimized or compacted) forms of
++ * that code without the copy of the GNU GPL normally required by
++ * section 4, provided you include this license notice and a URL
++ * through which recipients can access the Corresponding Source.
++ *
++ * As a special exception to the AGPL, any HTML file which merely makes function
++ * calls to this code, and for that purpose includes it by reference shall be
++ * deemed a separate work for copyright law purposes. In addition, the copyright
++ * holders of this code give you permission to combine this code with free
++ * software libraries that are released under the GNU LGPL. You may copy and
++ * distribute such a system following the terms of the GNU AGPL for this code
++ * and the LGPL for the libraries. If you modify this code, you may extend this
++ * exception to your version of the code, but you are not obligated to do so.
++ * If you do not wish to do so, delete this exception statement from your
++ * version.
++ *
++ * This license applies to this entire compilation.
++ * @licend
++ * @source: http://www.webodf.org/
++ * @source: https://github.com/kogmbh/WebODF/
++ */
++
++/*global define,require,document,odf */
++
++define("webodf/editor/widgets/editHyperlinks", [
++    "webodf/editor/EditorSession",
++    "webodf/editor/widgets/dialogWidgets/editHyperlinkPane",
++    "dijit/form/Button",
++    "dijit/form/DropDownButton",
++    "dijit/TooltipDialog"],
++
++    function (EditorSession, EditHyperlinkPane, Button, DropDownButton, TooltipDialog) {
++        "use strict";
++
++        runtime.loadClass("odf.OdfUtils");
++
++        var EditHyperlinks = function (callback) {
++            var self = this,
++                widget = {},
++                editorSession,
++                hyperlinkController,
++                linkEditorContent,
++                editHyperlinkButton,
++                removeHyperlinkButton,
++                odfUtils = new odf.OdfUtils(),
++                dialog;
++
++            linkEditorContent = new EditHyperlinkPane();
++            dialog = new TooltipDialog({
++                title: runtime.tr("Edit link"),
++                content: linkEditorContent.widget()
++            });
++
++            editHyperlinkButton = new DropDownButton({
++                label: runtime.tr('Edit link'),
++                showLabel: false,
++                iconClass: 'dijitEditorIcon dijitEditorIconCreateLink',
++                dropDown: dialog
++            });
++
++            removeHyperlinkButton = new Button({
++                label: runtime.tr('Remove link'),
++                showLabel: false,
++                disabled: true,
++                iconClass: 'dijitEditorIcon dijitEditorIconUnlink',
++                onClick: function () {
++                    hyperlinkController.removeHyperlinks();
++                    self.onToolDone();
++                }
++            });
++
++            linkEditorContent.onSave = function () {
++                var hyperlinkData = linkEditorContent.value();
++                editHyperlinkButton.closeDropDown(false);
++                if (hyperlinkData.isReadOnlyText == "true") {
++                    hyperlinkController.removeHyperlinks();
++                    hyperlinkController.addHyperlink(hyperlinkData.linkUrl);
++                } else {
++                    hyperlinkController.addHyperlink(hyperlinkData.linkUrl, hyperlinkData.linkDisplayText);
++                }
++                self.onToolDone();
++            };
++
++            linkEditorContent.onCancel = function () {
++                editHyperlinkButton.closeDropDown(false);
++                self.onToolDone();
++            };
++
++            widget.children = [editHyperlinkButton, removeHyperlinkButton];
++            widget.startup = function () {
++                widget.children.forEach(function (element) {
++                    element.startup();
++                });
++            };
++
++            widget.placeAt = function (container) {
++                widget.children.forEach(function (element) {
++                    element.placeAt(container);
++                });
++                return widget;
++            };
++
++            function checkHyperlinkButtons() {
++                var selection = editorSession.getSelectedRange(),
++                    textContent,
++                    linksInSelection = editorSession.getSelectedHyperlinks(),
++                    linkTarget = linksInSelection[0] ? odfUtils.getHyperlinkTarget(linksInSelection[0]) : "http://";
++
++                if (selection && selection.collapsed && linksInSelection.length === 1) {
++                    // Selection is collapsed within a single hyperlink. Assume user is modifying the hyperlink
++                    textContent = selection.cloneRange();
++                    textContent.selectNodeContents(linksInSelection[0]);
++                    linkEditorContent.set({
++                        linkDisplayText: textContent.toString(),
++                        linkUrl: linkTarget,
++                        isReadOnlyText: true
++                    });
++                    textContent.detach();
++                } else if (selection && !selection.collapsed) {
++                    // User has selected part of a hyperlink or a block of text. Assume user is attempting to modify the
++                    // existing hyperlink, or wants to convert the selection into a hyperlink
++                    linkEditorContent.set({
++                        linkDisplayText: selection.toString(),
++                        linkUrl: linkTarget,
++                        isReadOnlyText: true
++                    });
++                } else {
++                    // Selection is collapsed and is not in an existing hyperlink
++                    linkEditorContent.set({
++                        linkDisplayText: "",
++                        linkUrl: linkTarget,
++                        isReadOnlyText: false
++                    });
++                }
++
++                // The 3rd parameter is false to avoid firing onChange when setting the value programmatically.
++                removeHyperlinkButton.set('disabled', linksInSelection.length === 0, false);
++            }
++
++            this.setEditorSession = function (session) {
++                if (editorSession) {
++                    editorSession.unsubscribe(EditorSession.signalCursorMoved, checkHyperlinkButtons);
++                    editorSession.unsubscribe(EditorSession.signalParagraphChanged, checkHyperlinkButtons);
++                    editorSession.unsubscribe(EditorSession.signalParagraphStyleModified, checkHyperlinkButtons);
++                }
++                editorSession = session;
++                hyperlinkController = session && session.sessionController.getHyperlinkController();
++                widget.children.forEach(function (element) {
++                    element.setAttribute('disabled', !hyperlinkController);
++                });
++                if (editorSession) {
++                    editorSession.subscribe(EditorSession.signalCursorMoved, checkHyperlinkButtons);
++                    editorSession.subscribe(EditorSession.signalParagraphChanged, checkHyperlinkButtons);
++                    editorSession.subscribe(EditorSession.signalParagraphStyleModified, checkHyperlinkButtons);
++                    checkHyperlinkButtons();
++                }
++            };
++
++            this.onToolDone = function () {};
++
++            callback(widget);
++        };
++
++        return EditHyperlinks;
++});
diff --cc apps/documents/js/3rdparty/webodf/editor/widgets/paragraphAlignment.js
index ae833b0,0000000..afc7958
mode 100644,000000..100644
--- a/apps/documents/js/3rdparty/webodf/editor/widgets/paragraphAlignment.js
+++ b/apps/documents/js/3rdparty/webodf/editor/widgets/paragraphAlignment.js
@@@ -1,209 -1,0 +1,209 @@@
 +/**
 + * @license
 + * Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
 + *
 + * @licstart
 + * The JavaScript code in this page is free software: you can redistribute it
 + * and/or modify it under the terms of the GNU Affero General Public License
 + * (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + * the License, or (at your option) any later version.  The code is distributed
 + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 + *
 + * You should have received a copy of the GNU Affero General Public License
 + * along with this code.  If not, see <http://www.gnu.org/licenses/>.
 + *
 + * As additional permission under GNU AGPL version 3 section 7, you
 + * may distribute non-source (e.g., minimized or compacted) forms of
 + * that code without the copy of the GNU GPL normally required by
 + * section 4, provided you include this license notice and a URL
 + * through which recipients can access the Corresponding Source.
 + *
 + * As a special exception to the AGPL, any HTML file which merely makes function
 + * calls to this code, and for that purpose includes it by reference shall be
 + * deemed a separate work for copyright law purposes. In addition, the copyright
 + * holders of this code give you permission to combine this code with free
 + * software libraries that are released under the GNU LGPL. You may copy and
 + * distribute such a system following the terms of the GNU AGPL for this code
 + * and the LGPL for the libraries. If you modify this code, you may extend this
 + * exception to your version of the code, but you are not obligated to do so.
 + * If you do not wish to do so, delete this exception statement from your
 + * version.
 + *
 + * This license applies to this entire compilation.
 + * @licend
 + * @source: http://www.webodf.org/
 + * @source: https://github.com/kogmbh/WebODF/
 + */
 +
 +/*global define,require,ops,gui */
 +
 +define("webodf/editor/widgets/paragraphAlignment", [
 +    "dijit/form/ToggleButton",
 +    "dijit/form/Button",
 +    "webodf/editor/EditorSession"],
 +
 +    function (ToggleButton, Button, EditorSession) {
 +        "use strict";
 +
 +        var ParagraphAlignment = function (callback) {
 +            var self = this,
 +                editorSession,
 +                widget = {},
-                 directParagraphStyler,
++                directFormattingController,
 +                justifyLeft,
 +                justifyCenter,
 +                justifyRight,
 +                justifyFull,
 +                indent,
 +                outdent;
 +
 +            justifyLeft = new ToggleButton({
 +                label: runtime.tr('Align Left'),
 +                disabled: true,
 +                showLabel: false,
 +                checked: false,
 +                iconClass: "dijitEditorIcon dijitEditorIconJustifyLeft",
 +                onChange: function () {
-                     directParagraphStyler.alignParagraphLeft();
++                    directFormattingController.alignParagraphLeft();
 +                    self.onToolDone();
 +                }
 +            });
 +
 +            justifyCenter = new ToggleButton({
 +                label: runtime.tr('Center'),
 +                disabled: true,
 +                showLabel: false,
 +                checked: false,
 +                iconClass: "dijitEditorIcon dijitEditorIconJustifyCenter",
 +                onChange: function () {
-                     directParagraphStyler.alignParagraphCenter();
++                    directFormattingController.alignParagraphCenter();
 +                    self.onToolDone();
 +                }
 +            });
 +
 +            justifyRight = new ToggleButton({
 +                label: runtime.tr('Align Right'),
 +                disabled: true,
 +                showLabel: false,
 +                checked: false,
 +                iconClass: "dijitEditorIcon dijitEditorIconJustifyRight",
 +                onChange: function () {
-                     directParagraphStyler.alignParagraphRight();
++                    directFormattingController.alignParagraphRight();
 +                    self.onToolDone();
 +                }
 +            });
 +
 +            justifyFull = new ToggleButton({
 +                label: runtime.tr('Justify'),
 +                disabled: true,
 +                showLabel: false,
 +                checked: false,
 +                iconClass: "dijitEditorIcon dijitEditorIconJustifyFull",
 +                onChange: function () {
-                     directParagraphStyler.alignParagraphJustified();
++                    directFormattingController.alignParagraphJustified();
 +                    self.onToolDone();
 +                }
 +            });
 +
 +            outdent = new Button({
 +                label: runtime.tr('Decrease Indent'),
 +                disabled: true,
 +                showLabel: false,
 +                iconClass: "dijitEditorIcon dijitEditorIconOutdent",
 +                onClick: function () {
-                     directParagraphStyler.outdent();
++                    directFormattingController.outdent();
 +                    self.onToolDone();
 +                }
 +            });
 +
 +            indent = new Button({
 +                label: runtime.tr('Increase Indent'),
 +                disabled: true,
 +                showLabel: false,
 +                iconClass: "dijitEditorIcon dijitEditorIconIndent",
 +                onClick: function () {
-                     directParagraphStyler.indent();
++                    directFormattingController.indent();
 +                    self.onToolDone();
 +                }
 +            });
 +
 +            widget.children = [justifyLeft,
 +                justifyCenter,
 +                justifyRight,
 +                justifyFull,
 +                outdent,
 +                indent
 +            ];
 +
 +            widget.startup = function () {
 +                widget.children.forEach(function (element) {
 +                    element.startup();
 +                });
 +            };
 +
 +            widget.placeAt = function (container) {
 +                widget.children.forEach(function (element) {
 +                    element.placeAt(container);
 +                });
 +                return widget;
 +            };
 +
 +            function updateStyleButtons(changes) {
 +                var buttons = {
 +                    isAlignedLeft: justifyLeft,
 +                    isAlignedCenter: justifyCenter,
 +                    isAlignedRight: justifyRight,
 +                    isAlignedJustified: justifyFull
 +                };
 +
 +                Object.keys(changes).forEach(function (key) {
 +                    var button = buttons[key];
 +                    if (button) {
 +                        // The 3rd parameter to set(...) is false to avoid firing onChange when setting the value programmatically.
 +                        button.set('checked', changes[key], false);
 +                    }
 +                });
 +            }
 +
 +            function handleCursorMoved(cursor) {
 +                var disabled = cursor.getSelectionType() === ops.OdtCursor.RegionSelection;
 +                widget.children.forEach(function (element) {
 +                    element.setAttribute('disabled', disabled);
 +                });
 +            }
 +
 +            this.setEditorSession = function (session) {
-                 if (directParagraphStyler) {
-                     directParagraphStyler.unsubscribe(gui.DirectParagraphStyler.paragraphStylingChanged, updateStyleButtons);
++                if (directFormattingController) {
++                    directFormattingController.unsubscribe(gui.DirectFormattingController.paragraphStylingChanged, updateStyleButtons);
 +                }
-                 directParagraphStyler = session && session.sessionController.getDirectParagraphStyler();
-                 if (directParagraphStyler) {
-                     directParagraphStyler.subscribe(gui.DirectParagraphStyler.paragraphStylingChanged, updateStyleButtons);
++                directFormattingController = session && session.sessionController.getDirectFormattingController();
++                if (directFormattingController) {
++                    directFormattingController.subscribe(gui.DirectFormattingController.paragraphStylingChanged, updateStyleButtons);
 +                }
 +                widget.children.forEach(function (element) {
-                     element.setAttribute('disabled', !directParagraphStyler);
++                    element.setAttribute('disabled', !directFormattingController);
 +                });
 +                updateStyleButtons({
-                     isAlignedLeft:      directParagraphStyler ? directParagraphStyler.isAlignedLeft() :      false,
-                     isAlignedCenter:    directParagraphStyler ? directParagraphStyler.isAlignedCenter() :    false,
-                     isAlignedRight:     directParagraphStyler ? directParagraphStyler.isAlignedRight() :     false,
-                     isAlignedJustified: directParagraphStyler ? directParagraphStyler.isAlignedJustified() : false
++                    isAlignedLeft:      directFormattingController ? directFormattingController.isAlignedLeft() :      false,
++                    isAlignedCenter:    directFormattingController ? directFormattingController.isAlignedCenter() :    false,
++                    isAlignedRight:     directFormattingController ? directFormattingController.isAlignedRight() :     false,
++                    isAlignedJustified: directFormattingController ? directFormattingController.isAlignedJustified() : false
 +                });
 +
 +                if (editorSession) {
 +                    editorSession.unsubscribe(EditorSession.signalCursorMoved, handleCursorMoved);
 +                }
 +                editorSession = session;
 +                if (editorSession) {
 +                    editorSession.subscribe(EditorSession.signalCursorMoved, handleCursorMoved);
 +                }
 +            };
 +
 +            this.onToolDone = function () {};
 +
 +            callback(widget);
 +        };
 +
 +        return ParagraphAlignment;
 +});
diff --cc apps/documents/js/3rdparty/webodf/editor/widgets/simpleStyles.js
index 10a6a10,0000000..0059575
mode 100644,000000..100644
--- a/apps/documents/js/3rdparty/webodf/editor/widgets/simpleStyles.js
+++ b/apps/documents/js/3rdparty/webodf/editor/widgets/simpleStyles.js
@@@ -1,221 -1,0 +1,221 @@@
 +/**
 + * @license
 + * Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 + *
 + * @licstart
 + * The JavaScript code in this page is free software: you can redistribute it
 + * and/or modify it under the terms of the GNU Affero General Public License
 + * (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + * the License, or (at your option) any later version.  The code is distributed
 + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 + *
 + * You should have received a copy of the GNU Affero General Public License
 + * along with this code.  If not, see <http://www.gnu.org/licenses/>.
 + *
 + * As additional permission under GNU AGPL version 3 section 7, you
 + * may distribute non-source (e.g., minimized or compacted) forms of
 + * that code without the copy of the GNU GPL normally required by
 + * section 4, provided you include this license notice and a URL
 + * through which recipients can access the Corresponding Source.
 + *
 + * As a special exception to the AGPL, any HTML file which merely makes function
 + * calls to this code, and for that purpose includes it by reference shall be
 + * deemed a separate work for copyright law purposes. In addition, the copyright
 + * holders of this code give you permission to combine this code with free
 + * software libraries that are released under the GNU LGPL. You may copy and
 + * distribute such a system following the terms of the GNU AGPL for this code
 + * and the LGPL for the libraries. If you modify this code, you may extend this
 + * exception to your version of the code, but you are not obligated to do so.
 + * If you do not wish to do so, delete this exception statement from your
 + * version.
 + *
 + * This license applies to this entire compilation.
 + * @licend
 + * @source: http://www.webodf.org/
 + * @source: https://github.com/kogmbh/WebODF/
 + */
 +
 +/*global define,require,gui,ops */
 +
 +define("webodf/editor/widgets/simpleStyles", [
 +    "webodf/editor/widgets/fontPicker",
 +    "dijit/form/ToggleButton",
 +    "dijit/form/NumberSpinner",
 +    "webodf/editor/EditorSession"],
 +
 +    function (FontPicker, ToggleButton, NumberSpinner, EditorSession) {
 +        "use strict";
 +
 +        var SimpleStyles = function(callback) {
 +            var self = this,
 +                editorSession,
 +                widget = {},
-                 directTextStyler,
++                directFormattingController,
 +                boldButton,
 +                italicButton,
 +                underlineButton,
 +                strikethroughButton,
 +                fontSizeSpinner,
 +                fontPicker,
 +                fontPickerWidget;
 +
 +            boldButton = new ToggleButton({
 +                label: runtime.tr('Bold'),
 +                disabled: true,
 +                showLabel: false,
 +                checked: false,
 +                iconClass: "dijitEditorIcon dijitEditorIconBold",
 +                onChange: function (checked) {
-                     directTextStyler.setBold(checked);
++                    directFormattingController.setBold(checked);
 +                    self.onToolDone();
 +                }
 +            });
 +
 +            italicButton = new ToggleButton({
 +                label: runtime.tr('Italic'),
 +                disabled: true,
 +                showLabel: false,
 +                checked: false,
 +                iconClass: "dijitEditorIcon dijitEditorIconItalic",
 +                onChange: function (checked) {
-                     directTextStyler.setItalic(checked);
++                    directFormattingController.setItalic(checked);
 +                    self.onToolDone();
 +                }
 +            });
 +
 +            underlineButton = new ToggleButton({
 +                label: runtime.tr('Underline'),
 +                disabled: true,
 +                showLabel: false,
 +                checked: false,
 +                iconClass: "dijitEditorIcon dijitEditorIconUnderline",
 +                onChange: function (checked) {
-                     directTextStyler.setHasUnderline(checked);
++                    directFormattingController.setHasUnderline(checked);
 +                    self.onToolDone();
 +                }
 +            });
 +
 +            strikethroughButton = new ToggleButton({
 +                label: runtime.tr('Strikethrough'),
 +                disabled: true,
 +                showLabel: false,
 +                checked: false,
 +                iconClass: "dijitEditorIcon dijitEditorIconStrikethrough",
 +                onChange: function (checked) {
-                     directTextStyler.setHasStrikethrough(checked);
++                    directFormattingController.setHasStrikethrough(checked);
 +                    self.onToolDone();
 +                }
 +            });
 +
 +            fontSizeSpinner = new NumberSpinner({
 +                label: runtime.tr('Size'),
 +                disabled: true,
 +                showLabel: false,
 +                value: 12,
 +                smallDelta: 1,
 +                constraints: {min:6, max:96},
 +                intermediateChanges: true,
 +                onChange: function (value) {
-                     directTextStyler.setFontSize(value);
++                    directFormattingController.setFontSize(value);
 +                },
 +                onClick: function () {
 +                    self.onToolDone();
 +                },
 +                onInput: function () {
 +                    // Do not process any input in the text box;
 +                    // even paste events will not be processed
 +                    // so that no corrupt values can exist
 +                    return false;
 +                }
 +            });
 +
 +            fontPicker = new FontPicker(function () {});
 +            fontPickerWidget = fontPicker.widget();
 +            fontPickerWidget.setAttribute('disabled', true);
 +            fontPickerWidget.onChange = function(value) {
-                 directTextStyler.setFontName(value);
++                directFormattingController.setFontName(value);
 +                self.onToolDone();
 +            };
 +
 +            widget.children = [boldButton, italicButton, underlineButton, strikethroughButton, fontPickerWidget, fontSizeSpinner];
 +            widget.startup = function () {
 +                widget.children.forEach(function (element) {
 +                    element.startup();
 +                });
 +            };
 +
 +            widget.placeAt = function (container) {
 +                widget.children.forEach(function (element) {
 +                    element.placeAt(container);
 +                });
 +                return widget;
 +            };
 +
 +            function updateStyleButtons(changes) {
 +                // The 3rd parameter to set(...) is false to avoid firing onChange when setting the value programmatically.
 +                var updateCalls = {
 +                    isBold: function(value) { boldButton.set('checked', value, false); },
 +                    isItalic: function(value) { italicButton.set('checked', value, false); },
 +                    hasUnderline: function(value) { underlineButton.set('checked', value, false); },
 +                    hasStrikeThrough: function(value) { strikethroughButton.set('checked', value, false); },
 +                    fontSize: function(value) { 
 +                        fontSizeSpinner.set('intermediateChanges', false); // Necessary due to https://bugs.dojotoolkit.org/ticket/11588
 +                        fontSizeSpinner.set('value', value, false);
 +                        fontSizeSpinner.set('intermediateChanges', true);
 +                    },
 +                    fontName: function(value) { fontPickerWidget.set('value', value, false); }
 +                };
 +
 +                Object.keys(changes).forEach(function (key) {
 +                    var updateCall = updateCalls[key];
 +                    if (updateCall) {
 +                        updateCall(changes[key]);
 +                    }
 +                });
 +            }
 +
 +            function handleCursorMoved(cursor) {
 +                var disabled = cursor.getSelectionType() === ops.OdtCursor.RegionSelection;
 +                widget.children.forEach(function (element) {
 +                    element.setAttribute('disabled', disabled);
 +                });
 +            }
 +
 +            this.setEditorSession = function(session) {
-                 if (directTextStyler) {
-                     directTextStyler.unsubscribe(gui.DirectTextStyler.textStylingChanged, updateStyleButtons);
++                if (directFormattingController) {
++                    directFormattingController.unsubscribe(gui.DirectFormattingController.textStylingChanged, updateStyleButtons);
 +                }
-                 directTextStyler = session && session.sessionController.getDirectTextStyler();
++                directFormattingController = session && session.sessionController.getDirectFormattingController();
 +                fontPicker.setEditorSession(session);
-                 if (directTextStyler) {
-                     directTextStyler.subscribe(gui.DirectTextStyler.textStylingChanged, updateStyleButtons);
++                if (directFormattingController) {
++                    directFormattingController.subscribe(gui.DirectFormattingController.textStylingChanged, updateStyleButtons);
 +                }
 +                widget.children.forEach(function (element) {
-                     element.setAttribute('disabled', !directTextStyler);
++                    element.setAttribute('disabled', !directFormattingController);
 +                });
 +                updateStyleButtons({
-                     isBold: directTextStyler ? directTextStyler.isBold() : false,
-                     isItalic: directTextStyler ? directTextStyler.isItalic() : false,
-                     hasUnderline: directTextStyler ? directTextStyler.hasUnderline() : false,
-                     hasStrikeThrough: directTextStyler ? directTextStyler.hasStrikeThrough() : false,
-                     fontSize: directTextStyler ? directTextStyler.fontSize() : undefined,
-                     fontName: directTextStyler ? directTextStyler.fontName() : undefined
++                    isBold: directFormattingController ? directFormattingController.isBold() : false,
++                    isItalic: directFormattingController ? directFormattingController.isItalic() : false,
++                    hasUnderline: directFormattingController ? directFormattingController.hasUnderline() : false,
++                    hasStrikeThrough: directFormattingController ? directFormattingController.hasStrikeThrough() : false,
++                    fontSize: directFormattingController ? directFormattingController.fontSize() : undefined,
++                    fontName: directFormattingController ? directFormattingController.fontName() : undefined
 +                });
 +
 +                if (editorSession) {
 +                    editorSession.unsubscribe(EditorSession.signalCursorMoved, handleCursorMoved);
 +                }
 +                editorSession = session;
 +                if (editorSession) {
 +                    editorSession.subscribe(EditorSession.signalCursorMoved, handleCursorMoved);
 +                }
 +            };
 +
 +            this.onToolDone = function () {};
 +
 +            callback(widget);
 +        };
 +
 +        return SimpleStyles;
 +});
diff --cc apps/documents/js/3rdparty/webodf/editor/widgets/undoRedoMenu.js
index cf1a57c,0000000..e266615
mode 100644,000000..100644
--- a/apps/documents/js/3rdparty/webodf/editor/widgets/undoRedoMenu.js
+++ b/apps/documents/js/3rdparty/webodf/editor/widgets/undoRedoMenu.js
@@@ -1,123 -1,0 +1,119 @@@
 +/**
 + * @license
 + * Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 + *
 + * @licstart
 + * The JavaScript code in this page is free software: you can redistribute it
 + * and/or modify it under the terms of the GNU Affero General Public License
 + * (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + * the License, or (at your option) any later version.  The code is distributed
 + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 + *
 + * You should have received a copy of the GNU Affero General Public License
 + * along with this code.  If not, see <http://www.gnu.org/licenses/>.
 + *
 + * As additional permission under GNU AGPL version 3 section 7, you
 + * may distribute non-source (e.g., minimized or compacted) forms of
 + * that code without the copy of the GNU GPL normally required by
 + * section 4, provided you include this license notice and a URL
 + * through which recipients can access the Corresponding Source.
 + *
 + * As a special exception to the AGPL, any HTML file which merely makes function
 + * calls to this code, and for that purpose includes it by reference shall be
 + * deemed a separate work for copyright law purposes. In addition, the copyright
 + * holders of this code give you permission to combine this code with free
 + * software libraries that are released under the GNU LGPL. You may copy and
 + * distribute such a system following the terms of the GNU AGPL for this code
 + * and the LGPL for the libraries. If you modify this code, you may extend this
 + * exception to your version of the code, but you are not obligated to do so.
 + * If you do not wish to do so, delete this exception statement from your
 + * version.
 + *
 + * This license applies to this entire compilation.
 + * @licend
 + * @source: http://www.webodf.org/
 + * @source: https://github.com/kogmbh/WebODF/
 + */
 +
 +/*global define,require*/
 +
 +define("webodf/editor/widgets/undoRedoMenu",
-     ["webodf/editor/EditorSession"],
++    ["webodf/editor/EditorSession", "dijit/form/Button"],
 +
-     function (EditorSession) {
++    function (EditorSession, Button) {
 +        "use strict";
 +
 +        return function UndoRedoMenu(callback) {
-             var editorSession,
++            var self = this,
++                editorSession,
 +                undoButton,
-                 redoButton;
++                redoButton,
++                widget = {};
 +
-             function makeWidget(callback) {
-                 require(["dijit/form/Button"], function (Button) {
-                     var widget = {};
- 
-                     undoButton = new Button({
-                         label: runtime.tr('Undo'),
-                         showLabel: false,
-                         disabled: true, // TODO: get current session state
-                         iconClass: "dijitEditorIcon dijitEditorIconUndo",
-                         onClick: function () {
-                             if (editorSession) {
-                                 editorSession.undo();
-                             }
-                         }
-                     });
- 
-                     redoButton = new Button({
-                         label: runtime.tr('Redo'),
-                         showLabel: false,
-                         disabled: true, // TODO: get current session state
-                         iconClass: "dijitEditorIcon dijitEditorIconRedo",
-                         onClick: function () {
-                             if (editorSession) {
-                                 editorSession.redo();
-                             }
-                         }
-                     });
++            undoButton = new Button({
++                label: runtime.tr('Undo'),
++                showLabel: false,
++                disabled: true, // TODO: get current session state
++                iconClass: "dijitEditorIcon dijitEditorIconUndo",
++                onClick: function () {
++                    if (editorSession) {
++                        editorSession.undo();
++                        self.onToolDone();
++                    }
++                }
++            });
 +
-                     widget.children = [undoButton, redoButton];
-                     widget.startup = function () {
-                         widget.children.forEach(function (element) {
-                             element.startup();
-                         });
-                     };
++            redoButton = new Button({
++                label: runtime.tr('Redo'),
++                showLabel: false,
++                disabled: true, // TODO: get current session state
++                iconClass: "dijitEditorIcon dijitEditorIconRedo",
++                onClick: function () {
++                    if (editorSession) {
++                        editorSession.redo();
++                        self.onToolDone();
++                    }
++                }
++            });
 +
-                     widget.placeAt = function (container) {
-                         widget.children.forEach(function (element) {
-                             element.placeAt(container);
-                         });
-                         return widget;
-                     };
++            widget.children = [undoButton, redoButton];
++            widget.startup = function () {
++                widget.children.forEach(function (element) {
++                    element.startup();
++                });
++            };
 +
-                     return callback(widget);
++            widget.placeAt = function (container) {
++                widget.children.forEach(function (element) {
++                    element.placeAt(container);
 +                });
-             }
++                return widget;
++            };
 +
 +            function checkUndoButtons(e) {
 +                if (undoButton) {
 +                    undoButton.set('disabled', e.undoAvailable === false);
 +                }
 +                if (redoButton) {
 +                    redoButton.set('disabled', e.redoAvailable === false);
 +                }
 +            }
 +
 +            this.setEditorSession = function(session) {
 +                if (editorSession) {
 +                    editorSession.unsubscribe(EditorSession.signalUndoStackChanged, checkUndoButtons);
 +                }
 +                editorSession = session;
 +                if (editorSession) {
 +                    editorSession.subscribe(EditorSession.signalUndoStackChanged, checkUndoButtons);
 +                    // TODO: checkUndoButtons(editorSession.getundoredoavailablalalo());
 +                }
 +            };
 +
++            this.onToolDone = function () {};
++
 +            // init
-             makeWidget(function (widget) {
-                 return callback(widget);
-             });
++            callback(widget);
 +        };
 +    });
diff --cc apps/documents/js/3rdparty/webodf/editor/widgets/zoomSlider.js
index b445211,0000000..a5e1e37
mode 100644,000000..100644
--- a/apps/documents/js/3rdparty/webodf/editor/widgets/zoomSlider.js
+++ b/apps/documents/js/3rdparty/webodf/editor/widgets/zoomSlider.js
@@@ -1,90 -1,0 +1,109 @@@
 +/**
 + * @license
 + * Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 + *
 + * @licstart
 + * The JavaScript code in this page is free software: you can redistribute it
 + * and/or modify it under the terms of the GNU Affero General Public License
 + * (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + * the License, or (at your option) any later version.  The code is distributed
 + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 + *
 + * You should have received a copy of the GNU Affero General Public License
 + * along with this code.  If not, see <http://www.gnu.org/licenses/>.
 + *
 + * As additional permission under GNU AGPL version 3 section 7, you
 + * may distribute non-source (e.g., minimized or compacted) forms of
 + * that code without the copy of the GNU GPL normally required by
 + * section 4, provided you include this license notice and a URL
 + * through which recipients can access the Corresponding Source.
 + *
 + * As a special exception to the AGPL, any HTML file which merely makes function
 + * calls to this code, and for that purpose includes it by reference shall be
 + * deemed a separate work for copyright law purposes. In addition, the copyright
 + * holders of this code give you permission to combine this code with free
 + * software libraries that are released under the GNU LGPL. You may copy and
 + * distribute such a system following the terms of the GNU AGPL for this code
 + * and the LGPL for the libraries. If you modify this code, you may extend this
 + * exception to your version of the code, but you are not obligated to do so.
 + * If you do not wish to do so, delete this exception statement from your
 + * version.
 + *
 + * This license applies to this entire compilation.
 + * @licend
 + * @source: http://www.webodf.org/
 + * @source: https://github.com/kogmbh/WebODF/
 + */
 +
 +/*global define,require*/
 +
- define("webodf/editor/widgets/zoomSlider", [], function () {
++define("webodf/editor/widgets/zoomSlider", [
++    "webodf/editor/EditorSession"],
++    function (EditorSession) {
 +    "use strict";
 +
 +    return function ZoomSlider(callback) {
 +        var self = this,
 +            editorSession,
-             slider;
++            slider,
++            extremeZoomFactor = 4;
 +
++        // The slider zooms from -1 to +1, which corresponds
++        // to zoom levels of 1/extremeZoomFactor to extremeZoomFactor.
 +        function makeWidget(callback) {
 +            require(["dijit/form/HorizontalSlider", "dijit/form/NumberTextBox", "dojo"], function (HorizontalSlider, NumberTextBox, dojo) {
 +                var widget = {};
 +
 +                slider = new HorizontalSlider({
 +                    name: 'zoomSlider',
-                     value: 100,
-                     minimum: 30,
-                     maximum: 150,
-                     discreteValues: 100,
++                    value: 0,
++                    minimum: -1,
++                    maximum: 1,
++                    discreteValues: 0.01,
 +                    intermediateChanges: true,
 +                    style: {
 +                        width: '150px',
 +                        height: '25px',
 +                        float: 'right'
 +                    }
 +                });
 +
 +                slider.onChange = function (value) {
 +                    if (editorSession) {
-                         editorSession.getOdfCanvas().setZoomLevel(value / 100.0);
++                        editorSession.getOdfCanvas().getZoomHelper().setZoomLevel(Math.pow(extremeZoomFactor, value));
 +                    }
 +                    self.onToolDone();
 +                };
 + 
 +                return callback(slider);
 +            });
 +        }
 +
++        function updateSlider(zoomLevel) {
++            if (slider) {
++                slider.set('value', Math.log(zoomLevel) / Math.log(extremeZoomFactor), false);
++            }
++        }
++
 +        this.setEditorSession = function(session) {
++            var zoomHelper;
++            if (editorSession) {
++                editorSession.getOdfCanvas().getZoomHelper().unsubscribe(gui.ZoomHelper.signalZoomChanged, updateSlider);
++            }
 +            editorSession = session;
- //             if (slider) { slider.setValue(editorSession.getOdfCanvas().getZoomLevel() ); TODO!
++            if (editorSession) {
++                zoomHelper = editorSession.getOdfCanvas().getZoomHelper();
++                zoomHelper.subscribe(gui.ZoomHelper.signalZoomChanged, updateSlider);
++                updateSlider(zoomHelper.getZoomLevel());
++            }
 +        };
 +
 +        this.onToolDone = function () {};
 +
 +        // init
 +        makeWidget(function (widget) {
 +            return callback(widget);
 +        });
 +    };
 +});
diff --cc apps/documents/js/3rdparty/webodf/webodf-debug.js
index 4bb2eff,0000000..ee718ae
mode 100644,000000..100644
--- a/apps/documents/js/3rdparty/webodf/webodf-debug.js
+++ b/apps/documents/js/3rdparty/webodf/webodf-debug.js
@@@ -1,18193 -1,0 +1,17841 @@@
- var webodf_version = "0.4.2-1579-gfc3a4e6";
++var webodf_version = "0.4.2-2050-g8d8fc02";
 +function Runtime() {
 +}
 +Runtime.prototype.getVariable = function(name) {
 +};
 +Runtime.prototype.toJson = function(anything) {
 +};
 +Runtime.prototype.fromJson = function(jsonstr) {
 +};
 +Runtime.prototype.byteArrayFromString = function(string, encoding) {
 +};
 +Runtime.prototype.byteArrayToString = function(bytearray, encoding) {
 +};
 +Runtime.prototype.read = function(path, offset, length, callback) {
 +};
 +Runtime.prototype.readFile = function(path, encoding, callback) {
 +};
 +Runtime.prototype.readFileSync = function(path, encoding) {
 +};
 +Runtime.prototype.loadXML = function(path, callback) {
 +};
 +Runtime.prototype.writeFile = function(path, data, callback) {
 +};
 +Runtime.prototype.isFile = function(path, callback) {
 +};
 +Runtime.prototype.getFileSize = function(path, callback) {
 +};
 +Runtime.prototype.deleteFile = function(path, callback) {
 +};
 +Runtime.prototype.log = function(msgOrCategory, msg) {
 +};
 +Runtime.prototype.setTimeout = function(callback, milliseconds) {
 +};
 +Runtime.prototype.clearTimeout = function(timeoutID) {
 +};
 +Runtime.prototype.libraryPaths = function() {
 +};
 +Runtime.prototype.currentDirectory = function() {
 +};
 +Runtime.prototype.setCurrentDirectory = function(dir) {
 +};
 +Runtime.prototype.type = function() {
 +};
 +Runtime.prototype.getDOMImplementation = function() {
 +};
 +Runtime.prototype.parseXML = function(xml) {
 +};
 +Runtime.prototype.exit = function(exitCode) {
 +};
 +Runtime.prototype.getWindow = function() {
 +};
++Runtime.prototype.requestAnimationFrame = function(callback) {
++};
++Runtime.prototype.cancelAnimationFrame = function(requestId) {
++};
 +Runtime.prototype.assert = function(condition, message, callback) {
 +};
 +var IS_COMPILED_CODE = true;
 +Runtime.byteArrayToString = function(bytearray, encoding) {
 +  function byteArrayToString(bytearray) {
 +    var s = "", i, l = bytearray.length;
 +    for(i = 0;i < l;i += 1) {
 +      s += String.fromCharCode(bytearray[i] & 255)
 +    }
 +    return s
 +  }
 +  function utf8ByteArrayToString(bytearray) {
 +    var s = "", i, l = bytearray.length, chars = [], c0, c1, c2, c3, codepoint;
 +    for(i = 0;i < l;i += 1) {
 +      c0 = (bytearray[i]);
 +      if(c0 < 128) {
 +        chars.push(c0)
 +      }else {
 +        i += 1;
 +        c1 = (bytearray[i]);
 +        if(c0 >= 194 && c0 < 224) {
 +          chars.push((c0 & 31) << 6 | c1 & 63)
 +        }else {
 +          i += 1;
 +          c2 = (bytearray[i]);
 +          if(c0 >= 224 && c0 < 240) {
 +            chars.push((c0 & 15) << 12 | (c1 & 63) << 6 | c2 & 63)
 +          }else {
 +            i += 1;
 +            c3 = (bytearray[i]);
 +            if(c0 >= 240 && c0 < 245) {
 +              codepoint = (c0 & 7) << 18 | (c1 & 63) << 12 | (c2 & 63) << 6 | c3 & 63;
 +              codepoint -= 65536;
 +              chars.push((codepoint >> 10) + 55296, (codepoint & 1023) + 56320)
 +            }
 +          }
 +        }
 +      }
 +      if(chars.length === 1E3) {
 +        s += String.fromCharCode.apply(null, chars);
 +        chars.length = 0
 +      }
 +    }
 +    return s + String.fromCharCode.apply(null, chars)
 +  }
 +  var result;
 +  if(encoding === "utf8") {
 +    result = utf8ByteArrayToString(bytearray)
 +  }else {
 +    if(encoding !== "binary") {
 +      this.log("Unsupported encoding: " + encoding)
 +    }
 +    result = byteArrayToString(bytearray)
 +  }
 +  return result
 +};
 +Runtime.getVariable = function(name) {
 +  try {
 +    return eval(name)
 +  }catch(e) {
 +    return undefined
 +  }
 +};
 +Runtime.toJson = function(anything) {
 +  return JSON.stringify(anything)
 +};
 +Runtime.fromJson = function(jsonstr) {
 +  return JSON.parse(jsonstr)
 +};
 +Runtime.getFunctionName = function getFunctionName(f) {
 +  var m;
 +  if(f.name === undefined) {
 +    m = (new RegExp("function\\s+(\\w+)")).exec(f);
 +    return m && m[1]
 +  }
 +  return f.name
 +};
 +function BrowserRuntime(logoutput) {
 +  var self = this, cache = {};
-   function utf8ByteArrayFromString(string) {
-     var l = string.length, bytearray, i, n, j = 0;
++  function getUtf8LengthForString(string) {
++    var l = string.length, i, n, j = 0;
 +    for(i = 0;i < l;i += 1) {
 +      n = string.charCodeAt(i);
-       j += 1 + (n > 128) + (n > 2048)
++      j += 1 + (n > 128) + (n > 2048);
++      if(n > 55040 && n < 57344) {
++        j += 1;
++        i += 1
++      }
++    }
++    return j
++  }
++  function utf8ByteArrayFromString(string, length, addBOM) {
++    var l = string.length, bytearray, i, n, j;
++    bytearray = new Uint8Array(new ArrayBuffer(length));
++    if(addBOM) {
++      bytearray[0] = 239;
++      bytearray[1] = 187;
++      bytearray[2] = 191;
++      j = 3
++    }else {
++      j = 0
 +    }
-     bytearray = new Uint8Array(new ArrayBuffer(j));
-     j = 0;
 +    for(i = 0;i < l;i += 1) {
 +      n = string.charCodeAt(i);
 +      if(n < 128) {
 +        bytearray[j] = n;
 +        j += 1
 +      }else {
 +        if(n < 2048) {
 +          bytearray[j] = 192 | n >>> 6;
 +          bytearray[j + 1] = 128 | n & 63;
 +          j += 2
 +        }else {
-           bytearray[j] = 224 | n >>> 12 & 15;
-           bytearray[j + 1] = 128 | n >>> 6 & 63;
-           bytearray[j + 2] = 128 | n & 63;
-           j += 3
++          if(n <= 55040 || n >= 57344) {
++            bytearray[j] = 224 | n >>> 12 & 15;
++            bytearray[j + 1] = 128 | n >>> 6 & 63;
++            bytearray[j + 2] = 128 | n & 63;
++            j += 3
++          }else {
++            i += 1;
++            n = (n - 55296 << 10 | string.charCodeAt(i) - 56320) + 65536;
++            bytearray[j] = 240 | n >>> 18 & 7;
++            bytearray[j + 1] = 128 | n >>> 12 & 63;
++            bytearray[j + 2] = 128 | n >>> 6 & 63;
++            bytearray[j + 3] = 128 | n & 63;
++            j += 4
++          }
 +        }
 +      }
 +    }
 +    return bytearray
 +  }
++  function utf8ByteArrayFromXHRString(string, wishLength) {
++    var addBOM = false, length = getUtf8LengthForString(string);
++    if(typeof wishLength === "number") {
++      if(wishLength !== length && wishLength !== length + 3) {
++        return undefined
++      }
++      addBOM = length + 3 === wishLength;
++      length = wishLength
++    }
++    return utf8ByteArrayFromString(string, length, addBOM)
++  }
 +  function byteArrayFromString(string) {
 +    var l = string.length, a = new Uint8Array(new ArrayBuffer(l)), i;
 +    for(i = 0;i < l;i += 1) {
 +      a[i] = string.charCodeAt(i) & 255
 +    }
 +    return a
 +  }
 +  this.byteArrayFromString = function(string, encoding) {
 +    var result;
 +    if(encoding === "utf8") {
-       result = utf8ByteArrayFromString(string)
++      result = utf8ByteArrayFromString(string, getUtf8LengthForString(string), false)
 +    }else {
 +      if(encoding !== "binary") {
 +        self.log("unknown encoding: " + encoding)
 +      }
 +      result = byteArrayFromString(string)
 +    }
 +    return result
 +  };
 +  this.byteArrayToString = Runtime.byteArrayToString;
 +  this.getVariable = Runtime.getVariable;
 +  this.fromJson = Runtime.fromJson;
 +  this.toJson = Runtime.toJson;
 +  function log(msgOrCategory, msg) {
 +    var node, doc, category;
 +    if(msg !== undefined) {
 +      category = msgOrCategory
 +    }else {
 +      msg = msgOrCategory
 +    }
 +    if(logoutput) {
 +      doc = logoutput.ownerDocument;
 +      if(category) {
 +        node = doc.createElement("span");
 +        node.className = category;
 +        node.appendChild(doc.createTextNode(category));
 +        logoutput.appendChild(node);
 +        logoutput.appendChild(doc.createTextNode(" "))
 +      }
 +      node = doc.createElement("span");
 +      if(msg.length > 0 && msg[0] === "<") {
 +        node.innerHTML = msg
 +      }else {
 +        node.appendChild(doc.createTextNode(msg))
 +      }
 +      logoutput.appendChild(node);
 +      logoutput.appendChild(doc.createElement("br"))
 +    }else {
 +      if(console) {
 +        console.log(msg)
 +      }
 +    }
 +    if(category === "alert") {
 +      alert(msg)
 +    }
 +  }
 +  function assert(condition, message, callback) {
 +    if(!condition) {
 +      log("alert", "ASSERTION FAILED:\n" + message);
 +      if(callback) {
 +        callback()
 +      }
 +      throw message;
 +    }
 +  }
 +  function arrayToUint8Array(buffer) {
 +    var l = buffer.length, i, a = new Uint8Array(new ArrayBuffer(l));
 +    for(i = 0;i < l;i += 1) {
 +      a[i] = buffer[i]
 +    }
 +    return a
 +  }
++  function stringToBinaryWorkaround(xhr) {
++    var cl, data;
++    cl = xhr.getResponseHeader("Content-Length");
++    if(cl) {
++      cl = parseInt(cl, 10)
++    }
++    if(cl && cl !== xhr.responseText.length) {
++      data = utf8ByteArrayFromXHRString(xhr.responseText, cl)
++    }
++    if(data === undefined) {
++      data = byteArrayFromString(xhr.responseText)
++    }
++    return data
++  }
 +  function handleXHRResult(path, encoding, xhr) {
-     var data, r, d, a;
++    var r, d, a, data;
 +    if(xhr.status === 0 && !xhr.responseText) {
 +      r = {err:"File " + path + " is empty.", data:null}
 +    }else {
 +      if(xhr.status === 200 || xhr.status === 0) {
 +        if(xhr.response && typeof xhr.response !== "string") {
 +          if(encoding === "binary") {
 +            d = (xhr.response);
 +            data = new Uint8Array(d)
 +          }else {
 +            data = String(xhr.response)
 +          }
 +        }else {
 +          if(encoding === "binary") {
 +            if(xhr.responseBody !== null && String(typeof VBArray) !== "undefined") {
 +              a = (new VBArray(xhr.responseBody)).toArray();
 +              data = arrayToUint8Array(a)
 +            }else {
-               data = self.byteArrayFromString(xhr.responseText, "binary")
++              data = stringToBinaryWorkaround(xhr)
 +            }
 +          }else {
 +            data = xhr.responseText
 +          }
 +        }
 +        cache[path] = data;
 +        r = {err:null, data:data}
 +      }else {
 +        r = {err:xhr.responseText || xhr.statusText, data:null}
 +      }
 +    }
 +    return r
 +  }
 +  function createXHR(path, encoding, async) {
 +    var xhr = new XMLHttpRequest;
 +    xhr.open("GET", path, async);
 +    if(xhr.overrideMimeType) {
 +      if(encoding !== "binary") {
 +        xhr.overrideMimeType("text/plain; charset=" + encoding)
 +      }else {
 +        xhr.overrideMimeType("text/plain; charset=x-user-defined")
 +      }
 +    }
 +    return xhr
 +  }
 +  function readFile(path, encoding, callback) {
 +    if(cache.hasOwnProperty(path)) {
 +      callback(null, cache[path]);
 +      return
 +    }
 +    var xhr = createXHR(path, encoding, true);
 +    function handleResult() {
 +      var r;
 +      if(xhr.readyState === 4) {
 +        r = handleXHRResult(path, encoding, xhr);
 +        callback(r.err, r.data)
 +      }
 +    }
 +    xhr.onreadystatechange = handleResult;
 +    try {
 +      xhr.send(null)
 +    }catch(e) {
 +      callback(e.message, null)
 +    }
 +  }
 +  function read(path, offset, length, callback) {
 +    readFile(path, "binary", function(err, result) {
 +      var r = null;
 +      if(result) {
 +        if(typeof result === "string") {
 +          throw"This should not happen.";
 +        }
 +        r = (result.subarray(offset, offset + length))
 +      }
 +      callback(err, r)
 +    })
 +  }
 +  function readFileSync(path, encoding) {
 +    var xhr = createXHR(path, encoding, false), r;
 +    try {
 +      xhr.send(null);
 +      r = handleXHRResult(path, encoding, xhr);
 +      if(r.err) {
 +        throw r.err;
 +      }
 +      if(r.data === null) {
 +        throw"No data read from " + path + ".";
 +      }
 +    }catch(e) {
 +      throw e;
 +    }
 +    return r.data
 +  }
 +  function writeFile(path, data, callback) {
 +    cache[path] = data;
 +    var xhr = new XMLHttpRequest, d;
 +    function handleResult() {
 +      if(xhr.readyState === 4) {
 +        if(xhr.status === 0 && !xhr.responseText) {
 +          callback("File " + path + " is empty.")
 +        }else {
 +          if(xhr.status >= 200 && xhr.status < 300 || xhr.status === 0) {
 +            callback(null)
 +          }else {
 +            callback("Status " + String(xhr.status) + ": " + xhr.responseText || xhr.statusText)
 +          }
 +        }
 +      }
 +    }
 +    xhr.open("PUT", path, true);
 +    xhr.onreadystatechange = handleResult;
 +    if(data.buffer && !xhr.sendAsBinary) {
 +      d = data.buffer
 +    }else {
 +      d = self.byteArrayToString(data, "binary")
 +    }
 +    try {
 +      if(xhr.sendAsBinary) {
 +        xhr.sendAsBinary(d)
 +      }else {
 +        xhr.send(d)
 +      }
 +    }catch(e) {
 +      self.log("HUH? " + e + " " + data);
 +      callback(e.message)
 +    }
 +  }
 +  function deleteFile(path, callback) {
 +    delete cache[path];
 +    var xhr = new XMLHttpRequest;
 +    xhr.open("DELETE", path, true);
 +    xhr.onreadystatechange = function() {
 +      if(xhr.readyState === 4) {
 +        if(xhr.status < 200 && xhr.status >= 300) {
 +          callback(xhr.responseText)
 +        }else {
 +          callback(null)
 +        }
 +      }
 +    };
 +    xhr.send(null)
 +  }
 +  function loadXML(path, callback) {
 +    var xhr = new XMLHttpRequest;
 +    function handleResult() {
 +      if(xhr.readyState === 4) {
 +        if(xhr.status === 0 && !xhr.responseText) {
 +          callback("File " + path + " is empty.", null)
 +        }else {
 +          if(xhr.status === 200 || xhr.status === 0) {
 +            callback(null, xhr.responseXML)
 +          }else {
 +            callback(xhr.responseText, null)
 +          }
 +        }
 +      }
 +    }
 +    xhr.open("GET", path, true);
 +    if(xhr.overrideMimeType) {
 +      xhr.overrideMimeType("text/xml")
 +    }
 +    xhr.onreadystatechange = handleResult;
 +    try {
 +      xhr.send(null)
 +    }catch(e) {
 +      callback(e.message, null)
 +    }
 +  }
 +  function isFile(path, callback) {
 +    self.getFileSize(path, function(size) {
 +      callback(size !== -1)
 +    })
 +  }
 +  function getFileSize(path, callback) {
 +    if(cache.hasOwnProperty(path) && typeof cache[path] !== "string") {
 +      callback(cache[path].length);
 +      return
 +    }
 +    var xhr = new XMLHttpRequest;
 +    xhr.open("HEAD", path, true);
 +    xhr.onreadystatechange = function() {
 +      if(xhr.readyState !== 4) {
 +        return
 +      }
 +      var cl = xhr.getResponseHeader("Content-Length");
 +      if(cl) {
 +        callback(parseInt(cl, 10))
 +      }else {
 +        readFile(path, "binary", function(err, data) {
 +          if(!err) {
 +            callback(data.length)
 +          }else {
 +            callback(-1)
 +          }
 +        })
 +      }
 +    };
 +    xhr.send(null)
 +  }
 +  this.readFile = readFile;
 +  this.read = read;
 +  this.readFileSync = readFileSync;
 +  this.writeFile = writeFile;
 +  this.deleteFile = deleteFile;
 +  this.loadXML = loadXML;
 +  this.isFile = isFile;
 +  this.getFileSize = getFileSize;
 +  this.log = log;
 +  this.assert = assert;
 +  this.setTimeout = function(f, msec) {
 +    return setTimeout(function() {
 +      f()
 +    }, msec)
 +  };
 +  this.clearTimeout = function(timeoutID) {
 +    clearTimeout(timeoutID)
 +  };
 +  this.libraryPaths = function() {
 +    return["lib"]
 +  };
 +  this.setCurrentDirectory = function() {
 +  };
 +  this.currentDirectory = function() {
 +    return""
 +  };
 +  this.type = function() {
 +    return"BrowserRuntime"
 +  };
 +  this.getDOMImplementation = function() {
 +    return window.document.implementation
 +  };
 +  this.parseXML = function(xml) {
 +    var parser = new DOMParser;
 +    return parser.parseFromString(xml, "text/xml")
 +  };
 +  this.exit = function(exitCode) {
 +    log("Calling exit with code " + String(exitCode) + ", but exit() is not implemented.")
 +  };
 +  this.getWindow = function() {
 +    return window
++  };
++  this.requestAnimationFrame = function(callback) {
++    var rAF = window.requestAnimationFrame || (window.webkitRequestAnimationFrame || (window.mozRequestAnimationFrame || window.msRequestAnimationFrame)), requestId = 0;
++    if(rAF) {
++      rAF.bind(window);
++      requestId = (rAF)(callback)
++    }else {
++      return setTimeout(callback, 15)
++    }
++    return requestId
++  };
++  this.cancelAnimationFrame = function(requestId) {
++    var cAF = window.cancelAnimationFrame || (window.webkitCancelAnimationFrame || (window.mozCancelAnimationFrame || window.msCancelAnimationFrame));
++    if(cAF) {
++      cAF.bind(window);
++      (cAF)(requestId)
++    }else {
++      clearTimeout(requestId)
++    }
 +  }
 +}
 +function NodeJSRuntime() {
 +  var self = this, fs = require("fs"), pathmod = require("path"), currentDirectory = "", parser, domImplementation;
 +  function bufferToUint8Array(buffer) {
 +    var l = buffer.length, i, a = new Uint8Array(new ArrayBuffer(l));
 +    for(i = 0;i < l;i += 1) {
 +      a[i] = buffer[i]
 +    }
 +    return a
 +  }
 +  this.byteArrayFromString = function(string, encoding) {
 +    var buf = new Buffer(string, encoding), i, l = buf.length, a = new Uint8Array(new ArrayBuffer(l));
 +    for(i = 0;i < l;i += 1) {
 +      a[i] = buf[i]
 +    }
 +    return a
 +  };
 +  this.byteArrayToString = Runtime.byteArrayToString;
 +  this.getVariable = Runtime.getVariable;
 +  this.fromJson = Runtime.fromJson;
 +  this.toJson = Runtime.toJson;
 +  function isFile(path, callback) {
 +    path = pathmod.resolve(currentDirectory, path);
 +    fs.stat(path, function(err, stats) {
 +      callback(!err && stats.isFile())
 +    })
 +  }
 +  function readFile(path, encoding, callback) {
 +    function convert(err, data) {
 +      if(err) {
 +        return callback(err, null)
 +      }
 +      if(!data) {
 +        return callback("No data for " + path + ".", null)
 +      }
 +      var d;
 +      if(typeof data === "string") {
 +        d = (data);
 +        return callback(err, d)
 +      }
 +      d = (data);
 +      callback(err, bufferToUint8Array(d))
 +    }
 +    path = pathmod.resolve(currentDirectory, path);
 +    if(encoding !== "binary") {
 +      fs.readFile(path, encoding, convert)
 +    }else {
 +      fs.readFile(path, null, convert)
 +    }
 +  }
 +  this.readFile = readFile;
 +  function loadXML(path, callback) {
 +    readFile(path, "utf-8", function(err, data) {
 +      if(err) {
 +        return callback(err, null)
 +      }
 +      if(!data) {
 +        return callback("No data for " + path + ".", null)
 +      }
 +      var d = (data);
 +      callback(null, self.parseXML(d))
 +    })
 +  }
 +  this.loadXML = loadXML;
 +  this.writeFile = function(path, data, callback) {
 +    var buf = new Buffer(data);
 +    path = pathmod.resolve(currentDirectory, path);
 +    fs.writeFile(path, buf, "binary", function(err) {
 +      callback(err || null)
 +    })
 +  };
 +  this.deleteFile = function(path, callback) {
 +    path = pathmod.resolve(currentDirectory, path);
 +    fs.unlink(path, callback)
 +  };
 +  this.read = function(path, offset, length, callback) {
 +    path = pathmod.resolve(currentDirectory, path);
 +    fs.open(path, "r+", 666, function(err, fd) {
 +      if(err) {
 +        callback(err, null);
 +        return
 +      }
 +      var buffer = new Buffer(length);
 +      fs.read(fd, buffer, 0, length, offset, function(err) {
 +        fs.close(fd);
 +        callback(err, bufferToUint8Array(buffer))
 +      })
 +    })
 +  };
 +  this.readFileSync = function(path, encoding) {
 +    var s, enc = encoding === "binary" ? null : encoding, r = fs.readFileSync(path, enc);
 +    if(r === null) {
 +      throw"File " + path + " could not be read.";
 +    }
 +    if(encoding === "binary") {
 +      s = (r);
 +      s = bufferToUint8Array(s)
 +    }else {
 +      s = (r)
 +    }
 +    return s
 +  };
 +  this.isFile = isFile;
 +  this.getFileSize = function(path, callback) {
 +    path = pathmod.resolve(currentDirectory, path);
 +    fs.stat(path, function(err, stats) {
 +      if(err) {
 +        callback(-1)
 +      }else {
 +        callback(stats.size)
 +      }
 +    })
 +  };
 +  function log(msgOrCategory, msg) {
 +    var category;
 +    if(msg !== undefined) {
 +      category = msgOrCategory
 +    }else {
 +      msg = msgOrCategory
 +    }
 +    if(category === "alert") {
 +      process.stderr.write("\n!!!!! ALERT !!!!!" + "\n")
 +    }
 +    process.stderr.write(msg + "\n");
 +    if(category === "alert") {
 +      process.stderr.write("!!!!! ALERT !!!!!" + "\n")
 +    }
 +  }
 +  this.log = log;
 +  function assert(condition, message, callback) {
 +    if(!condition) {
 +      process.stderr.write("ASSERTION FAILED: " + message);
 +      if(callback) {
 +        callback()
 +      }
 +    }
 +  }
 +  this.assert = assert;
 +  this.setTimeout = function(f, msec) {
 +    return setTimeout(function() {
 +      f()
 +    }, msec)
 +  };
 +  this.clearTimeout = function(timeoutID) {
 +    clearTimeout(timeoutID)
 +  };
 +  this.libraryPaths = function() {
 +    return[__dirname]
 +  };
 +  this.setCurrentDirectory = function(dir) {
 +    currentDirectory = dir
 +  };
 +  this.currentDirectory = function() {
 +    return currentDirectory
 +  };
 +  this.type = function() {
 +    return"NodeJSRuntime"
 +  };
 +  this.getDOMImplementation = function() {
 +    return domImplementation
 +  };
 +  this.parseXML = function(xml) {
 +    return parser.parseFromString(xml, "text/xml")
 +  };
 +  this.exit = process.exit;
 +  this.getWindow = function() {
 +    return null
 +  };
++  this.requestAnimationFrame = function(callback) {
++    return setTimeout(callback, 15)
++  };
++  this.cancelAnimationFrame = function(requestId) {
++    clearTimeout(requestId)
++  };
 +  function init() {
 +    var DOMParser = require("xmldom").DOMParser;
 +    parser = new DOMParser;
 +    domImplementation = self.parseXML("<a/>").implementation
 +  }
 +  init()
 +}
 +function RhinoRuntime() {
 +  var self = this, Packages = {}, dom = Packages.javax.xml.parsers.DocumentBuilderFactory.newInstance(), builder, entityresolver, currentDirectory = "";
 +  dom.setValidating(false);
 +  dom.setNamespaceAware(true);
 +  dom.setExpandEntityReferences(false);
 +  dom.setSchema(null);
 +  entityresolver = Packages.org.xml.sax.EntityResolver({resolveEntity:function(publicId, systemId) {
 +    var file;
 +    function open(path) {
 +      var reader = new Packages.java.io.FileReader(path), source = new Packages.org.xml.sax.InputSource(reader);
 +      return source
 +    }
 +    file = systemId;
 +    return open(file)
 +  }});
 +  builder = dom.newDocumentBuilder();
 +  builder.setEntityResolver(entityresolver);
 +  this.byteArrayFromString = function(string, encoding) {
 +    var i, l = string.length, a = new Uint8Array(new ArrayBuffer(l));
 +    for(i = 0;i < l;i += 1) {
 +      a[i] = string.charCodeAt(i) & 255
 +    }
 +    return a
 +  };
 +  this.byteArrayToString = Runtime.byteArrayToString;
 +  this.getVariable = Runtime.getVariable;
 +  this.fromJson = Runtime.fromJson;
 +  this.toJson = Runtime.toJson;
 +  function loadXML(path, callback) {
 +    var file = new Packages.java.io.File(path), xmlDocument = null;
 +    try {
 +      xmlDocument = builder.parse(file)
 +    }catch(err) {
 +      print(err);
 +      return callback(err, null)
 +    }
 +    callback(null, xmlDocument)
 +  }
 +  function runtimeReadFile(path, encoding, callback) {
 +    if(currentDirectory) {
 +      path = currentDirectory + "/" + path
 +    }
 +    var file = new Packages.java.io.File(path), data, rhinoencoding = encoding === "binary" ? "latin1" : encoding;
 +    if(!file.isFile()) {
 +      callback(path + " is not a file.", null)
 +    }else {
 +      data = readFile(path, rhinoencoding);
 +      if(data && encoding === "binary") {
 +        data = self.byteArrayFromString(data, "binary")
 +      }
 +      callback(null, data)
 +    }
 +  }
 +  function runtimeReadFileSync(path, encoding) {
 +    var file = new Packages.java.io.File(path);
 +    if(!file.isFile()) {
 +      return null
 +    }
 +    if(encoding === "binary") {
 +      encoding = "latin1"
 +    }
 +    return readFile(path, encoding)
 +  }
 +  function isFile(path, callback) {
 +    if(currentDirectory) {
 +      path = currentDirectory + "/" + path
 +    }
 +    var file = new Packages.java.io.File(path);
 +    callback(file.isFile())
 +  }
 +  this.loadXML = loadXML;
 +  this.readFile = runtimeReadFile;
 +  this.writeFile = function(path, data, callback) {
 +    if(currentDirectory) {
 +      path = currentDirectory + "/" + path
 +    }
 +    var out = new Packages.java.io.FileOutputStream(path), i, l = data.length;
 +    for(i = 0;i < l;i += 1) {
 +      out.write(data[i])
 +    }
 +    out.close();
 +    callback(null)
 +  };
 +  this.deleteFile = function(path, callback) {
 +    if(currentDirectory) {
 +      path = currentDirectory + "/" + path
 +    }
 +    var file = new Packages.java.io.File(path), otherPath = path + Math.random(), other = new Packages.java.io.File(otherPath);
 +    if(file.rename(other)) {
 +      other.deleteOnExit();
 +      callback(null)
 +    }else {
 +      callback("Could not delete " + path)
 +    }
 +  };
 +  this.read = function(path, offset, length, callback) {
 +    if(currentDirectory) {
 +      path = currentDirectory + "/" + path
 +    }
 +    var data = runtimeReadFileSync(path, "binary");
 +    if(data) {
 +      callback(null, this.byteArrayFromString(data.substring(offset, offset + length), "binary"))
 +    }else {
 +      callback("Cannot read " + path, null)
 +    }
 +  };
 +  this.readFileSync = function(path, encoding) {
 +    if(!encoding) {
 +      return""
 +    }
 +    var s = readFile(path, encoding);
 +    if(s === null) {
 +      throw"File could not be read.";
 +    }
 +    return s
 +  };
 +  this.isFile = isFile;
 +  this.getFileSize = function(path, callback) {
 +    if(currentDirectory) {
 +      path = currentDirectory + "/" + path
 +    }
 +    var file = new Packages.java.io.File(path);
 +    callback(file.length())
 +  };
 +  function log(msgOrCategory, msg) {
 +    var category;
 +    if(msg !== undefined) {
 +      category = msgOrCategory
 +    }else {
 +      msg = msgOrCategory
 +    }
 +    if(category === "alert") {
 +      print("\n!!!!! ALERT !!!!!")
 +    }
 +    print(msg);
 +    if(category === "alert") {
 +      print("!!!!! ALERT !!!!!")
 +    }
 +  }
 +  this.log = log;
 +  function assert(condition, message, callback) {
 +    if(!condition) {
 +      log("alert", "ASSERTION FAILED: " + message);
 +      if(callback) {
 +        callback()
 +      }
 +    }
 +  }
 +  this.assert = assert;
 +  this.setTimeout = function(f) {
 +    f();
 +    return 0
 +  };
 +  this.clearTimeout = function() {
 +  };
 +  this.libraryPaths = function() {
 +    return["lib"]
 +  };
 +  this.setCurrentDirectory = function(dir) {
 +    currentDirectory = dir
 +  };
 +  this.currentDirectory = function() {
 +    return currentDirectory
 +  };
 +  this.type = function() {
 +    return"RhinoRuntime"
 +  };
 +  this.getDOMImplementation = function() {
 +    return builder.getDOMImplementation()
 +  };
 +  this.parseXML = function(xml) {
 +    var reader = new Packages.java.io.StringReader(xml), source = new Packages.org.xml.sax.InputSource(reader);
 +    return builder.parse(source)
 +  };
 +  this.exit = quit;
 +  this.getWindow = function() {
 +    return null
++  };
++  this.requestAnimationFrame = function(callback) {
++    callback();
++    return 0
++  };
++  this.cancelAnimationFrame = function() {
 +  }
 +}
 +Runtime.create = function create() {
 +  var result;
 +  if(String(typeof window) !== "undefined") {
 +    result = new BrowserRuntime(window.document.getElementById("logoutput"))
 +  }else {
 +    if(String(typeof require) !== "undefined") {
 +      result = new NodeJSRuntime
 +    }else {
 +      result = new RhinoRuntime
 +    }
 +  }
 +  return result
 +};
 +var runtime = Runtime.create();
 +var core = {};
 +var gui = {};
 +var xmldom = {};
 +var odf = {};
 +var ops = {};
 +(function() {
-   var dependencies = {}, loadedFiles = {};
-   function loadManifest(dir, manifests) {
++  function loadDependenciesFromManifest(dir, dependencies, expectFail) {
 +    var path = dir + "/manifest.json", content, list, manifest, m;
-     if(loadedFiles.hasOwnProperty(path)) {
-       return
-     }
-     loadedFiles[path] = 1;
++    runtime.log("Loading manifest: " + path);
 +    try {
 +      content = runtime.readFileSync(path, "utf-8")
 +    }catch(e) {
-       console.log(String(e));
++      if(expectFail) {
++        runtime.log("No loadable manifest found.")
++      }else {
++        console.log(String(e));
++        throw e;
++      }
 +      return
 +    }
 +    list = JSON.parse((content));
 +    manifest = (list);
 +    for(m in manifest) {
 +      if(manifest.hasOwnProperty(m)) {
-         manifests[m] = {dir:dir, deps:manifest[m]}
++        dependencies[m] = {dir:dir, deps:manifest[m]}
 +      }
 +    }
 +  }
-   function expandPathDependencies(path, manifests, allDeps) {
-     var d = manifests[path].deps, deps = {};
-     allDeps[path] = deps;
-     d.forEach(function(dp) {
-       deps[dp] = 1
-     });
-     d.forEach(function(dp) {
-       if(!allDeps[dp]) {
-         expandPathDependencies(dp, manifests, allDeps)
-       }
-     });
-     d.forEach(function(dp) {
-       Object.keys(allDeps[dp]).forEach(function(k) {
-         deps[k] = 1
-       })
-     })
-   }
-   function sortDeps(deps, allDeps) {
-     var i, sorted = [];
-     function add(path, stack) {
-       var j, d = allDeps[path];
-       if(sorted.indexOf(path) === -1 && stack.indexOf(path) === -1) {
-         stack.push(path);
-         for(j = 0;j < deps.length;j += 1) {
-           if(d[deps[j]]) {
-             add(deps[j], stack)
-           }
-         }
-         stack.pop();
-         sorted.push(path)
-       }
++  function loadDependenciesFromManifests() {
++    var dependencies = [], paths = runtime.libraryPaths(), i;
++    if(runtime.currentDirectory() && paths.indexOf(runtime.currentDirectory()) === -1) {
++      loadDependenciesFromManifest(runtime.currentDirectory(), dependencies, true)
 +    }
-     for(i = 0;i < deps.length;i += 1) {
-       add(deps[i], [])
++    for(i = 0;i < paths.length;i += 1) {
++      loadDependenciesFromManifest(paths[i], dependencies)
 +    }
-     return sorted
++    return dependencies
 +  }
-   function expandDependencies(manifests) {
-     var path, deps, allDeps = {};
-     for(path in manifests) {
-       if(manifests.hasOwnProperty(path)) {
-         expandPathDependencies(path, manifests, allDeps)
++  function getPath(dir, className) {
++    return dir + "/" + className.replace(".", "/") + ".js"
++  }
++  function getLoadList(classNames, dependencies, isDefined) {
++    var loadList = [], stack = {}, visited = {};
++    function visit(n) {
++      if(visited[n] || isDefined(n)) {
++        return
 +      }
-     }
-     for(path in manifests) {
-       if(manifests.hasOwnProperty(path)) {
-         deps = (Object.keys(allDeps[path]));
-         manifests[path].deps = sortDeps(deps, allDeps);
-         manifests[path].deps.push(path)
++      if(stack[n]) {
++        throw"Circular dependency detected for " + n + ".";
++      }
++      stack[n] = true;
++      if(!dependencies[n]) {
++        throw"Missing dependency information for class " + n + ".";
 +      }
++      var d = dependencies[n], deps = d.deps, i, l = deps.length;
++      for(i = 0;i < l;i += 1) {
++        visit(deps[i])
++      }
++      stack[n] = false;
++      visited[n] = true;
++      loadList.push(getPath(d.dir, n))
 +    }
-     dependencies = manifests
++    classNames.forEach(visit);
++    return loadList
 +  }
-   function loadManifests() {
-     if(Object.keys(dependencies).length > 0) {
-       return
-     }
-     var paths = runtime.libraryPaths(), manifests = {}, i;
-     if(runtime.currentDirectory()) {
-       loadManifest(runtime.currentDirectory(), manifests)
-     }
++  function addContent(path, content) {
++    content += "\n//# sourceURL=" + path;
++    content += "\n//@ sourceURL=" + path;
++    return content
++  }
++  function loadFiles(paths) {
++    var i, content;
 +    for(i = 0;i < paths.length;i += 1) {
-       loadManifest(paths[i], manifests)
++      content = runtime.readFileSync(paths[i], "utf-8");
++      content = addContent(paths[i], (content));
++      eval(content)
 +    }
-     expandDependencies(manifests)
-   }
-   function classPath(classname) {
-     return classname.replace(".", "/") + ".js"
 +  }
-   function getDependencies(classname) {
-     var classpath = classPath(classname), deps = [], d = dependencies[classpath].deps, i;
-     for(i = 0;i < d.length;i += 1) {
-       if(!loadedFiles.hasOwnProperty(d[i])) {
-         deps.push(d[i])
-       }
++  function loadFilesInBrowser(paths, callback) {
++    var e = document.currentScript || document.documentElement.lastChild, df = document.createDocumentFragment(), script, i;
++    for(i = 0;i < paths.length;i += 1) {
++      script = document.createElement("script");
++      script.type = "text/javascript";
++      script.charset = "utf-8";
++      script.async = false;
++      script.setAttribute("src", paths[i]);
++      df.appendChild(script)
++    }
++    if(callback) {
++      script.onload = callback
 +    }
-     return deps
++    e.parentNode.insertBefore(df, e)
 +  }
-   function evalArray(paths, contents) {
-     var i = 0;
-     while(i < paths.length && contents[i] !== undefined) {
-       if(contents[i] !== null) {
-         eval((contents[i]));
-         contents[i] = null
++  var dependencies, packages = {core:core, gui:gui, xmldom:xmldom, odf:odf, ops:ops};
++  function isDefined(classname) {
++    var parts = classname.split("."), i, p = packages, l = parts.length;
++    for(i = 0;i < l;i += 1) {
++      if(!p.hasOwnProperty(parts[i])) {
++        return false
 +      }
-       i += 1
++      p = (p[parts[i]])
 +    }
++    return true
 +  }
-   function loadFiles(paths) {
-     var contents = [], i, p, c, async = false;
-     contents.length = paths.length;
-     function addContent(pos, path, content) {
-       content += "\n//# sourceURL=" + path;
-       content += "\n//@ sourceURL=" + path;
-       contents[pos] = content
-     }
-     function loadFile(pos) {
-       var path = dependencies[paths[pos]].dir + "/" + paths[pos];
-       runtime.readFile(path, "utf8", function(err, content) {
-         if(err) {
-           throw err;
-         }
-         if(contents[pos] === undefined) {
-           addContent(pos, path, (content))
-         }
-       })
++  runtime.loadClasses = function(classnames, callback) {
++    if(IS_COMPILED_CODE || classnames.length === 0) {
++      return callback && callback()
 +    }
-     if(async) {
-       for(i = 0;i < paths.length;i += 1) {
-         loadedFiles[paths[i]] = 1;
-         loadFile(i)
-       }
++    dependencies = dependencies || loadDependenciesFromManifests();
++    classnames = getLoadList(classnames, dependencies, isDefined);
++    if(classnames.length === 0) {
++      return callback && callback()
 +    }
-     for(i = paths.length - 1;i >= 0;i -= 1) {
-       loadedFiles[paths[i]] = 1;
-       if(contents[i] === undefined) {
-         p = paths[i];
-         p = dependencies[p].dir + "/" + p;
-         c = runtime.readFileSync(p, "utf-8");
-         addContent(i, p, (c))
++    if(runtime.type() === "BrowserRuntime" && callback) {
++      loadFilesInBrowser(classnames, callback)
++    }else {
++      loadFiles(classnames);
++      if(callback) {
++        callback()
 +      }
 +    }
-     evalArray(paths, contents)
-   }
-   runtime.loadClass = function(classname) {
-     if(IS_COMPILED_CODE) {
-       return
-     }
-     var classpath = classPath(classname), paths;
-     if(loadedFiles.hasOwnProperty(classpath)) {
-       return
-     }
-     loadManifests();
-     paths = getDependencies(classname);
-     loadFiles(paths)
++  };
++  runtime.loadClass = function(classname, callback) {
++    runtime.loadClasses([classname], callback)
 +  }
 +})();
 +(function() {
 +  var translator = function(string) {
 +    return string
 +  };
 +  function tr(original) {
 +    var result = translator(original);
 +    if(!result || String(typeof result) !== "string") {
 +      return original
 +    }
 +    return result
 +  }
 +  runtime.getTranslator = function() {
 +    return translator
 +  };
 +  runtime.setTranslator = function(translatorFunction) {
 +    translator = translatorFunction
 +  };
 +  runtime.tr = tr
 +})();
 +(function(args) {
 +  if(args) {
 +    args = Array.prototype.slice.call((args))
 +  }else {
 +    args = []
 +  }
 +  function run(argv) {
 +    if(!argv.length) {
 +      return
 +    }
 +    var script = argv[0];
 +    runtime.readFile(script, "utf8", function(err, code) {
-       var path = "", codestring = (code);
-       if(script.indexOf("/") !== -1) {
-         path = script.substring(0, script.indexOf("/"))
++      var path = "", pathEndIndex = script.lastIndexOf("/"), codestring = (code);
++      if(pathEndIndex !== -1) {
++        path = script.substring(0, pathEndIndex)
++      }else {
++        path = "."
 +      }
 +      runtime.setCurrentDirectory(path);
 +      function inner_run() {
 +        var script, path, args, argv, result;
 +        result = (eval(codestring));
 +        if(result) {
 +          runtime.exit(result)
 +        }
 +        return
 +      }
 +      if(err) {
 +        runtime.log(err);
 +        runtime.exit(1)
 +      }else {
 +        if(codestring === null) {
 +          runtime.log("No code found for " + script);
 +          runtime.exit(1)
 +        }else {
 +          inner_run.apply(null, argv)
 +        }
 +      }
 +    })
 +  }
 +  if(runtime.type() === "NodeJSRuntime") {
 +    run(process.argv.slice(2))
 +  }else {
 +    if(runtime.type() === "RhinoRuntime") {
 +      run(args)
 +    }else {
 +      run(args.slice(1))
 +    }
 +  }
 +})(String(typeof arguments) !== "undefined" && arguments);
 +core.Async = function Async() {
 +  this.forEach = function(items, f, callback) {
 +    var i, l = items.length, itemsDone = 0;
 +    function end(err) {
 +      if(itemsDone !== l) {
 +        if(err) {
 +          itemsDone = l;
 +          callback(err)
 +        }else {
 +          itemsDone += 1;
 +          if(itemsDone === l) {
 +            callback(null)
 +          }
 +        }
 +      }
 +    }
 +    for(i = 0;i < l;i += 1) {
 +      f(items[i], end)
 +    }
 +  };
 +  this.destroyAll = function(items, callback) {
 +    function destroy(itemIndex, err) {
 +      if(err) {
 +        callback(err)
 +      }else {
 +        if(itemIndex < items.length) {
 +          items[itemIndex](function(err) {
 +            destroy(itemIndex + 1, err)
 +          })
 +        }else {
 +          callback()
 +        }
 +      }
 +    }
 +    destroy(0, undefined)
 +  }
 +};
 +function makeBase64() {
 +  function makeB64tab(bin) {
 +    var t = {}, i, l;
 +    for(i = 0, l = bin.length;i < l;i += 1) {
 +      t[bin.charAt(i)] = i
 +    }
 +    return t
 +  }
 +  var b64chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", b64tab = makeB64tab(b64chars), convertUTF16StringToBase64, convertBase64ToUTF16String, window = runtime.getWindow(), btoa, atob;
 +  function stringToArray(s) {
 +    var i, l = s.length, a = new Uint8Array(new ArrayBuffer(l));
 +    for(i = 0;i < l;i += 1) {
 +      a[i] = s.charCodeAt(i) & 255
 +    }
 +    return a
 +  }
 +  function convertUTF8ArrayToBase64(bin) {
 +    var n, b64 = "", i, l = bin.length - 2;
 +    for(i = 0;i < l;i += 3) {
 +      n = bin[i] << 16 | bin[i + 1] << 8 | bin[i + 2];
 +      b64 += (b64chars[n >>> 18]);
 +      b64 += (b64chars[n >>> 12 & 63]);
 +      b64 += (b64chars[n >>> 6 & 63]);
 +      b64 += (b64chars[n & 63])
 +    }
 +    if(i === l + 1) {
 +      n = bin[i] << 4;
 +      b64 += (b64chars[n >>> 6]);
 +      b64 += (b64chars[n & 63]);
 +      b64 += "=="
 +    }else {
 +      if(i === l) {
 +        n = bin[i] << 10 | bin[i + 1] << 2;
 +        b64 += (b64chars[n >>> 12]);
 +        b64 += (b64chars[n >>> 6 & 63]);
 +        b64 += (b64chars[n & 63]);
 +        b64 += "="
 +      }
 +    }
 +    return b64
 +  }
 +  function convertBase64ToUTF8Array(b64) {
 +    b64 = b64.replace(/[^A-Za-z0-9+\/]+/g, "");
 +    var l = b64.length, bin = new Uint8Array(new ArrayBuffer(3 * l)), padlen = b64.length % 4, o = 0, i, n;
 +    for(i = 0;i < l;i += 4) {
 +      n = (b64tab[b64.charAt(i)] || 0) << 18 | (b64tab[b64.charAt(i + 1)] || 0) << 12 | (b64tab[b64.charAt(i + 2)] || 0) << 6 | (b64tab[b64.charAt(i + 3)] || 0);
 +      bin[o] = n >> 16;
 +      bin[o + 1] = n >> 8 & 255;
 +      bin[o + 2] = n & 255;
 +      o += 3
 +    }
 +    l = 3 * l - [0, 0, 2, 1][padlen];
 +    return bin.subarray(0, l)
 +  }
 +  function convertUTF16ArrayToUTF8Array(uni) {
 +    var i, n, l = uni.length, o = 0, bin = new Uint8Array(new ArrayBuffer(3 * l));
 +    for(i = 0;i < l;i += 1) {
 +      n = (uni[i]);
 +      if(n < 128) {
 +        bin[o++] = n
 +      }else {
 +        if(n < 2048) {
 +          bin[o++] = 192 | n >>> 6;
 +          bin[o++] = 128 | n & 63
 +        }else {
 +          bin[o++] = 224 | n >>> 12 & 15;
 +          bin[o++] = 128 | n >>> 6 & 63;
 +          bin[o++] = 128 | n & 63
 +        }
 +      }
 +    }
 +    return bin.subarray(0, o)
 +  }
 +  function convertUTF8ArrayToUTF16Array(bin) {
 +    var i, c0, c1, c2, l = bin.length, uni = new Uint8Array(new ArrayBuffer(l)), o = 0;
 +    for(i = 0;i < l;i += 1) {
 +      c0 = (bin[i]);
 +      if(c0 < 128) {
 +        uni[o++] = c0
 +      }else {
 +        i += 1;
 +        c1 = (bin[i]);
 +        if(c0 < 224) {
 +          uni[o++] = (c0 & 31) << 6 | c1 & 63
 +        }else {
 +          i += 1;
 +          c2 = (bin[i]);
 +          uni[o++] = (c0 & 15) << 12 | (c1 & 63) << 6 | c2 & 63
 +        }
 +      }
 +    }
 +    return uni.subarray(0, o)
 +  }
 +  function convertUTF8StringToBase64(bin) {
 +    return convertUTF8ArrayToBase64(stringToArray(bin))
 +  }
 +  function convertBase64ToUTF8String(b64) {
 +    return String.fromCharCode.apply(String, convertBase64ToUTF8Array(b64))
 +  }
 +  function convertUTF8StringToUTF16Array(bin) {
 +    return convertUTF8ArrayToUTF16Array(stringToArray(bin))
 +  }
 +  function convertUTF8ArrayToUTF16String(bin) {
 +    var b = convertUTF8ArrayToUTF16Array(bin), r = "", i = 0, chunksize = 45E3;
 +    while(i < b.length) {
 +      r += String.fromCharCode.apply(String, b.subarray(i, i + chunksize));
 +      i += chunksize
 +    }
 +    return r
 +  }
 +  function convertUTF8StringToUTF16String_internal(bin, i, end) {
 +    var c0, c1, c2, j, str = "";
 +    for(j = i;j < end;j += 1) {
 +      c0 = bin.charCodeAt(j) & 255;
 +      if(c0 < 128) {
 +        str += String.fromCharCode(c0)
 +      }else {
 +        j += 1;
 +        c1 = bin.charCodeAt(j) & 255;
 +        if(c0 < 224) {
 +          str += String.fromCharCode((c0 & 31) << 6 | c1 & 63)
 +        }else {
 +          j += 1;
 +          c2 = bin.charCodeAt(j) & 255;
 +          str += String.fromCharCode((c0 & 15) << 12 | (c1 & 63) << 6 | c2 & 63)
 +        }
 +      }
 +    }
 +    return str
 +  }
 +  function convertUTF8StringToUTF16String(bin, callback) {
 +    var partsize = 1E5, str = "", pos = 0;
 +    if(bin.length < partsize) {
 +      callback(convertUTF8StringToUTF16String_internal(bin, 0, bin.length), true);
 +      return
 +    }
 +    if(typeof bin !== "string") {
 +      bin = bin.slice()
 +    }
 +    function f() {
 +      var end = pos + partsize;
 +      if(end > bin.length) {
 +        end = bin.length
 +      }
 +      str += convertUTF8StringToUTF16String_internal(bin, pos, end);
 +      pos = end;
 +      end = pos === bin.length;
 +      if(callback(str, end) && !end) {
 +        runtime.setTimeout(f, 0)
 +      }
 +    }
 +    f()
 +  }
 +  function convertUTF16StringToUTF8Array(uni) {
 +    return convertUTF16ArrayToUTF8Array(stringToArray(uni))
 +  }
 +  function convertUTF16ArrayToUTF8String(uni) {
 +    return String.fromCharCode.apply(String, convertUTF16ArrayToUTF8Array(uni))
 +  }
 +  function convertUTF16StringToUTF8String(uni) {
 +    return String.fromCharCode.apply(String, convertUTF16ArrayToUTF8Array(stringToArray(uni)))
 +  }
 +  if(window && window.btoa) {
 +    btoa = window.btoa;
 +    convertUTF16StringToBase64 = function(uni) {
 +      return btoa(convertUTF16StringToUTF8String(uni))
 +    }
 +  }else {
 +    btoa = convertUTF8StringToBase64;
 +    convertUTF16StringToBase64 = function(uni) {
 +      return convertUTF8ArrayToBase64(convertUTF16StringToUTF8Array(uni))
 +    }
 +  }
 +  if(window && window.atob) {
 +    atob = window.atob;
 +    convertBase64ToUTF16String = function(b64) {
 +      var b = atob(b64);
 +      return convertUTF8StringToUTF16String_internal(b, 0, b.length)
 +    }
 +  }else {
 +    atob = convertBase64ToUTF8String;
 +    convertBase64ToUTF16String = function(b64) {
 +      return convertUTF8ArrayToUTF16String(convertBase64ToUTF8Array(b64))
 +    }
 +  }
 +  core.Base64 = function Base64() {
 +    this.convertUTF8ArrayToBase64 = convertUTF8ArrayToBase64;
 +    this.convertByteArrayToBase64 = convertUTF8ArrayToBase64;
 +    this.convertBase64ToUTF8Array = convertBase64ToUTF8Array;
 +    this.convertBase64ToByteArray = convertBase64ToUTF8Array;
 +    this.convertUTF16ArrayToUTF8Array = convertUTF16ArrayToUTF8Array;
 +    this.convertUTF16ArrayToByteArray = convertUTF16ArrayToUTF8Array;
 +    this.convertUTF8ArrayToUTF16Array = convertUTF8ArrayToUTF16Array;
 +    this.convertByteArrayToUTF16Array = convertUTF8ArrayToUTF16Array;
 +    this.convertUTF8StringToBase64 = convertUTF8StringToBase64;
 +    this.convertBase64ToUTF8String = convertBase64ToUTF8String;
 +    this.convertUTF8StringToUTF16Array = convertUTF8StringToUTF16Array;
 +    this.convertUTF8ArrayToUTF16String = convertUTF8ArrayToUTF16String;
 +    this.convertByteArrayToUTF16String = convertUTF8ArrayToUTF16String;
 +    this.convertUTF8StringToUTF16String = convertUTF8StringToUTF16String;
 +    this.convertUTF16StringToUTF8Array = convertUTF16StringToUTF8Array;
 +    this.convertUTF16StringToByteArray = convertUTF16StringToUTF8Array;
 +    this.convertUTF16ArrayToUTF8String = convertUTF16ArrayToUTF8String;
 +    this.convertUTF16StringToUTF8String = convertUTF16StringToUTF8String;
 +    this.convertUTF16StringToBase64 = convertUTF16StringToBase64;
 +    this.convertBase64ToUTF16String = convertBase64ToUTF16String;
 +    this.fromBase64 = convertBase64ToUTF8String;
 +    this.toBase64 = convertUTF8StringToBase64;
 +    this.atob = atob;
 +    this.btoa = btoa;
 +    this.utob = convertUTF16StringToUTF8String;
 +    this.btou = convertUTF8StringToUTF16String;
 +    this.encode = convertUTF16StringToBase64;
 +    this.encodeURI = function(u) {
 +      return convertUTF16StringToBase64(u).replace(/[+\/]/g, function(m0) {
 +        return m0 === "+" ? "-" : "_"
 +      }).replace(/\\=+$/, "")
 +    };
 +    this.decode = function(a) {
 +      return convertBase64ToUTF16String(a.replace(/[\-_]/g, function(m0) {
 +        return m0 === "-" ? "+" : "/"
 +      }))
 +    };
 +    return this
 +  };
 +  return core.Base64
 +}
 +core.Base64 = makeBase64();
 +core.ByteArray = function ByteArray(data) {
 +  this.pos = 0;
 +  this.data = data;
 +  this.readUInt32LE = function() {
 +    this.pos += 4;
 +    var d = this.data, pos = this.pos;
 +    return d[--pos] << 24 | d[--pos] << 16 | d[--pos] << 8 | d[--pos]
 +  };
 +  this.readUInt16LE = function() {
 +    this.pos += 2;
 +    var d = this.data, pos = this.pos;
 +    return d[--pos] << 8 | d[--pos]
 +  }
 +};
 +core.ByteArrayWriter = function ByteArrayWriter(encoding) {
 +  var self = this, length = 0, bufferSize = 1024, data = new Uint8Array(new ArrayBuffer(bufferSize));
 +  function expand(extraLength) {
 +    var newData;
 +    if(extraLength > bufferSize - length) {
 +      bufferSize = Math.max(2 * bufferSize, length + extraLength);
 +      newData = new Uint8Array(new ArrayBuffer(bufferSize));
 +      newData.set(data);
 +      data = newData
 +    }
 +  }
 +  this.appendByteArrayWriter = function(writer) {
 +    self.appendByteArray(writer.getByteArray())
 +  };
 +  this.appendByteArray = function(array) {
 +    var l = array.length;
 +    expand(l);
 +    data.set(array, length);
 +    length += l
 +  };
 +  this.appendArray = function(array) {
 +    var l = array.length;
 +    expand(l);
 +    data.set(array, length);
 +    length += l
 +  };
 +  this.appendUInt16LE = function(value) {
 +    self.appendArray([value & 255, value >> 8 & 255])
 +  };
 +  this.appendUInt32LE = function(value) {
 +    self.appendArray([value & 255, value >> 8 & 255, value >> 16 & 255, value >> 24 & 255])
 +  };
 +  this.appendString = function(string) {
 +    self.appendByteArray(runtime.byteArrayFromString(string, encoding))
 +  };
 +  this.getLength = function() {
 +    return length
 +  };
 +  this.getByteArray = function() {
 +    var a = new Uint8Array(new ArrayBuffer(length));
 +    a.set(data.subarray(0, length));
 +    return a
 +  }
 +};
 +core.CSSUnits = function CSSUnits() {
 +  var self = this, sizemap = {"in":1, "cm":2.54, "mm":25.4, "pt":72, "pc":12};
 +  this.convert = function(value, oldUnit, newUnit) {
 +    return value * sizemap[newUnit] / sizemap[oldUnit]
 +  };
 +  this.convertMeasure = function(measure, newUnit) {
 +    var value, oldUnit, newMeasure;
 +    if(measure && newUnit) {
 +      value = parseFloat(measure);
 +      oldUnit = measure.replace(value.toString(), "");
 +      newMeasure = self.convert(value, oldUnit, newUnit).toString()
 +    }else {
 +      newMeasure = ""
 +    }
 +    return newMeasure
 +  };
 +  this.getUnits = function(measure) {
 +    return measure.substr(measure.length - 2, measure.length)
 +  }
 +};
 +/*
 +
 + Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
 +(function() {
 +  var browserQuirks;
 +  function getBrowserQuirks() {
-     var range, directBoundingRect, rangeBoundingRect, testContainer, testElement, detectedQuirks, window, document;
++    var range, directBoundingRect, rangeBoundingRect, testContainer, testElement, detectedQuirks, window, document, docElement, body, docOverflow, bodyOverflow, bodyHeight, bodyScroll;
 +    if(browserQuirks === undefined) {
 +      window = runtime.getWindow();
 +      document = window && window.document;
-       browserQuirks = {rangeBCRIgnoresElementBCR:false, unscaledRangeClientRects:false};
++      docElement = document.documentElement;
++      body = document.body;
++      browserQuirks = {rangeBCRIgnoresElementBCR:false, unscaledRangeClientRects:false, elementBCRIgnoresBodyScroll:false};
 +      if(document) {
 +        testContainer = document.createElement("div");
 +        testContainer.style.position = "absolute";
 +        testContainer.style.left = "-99999px";
 +        testContainer.style.transform = "scale(2)";
 +        testContainer.style["-webkit-transform"] = "scale(2)";
 +        testElement = document.createElement("div");
 +        testContainer.appendChild(testElement);
-         document.body.appendChild(testContainer);
++        body.appendChild(testContainer);
 +        range = document.createRange();
 +        range.selectNode(testElement);
 +        browserQuirks.rangeBCRIgnoresElementBCR = range.getClientRects().length === 0;
 +        testElement.appendChild(document.createTextNode("Rect transform test"));
 +        directBoundingRect = testElement.getBoundingClientRect();
 +        rangeBoundingRect = range.getBoundingClientRect();
 +        browserQuirks.unscaledRangeClientRects = Math.abs(directBoundingRect.height - rangeBoundingRect.height) > 2;
++        testContainer.style.transform = "";
++        testContainer.style["-webkit-transform"] = "";
++        docOverflow = docElement.style.overflow;
++        bodyOverflow = body.style.overflow;
++        bodyHeight = body.style.height;
++        bodyScroll = body.scrollTop;
++        docElement.style.overflow = "visible";
++        body.style.overflow = "visible";
++        body.style.height = "200%";
++        body.scrollTop = body.scrollHeight;
++        browserQuirks.elementBCRIgnoresBodyScroll = range.getBoundingClientRect().top !== testElement.getBoundingClientRect().top;
++        body.scrollTop = bodyScroll;
++        body.style.height = bodyHeight;
++        body.style.overflow = bodyOverflow;
++        docElement.style.overflow = docOverflow;
 +        range.detach();
-         document.body.removeChild(testContainer);
++        body.removeChild(testContainer);
 +        detectedQuirks = Object.keys(browserQuirks).map(function(quirk) {
 +          return quirk + ":" + String(browserQuirks[quirk])
 +        }).join(", ");
 +        runtime.log("Detected browser quirks - " + detectedQuirks)
 +      }
 +    }
 +    return browserQuirks
 +  }
++  function getDirectChild(parent, ns, name) {
++    var node = parent ? parent.firstElementChild : null;
++    while(node) {
++      if(node.localName === name && node.namespaceURI === ns) {
++        return(node)
++      }
++      node = node.nextElementSibling
++    }
++    return null
++  }
 +  core.DomUtils = function DomUtils() {
 +    var sharedRange = null;
 +    function getSharedRange(doc) {
 +      var range;
 +      if(sharedRange) {
 +        range = sharedRange
 +      }else {
 +        sharedRange = range = (doc.createRange())
 +      }
 +      return range
 +    }
 +    function findStablePoint(container, offset) {
 +      var c = container;
 +      if(offset < c.childNodes.length) {
 +        c = c.childNodes.item(offset);
 +        offset = 0;
 +        while(c.firstChild) {
 +          c = c.firstChild
 +        }
 +      }else {
 +        while(c.lastChild) {
 +          c = c.lastChild;
 +          offset = c.nodeType === Node.TEXT_NODE ? c.textContent.length : c.childNodes.length
 +        }
 +      }
 +      return{container:c, offset:offset}
 +    }
++    function getPositionInContainingNode(node, container) {
++      var offset = 0, n;
++      while(node.parentNode !== container) {
++        runtime.assert(node.parentNode !== null, "parent is null");
++        node = (node.parentNode)
++      }
++      n = container.firstChild;
++      while(n !== node) {
++        offset += 1;
++        n = n.nextSibling
++      }
++      return offset
++    }
 +    function splitBoundaries(range) {
-       var modifiedNodes = [], end, splitStart, node, text;
++      var modifiedNodes = [], originalEndContainer, resetToContainerLength, end, splitStart, node, text, offset;
 +      if(range.startContainer.nodeType === Node.TEXT_NODE || range.endContainer.nodeType === Node.TEXT_NODE) {
-         end = range.endContainer && findStablePoint(range.endContainer, range.endOffset);
++        originalEndContainer = range.endContainer;
++        resetToContainerLength = range.endContainer.nodeType !== Node.TEXT_NODE ? range.endOffset === range.endContainer.childNodes.length : false;
++        end = findStablePoint(range.endContainer, range.endOffset);
++        if(end.container === originalEndContainer) {
++          originalEndContainer = null
++        }
 +        range.setEnd(end.container, end.offset);
 +        node = range.endContainer;
 +        if(range.endOffset !== 0 && node.nodeType === Node.TEXT_NODE) {
 +          text = (node);
 +          if(range.endOffset !== text.length) {
 +            modifiedNodes.push(text.splitText(range.endOffset));
 +            modifiedNodes.push(text)
 +          }
 +        }
 +        node = range.startContainer;
 +        if(range.startOffset !== 0 && node.nodeType === Node.TEXT_NODE) {
 +          text = (node);
 +          if(range.startOffset !== text.length) {
 +            splitStart = text.splitText(range.startOffset);
 +            modifiedNodes.push(text);
 +            modifiedNodes.push(splitStart);
 +            range.setStart(splitStart, 0)
 +          }
 +        }
++        if(originalEndContainer !== null) {
++          node = range.endContainer;
++          while(node.parentNode && node.parentNode !== originalEndContainer) {
++            node = node.parentNode
++          }
++          if(resetToContainerLength) {
++            offset = originalEndContainer.childNodes.length
++          }else {
++            offset = getPositionInContainingNode(node, originalEndContainer)
++          }
++          range.setEnd(originalEndContainer, offset)
++        }
 +      }
 +      return modifiedNodes
 +    }
 +    this.splitBoundaries = splitBoundaries;
 +    function containsRange(container, insideRange) {
 +      return container.compareBoundaryPoints(Range.START_TO_START, insideRange) <= 0 && container.compareBoundaryPoints(Range.END_TO_END, insideRange) >= 0
 +    }
 +    this.containsRange = containsRange;
 +    function rangesIntersect(range1, range2) {
 +      return range1.compareBoundaryPoints(Range.END_TO_START, range2) <= 0 && range1.compareBoundaryPoints(Range.START_TO_END, range2) >= 0
 +    }
 +    this.rangesIntersect = rangesIntersect;
-     function getNodesInRange(range, nodeFilter) {
-       var document = range.startContainer.ownerDocument, elements = [], rangeRoot = range.commonAncestorContainer, root = (rangeRoot.nodeType === Node.TEXT_NODE ? rangeRoot.parentNode : rangeRoot), n, filterResult, treeWalker = document.createTreeWalker(root, NodeFilter.SHOW_ALL, nodeFilter, false);
-       treeWalker.currentNode = range.startContainer;
-       n = range.startContainer;
-       while(n) {
-         filterResult = nodeFilter(n);
-         if(filterResult === NodeFilter.FILTER_ACCEPT) {
-           elements.push(n)
++    function maximumOffset(node) {
++      return node.nodeType === Node.TEXT_NODE ? (node).length : node.childNodes.length
++    }
++    function getNodesInRange(range, nodeFilter, whatToShow) {
++      var document = range.startContainer.ownerDocument, elements = [], rangeRoot = range.commonAncestorContainer, root = (rangeRoot.nodeType === Node.TEXT_NODE ? rangeRoot.parentNode : rangeRoot), treeWalker = document.createTreeWalker(root, whatToShow, nodeFilter, false), currentNode, lastNodeInRange, endNodeCompareFlags, comparePositionResult;
++      if(range.endContainer.childNodes[range.endOffset - 1]) {
++        lastNodeInRange = (range.endContainer.childNodes[range.endOffset - 1]);
++        endNodeCompareFlags = Node.DOCUMENT_POSITION_PRECEDING | Node.DOCUMENT_POSITION_CONTAINED_BY
++      }else {
++        lastNodeInRange = (range.endContainer);
++        endNodeCompareFlags = Node.DOCUMENT_POSITION_PRECEDING
++      }
++      if(range.startContainer.childNodes[range.startOffset]) {
++        currentNode = (range.startContainer.childNodes[range.startOffset]);
++        treeWalker.currentNode = currentNode
++      }else {
++        if(range.startOffset === maximumOffset(range.startContainer)) {
++          currentNode = (range.startContainer);
++          treeWalker.currentNode = currentNode;
++          treeWalker.lastChild();
++          currentNode = treeWalker.nextNode()
 +        }else {
-           if(filterResult === NodeFilter.FILTER_REJECT) {
-             break
-           }
++          currentNode = (range.startContainer);
++          treeWalker.currentNode = currentNode
 +        }
-         n = n.parentNode
 +      }
-       elements.reverse();
-       n = treeWalker.nextNode();
-       while(n) {
-         elements.push(n);
-         n = treeWalker.nextNode()
++      if(currentNode && nodeFilter(currentNode) === NodeFilter.FILTER_ACCEPT) {
++        elements.push(currentNode)
++      }
++      currentNode = treeWalker.nextNode();
++      while(currentNode) {
++        comparePositionResult = lastNodeInRange.compareDocumentPosition(currentNode);
++        if(comparePositionResult !== 0 && (comparePositionResult & endNodeCompareFlags) === 0) {
++          break
++        }
++        elements.push(currentNode);
++        currentNode = treeWalker.nextNode()
 +      }
 +      return elements
 +    }
 +    this.getNodesInRange = getNodesInRange;
 +    function mergeTextNodes(node, nextNode) {
 +      var mergedNode = null, text, nextText;
 +      if(node.nodeType === Node.TEXT_NODE) {
 +        text = (node);
 +        if(text.length === 0) {
 +          text.parentNode.removeChild(text);
 +          if(nextNode.nodeType === Node.TEXT_NODE) {
 +            mergedNode = nextNode
 +          }
 +        }else {
 +          if(nextNode.nodeType === Node.TEXT_NODE) {
 +            nextText = (nextNode);
 +            text.appendData(nextText.data);
 +            nextNode.parentNode.removeChild(nextNode)
 +          }
 +          mergedNode = node
 +        }
 +      }
 +      return mergedNode
 +    }
 +    function normalizeTextNodes(node) {
 +      if(node && node.nextSibling) {
 +        node = mergeTextNodes(node, node.nextSibling)
 +      }
 +      if(node && node.previousSibling) {
 +        mergeTextNodes(node.previousSibling, node)
 +      }
 +    }
 +    this.normalizeTextNodes = normalizeTextNodes;
 +    function rangeContainsNode(limits, node) {
 +      var range = node.ownerDocument.createRange(), nodeRange = node.ownerDocument.createRange(), result;
 +      range.setStart(limits.startContainer, limits.startOffset);
 +      range.setEnd(limits.endContainer, limits.endOffset);
 +      nodeRange.selectNodeContents(node);
 +      result = containsRange(range, nodeRange);
 +      range.detach();
 +      nodeRange.detach();
 +      return result
 +    }
 +    this.rangeContainsNode = rangeContainsNode;
 +    function mergeIntoParent(targetNode) {
 +      var parent = targetNode.parentNode;
 +      while(targetNode.firstChild) {
 +        parent.insertBefore(targetNode.firstChild, targetNode)
 +      }
 +      parent.removeChild(targetNode);
 +      return parent
 +    }
 +    this.mergeIntoParent = mergeIntoParent;
 +    function removeUnwantedNodes(targetNode, shouldRemove) {
 +      var parent = targetNode.parentNode, node = targetNode.firstChild, next;
 +      while(node) {
 +        next = node.nextSibling;
 +        removeUnwantedNodes(node, shouldRemove);
 +        node = next
 +      }
-       if(shouldRemove(targetNode)) {
-         parent = mergeIntoParent(targetNode)
++      if(parent && shouldRemove(targetNode)) {
++        mergeIntoParent(targetNode)
 +      }
 +      return parent
 +    }
 +    this.removeUnwantedNodes = removeUnwantedNodes;
 +    function getElementsByTagNameNS(node, namespace, tagName) {
 +      var e = [], list, i, l;
 +      list = node.getElementsByTagNameNS(namespace, tagName);
 +      e.length = l = list.length;
 +      for(i = 0;i < l;i += 1) {
 +        e[i] = (list.item(i))
 +      }
 +      return e
 +    }
 +    this.getElementsByTagNameNS = getElementsByTagNameNS;
-     function rangeIntersectsNode(range, node) {
-       var nodeRange = node.ownerDocument.createRange(), result;
-       nodeRange.selectNodeContents(node);
-       result = rangesIntersect(range, nodeRange);
-       nodeRange.detach();
-       return result
-     }
-     this.rangeIntersectsNode = rangeIntersectsNode;
 +    function containsNode(parent, descendant) {
 +      return parent === descendant || (parent).contains((descendant))
 +    }
 +    this.containsNode = containsNode;
 +    function containsNodeForBrokenWebKit(parent, descendant) {
 +      return parent === descendant || Boolean(parent.compareDocumentPosition(descendant) & Node.DOCUMENT_POSITION_CONTAINED_BY)
 +    }
-     function getPositionInContainingNode(node, container) {
-       var offset = 0, n;
-       while(node.parentNode !== container) {
-         runtime.assert(node.parentNode !== null, "parent is null");
-         node = (node.parentNode)
-       }
-       n = container.firstChild;
-       while(n !== node) {
-         offset += 1;
-         n = n.nextSibling
-       }
-       return offset
-     }
 +    function comparePoints(c1, o1, c2, o2) {
 +      if(c1 === c2) {
 +        return o2 - o1
 +      }
 +      var comparison = c1.compareDocumentPosition(c2);
 +      if(comparison === 2) {
 +        comparison = -1
 +      }else {
 +        if(comparison === 4) {
 +          comparison = 1
 +        }else {
 +          if(comparison === 10) {
 +            o1 = getPositionInContainingNode(c1, c2);
 +            comparison = o1 < o2 ? 1 : -1
 +          }else {
 +            o2 = getPositionInContainingNode(c2, c1);
 +            comparison = o2 < o1 ? -1 : 1
 +          }
 +        }
 +      }
 +      return comparison
 +    }
 +    this.comparePoints = comparePoints;
 +    function adaptRangeDifferenceToZoomLevel(inputNumber, zoomLevel) {
 +      if(getBrowserQuirks().unscaledRangeClientRects) {
 +        return inputNumber
 +      }
 +      return inputNumber / zoomLevel
 +    }
 +    this.adaptRangeDifferenceToZoomLevel = adaptRangeDifferenceToZoomLevel;
 +    function getBoundingClientRect(node) {
-       var doc = (node.ownerDocument), quirks = getBrowserQuirks(), range, element;
++      var doc = (node.ownerDocument), quirks = getBrowserQuirks(), range, element, rect, body = doc.body;
 +      if(quirks.unscaledRangeClientRects === false || quirks.rangeBCRIgnoresElementBCR) {
 +        if(node.nodeType === Node.ELEMENT_NODE) {
 +          element = (node);
-           return element.getBoundingClientRect()
++          rect = element.getBoundingClientRect();
++          if(quirks.elementBCRIgnoresBodyScroll) {
++            return({left:rect.left + body.scrollLeft, right:rect.right + body.scrollLeft, top:rect.top + body.scrollTop, bottom:rect.bottom + body.scrollTop, width:rect.width, height:rect.height})
++          }
++          return rect
 +        }
 +      }
 +      range = getSharedRange(doc);
 +      range.selectNode(node);
 +      return range.getBoundingClientRect()
 +    }
 +    this.getBoundingClientRect = getBoundingClientRect;
 +    function mapKeyValObjOntoNode(node, properties, nsResolver) {
 +      Object.keys(properties).forEach(function(key) {
 +        var parts = key.split(":"), prefix = parts[0], localName = parts[1], ns = nsResolver(prefix), value = properties[key], element;
 +        if(ns) {
 +          element = (node.getElementsByTagNameNS(ns, localName)[0]);
 +          if(!element) {
 +            element = node.ownerDocument.createElementNS(ns, key);
 +            node.appendChild(element)
 +          }
 +          element.textContent = value
 +        }else {
 +          runtime.log("Key ignored: " + key)
 +        }
 +      })
 +    }
 +    this.mapKeyValObjOntoNode = mapKeyValObjOntoNode;
 +    function removeKeyElementsFromNode(node, propertyNames, nsResolver) {
 +      propertyNames.forEach(function(propertyName) {
 +        var parts = propertyName.split(":"), prefix = parts[0], localName = parts[1], ns = nsResolver(prefix), element;
 +        if(ns) {
 +          element = (node.getElementsByTagNameNS(ns, localName)[0]);
 +          if(element) {
 +            element.parentNode.removeChild(element)
 +          }else {
 +            runtime.log("Element for " + propertyName + " not found.")
 +          }
 +        }else {
 +          runtime.log("Property Name ignored: " + propertyName)
 +        }
 +      })
 +    }
 +    this.removeKeyElementsFromNode = removeKeyElementsFromNode;
 +    function getKeyValRepresentationOfNode(node, prefixResolver) {
 +      var properties = {}, currentSibling = node.firstElementChild, prefix;
 +      while(currentSibling) {
 +        prefix = prefixResolver(currentSibling.namespaceURI);
 +        if(prefix) {
 +          properties[prefix + ":" + currentSibling.localName] = currentSibling.textContent
 +        }
 +        currentSibling = currentSibling.nextElementSibling
 +      }
 +      return properties
 +    }
 +    this.getKeyValRepresentationOfNode = getKeyValRepresentationOfNode;
 +    function mapObjOntoNode(node, properties, nsResolver) {
 +      Object.keys(properties).forEach(function(key) {
-         var parts = key.split(":"), prefix = parts[0], localName = parts[1], ns = nsResolver(prefix), value = properties[key], element;
-         if(typeof value === "object" && Object.keys((value)).length) {
-           if(ns) {
-             element = (node.getElementsByTagNameNS(ns, localName)[0]) || node.ownerDocument.createElementNS(ns, key)
-           }else {
-             element = (node.getElementsByTagName(localName)[0]) || node.ownerDocument.createElement(key)
++        var parts = key.split(":"), prefix = parts[0], localName = parts[1], ns = nsResolver(prefix), value = properties[key], valueType = typeof value, element;
++        if(valueType === "object") {
++          if(Object.keys((value)).length) {
++            if(ns) {
++              element = (node.getElementsByTagNameNS(ns, localName)[0]) || node.ownerDocument.createElementNS(ns, key)
++            }else {
++              element = (node.getElementsByTagName(localName)[0]) || node.ownerDocument.createElement(key)
++            }
++            node.appendChild(element);
++            mapObjOntoNode(element, (value), nsResolver)
 +          }
-           node.appendChild(element);
-           mapObjOntoNode(element, (value), nsResolver)
 +        }else {
 +          if(ns) {
++            runtime.assert(valueType === "number" || valueType === "string", "attempting to map unsupported type '" + valueType + "' (key: " + key + ")");
 +            node.setAttributeNS(ns, key, String(value))
 +          }
 +        }
 +      })
 +    }
 +    this.mapObjOntoNode = mapObjOntoNode;
++    this.getDirectChild = getDirectChild;
 +    function init(self) {
 +      var appVersion, webKitOrSafari, ie, window = runtime.getWindow();
 +      if(window === null) {
 +        return
 +      }
 +      appVersion = window.navigator.appVersion.toLowerCase();
 +      webKitOrSafari = appVersion.indexOf("chrome") === -1 && (appVersion.indexOf("applewebkit") !== -1 || appVersion.indexOf("safari") !== -1);
 +      ie = appVersion.indexOf("msie");
 +      if(webKitOrSafari || ie) {
 +        self.containsNode = containsNodeForBrokenWebKit
 +      }
 +    }
 +    init(this)
 +  };
 +  return core.DomUtils
 +})();
++core.Cursor = function Cursor(document, memberId) {
++  var cursorns = "urn:webodf:names:cursor", cursorNode = document.createElementNS(cursorns, "cursor"), anchorNode = document.createElementNS(cursorns, "anchor"), forwardSelection, recentlyModifiedNodes = [], selectedRange = (document.createRange()), isCollapsed, domUtils = new core.DomUtils;
++  function putIntoTextNode(node, container, offset) {
++    runtime.assert(Boolean(container), "putCursorIntoTextNode: invalid container");
++    var parent = container.parentNode;
++    runtime.assert(Boolean(parent), "putCursorIntoTextNode: container without parent");
++    runtime.assert(offset >= 0 && offset <= container.length, "putCursorIntoTextNode: offset is out of bounds");
++    if(offset === 0) {
++      parent.insertBefore(node, container)
++    }else {
++      if(offset === container.length) {
++        parent.insertBefore(node, container.nextSibling)
++      }else {
++        container.splitText(offset);
++        parent.insertBefore(node, container.nextSibling)
++      }
++    }
++  }
++  function removeNode(node) {
++    if(node.parentNode) {
++      recentlyModifiedNodes.push(node.previousSibling);
++      recentlyModifiedNodes.push(node.nextSibling);
++      node.parentNode.removeChild(node)
++    }
++  }
++  function putNode(node, container, offset) {
++    if(container.nodeType === Node.TEXT_NODE) {
++      putIntoTextNode(node, (container), offset)
++    }else {
++      if(container.nodeType === Node.ELEMENT_NODE) {
++        container.insertBefore(node, container.childNodes.item(offset))
++      }
++    }
++    recentlyModifiedNodes.push(node.previousSibling);
++    recentlyModifiedNodes.push(node.nextSibling)
++  }
++  function getStartNode() {
++    return forwardSelection ? anchorNode : cursorNode
++  }
++  function getEndNode() {
++    return forwardSelection ? cursorNode : anchorNode
++  }
++  this.getNode = function() {
++    return cursorNode
++  };
++  this.getAnchorNode = function() {
++    return anchorNode.parentNode ? anchorNode : cursorNode
++  };
++  this.getSelectedRange = function() {
++    if(isCollapsed) {
++      selectedRange.setStartBefore(cursorNode);
++      selectedRange.collapse(true)
++    }else {
++      selectedRange.setStartAfter(getStartNode());
++      selectedRange.setEndBefore(getEndNode())
++    }
++    return selectedRange
++  };
++  this.setSelectedRange = function(range, isForwardSelection) {
++    if(selectedRange && selectedRange !== range) {
++      selectedRange.detach()
++    }
++    selectedRange = range;
++    forwardSelection = isForwardSelection !== false;
++    isCollapsed = range.collapsed;
++    if(range.collapsed) {
++      removeNode(anchorNode);
++      removeNode(cursorNode);
++      putNode(cursorNode, (range.startContainer), range.startOffset)
++    }else {
++      removeNode(anchorNode);
++      removeNode(cursorNode);
++      putNode(getEndNode(), (range.endContainer), range.endOffset);
++      putNode(getStartNode(), (range.startContainer), range.startOffset)
++    }
++    recentlyModifiedNodes.forEach(domUtils.normalizeTextNodes);
++    recentlyModifiedNodes.length = 0
++  };
++  this.hasForwardSelection = function() {
++    return forwardSelection
++  };
++  this.remove = function() {
++    removeNode(cursorNode);
++    recentlyModifiedNodes.forEach(domUtils.normalizeTextNodes);
++    recentlyModifiedNodes.length = 0
++  };
++  function init() {
++    cursorNode.setAttributeNS(cursorns, "memberId", memberId);
++    anchorNode.setAttributeNS(cursorns, "memberId", memberId)
++  }
++  init()
++};
 +/*
 +
-  Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
++ Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- core.EventNotifier = function EventNotifier(eventIds) {
-   var eventListener = {};
-   this.emit = function(eventId, args) {
-     var i, subscribers;
-     runtime.assert(eventListener.hasOwnProperty(eventId), 'unknown event fired "' + eventId + '"');
-     subscribers = eventListener[eventId];
-     for(i = 0;i < subscribers.length;i += 1) {
-       subscribers[i](args)
-     }
-   };
-   this.subscribe = function(eventId, cb) {
-     runtime.assert(eventListener.hasOwnProperty(eventId), 'tried to subscribe to unknown event "' + eventId + '"');
-     eventListener[eventId].push(cb);
-     runtime.log('event "' + eventId + '" subscribed.')
-   };
-   this.unsubscribe = function(eventId, cb) {
-     var cbIndex;
-     runtime.assert(eventListener.hasOwnProperty(eventId), 'tried to unsubscribe from unknown event "' + eventId + '"');
-     cbIndex = eventListener[eventId].indexOf(cb);
-     runtime.assert(cbIndex !== -1, 'tried to unsubscribe unknown callback from event "' + eventId + '"');
-     if(cbIndex !== -1) {
-       eventListener[eventId].splice(cbIndex, 1)
-     }
-     runtime.log('event "' + eventId + '" unsubscribed.')
-   };
++core.Destroyable = function Destroyable() {
++};
++core.Destroyable.prototype.destroy = function(callback) {
++};
++/*
++
++ Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
++
++ @licstart
++ The JavaScript code in this page is free software: you can redistribute it
++ and/or modify it under the terms of the GNU Affero General Public License
++ (GNU AGPL) as published by the Free Software Foundation, either version 3 of
++ the License, or (at your option) any later version.  The code is distributed
++ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
++
++ You should have received a copy of the GNU Affero General Public License
++ along with this code.  If not, see <http://www.gnu.org/licenses/>.
++
++ As additional permission under GNU AGPL version 3 section 7, you
++ may distribute non-source (e.g., minimized or compacted) forms of
++ that code without the copy of the GNU GPL normally required by
++ section 4, provided you include this license notice and a URL
++ through which recipients can access the Corresponding Source.
++
++ As a special exception to the AGPL, any HTML file which merely makes function
++ calls to this code, and for that purpose includes it by reference shall be
++ deemed a separate work for copyright law purposes. In addition, the copyright
++ holders of this code give you permission to combine this code with free
++ software libraries that are released under the GNU LGPL. You may copy and
++ distribute such a system following the terms of the GNU AGPL for this code
++ and the LGPL for the libraries. If you modify this code, you may extend this
++ exception to your version of the code, but you are not obligated to do so.
++ If you do not wish to do so, delete this exception statement from your
++ version.
++
++ This license applies to this entire compilation.
++ @licend
++ @source: http://www.webodf.org/
++ @source: https://github.com/kogmbh/WebODF/
++*/
++core.EventNotifier = function EventNotifier(eventIds) {
++  var eventListener = {};
++  this.emit = function(eventId, args) {
++    var i, subscribers;
++    runtime.assert(eventListener.hasOwnProperty(eventId), 'unknown event fired "' + eventId + '"');
++    subscribers = eventListener[eventId];
++    for(i = 0;i < subscribers.length;i += 1) {
++      subscribers[i](args)
++    }
++  };
++  this.subscribe = function(eventId, cb) {
++    runtime.assert(eventListener.hasOwnProperty(eventId), 'tried to subscribe to unknown event "' + eventId + '"');
++    eventListener[eventId].push(cb)
++  };
++  this.unsubscribe = function(eventId, cb) {
++    var cbIndex;
++    runtime.assert(eventListener.hasOwnProperty(eventId), 'tried to unsubscribe from unknown event "' + eventId + '"');
++    cbIndex = eventListener[eventId].indexOf(cb);
++    runtime.assert(cbIndex !== -1, 'tried to unsubscribe unknown callback from event "' + eventId + '"');
++    if(cbIndex !== -1) {
++      eventListener[eventId].splice(cbIndex, 1)
++    }
++  };
 +  function init() {
 +    var i, eventId;
 +    for(i = 0;i < eventIds.length;i += 1) {
 +      eventId = eventIds[i];
 +      runtime.assert(!eventListener.hasOwnProperty(eventId), 'Duplicated event ids: "' + eventId + '" registered more than once.');
 +      eventListener[eventId] = []
 +    }
 +  }
 +  init()
 +};
 +/*
 +
 + Copyright (C) 2012 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
 +core.LoopWatchDog = function LoopWatchDog(timeout, maxChecks) {
 +  var startTime = Date.now(), checks = 0;
 +  function check() {
 +    var t;
 +    if(timeout) {
 +      t = Date.now();
 +      if(t - startTime > timeout) {
 +        runtime.log("alert", "watchdog timeout");
 +        throw"timeout!";
 +      }
 +    }
 +    if(maxChecks > 0) {
 +      checks += 1;
 +      if(checks > maxChecks) {
 +        runtime.log("alert", "watchdog loop overflow");
 +        throw"loop overflow";
 +      }
 +    }
 +  }
 +  this.check = check
 +};
 +core.PositionIterator = function PositionIterator(root, whatToShow, filter, expandEntityReferences) {
 +  var self = this, walker, currentPos, nodeFilter, TEXT_NODE = Node.TEXT_NODE, ELEMENT_NODE = Node.ELEMENT_NODE, FILTER_ACCEPT = NodeFilter.FILTER_ACCEPT, FILTER_REJECT = NodeFilter.FILTER_REJECT;
 +  function EmptyTextNodeFilter() {
 +    this.acceptNode = function(node) {
 +      var text = (node);
 +      if(!node || node.nodeType === TEXT_NODE && text.length === 0) {
 +        return FILTER_REJECT
 +      }
 +      return FILTER_ACCEPT
 +    }
 +  }
 +  function FilteredEmptyTextNodeFilter(filter) {
 +    this.acceptNode = function(node) {
 +      var text = (node);
 +      if(!node || node.nodeType === TEXT_NODE && text.length === 0) {
 +        return FILTER_REJECT
 +      }
 +      return filter.acceptNode(node)
 +    }
 +  }
 +  this.nextPosition = function() {
 +    var currentNode = walker.currentNode, nodeType = currentNode.nodeType, text = (currentNode);
 +    if(currentNode === root) {
 +      return false
 +    }
 +    if(currentPos === 0 && nodeType === ELEMENT_NODE) {
 +      if(walker.firstChild() === null) {
 +        currentPos = 1
 +      }
 +    }else {
 +      if(nodeType === TEXT_NODE && currentPos + 1 < text.length) {
 +        currentPos += 1
 +      }else {
 +        if(walker.nextSibling() !== null) {
 +          currentPos = 0
 +        }else {
 +          if(walker.parentNode()) {
 +            currentPos = 1
 +          }else {
 +            return false
 +          }
 +        }
 +      }
 +    }
 +    return true
 +  };
 +  function setAtEnd() {
 +    var text = (walker.currentNode), type = text.nodeType;
 +    if(type === TEXT_NODE) {
 +      currentPos = text.length - 1
 +    }else {
 +      currentPos = type === ELEMENT_NODE ? 1 : 0
 +    }
 +  }
 +  function previousNode() {
 +    if(walker.previousSibling() === null) {
 +      if(!walker.parentNode() || walker.currentNode === root) {
 +        walker.firstChild();
 +        return false
 +      }
 +      currentPos = 0
 +    }else {
 +      setAtEnd()
 +    }
 +    return true
 +  }
 +  this.previousPosition = function() {
 +    var moved = true, currentNode = walker.currentNode;
 +    if(currentPos === 0) {
 +      moved = previousNode()
 +    }else {
 +      if(currentNode.nodeType === TEXT_NODE) {
 +        currentPos -= 1
 +      }else {
 +        if(walker.lastChild() !== null) {
 +          setAtEnd()
 +        }else {
 +          if(currentNode === root) {
 +            moved = false
 +          }else {
 +            currentPos = 0
 +          }
 +        }
 +      }
 +    }
 +    return moved
 +  };
 +  this.previousNode = previousNode;
 +  this.container = function() {
 +    var n = (walker.currentNode), t = n.nodeType;
 +    if(currentPos === 0 && t !== TEXT_NODE) {
 +      n = (n.parentNode)
 +    }
 +    return n
 +  };
 +  this.rightNode = function() {
 +    var n = walker.currentNode, text = (n), nodeType = n.nodeType;
 +    if(nodeType === TEXT_NODE && currentPos === text.length) {
 +      n = n.nextSibling;
 +      while(n && nodeFilter(n) !== FILTER_ACCEPT) {
 +        n = n.nextSibling
 +      }
 +    }else {
 +      if(nodeType === ELEMENT_NODE && currentPos === 1) {
 +        n = null
 +      }
 +    }
 +    return n
 +  };
 +  this.leftNode = function() {
 +    var n = walker.currentNode;
 +    if(currentPos === 0) {
 +      n = n.previousSibling;
 +      while(n && nodeFilter(n) !== FILTER_ACCEPT) {
 +        n = n.previousSibling
 +      }
 +    }else {
 +      if(n.nodeType === ELEMENT_NODE) {
 +        n = n.lastChild;
 +        while(n && nodeFilter(n) !== FILTER_ACCEPT) {
 +          n = n.previousSibling
 +        }
 +      }
 +    }
 +    return n
 +  };
 +  this.getCurrentNode = function() {
 +    var n = (walker.currentNode);
 +    return n
 +  };
 +  this.unfilteredDomOffset = function() {
 +    if(walker.currentNode.nodeType === TEXT_NODE) {
 +      return currentPos
 +    }
 +    var c = 0, n = walker.currentNode;
 +    if(currentPos === 1) {
 +      n = n.lastChild
 +    }else {
 +      n = n.previousSibling
 +    }
 +    while(n) {
 +      c += 1;
 +      n = n.previousSibling
 +    }
 +    return c
 +  };
 +  this.getPreviousSibling = function() {
 +    var currentNode = walker.currentNode, sibling = walker.previousSibling();
 +    walker.currentNode = currentNode;
 +    return sibling
 +  };
 +  this.getNextSibling = function() {
 +    var currentNode = walker.currentNode, sibling = walker.nextSibling();
 +    walker.currentNode = currentNode;
 +    return sibling
 +  };
++  function moveToAcceptedNode() {
++    var node = walker.currentNode, filterResult, moveResult;
++    filterResult = nodeFilter(node);
++    if(node !== root) {
++      node = node.parentNode;
++      while(node && node !== root) {
++        if(nodeFilter(node) === FILTER_REJECT) {
++          walker.currentNode = node;
++          filterResult = FILTER_REJECT
++        }
++        node = node.parentNode
++      }
++    }
++    if(filterResult === FILTER_REJECT) {
++      currentPos = 1;
++      moveResult = self.nextPosition()
++    }else {
++      if(filterResult === FILTER_ACCEPT) {
++        moveResult = true
++      }else {
++        moveResult = self.nextPosition()
++      }
++    }
++    if(moveResult) {
++      runtime.assert(nodeFilter(walker.currentNode) === FILTER_ACCEPT, "moveToAcceptedNode did not result in walker being on an accepted node")
++    }
++    return moveResult
++  }
++  this.setPositionBeforeElement = function(element) {
++    runtime.assert(Boolean(element), "setPositionBeforeElement called without element");
++    walker.currentNode = element;
++    currentPos = 0;
++    return moveToAcceptedNode()
++  };
 +  this.setUnfilteredPosition = function(container, offset) {
-     var filterResult, node, text;
-     runtime.assert(container !== null && container !== undefined, "PositionIterator.setUnfilteredPosition called without container");
++    var text;
++    runtime.assert(Boolean(container), "PositionIterator.setUnfilteredPosition called without container");
 +    walker.currentNode = container;
 +    if(container.nodeType === TEXT_NODE) {
 +      currentPos = offset;
 +      text = (container);
 +      runtime.assert(offset <= text.length, "Error in setPosition: " + offset + " > " + text.length);
 +      runtime.assert(offset >= 0, "Error in setPosition: " + offset + " < 0");
 +      if(offset === text.length) {
 +        if(walker.nextSibling()) {
 +          currentPos = 0
 +        }else {
 +          if(walker.parentNode()) {
 +            currentPos = 1
 +          }else {
 +            runtime.assert(false, "Error in setUnfilteredPosition: position not valid.")
 +          }
 +        }
 +      }
 +      return true
 +    }
-     filterResult = nodeFilter(container);
-     node = container.parentNode;
-     while(node && (node !== root && filterResult === FILTER_ACCEPT)) {
-       filterResult = nodeFilter(node);
-       if(filterResult !== FILTER_ACCEPT) {
-         walker.currentNode = node
-       }
-       node = node.parentNode
-     }
-     if(offset < container.childNodes.length && filterResult !== NodeFilter.FILTER_REJECT) {
++    if(offset < container.childNodes.length) {
 +      walker.currentNode = (container.childNodes.item(offset));
-       filterResult = nodeFilter(walker.currentNode);
 +      currentPos = 0
 +    }else {
 +      currentPos = 1
 +    }
-     if(filterResult === NodeFilter.FILTER_REJECT) {
-       currentPos = 1
-     }
-     if(filterResult !== FILTER_ACCEPT) {
-       return self.nextPosition()
-     }
-     runtime.assert(nodeFilter(walker.currentNode) === FILTER_ACCEPT, "PositionIterater.setUnfilteredPosition call resulted in an non-visible node being set");
-     return true
++    return moveToAcceptedNode()
 +  };
 +  this.moveToEnd = function() {
 +    walker.currentNode = root;
 +    currentPos = 1
 +  };
 +  this.moveToEndOfNode = function(node) {
 +    var text;
 +    if(node.nodeType === TEXT_NODE) {
 +      text = (node);
 +      self.setUnfilteredPosition(text, text.length)
 +    }else {
 +      walker.currentNode = node;
 +      currentPos = 1
 +    }
 +  };
++  this.isBeforeNode = function() {
++    return currentPos === 0
++  };
 +  this.getNodeFilter = function() {
 +    return nodeFilter
 +  };
 +  function init() {
 +    var f;
 +    if(filter) {
 +      f = new FilteredEmptyTextNodeFilter(filter)
 +    }else {
 +      f = new EmptyTextNodeFilter
 +    }
 +    nodeFilter = (f.acceptNode);
 +    nodeFilter.acceptNode = nodeFilter;
-     whatToShow = whatToShow || 4294967295;
++    whatToShow = whatToShow || NodeFilter.SHOW_ALL;
 +    runtime.assert(root.nodeType !== Node.TEXT_NODE, "Internet Explorer doesn't allow tree walker roots to be text nodes");
 +    walker = root.ownerDocument.createTreeWalker(root, whatToShow, nodeFilter, expandEntityReferences);
 +    currentPos = 0;
 +    if(walker.firstChild() === null) {
 +      currentPos = 1
 +    }
 +  }
 +  init()
 +};
++core.PositionFilter = function PositionFilter() {
++};
++core.PositionFilter.FilterResult = {FILTER_ACCEPT:1, FILTER_REJECT:2, FILTER_SKIP:3};
++core.PositionFilter.prototype.acceptPosition = function(point) {
++};
++(function() {
++  return core.PositionFilter
++})();
++core.PositionFilterChain = function PositionFilterChain() {
++  var filterChain = [], FILTER_ACCEPT = core.PositionFilter.FilterResult.FILTER_ACCEPT, FILTER_REJECT = core.PositionFilter.FilterResult.FILTER_REJECT;
++  this.acceptPosition = function(iterator) {
++    var i;
++    for(i = 0;i < filterChain.length;i += 1) {
++      if(filterChain[i].acceptPosition(iterator) === FILTER_REJECT) {
++        return FILTER_REJECT
++      }
++    }
++    return FILTER_ACCEPT
++  };
++  this.addFilter = function(filterInstance) {
++    filterChain.push(filterInstance)
++  }
++};
 +core.zip_HuftNode = function() {
 +  this.e = 0;
 +  this.b = 0;
 +  this.n = 0;
 +  this.t = null
 +};
 +core.zip_HuftList = function() {
 +  this.next = null;
 +  this.list = null
 +};
 +core.RawInflate = function RawInflate() {
 +  var zip_WSIZE = 32768;
 +  var zip_STORED_BLOCK = 0;
 +  var zip_lbits = 9;
 +  var zip_dbits = 6;
 +  var zip_slide = [];
 +  var zip_wp;
 +  var zip_fixed_tl = null;
 +  var zip_fixed_td;
 +  var zip_fixed_bl;
 +  var zip_bit_buf;
 +  var zip_bit_len;
 +  var zip_method;
 +  var zip_eof;
 +  var zip_copy_leng;
 +  var zip_copy_dist;
 +  var zip_tl, zip_td;
 +  var zip_bl, zip_bd;
 +  var zip_inflate_data;
 +  var zip_inflate_pos;
 +  var zip_MASK_BITS = [0, 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191, 16383, 32767, 65535];
 +  var zip_cplens = [3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0];
 +  var zip_cplext = [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99];
 +  var zip_cpdist = [1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577];
 +  var zip_cpdext = [0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13];
 +  var zip_border = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15];
 +  function Zip_HuftBuild(b, n, s, d, e, mm) {
 +    this.BMAX = 16;
 +    this.N_MAX = 288;
 +    this.status = 0;
 +    this.root = null;
 +    this.m = 0;
 +    var a, c = new Array(this.BMAX + 1), el, f, g, h, i, j, k, lx = new Array(this.BMAX + 1), p, pidx, q, r = new core.zip_HuftNode, u = new Array(this.BMAX), v = new Array(this.N_MAX), w, x = new Array(this.BMAX + 1), xp, y, z, o, tail;
 +    tail = this.root = null;
 +    for(i = 0;i < c.length;i++) {
 +      c[i] = 0
 +    }
 +    for(i = 0;i < lx.length;i++) {
 +      lx[i] = 0
 +    }
 +    for(i = 0;i < u.length;i++) {
 +      u[i] = null
 +    }
 +    for(i = 0;i < v.length;i++) {
 +      v[i] = 0
 +    }
 +    for(i = 0;i < x.length;i++) {
 +      x[i] = 0
 +    }
 +    el = n > 256 ? b[256] : this.BMAX;
 +    p = b;
 +    pidx = 0;
 +    i = n;
 +    do {
 +      c[p[pidx]]++;
 +      pidx++
 +    }while(--i > 0);
 +    if(c[0] === n) {
 +      this.root = null;
 +      this.m = 0;
 +      this.status = 0;
 +      return
 +    }
 +    for(j = 1;j <= this.BMAX;j++) {
 +      if(c[j] !== 0) {
 +        break
 +      }
 +    }
 +    k = j;
 +    if(mm < j) {
 +      mm = j
 +    }
 +    for(i = this.BMAX;i !== 0;i--) {
 +      if(c[i] !== 0) {
 +        break
 +      }
 +    }
 +    g = i;
 +    if(mm > i) {
 +      mm = i
 +    }
 +    for(y = 1 << j;j < i;j++, y <<= 1) {
 +      y -= c[j];
 +      if(y < 0) {
 +        this.status = 2;
 +        this.m = mm;
 +        return
 +      }
 +    }
 +    y -= c[i];
 +    if(y < 0) {
 +      this.status = 2;
 +      this.m = mm;
 +      return
 +    }
 +    c[i] += y;
 +    x[1] = j = 0;
 +    p = c;
 +    pidx = 1;
 +    xp = 2;
 +    while(--i > 0) {
 +      j += p[pidx++];
 +      x[xp++] = j
 +    }
 +    p = b;
 +    pidx = 0;
 +    i = 0;
 +    do {
 +      j = p[pidx++];
 +      if(j !== 0) {
 +        v[x[j]++] = i
 +      }
 +    }while(++i < n);
 +    n = x[g];
 +    x[0] = i = 0;
 +    p = v;
 +    pidx = 0;
 +    h = -1;
 +    w = lx[0] = 0;
 +    q = null;
 +    z = 0;
 +    k -= 1;
 +    for(k += 1;k <= g;k++) {
 +      a = c[k];
 +      while(a-- > 0) {
 +        while(k > w + lx[1 + h]) {
 +          w += lx[1 + h];
 +          h++;
 +          z = g - w;
 +          z = z > mm ? mm : z;
 +          j = k - w;
 +          f = 1 << j;
 +          if(f > a + 1) {
 +            f -= a + 1;
 +            xp = k;
 +            while(++j < z) {
 +              f <<= 1;
 +              if(f <= c[++xp]) {
 +                break
 +              }
 +              f -= c[xp]
 +            }
 +          }
 +          if(w + j > el && w < el) {
 +            j = el - w
 +          }
 +          z = 1 << j;
 +          lx[1 + h] = j;
 +          q = new Array(z);
 +          for(o = 0;o < z;o++) {
 +            q[o] = new core.zip_HuftNode
 +          }
 +          if(tail === null) {
 +            tail = this.root = new core.zip_HuftList
 +          }else {
 +            tail = tail.next = new core.zip_HuftList
 +          }
 +          tail.next = null;
 +          tail.list = q;
 +          u[h] = q;
 +          if(h > 0) {
 +            x[h] = i;
 +            r.b = lx[h];
 +            r.e = 16 + j;
 +            r.t = q;
 +            j = (i & (1 << w) - 1) >> w - lx[h];
 +            u[h - 1][j].e = r.e;
 +            u[h - 1][j].b = r.b;
 +            u[h - 1][j].n = (r).n;
 +            u[h - 1][j].t = r.t
 +          }
 +        }
 +        r.b = k - w;
 +        if(pidx >= n) {
 +          r.e = 99
 +        }else {
 +          if(p[pidx] < s) {
 +            r.e = p[pidx] < 256 ? 16 : 15;
 +            r.n = p[pidx++]
 +          }else {
 +            r.e = e[p[pidx] - s];
 +            r.n = d[p[pidx++] - s]
 +          }
 +        }
 +        f = 1 << k - w;
 +        for(j = i >> w;j < z;j += f) {
 +          q[j].e = r.e;
 +          q[j].b = r.b;
 +          q[j].n = (r).n;
 +          q[j].t = r.t
 +        }
 +        for(j = 1 << k - 1;(i & j) !== 0;j >>= 1) {
 +          i ^= j
 +        }
 +        i ^= j;
 +        while((i & (1 << w) - 1) !== x[h]) {
 +          w -= lx[h];
 +          h--
 +        }
 +      }
 +    }
 +    this.m = lx[1];
 +    this.status = y !== 0 && g !== 1 ? 1 : 0
 +  }
 +  function zip_GET_BYTE() {
 +    if(zip_inflate_data.length === zip_inflate_pos) {
 +      return-1
 +    }
 +    return zip_inflate_data[zip_inflate_pos++]
 +  }
 +  function zip_NEEDBITS(n) {
 +    while(zip_bit_len < n) {
 +      zip_bit_buf |= zip_GET_BYTE() << zip_bit_len;
 +      zip_bit_len += 8
 +    }
 +  }
 +  function zip_GETBITS(n) {
 +    return zip_bit_buf & zip_MASK_BITS[n]
 +  }
 +  function zip_DUMPBITS(n) {
 +    zip_bit_buf >>= n;
 +    zip_bit_len -= n
 +  }
 +  function zip_inflate_codes(buff, off, size) {
 +    var e, t, n;
 +    if(size === 0) {
 +      return 0
 +    }
 +    n = 0;
 +    for(;;) {
 +      zip_NEEDBITS(zip_bl);
 +      t = zip_tl.list[zip_GETBITS(zip_bl)];
 +      e = t.e;
 +      while(e > 16) {
 +        if(e === 99) {
 +          return-1
 +        }
 +        zip_DUMPBITS(t.b);
 +        e -= 16;
 +        zip_NEEDBITS(e);
 +        t = t.t[zip_GETBITS(e)];
 +        e = t.e
 +      }
 +      zip_DUMPBITS(t.b);
 +      if(e === 16) {
 +        zip_wp &= zip_WSIZE - 1;
 +        buff[off + n++] = zip_slide[zip_wp++] = t.n;
 +        if(n === size) {
 +          return size
 +        }
 +      }else {
 +        if(e === 15) {
 +          break
 +        }
 +        zip_NEEDBITS(e);
 +        zip_copy_leng = t.n + zip_GETBITS(e);
 +        zip_DUMPBITS(e);
 +        zip_NEEDBITS(zip_bd);
 +        t = zip_td.list[zip_GETBITS(zip_bd)];
 +        e = t.e;
 +        while(e > 16) {
 +          if(e === 99) {
 +            return-1
 +          }
 +          zip_DUMPBITS(t.b);
 +          e -= 16;
 +          zip_NEEDBITS(e);
 +          t = t.t[zip_GETBITS(e)];
 +          e = t.e
 +        }
 +        zip_DUMPBITS(t.b);
 +        zip_NEEDBITS(e);
 +        zip_copy_dist = zip_wp - t.n - zip_GETBITS(e);
 +        zip_DUMPBITS(e);
 +        while(zip_copy_leng > 0 && n < size) {
 +          zip_copy_leng--;
 +          zip_copy_dist &= zip_WSIZE - 1;
 +          zip_wp &= zip_WSIZE - 1;
 +          buff[off + n++] = zip_slide[zip_wp++] = zip_slide[zip_copy_dist++]
 +        }
 +        if(n === size) {
 +          return size
 +        }
 +      }
 +    }
 +    zip_method = -1;
 +    return n
 +  }
 +  function zip_inflate_stored(buff, off, size) {
 +    var n;
 +    n = zip_bit_len & 7;
 +    zip_DUMPBITS(n);
 +    zip_NEEDBITS(16);
 +    n = zip_GETBITS(16);
 +    zip_DUMPBITS(16);
 +    zip_NEEDBITS(16);
 +    if(n !== (~zip_bit_buf & 65535)) {
 +      return-1
 +    }
 +    zip_DUMPBITS(16);
 +    zip_copy_leng = n;
 +    n = 0;
 +    while(zip_copy_leng > 0 && n < size) {
 +      zip_copy_leng--;
 +      zip_wp &= zip_WSIZE - 1;
 +      zip_NEEDBITS(8);
 +      buff[off + n++] = zip_slide[zip_wp++] = zip_GETBITS(8);
 +      zip_DUMPBITS(8)
 +    }
 +    if(zip_copy_leng === 0) {
 +      zip_method = -1
 +    }
 +    return n
 +  }
 +  var zip_fixed_bd;
 +  function zip_inflate_fixed(buff, off, size) {
 +    if(zip_fixed_tl === null) {
 +      var i;
 +      var l = new Array(288);
 +      var h;
 +      for(i = 0;i < 144;i++) {
 +        l[i] = 8
 +      }
 +      for(i = 144;i < 256;i++) {
 +        l[i] = 9
 +      }
 +      for(i = 256;i < 280;i++) {
 +        l[i] = 7
 +      }
 +      for(i = 280;i < 288;i++) {
 +        l[i] = 8
 +      }
 +      zip_fixed_bl = 7;
 +      h = new Zip_HuftBuild(l, 288, 257, zip_cplens, zip_cplext, zip_fixed_bl);
 +      if(h.status !== 0) {
 +        alert("HufBuild error: " + h.status);
 +        return-1
 +      }
 +      zip_fixed_tl = h.root;
 +      zip_fixed_bl = h.m;
 +      for(i = 0;i < 30;i++) {
 +        l[i] = 5
 +      }
 +      zip_fixed_bd = 5;
 +      h = new Zip_HuftBuild(l, 30, 0, zip_cpdist, zip_cpdext, zip_fixed_bd);
 +      if(h.status > 1) {
 +        zip_fixed_tl = null;
 +        alert("HufBuild error: " + h.status);
 +        return-1
 +      }
 +      zip_fixed_td = h.root;
 +      zip_fixed_bd = h.m
 +    }
 +    zip_tl = zip_fixed_tl;
 +    zip_td = zip_fixed_td;
 +    zip_bl = zip_fixed_bl;
 +    zip_bd = zip_fixed_bd;
 +    return zip_inflate_codes(buff, off, size)
 +  }
 +  function zip_inflate_dynamic(buff, off, size) {
 +    var i;
 +    var j;
 +    var l;
 +    var n;
 +    var t;
 +    var nb;
 +    var nl;
 +    var nd;
 +    var ll = new Array(286 + 30);
 +    var h;
 +    for(i = 0;i < ll.length;i++) {
 +      ll[i] = 0
 +    }
 +    zip_NEEDBITS(5);
 +    nl = 257 + zip_GETBITS(5);
 +    zip_DUMPBITS(5);
 +    zip_NEEDBITS(5);
 +    nd = 1 + zip_GETBITS(5);
 +    zip_DUMPBITS(5);
 +    zip_NEEDBITS(4);
 +    nb = 4 + zip_GETBITS(4);
 +    zip_DUMPBITS(4);
 +    if(nl > 286 || nd > 30) {
 +      return-1
 +    }
 +    for(j = 0;j < nb;j++) {
 +      zip_NEEDBITS(3);
 +      ll[zip_border[j]] = zip_GETBITS(3);
 +      zip_DUMPBITS(3)
 +    }
 +    for(j = nb;j < 19;j++) {
 +      ll[zip_border[j]] = 0
 +    }
 +    zip_bl = 7;
 +    h = new Zip_HuftBuild(ll, 19, 19, null, null, zip_bl);
 +    if(h.status !== 0) {
 +      return-1
 +    }
 +    zip_tl = h.root;
 +    zip_bl = h.m;
 +    n = nl + nd;
 +    i = l = 0;
 +    while(i < n) {
 +      zip_NEEDBITS(zip_bl);
 +      t = zip_tl.list[zip_GETBITS(zip_bl)];
 +      j = t.b;
 +      zip_DUMPBITS(j);
 +      j = t.n;
 +      if(j < 16) {
 +        ll[i++] = l = j
 +      }else {
 +        if(j === 16) {
 +          zip_NEEDBITS(2);
 +          j = 3 + zip_GETBITS(2);
 +          zip_DUMPBITS(2);
 +          if(i + j > n) {
 +            return-1
 +          }
 +          while(j-- > 0) {
 +            ll[i++] = l
 +          }
 +        }else {
 +          if(j === 17) {
 +            zip_NEEDBITS(3);
 +            j = 3 + zip_GETBITS(3);
 +            zip_DUMPBITS(3);
 +            if(i + j > n) {
 +              return-1
 +            }
 +            while(j-- > 0) {
 +              ll[i++] = 0
 +            }
 +            l = 0
 +          }else {
 +            zip_NEEDBITS(7);
 +            j = 11 + zip_GETBITS(7);
 +            zip_DUMPBITS(7);
 +            if(i + j > n) {
 +              return-1
 +            }
 +            while(j-- > 0) {
 +              ll[i++] = 0
 +            }
 +            l = 0
 +          }
 +        }
 +      }
 +    }
 +    zip_bl = zip_lbits;
 +    h = new Zip_HuftBuild(ll, nl, 257, zip_cplens, zip_cplext, zip_bl);
 +    if(zip_bl === 0) {
 +      h.status = 1
 +    }
 +    if(h.status !== 0) {
 +      return-1
 +    }
 +    zip_tl = h.root;
 +    zip_bl = h.m;
 +    for(i = 0;i < nd;i++) {
 +      ll[i] = ll[i + nl]
 +    }
 +    zip_bd = zip_dbits;
 +    h = new Zip_HuftBuild(ll, nd, 0, zip_cpdist, zip_cpdext, zip_bd);
 +    zip_td = h.root;
 +    zip_bd = h.m;
 +    if(zip_bd === 0 && nl > 257) {
 +      return-1
 +    }
 +    if(h.status !== 0) {
 +      return-1
 +    }
 +    return zip_inflate_codes(buff, off, size)
 +  }
 +  function zip_inflate_start() {
 +    zip_slide.length = 2 * zip_WSIZE;
 +    zip_wp = 0;
 +    zip_bit_buf = 0;
 +    zip_bit_len = 0;
 +    zip_method = -1;
 +    zip_eof = false;
 +    zip_copy_leng = zip_copy_dist = 0;
 +    zip_tl = null
 +  }
 +  function zip_inflate_internal(buff, off, size) {
 +    var n = 0, i;
 +    while(n < size) {
 +      if(zip_eof && zip_method === -1) {
 +        return n
 +      }
 +      if(zip_copy_leng > 0) {
 +        if(zip_method !== zip_STORED_BLOCK) {
 +          while(zip_copy_leng > 0 && n < size) {
 +            zip_copy_leng--;
 +            zip_copy_dist &= zip_WSIZE - 1;
 +            zip_wp &= zip_WSIZE - 1;
 +            buff[off + n] = zip_slide[zip_wp] = zip_slide[zip_copy_dist];
 +            n += 1;
 +            zip_wp += 1;
 +            zip_copy_dist += 1
 +          }
 +        }else {
 +          while(zip_copy_leng > 0 && n < size) {
 +            zip_copy_leng -= 1;
 +            zip_wp &= zip_WSIZE - 1;
 +            zip_NEEDBITS(8);
 +            buff[off + n] = zip_slide[zip_wp] = zip_GETBITS(8);
 +            n += 1;
 +            zip_wp += 1;
 +            zip_DUMPBITS(8)
 +          }
 +          if(zip_copy_leng === 0) {
 +            zip_method = -1
 +          }
 +        }
 +        if(n === size) {
 +          return n
 +        }
 +      }
 +      if(zip_method === -1) {
 +        if(zip_eof) {
 +          break
 +        }
 +        zip_NEEDBITS(1);
 +        if(zip_GETBITS(1) !== 0) {
 +          zip_eof = true
 +        }
 +        zip_DUMPBITS(1);
 +        zip_NEEDBITS(2);
 +        zip_method = zip_GETBITS(2);
 +        zip_DUMPBITS(2);
 +        zip_tl = null;
 +        zip_copy_leng = 0
 +      }
 +      switch(zip_method) {
 +        case 0:
 +          i = zip_inflate_stored(buff, off + n, size - n);
 +          break;
 +        case 1:
 +          if(zip_tl !== null) {
 +            i = zip_inflate_codes(buff, off + n, size - n)
 +          }else {
 +            i = zip_inflate_fixed(buff, off + n, size - n)
 +          }
 +          break;
 +        case 2:
 +          if(zip_tl !== null) {
 +            i = zip_inflate_codes(buff, off + n, size - n)
 +          }else {
 +            i = zip_inflate_dynamic(buff, off + n, size - n)
 +          }
 +          break;
 +        default:
 +          i = -1;
 +          break
 +      }
 +      if(i === -1) {
 +        if(zip_eof) {
 +          return 0
 +        }
 +        return-1
 +      }
 +      n += i
 +    }
 +    return n
 +  }
 +  function zip_inflate(data, size) {
 +    zip_inflate_start();
 +    zip_inflate_data = data;
 +    zip_inflate_pos = 0;
 +    var buff = new Uint8Array(new ArrayBuffer(size));
 +    zip_inflate_internal(buff, 0, size);
 +    zip_inflate_data = new Uint8Array(new ArrayBuffer(0));
 +    return buff
 +  }
 +  this.inflate = zip_inflate
 +};
 +core.ScheduledTask = function ScheduledTask(fn, delay) {
 +  var timeoutId, scheduled = false, args = [];
 +  function cancel() {
 +    if(scheduled) {
 +      runtime.clearTimeout(timeoutId);
 +      scheduled = false
 +    }
 +  }
 +  function execute() {
 +    cancel();
 +    fn.apply(undefined, args);
 +    args = null
 +  }
 +  this.trigger = function() {
 +    args = Array.prototype.slice.call(arguments);
 +    if(!scheduled) {
 +      scheduled = true;
 +      timeoutId = runtime.setTimeout(execute, delay)
 +    }
 +  };
 +  this.triggerImmediate = function() {
 +    args = Array.prototype.slice.call(arguments);
 +    execute()
 +  };
 +  this.processRequests = function() {
 +    if(scheduled) {
 +      execute()
 +    }
 +  };
 +  this.cancel = cancel;
 +  this.destroy = function(callback) {
 +    cancel();
 +    callback()
 +  }
 +};
- core.NamedFunction;
- core.NamedAsyncFunction;
++/*
++
++ Copyright (C) 2014 KO GmbH <copyright at kogmbh.com>
++
++ @licstart
++ The JavaScript code in this page is free software: you can redistribute it
++ and/or modify it under the terms of the GNU Affero General Public License
++ (GNU AGPL) as published by the Free Software Foundation, either version 3 of
++ the License, or (at your option) any later version.  The code is distributed
++ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
++
++ You should have received a copy of the GNU Affero General Public License
++ along with this code.  If not, see <http://www.gnu.org/licenses/>.
++
++ As additional permission under GNU AGPL version 3 section 7, you
++ may distribute non-source (e.g., minimized or compacted) forms of
++ that code without the copy of the GNU GPL normally required by
++ section 4, provided you include this license notice and a URL
++ through which recipients can access the Corresponding Source.
++
++ As a special exception to the AGPL, any HTML file which merely makes function
++ calls to this code, and for that purpose includes it by reference shall be
++ deemed a separate work for copyright law purposes. In addition, the copyright
++ holders of this code give you permission to combine this code with free
++ software libraries that are released under the GNU LGPL. You may copy and
++ distribute such a system following the terms of the GNU AGPL for this code
++ and the LGPL for the libraries. If you modify this code, you may extend this
++ exception to your version of the code, but you are not obligated to do so.
++ If you do not wish to do so, delete this exception statement from your
++ version.
++
++ This license applies to this entire compilation.
++ @licend
++ @source: http://www.webodf.org/
++ @source: https://github.com/kogmbh/WebODF/
++*/
++core.StepIterator = function StepIterator(filter, iterator) {
++  var FILTER_ACCEPT = core.PositionFilter.FilterResult.FILTER_ACCEPT, cachedContainer, cachedOffset, cachedFilterResult;
++  function resetCache() {
++    cachedContainer = null;
++    cachedOffset = undefined;
++    cachedFilterResult = undefined
++  }
++  function isStep() {
++    if(cachedFilterResult === undefined) {
++      cachedFilterResult = filter.acceptPosition(iterator) === FILTER_ACCEPT
++    }
++    return(cachedFilterResult)
++  }
++  this.isStep = isStep;
++  function setPosition(newContainer, newOffset) {
++    resetCache();
++    return iterator.setUnfilteredPosition(newContainer, newOffset)
++  }
++  this.setPosition = setPosition;
++  function container() {
++    if(!cachedContainer) {
++      cachedContainer = iterator.container()
++    }
++    return cachedContainer
++  }
++  this.container = container;
++  function offset() {
++    if(cachedOffset === undefined) {
++      cachedOffset = iterator.unfilteredDomOffset()
++    }
++    return(cachedOffset)
++  }
++  this.offset = offset;
++  function nextStep() {
++    resetCache();
++    while(iterator.nextPosition()) {
++      resetCache();
++      if(isStep()) {
++        return true
++      }
++    }
++    return false
++  }
++  this.nextStep = nextStep;
++  function previousStep() {
++    resetCache();
++    while(iterator.previousPosition()) {
++      resetCache();
++      if(isStep()) {
++        return true
++      }
++    }
++    return false
++  }
++  this.previousStep = previousStep;
++  this.roundToClosestStep = function() {
++    var currentContainer = container(), currentOffset = offset(), isAtStep = isStep();
++    if(!isAtStep) {
++      isAtStep = previousStep();
++      if(!isAtStep) {
++        setPosition(currentContainer, currentOffset);
++        isAtStep = nextStep()
++      }
++    }
++    return isAtStep
++  };
++  this.roundToPreviousStep = function() {
++    var isAtStep = isStep();
++    if(!isAtStep) {
++      isAtStep = previousStep()
++    }
++    return isAtStep
++  };
++  this.roundToNextStep = function() {
++    var isAtStep = isStep();
++    if(!isAtStep) {
++      isAtStep = nextStep()
++    }
++    return isAtStep
++  }
++};
++core.TestData;
++core.AsyncTestData;
 +core.UnitTest = function UnitTest() {
 +};
 +core.UnitTest.prototype.setUp = function() {
 +};
 +core.UnitTest.prototype.tearDown = function() {
 +};
 +core.UnitTest.prototype.description = function() {
 +};
 +core.UnitTest.prototype.tests = function() {
 +};
 +core.UnitTest.prototype.asyncTests = function() {
 +};
 +core.UnitTest.provideTestAreaDiv = function() {
 +  var maindoc = runtime.getWindow().document, testarea = maindoc.getElementById("testarea");
 +  runtime.assert(!testarea, 'Unclean test environment, found a div with id "testarea".');
 +  testarea = maindoc.createElement("div");
 +  testarea.setAttribute("id", "testarea");
 +  maindoc.body.appendChild(testarea);
 +  return(testarea)
 +};
 +core.UnitTest.cleanupTestAreaDiv = function() {
 +  var maindoc = runtime.getWindow().document, testarea = maindoc.getElementById("testarea");
 +  runtime.assert(!!testarea && testarea.parentNode === maindoc.body, 'Test environment broken, found no div with id "testarea" below body.');
 +  maindoc.body.removeChild(testarea)
 +};
 +core.UnitTest.createOdtDocument = function(xml, namespaceMap) {
 +  var xmlDoc = "<?xml version='1.0' encoding='UTF-8'?>";
 +  xmlDoc += "<office:document";
 +  Object.keys(namespaceMap).forEach(function(key) {
 +    xmlDoc += " xmlns:" + key + '="' + namespaceMap[key] + '"'
 +  });
 +  xmlDoc += ">";
 +  xmlDoc += xml;
 +  xmlDoc += "</office:document>";
 +  return runtime.parseXML(xmlDoc)
 +};
- core.UnitTestRunner = function UnitTestRunner() {
-   var failedTests = 0, areObjectsEqual;
++core.UnitTestLogger = function UnitTestLogger() {
++  var messages = [], errors = 0, start = 0, suite = "", test = "";
++  this.startTest = function(suiteName, testName) {
++    messages = [];
++    errors = 0;
++    suite = suiteName;
++    test = testName;
++    start = (new Date).getTime()
++  };
++  this.endTest = function() {
++    var end = (new Date).getTime();
++    return{description:test, suite:[suite, test], success:errors === 0, log:messages, time:end - start}
++  };
++  this.debug = function(msg) {
++    messages.push({category:"debug", message:msg})
++  };
++  this.fail = function(msg) {
++    errors += 1;
++    messages.push({category:"fail", message:msg})
++  };
++  this.pass = function(msg) {
++    messages.push({category:"pass", message:msg})
++  }
++};
++core.UnitTestRunner = function UnitTestRunner(resourcePrefix, logger) {
++  var failedTests = 0, failedTestsOnBeginExpectFail, areObjectsEqual, expectFail = false;
++  this.resourcePrefix = function() {
++    return resourcePrefix
++  };
++  this.beginExpectFail = function() {
++    failedTestsOnBeginExpectFail = failedTests;
++    expectFail = true
++  };
++  this.endExpectFail = function() {
++    var hasNoFailedTests = failedTestsOnBeginExpectFail === failedTests;
++    expectFail = false;
++    failedTests = failedTestsOnBeginExpectFail;
++    if(hasNoFailedTests) {
++      failedTests += 1;
++      logger.fail("Expected at least one failed test, but none registered.")
++    }
++  };
 +  function debug(msg) {
-     runtime.log(msg)
++    logger.debug(msg)
 +  }
 +  function testFailed(msg) {
 +    failedTests += 1;
-     runtime.log("fail", msg)
++    if(!expectFail) {
++      logger.fail(msg)
++    }else {
++      logger.debug(msg)
++    }
 +  }
 +  function testPassed(msg) {
-     runtime.log("pass", msg)
++    logger.pass(msg)
 +  }
 +  function areArraysEqual(a, b) {
 +    var i;
 +    try {
 +      if(a.length !== b.length) {
 +        testFailed("array of length " + a.length + " should be " + b.length + " long");
 +        return false
 +      }
 +      for(i = 0;i < a.length;i += 1) {
 +        if(a[i] !== b[i]) {
 +          testFailed(a[i] + " should be " + b[i] + " at array index " + i);
 +          return false
 +        }
 +      }
 +    }catch(ex) {
 +      return false
 +    }
 +    return true
 +  }
 +  function areAttributesEqual(a, b, skipReverseCheck) {
 +    var aatts = a.attributes, n = aatts.length, i, att, v;
 +    for(i = 0;i < n;i += 1) {
 +      att = (aatts.item(i));
 +      if(att.prefix !== "xmlns" && att.namespaceURI !== "urn:webodf:names:steps") {
 +        v = b.getAttributeNS(att.namespaceURI, att.localName);
 +        if(!b.hasAttributeNS(att.namespaceURI, att.localName)) {
 +          testFailed("Attribute " + att.localName + " with value " + att.value + " was not present");
 +          return false
 +        }
 +        if(v !== att.value) {
 +          testFailed("Attribute " + att.localName + " was " + v + " should be " + att.value);
 +          return false
 +        }
 +      }
 +    }
 +    return skipReverseCheck ? true : areAttributesEqual(b, a, true)
 +  }
 +  function areNodesEqual(a, b) {
 +    var an, bn, atype = a.nodeType, btype = b.nodeType;
 +    if(atype !== btype) {
 +      testFailed("Nodetype '" + atype + "' should be '" + btype + "'");
 +      return false
 +    }
 +    if(atype === Node.TEXT_NODE) {
 +      if((a).data === (b).data) {
 +        return true
 +      }
 +      testFailed("Textnode data '" + (a).data + "' should be '" + (b).data + "'");
 +      return false
 +    }
 +    runtime.assert(atype === Node.ELEMENT_NODE, "Only textnodes and elements supported.");
 +    if(a.namespaceURI !== b.namespaceURI) {
 +      testFailed("namespace '" + a.namespaceURI + "' should be '" + b.namespaceURI + "'");
 +      return false
 +    }
 +    if(a.localName !== b.localName) {
 +      testFailed("localName '" + a.localName + "' should be '" + b.localName + "'");
 +      return false
 +    }
 +    if(!areAttributesEqual((a), (b), false)) {
 +      return false
 +    }
 +    an = a.firstChild;
 +    bn = b.firstChild;
 +    while(an) {
 +      if(!bn) {
 +        testFailed("Nodetype '" + an.nodeType + "' is unexpected here.");
 +        return false
 +      }
 +      if(!areNodesEqual(an, bn)) {
 +        return false
 +      }
 +      an = an.nextSibling;
 +      bn = bn.nextSibling
 +    }
 +    if(bn) {
 +      testFailed("Nodetype '" + bn.nodeType + "' is missing here.");
 +      return false
 +    }
 +    return true
 +  }
 +  function isResultCorrect(actual, expected) {
 +    if(expected === 0) {
 +      return actual === expected && 1 / actual === 1 / expected
 +    }
 +    if(actual === expected) {
 +      return true
 +    }
++    if(actual === null || expected === null) {
++      return false
++    }
 +    if(typeof expected === "number" && isNaN(expected)) {
 +      return typeof actual === "number" && isNaN(actual)
 +    }
 +    if(Object.prototype.toString.call(expected) === Object.prototype.toString.call([])) {
 +      return areArraysEqual((actual), (expected))
 +    }
 +    if(typeof expected === "object" && typeof actual === "object") {
 +      if((expected).constructor === Element || (expected).constructor === Node) {
-         return areNodesEqual((expected), (actual))
++        return areNodesEqual((actual), (expected))
 +      }
-       return areObjectsEqual((expected), (actual))
++      return areObjectsEqual((actual), (expected))
 +    }
 +    return false
 +  }
 +  function stringify(v) {
 +    if(v === 0 && 1 / v < 0) {
 +      return"-0"
 +    }
 +    return String(v)
 +  }
 +  function shouldBe(t, a, b) {
 +    if(typeof a !== "string" || typeof b !== "string") {
 +      debug("WARN: shouldBe() expects string arguments")
 +    }
 +    var exception, av, bv;
 +    try {
 +      av = eval(a)
 +    }catch(e) {
 +      exception = e
 +    }
 +    bv = eval(b);
 +    if(exception) {
 +      testFailed(a + " should be " + bv + ". Threw exception " + exception)
 +    }else {
 +      if(isResultCorrect(av, bv)) {
 +        testPassed(a + " is " + b)
 +      }else {
 +        if(String(typeof av) === String(typeof bv)) {
 +          testFailed(a + " should be " + bv + ". Was " + stringify(av) + ".")
 +        }else {
 +          testFailed(a + " should be " + bv + " (of type " + typeof bv + "). Was " + av + " (of type " + typeof av + ").")
 +        }
 +      }
 +    }
 +  }
 +  function shouldBeNonNull(t, a) {
 +    var exception, av;
 +    try {
 +      av = eval(a)
 +    }catch(e) {
 +      exception = e
 +    }
 +    if(exception) {
 +      testFailed(a + " should be non-null. Threw exception " + exception)
 +    }else {
 +      if(av !== null) {
 +        testPassed(a + " is non-null.")
 +      }else {
 +        testFailed(a + " should be non-null. Was " + av)
 +      }
 +    }
 +  }
 +  function shouldBeNull(t, a) {
 +    shouldBe(t, a, "null")
 +  }
 +  areObjectsEqual = function(a, b) {
 +    var akeys = Object.keys(a), bkeys = Object.keys(b);
 +    akeys.sort();
 +    bkeys.sort();
 +    return areArraysEqual(akeys, bkeys) && Object.keys(a).every(function(key) {
 +      var aval = a[key], bval = b[key];
 +      if(!isResultCorrect(aval, bval)) {
 +        testFailed(aval + " should be " + bval + " for key " + key);
 +        return false
 +      }
 +      return true
 +    })
 +  };
 +  this.areNodesEqual = areNodesEqual;
 +  this.shouldBeNull = shouldBeNull;
 +  this.shouldBeNonNull = shouldBeNonNull;
 +  this.shouldBe = shouldBe;
++  this.testFailed = testFailed;
 +  this.countFailedTests = function() {
 +    return failedTests
 +  };
 +  this.name = function(functions) {
 +    var i, fname, nf = [], l = functions.length;
 +    nf.length = l;
 +    for(i = 0;i < l;i += 1) {
 +      fname = Runtime.getFunctionName(functions[i]) || "";
 +      if(fname === "") {
 +        throw"Found a function without a name.";
 +      }
 +      nf[i] = {f:functions[i], name:fname}
 +    }
 +    return nf
 +  }
 +};
 +core.UnitTester = function UnitTester() {
-   var failedTests = 0, results = {};
++  var self = this, failedTests = 0, logger = new core.UnitTestLogger, results = {}, inBrowser = runtime.type() === "BrowserRuntime";
++  this.resourcePrefix = "";
 +  function link(text, code) {
 +    return"<span style='color:blue;cursor:pointer' onclick='" + code + "'>" + text + "</span>"
 +  }
++  this.reporter = function(r) {
++    var i, m;
++    if(inBrowser) {
++      runtime.log("<span>Running " + link(r.description, 'runTest("' + r.suite[0] + '","' + r.description + '")') + "</span>")
++    }else {
++      runtime.log("Running " + r.description)
++    }
++    if(!r.success) {
++      for(i = 0;i < r.log.length;i += 1) {
++        m = r.log[i];
++        runtime.log(m.category, m.message)
++      }
++    }
++  };
++  function report(r) {
++    if(self.reporter) {
++      self.reporter(r)
++    }
++  }
 +  this.runTests = function(TestClass, callback, testNames) {
-     var testName = Runtime.getFunctionName(TestClass) || "", tname, runner = new core.UnitTestRunner, test = new TestClass(runner), testResults = {}, i, t, tests, lastFailCount, inBrowser = runtime.type() === "BrowserRuntime";
++    var testName = Runtime.getFunctionName(TestClass) || "", tname, runner = new core.UnitTestRunner(self.resourcePrefix, logger), test = new TestClass(runner), testResults = {}, i, t, tests, texpectFail, lastFailCount;
 +    if(results.hasOwnProperty(testName)) {
 +      runtime.log("Test " + testName + " has already run.");
 +      return
 +    }
 +    if(inBrowser) {
 +      runtime.log("<span>Running " + link(testName, 'runSuite("' + testName + '");') + ": " + test.description() + "</span>")
 +    }else {
 +      runtime.log("Running " + testName + ": " + test.description)
 +    }
 +    tests = test.tests();
 +    for(i = 0;i < tests.length;i += 1) {
 +      t = tests[i].f;
 +      tname = tests[i].name;
++      texpectFail = tests[i].expectFail === true;
 +      if(testNames.length && testNames.indexOf(tname) === -1) {
 +        continue
 +      }
-       if(inBrowser) {
-         runtime.log("<span>Running " + link(tname, 'runTest("' + testName + '","' + tname + '")') + "</span>")
-       }else {
-         runtime.log("Running " + tname)
-       }
 +      lastFailCount = runner.countFailedTests();
 +      test.setUp();
-       t();
++      logger.startTest(testName, tname);
++      if(texpectFail) {
++        runner.beginExpectFail()
++      }
++      try {
++        t()
++      }catch(e) {
++        runner.testFailed("Unexpected exception encountered: " + e.toString() + "\n" + e.stack)
++      }
++      if(texpectFail) {
++        runner.endExpectFail()
++      }
++      report(logger.endTest());
 +      test.tearDown();
 +      testResults[tname] = lastFailCount === runner.countFailedTests()
 +    }
 +    function runAsyncTests(todo) {
 +      if(todo.length === 0) {
 +        results[testName] = testResults;
 +        failedTests += runner.countFailedTests();
 +        callback();
 +        return
 +      }
 +      t = todo[0].f;
-       var fname = todo[0].name;
-       runtime.log("Running " + fname);
++      var fname = todo[0].name, expectFail = todo[0].expectFail === true;
 +      lastFailCount = runner.countFailedTests();
-       test.setUp();
-       t(function() {
-         test.tearDown();
-         testResults[fname] = lastFailCount === runner.countFailedTests();
++      if(testNames.length && testNames.indexOf(fname) === -1) {
 +        runAsyncTests(todo.slice(1))
-       })
++      }else {
++        test.setUp();
++        logger.startTest(testName, fname);
++        if(expectFail) {
++          runner.beginExpectFail()
++        }
++        t(function() {
++          if(expectFail) {
++            runner.endExpectFail()
++          }
++          report(logger.endTest());
++          test.tearDown();
++          testResults[fname] = lastFailCount === runner.countFailedTests();
++          runAsyncTests(todo.slice(1))
++        })
++      }
 +    }
 +    runAsyncTests(test.asyncTests())
 +  };
 +  this.countFailedTests = function() {
 +    return failedTests
 +  };
 +  this.results = function() {
 +    return results
 +  }
 +};
 +core.Utils = function Utils() {
 +  function hashString(value) {
 +    var hash = 0, i, l;
 +    for(i = 0, l = value.length;i < l;i += 1) {
 +      hash = (hash << 5) - hash + value.charCodeAt(i);
 +      hash |= 0
 +    }
 +    return hash
 +  }
 +  this.hashString = hashString;
 +  var mergeObjects;
 +  function mergeItems(destination, source) {
 +    if(source && Array.isArray(source)) {
 +      destination = destination || [];
 +      if(!Array.isArray(destination)) {
 +        throw"Destination is not an array.";
 +      }
 +      destination = (destination).concat((source).map(function(obj) {
 +        return mergeItems(null, obj)
 +      }))
 +    }else {
 +      if(source && typeof source === "object") {
 +        destination = destination || {};
 +        if(typeof destination !== "object") {
 +          throw"Destination is not an object.";
 +        }
 +        Object.keys((source)).forEach(function(p) {
 +          destination[p] = mergeItems(destination[p], source[p])
 +        })
 +      }else {
 +        destination = source
 +      }
 +    }
 +    return destination
 +  }
 +  mergeObjects = function(destination, source) {
 +    Object.keys(source).forEach(function(p) {
 +      destination[p] = mergeItems(destination[p], source[p])
 +    });
 +    return destination
 +  };
 +  this.mergeObjects = mergeObjects
 +};
 +/*
 +
 + WebODF
 + Copyright (c) 2010 Jos van den Oever
 + Licensed under the ... License:
 +
 + Project home: http://www.webodf.org/
 +*/
- runtime.loadClass("core.RawInflate");
- runtime.loadClass("core.ByteArray");
- runtime.loadClass("core.ByteArrayWriter");
- runtime.loadClass("core.Base64");
 +core.Zip = function Zip(url, entriesReadCallback) {
 +  var entries, filesize, nEntries, inflate = (new core.RawInflate).inflate, zip = this, base64 = new core.Base64;
 +  function crc32(data) {
 +    var table = [0, 1996959894, 3993919788, 2567524794, 124634137, 1886057615, 3915621685, 2657392035, 249268274, 2044508324, 3772115230, 2547177864, 162941995, 2125561021, 3887607047, 2428444049, 498536548, 1789927666, 4089016648, 2227061214, 450548861, 1843258603, 4107580753, 2211677639, 325883990, 1684777152, 4251122042, 2321926636, 335633487, 1661365465, 4195302755, 2366115317, 997073096, 1281953886, 3579855332, 2724688242, 1006888145, 1258607687, 3524101629, 2768942443, 901097722,  [...]
 +    3686517206, 2898065728, 853044451, 1172266101, 3705015759, 2882616665, 651767980, 1373503546, 3369554304, 3218104598, 565507253, 1454621731, 3485111705, 3099436303, 671266974, 1594198024, 3322730930, 2970347812, 795835527, 1483230225, 3244367275, 3060149565, 1994146192, 31158534, 2563907772, 4023717930, 1907459465, 112637215, 2680153253, 3904427059, 2013776290, 251722036, 2517215374, 3775830040, 2137656763, 141376813, 2439277719, 3865271297, 1802195444, 476864866, 2238001368, 406650 [...]
 +    453092731, 2181625025, 4111451223, 1706088902, 314042704, 2344532202, 4240017532, 1658658271, 366619977, 2362670323, 4224994405, 1303535960, 984961486, 2747007092, 3569037538, 1256170817, 1037604311, 2765210733, 3554079995, 1131014506, 879679996, 2909243462, 3663771856, 1141124467, 855842277, 2852801631, 3708648649, 1342533948, 654459306, 3188396048, 3373015174, 1466479909, 544179635, 3110523913, 3462522015, 1591671054, 702138776, 2966460450, 3352799412, 1504918807, 783551873, 30826 [...]
 +    3988292384, 2596254646, 62317068, 1957810842, 3939845945, 2647816111, 81470997, 1943803523, 3814918930, 2489596804, 225274430, 2053790376, 3826175755, 2466906013, 167816743, 2097651377, 4027552580, 2265490386, 503444072, 1762050814, 4150417245, 2154129355, 426522225, 1852507879, 4275313526, 2312317920, 282753626, 1742555852, 4189708143, 2394877945, 397917763, 1622183637, 3604390888, 2714866558, 953729732, 1340076626, 3518719985, 2797360999, 1068828381, 1219638859, 3624741850, 293667 [...]
 +    1090812512, 3747672003, 2825379669, 829329135, 1181335161, 3412177804, 3160834842, 628085408, 1382605366, 3423369109, 3138078467, 570562233, 1426400815, 3317316542, 2998733608, 733239954, 1555261956, 3268935591, 3050360625, 752459403, 1541320221, 2607071920, 3965973030, 1969922972, 40735498, 2617837225, 3943577151, 1913087877, 83908371, 2512341634, 3803740692, 2075208622, 213261112, 2463272603, 3855990285, 2094854071, 198958881, 2262029012, 4057260610, 1759359992, 534414190, 2176718 [...]
 +    1873836001, 414664567, 2282248934, 4279200368, 1711684554, 285281116, 2405801727, 4167216745, 1634467795, 376229701, 2685067896, 3608007406, 1308918612, 956543938, 2808555105, 3495958263, 1231636301, 1047427035, 2932959818, 3654703836, 1088359270, 936918E3, 2847714899, 3736837829, 1202900863, 817233897, 3183342108, 3401237130, 1404277552, 615818150, 3134207493, 3453421203, 1423857449, 601450431, 3009837614, 3294710456, 1567103746, 711928724, 3020668471, 3272380065, 1510334235, 75516 [...]
 +    0, i, iTop = data.length, x = 0, y = 0;
 +    crc = crc ^ -1;
 +    for(i = 0;i < iTop;i += 1) {
 +      y = (crc ^ data[i]) & 255;
 +      x = table[y];
 +      crc = crc >>> 8 ^ x
 +    }
 +    return crc ^ -1
 +  }
 +  function dosTime2Date(dostime) {
 +    var year = (dostime >> 25 & 127) + 1980, month = (dostime >> 21 & 15) - 1, mday = dostime >> 16 & 31, hour = dostime >> 11 & 15, min = dostime >> 5 & 63, sec = (dostime & 31) << 1, d = new Date(year, month, mday, hour, min, sec);
 +    return d
 +  }
 +  function date2DosTime(date) {
 +    var y = date.getFullYear();
 +    return y < 1980 ? 0 : y - 1980 << 25 | date.getMonth() + 1 << 21 | date.getDate() << 16 | date.getHours() << 11 | date.getMinutes() << 5 | date.getSeconds() >> 1
 +  }
 +  function ZipEntry(url, stream) {
 +    var sig, namelen, extralen, commentlen, compressionMethod, compressedSize, uncompressedSize, offset, entry = this;
 +    function handleEntryData(data, callback) {
 +      var estream = new core.ByteArray(data), esig = estream.readUInt32LE(), filenamelen, eextralen;
 +      if(esig !== 67324752) {
 +        callback("File entry signature is wrong." + esig.toString() + " " + data.length.toString(), null);
 +        return
 +      }
 +      estream.pos += 22;
 +      filenamelen = estream.readUInt16LE();
 +      eextralen = estream.readUInt16LE();
 +      estream.pos += filenamelen + eextralen;
 +      if(compressionMethod) {
 +        data = data.subarray(estream.pos, estream.pos + compressedSize);
 +        if(compressedSize !== data.length) {
 +          callback("The amount of compressed bytes read was " + data.length.toString() + " instead of " + compressedSize.toString() + " for " + entry.filename + " in " + url + ".", null);
 +          return
 +        }
 +        data = inflate(data, uncompressedSize)
 +      }else {
 +        data = data.subarray(estream.pos, estream.pos + uncompressedSize)
 +      }
 +      if(uncompressedSize !== data.length) {
 +        callback("The amount of bytes read was " + data.length.toString() + " instead of " + uncompressedSize.toString() + " for " + entry.filename + " in " + url + ".", null);
 +        return
 +      }
 +      entry.data = data;
 +      callback(null, data)
 +    }
 +    function load(callback) {
 +      if(entry.data !== null) {
 +        callback(null, entry.data);
 +        return
 +      }
 +      var size = compressedSize + 34 + namelen + extralen + 256;
 +      if(size + offset > filesize) {
 +        size = filesize - offset
 +      }
 +      runtime.read(url, offset, size, function(err, data) {
 +        if(err || data === null) {
 +          callback(err, data)
 +        }else {
 +          handleEntryData(data, callback)
 +        }
 +      })
 +    }
 +    this.load = load;
 +    function set(filename, data, compressed, date) {
 +      entry.filename = filename;
 +      entry.data = data;
 +      entry.compressed = compressed;
 +      entry.date = date
 +    }
 +    this.set = set;
 +    this.error = null;
 +    if(!stream) {
 +      return
 +    }
 +    sig = stream.readUInt32LE();
 +    if(sig !== 33639248) {
 +      this.error = "Central directory entry has wrong signature at position " + (stream.pos - 4).toString() + ' for file "' + url + '": ' + stream.data.length.toString();
 +      return
 +    }
 +    stream.pos += 6;
 +    compressionMethod = stream.readUInt16LE();
 +    this.date = dosTime2Date(stream.readUInt32LE());
 +    stream.readUInt32LE();
 +    compressedSize = stream.readUInt32LE();
 +    uncompressedSize = stream.readUInt32LE();
 +    namelen = stream.readUInt16LE();
 +    extralen = stream.readUInt16LE();
 +    commentlen = stream.readUInt16LE();
 +    stream.pos += 8;
 +    offset = stream.readUInt32LE();
 +    this.filename = runtime.byteArrayToString(stream.data.subarray(stream.pos, stream.pos + namelen), "utf8");
 +    this.data = null;
 +    stream.pos += namelen + extralen + commentlen
 +  }
 +  function handleCentralDirectory(data, callback) {
 +    var stream = new core.ByteArray(data), i, e;
 +    entries = [];
 +    for(i = 0;i < nEntries;i += 1) {
 +      e = new ZipEntry(url, stream);
 +      if(e.error) {
 +        callback(e.error, zip);
 +        return
 +      }
 +      entries[entries.length] = e
 +    }
 +    callback(null, zip)
 +  }
 +  function handleCentralDirectoryEnd(data, callback) {
 +    if(data.length !== 22) {
 +      callback("Central directory length should be 22.", zip);
 +      return
 +    }
 +    var stream = new core.ByteArray(data), sig, disk, cddisk, diskNEntries, cdsSize, cdsOffset;
 +    sig = stream.readUInt32LE();
 +    if(sig !== 101010256) {
 +      callback("Central directory signature is wrong: " + sig.toString(), zip);
 +      return
 +    }
 +    disk = stream.readUInt16LE();
 +    if(disk !== 0) {
 +      callback("Zip files with non-zero disk numbers are not supported.", zip);
 +      return
 +    }
 +    cddisk = stream.readUInt16LE();
 +    if(cddisk !== 0) {
 +      callback("Zip files with non-zero disk numbers are not supported.", zip);
 +      return
 +    }
 +    diskNEntries = stream.readUInt16LE();
 +    nEntries = stream.readUInt16LE();
 +    if(diskNEntries !== nEntries) {
 +      callback("Number of entries is inconsistent.", zip);
 +      return
 +    }
 +    cdsSize = stream.readUInt32LE();
 +    cdsOffset = stream.readUInt16LE();
 +    cdsOffset = filesize - 22 - cdsSize;
 +    runtime.read(url, cdsOffset, filesize - cdsOffset, function(err, data) {
 +      if(err || data === null) {
 +        callback(err, zip)
 +      }else {
 +        handleCentralDirectory(data, callback)
 +      }
 +    })
 +  }
 +  function load(filename, callback) {
 +    var entry = null, e, i;
 +    for(i = 0;i < entries.length;i += 1) {
 +      e = entries[i];
 +      if(e.filename === filename) {
 +        entry = e;
 +        break
 +      }
 +    }
 +    if(entry) {
 +      if(entry.data) {
 +        callback(null, entry.data)
 +      }else {
 +        entry.load(callback)
 +      }
 +    }else {
 +      callback(filename + " not found.", null)
 +    }
 +  }
 +  function loadAsString(filename, callback) {
 +    load(filename, function(err, data) {
 +      if(err || data === null) {
 +        return callback(err, null)
 +      }
 +      var d = runtime.byteArrayToString(data, "utf8");
 +      callback(null, d)
 +    })
 +  }
 +  function loadContentXmlAsFragments(filename, handler) {
 +    zip.loadAsString(filename, function(err, data) {
 +      if(err) {
 +        return handler.rootElementReady(err)
 +      }
 +      handler.rootElementReady(null, data, true)
 +    })
 +  }
 +  function loadAsDataURL(filename, mimetype, callback) {
 +    load(filename, function(err, data) {
 +      if(err || !data) {
 +        return callback(err, null)
 +      }
 +      var p = data, chunksize = 45E3, i = 0, dataurl;
 +      if(!mimetype) {
 +        if(p[1] === 80 && (p[2] === 78 && p[3] === 71)) {
 +          mimetype = "image/png"
 +        }else {
 +          if(p[0] === 255 && (p[1] === 216 && p[2] === 255)) {
 +            mimetype = "image/jpeg"
 +          }else {
 +            if(p[0] === 71 && (p[1] === 73 && p[2] === 70)) {
 +              mimetype = "image/gif"
 +            }else {
 +              mimetype = ""
 +            }
 +          }
 +        }
 +      }
 +      dataurl = "data:" + mimetype + ";base64,";
 +      while(i < data.length) {
 +        dataurl += base64.convertUTF8ArrayToBase64(p.subarray(i, Math.min(i + chunksize, p.length)));
 +        i += chunksize
 +      }
 +      callback(null, dataurl)
 +    })
 +  }
 +  function loadAsDOM(filename, callback) {
 +    zip.loadAsString(filename, function(err, xmldata) {
 +      if(err || xmldata === null) {
 +        callback(err, null);
 +        return
 +      }
 +      var parser = new DOMParser, dom = parser.parseFromString(xmldata, "text/xml");
 +      callback(null, dom)
 +    })
 +  }
 +  function save(filename, data, compressed, date) {
 +    var i, entry;
 +    for(i = 0;i < entries.length;i += 1) {
 +      entry = entries[i];
 +      if(entry.filename === filename) {
 +        entry.set(filename, data, compressed, date);
 +        return
 +      }
 +    }
 +    entry = new ZipEntry(url);
 +    entry.set(filename, data, compressed, date);
 +    entries.push(entry)
 +  }
 +  function remove(filename) {
 +    var i, entry;
 +    for(i = 0;i < entries.length;i += 1) {
 +      entry = entries[i];
 +      if(entry.filename === filename) {
 +        entries.splice(i, 1);
 +        return true
 +      }
 +    }
 +    return false
 +  }
 +  function writeEntry(entry) {
 +    var data = new core.ByteArrayWriter("utf8"), length = 0;
 +    data.appendArray([80, 75, 3, 4, 20, 0, 0, 0, 0, 0]);
 +    if(entry.data) {
 +      length = entry.data.length
 +    }
 +    data.appendUInt32LE(date2DosTime(entry.date));
 +    data.appendUInt32LE(entry.data ? crc32(entry.data) : 0);
 +    data.appendUInt32LE(length);
 +    data.appendUInt32LE(length);
 +    data.appendUInt16LE(entry.filename.length);
 +    data.appendUInt16LE(0);
 +    data.appendString(entry.filename);
 +    if(entry.data) {
 +      data.appendByteArray(entry.data)
 +    }
 +    return data
 +  }
 +  function writeCODEntry(entry, offset) {
 +    var data = new core.ByteArrayWriter("utf8"), length = 0;
 +    data.appendArray([80, 75, 1, 2, 20, 0, 20, 0, 0, 0, 0, 0]);
 +    if(entry.data) {
 +      length = entry.data.length
 +    }
 +    data.appendUInt32LE(date2DosTime(entry.date));
 +    data.appendUInt32LE(entry.data ? crc32(entry.data) : 0);
 +    data.appendUInt32LE(length);
 +    data.appendUInt32LE(length);
 +    data.appendUInt16LE(entry.filename.length);
 +    data.appendArray([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
 +    data.appendUInt32LE(offset);
 +    data.appendString(entry.filename);
 +    return data
 +  }
 +  function loadAllEntries(position, callback) {
 +    if(position === entries.length) {
 +      callback(null);
 +      return
 +    }
 +    var entry = entries[position];
 +    if(entry.data !== null) {
 +      loadAllEntries(position + 1, callback);
 +      return
 +    }
 +    entry.load(function(err) {
 +      if(err) {
 +        callback(err);
 +        return
 +      }
 +      loadAllEntries(position + 1, callback)
 +    })
 +  }
 +  function createByteArray(successCallback, errorCallback) {
 +    loadAllEntries(0, function(err) {
 +      if(err) {
 +        errorCallback(err);
 +        return
 +      }
 +      var i, e, codoffset, codsize, data = new core.ByteArrayWriter("utf8"), offsets = [0];
 +      for(i = 0;i < entries.length;i += 1) {
 +        data.appendByteArrayWriter(writeEntry(entries[i]));
 +        offsets.push(data.getLength())
 +      }
 +      codoffset = data.getLength();
 +      for(i = 0;i < entries.length;i += 1) {
 +        e = entries[i];
 +        data.appendByteArrayWriter(writeCODEntry(e, offsets[i]))
 +      }
 +      codsize = data.getLength() - codoffset;
 +      data.appendArray([80, 75, 5, 6, 0, 0, 0, 0]);
 +      data.appendUInt16LE(entries.length);
 +      data.appendUInt16LE(entries.length);
 +      data.appendUInt32LE(codsize);
 +      data.appendUInt32LE(codoffset);
 +      data.appendArray([0, 0]);
 +      successCallback(data.getByteArray())
 +    })
 +  }
 +  function writeAs(newurl, callback) {
 +    createByteArray(function(data) {
 +      runtime.writeFile(newurl, data, callback)
 +    }, callback)
 +  }
 +  function write(callback) {
 +    writeAs(url, callback)
 +  }
 +  this.load = load;
 +  this.save = save;
 +  this.remove = remove;
 +  this.write = write;
 +  this.writeAs = writeAs;
 +  this.createByteArray = createByteArray;
 +  this.loadContentXmlAsFragments = loadContentXmlAsFragments;
 +  this.loadAsString = loadAsString;
 +  this.loadAsDOM = loadAsDOM;
 +  this.loadAsDataURL = loadAsDataURL;
 +  this.getEntries = function() {
 +    return entries.slice()
 +  };
 +  filesize = -1;
 +  if(entriesReadCallback === null) {
 +    entries = [];
 +    return
 +  }
 +  runtime.getFileSize(url, function(size) {
 +    filesize = size;
 +    if(filesize < 0) {
 +      entriesReadCallback("File '" + url + "' cannot be read.", zip)
 +    }else {
 +      runtime.read(url, filesize - 22, 22, function(err, data) {
 +        if(err || (entriesReadCallback === null || data === null)) {
 +          entriesReadCallback(err, zip)
 +        }else {
 +          handleCentralDirectoryEnd(data, entriesReadCallback)
 +        }
 +      })
 +    }
 +  })
 +};
- gui.Avatar = function Avatar(parentElement, avatarInitiallyVisible) {
-   var self = this, handle, image, pendingImageUrl, displayShown = "block", displayHidden = "none";
-   this.setColor = function(color) {
-     image.style.borderColor = color
-   };
-   this.setImageUrl = function(url) {
-     if(self.isVisible()) {
-       image.src = url
++xmldom.LSSerializerFilter = function LSSerializerFilter() {
++};
++xmldom.LSSerializerFilter.prototype.acceptNode = function(node) {
++};
++/*
++
++ Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
++
++ @licstart
++ The JavaScript code in this page is free software: you can redistribute it
++ and/or modify it under the terms of the GNU Affero General Public License
++ (GNU AGPL) as published by the Free Software Foundation, either version 3 of
++ the License, or (at your option) any later version.  The code is distributed
++ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
++
++ You should have received a copy of the GNU Affero General Public License
++ along with this code.  If not, see <http://www.gnu.org/licenses/>.
++
++ As additional permission under GNU AGPL version 3 section 7, you
++ may distribute non-source (e.g., minimized or compacted) forms of
++ that code without the copy of the GNU GPL normally required by
++ section 4, provided you include this license notice and a URL
++ through which recipients can access the Corresponding Source.
++
++ As a special exception to the AGPL, any HTML file which merely makes function
++ calls to this code, and for that purpose includes it by reference shall be
++ deemed a separate work for copyright law purposes. In addition, the copyright
++ holders of this code give you permission to combine this code with free
++ software libraries that are released under the GNU LGPL. You may copy and
++ distribute such a system following the terms of the GNU AGPL for this code
++ and the LGPL for the libraries. If you modify this code, you may extend this
++ exception to your version of the code, but you are not obligated to do so.
++ If you do not wish to do so, delete this exception statement from your
++ version.
++
++ This license applies to this entire compilation.
++ @licend
++ @source: http://www.webodf.org/
++ @source: https://github.com/kogmbh/WebODF/
++*/
++odf.OdfNodeFilter = function OdfNodeFilter() {
++  this.acceptNode = function(node) {
++    var result;
++    if(node.namespaceURI === "http://www.w3.org/1999/xhtml") {
++      result = NodeFilter.FILTER_SKIP
 +    }else {
-       pendingImageUrl = url
-     }
-   };
-   this.isVisible = function() {
-     return handle.style.display === displayShown
-   };
-   this.show = function() {
-     if(pendingImageUrl) {
-       image.src = pendingImageUrl;
-       pendingImageUrl = undefined
-     }
-     handle.style.display = displayShown
-   };
-   this.hide = function() {
-     handle.style.display = displayHidden
-   };
-   this.markAsFocussed = function(isFocussed) {
-     handle.className = isFocussed ? "active" : ""
-   };
-   this.destroy = function(callback) {
-     parentElement.removeChild(handle);
-     callback()
-   };
-   function init() {
-     var document = (parentElement.ownerDocument), htmlns = document.documentElement.namespaceURI;
-     handle = (document.createElementNS(htmlns, "div"));
-     image = (document.createElementNS(htmlns, "img"));
-     image.width = 64;
-     image.height = 64;
-     handle.appendChild(image);
-     handle.style.width = "64px";
-     handle.style.height = "70px";
-     handle.style.position = "absolute";
-     handle.style.top = "-80px";
-     handle.style.left = "-34px";
-     handle.style.display = avatarInitiallyVisible ? displayShown : displayHidden;
-     parentElement.appendChild(handle)
-   }
-   init()
- };
- gui.EditInfoHandle = function EditInfoHandle(parentElement) {
-   var edits = [], handle, document = (parentElement.ownerDocument), htmlns = document.documentElement.namespaceURI, editinfons = "urn:webodf:names:editinfo";
-   function renderEdits() {
-     var i, infoDiv, colorSpan, authorSpan, timeSpan;
-     handle.innerHTML = "";
-     for(i = 0;i < edits.length;i += 1) {
-       infoDiv = document.createElementNS(htmlns, "div");
-       infoDiv.className = "editInfo";
-       colorSpan = document.createElementNS(htmlns, "span");
-       colorSpan.className = "editInfoColor";
-       colorSpan.setAttributeNS(editinfons, "editinfo:memberid", edits[i].memberid);
-       authorSpan = document.createElementNS(htmlns, "span");
-       authorSpan.className = "editInfoAuthor";
-       authorSpan.setAttributeNS(editinfons, "editinfo:memberid", edits[i].memberid);
-       timeSpan = document.createElementNS(htmlns, "span");
-       timeSpan.className = "editInfoTime";
-       timeSpan.setAttributeNS(editinfons, "editinfo:memberid", edits[i].memberid);
-       timeSpan.innerHTML = edits[i].time;
-       infoDiv.appendChild(colorSpan);
-       infoDiv.appendChild(authorSpan);
-       infoDiv.appendChild(timeSpan);
-       handle.appendChild(infoDiv)
-     }
-   }
-   this.setEdits = function(editArray) {
-     edits = editArray;
-     renderEdits()
-   };
-   this.show = function() {
-     handle.style.display = "block"
-   };
-   this.hide = function() {
-     handle.style.display = "none"
-   };
-   this.destroy = function(callback) {
-     parentElement.removeChild(handle);
-     callback()
-   };
-   function init() {
-     handle = (document.createElementNS(htmlns, "div"));
-     handle.setAttribute("class", "editInfoHandle");
-     handle.style.display = "none";
-     parentElement.appendChild(handle)
-   }
-   init()
- };
- /*
- 
-  Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
- 
-  @licstart
-  The JavaScript code in this page is free software: you can redistribute it
-  and/or modify it under the terms of the GNU Affero General Public License
-  (GNU AGPL) as published by the Free Software Foundation, either version 3 of
-  the License, or (at your option) any later version.  The code is distributed
-  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
- 
-  You should have received a copy of the GNU Affero General Public License
-  along with this code.  If not, see <http://www.gnu.org/licenses/>.
- 
-  As additional permission under GNU AGPL version 3 section 7, you
-  may distribute non-source (e.g., minimized or compacted) forms of
-  that code without the copy of the GNU GPL normally required by
-  section 4, provided you include this license notice and a URL
-  through which recipients can access the Corresponding Source.
- 
-  As a special exception to the AGPL, any HTML file which merely makes function
-  calls to this code, and for that purpose includes it by reference shall be
-  deemed a separate work for copyright law purposes. In addition, the copyright
-  holders of this code give you permission to combine this code with free
-  software libraries that are released under the GNU LGPL. You may copy and
-  distribute such a system following the terms of the GNU AGPL for this code
-  and the LGPL for the libraries. If you modify this code, you may extend this
-  exception to your version of the code, but you are not obligated to do so.
-  If you do not wish to do so, delete this exception statement from your
-  version.
- 
-  This license applies to this entire compilation.
-  @licend
-  @source: http://www.webodf.org/
-  @source: https://github.com/kogmbh/WebODF/
- */
- gui.KeyboardHandler = function KeyboardHandler() {
-   var modifier = gui.KeyboardHandler.Modifier, defaultBinding = null, bindings = {};
-   function getModifiers(e) {
-     var modifiers = modifier.None;
-     if(e.metaKey) {
-       modifiers |= modifier.Meta
-     }
-     if(e.ctrlKey) {
-       modifiers |= modifier.Ctrl
-     }
-     if(e.altKey) {
-       modifiers |= modifier.Alt
-     }
-     if(e.shiftKey) {
-       modifiers |= modifier.Shift
-     }
-     return modifiers
-   }
-   function getKeyCombo(keyCode, modifiers) {
-     if(!modifiers) {
-       modifiers = modifier.None
-     }
-     return keyCode + ":" + modifiers
-   }
-   this.setDefault = function(callback) {
-     defaultBinding = callback
-   };
-   this.bind = function(keyCode, modifiers, callback) {
-     var keyCombo = getKeyCombo(keyCode, modifiers);
-     runtime.assert(bindings.hasOwnProperty(keyCombo) === false, "tried to overwrite the callback handler of key combo: " + keyCombo);
-     bindings[keyCombo] = callback
-   };
-   this.unbind = function(keyCode, modifiers) {
-     var keyCombo = getKeyCombo(keyCode, modifiers);
-     delete bindings[keyCombo]
-   };
-   this.reset = function() {
-     defaultBinding = null;
-     bindings = {}
-   };
-   this.handleEvent = function(e) {
-     var keyCombo = getKeyCombo(e.keyCode, getModifiers(e)), callback = bindings[keyCombo], handled = false;
-     if(callback) {
-       handled = callback()
-     }else {
-       if(defaultBinding !== null) {
-         handled = defaultBinding(e)
-       }
-     }
-     if(handled) {
-       if(e.preventDefault) {
-         e.preventDefault()
-       }else {
-         e.returnValue = false
-       }
++      if(node.namespaceURI && node.namespaceURI.match(/^urn:webodf:/)) {
++        result = NodeFilter.FILTER_REJECT
++      }else {
++        result = NodeFilter.FILTER_ACCEPT
++      }
 +    }
++    return result
 +  }
 +};
- gui.KeyboardHandler.Modifier = {None:0, Meta:1, Ctrl:2, Alt:4, CtrlAlt:6, Shift:8, MetaShift:9, CtrlShift:10, AltShift:12};
- gui.KeyboardHandler.KeyCode = {Backspace:8, Tab:9, Clear:12, Enter:13, End:35, Home:36, Left:37, Up:38, Right:39, Down:40, Delete:46, A:65, B:66, C:67, D:68, E:69, F:70, G:71, H:72, I:73, J:74, K:75, L:76, M:77, N:78, O:79, P:80, Q:81, R:82, S:83, T:84, U:85, V:86, W:87, X:88, Y:89, Z:90};
- (function() {
-   return gui.KeyboardHandler
- })();
 +/*
 +
 + Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
 +odf.Namespaces = {namespaceMap:{db:"urn:oasis:names:tc:opendocument:xmlns:database:1.0", dc:"http://purl.org/dc/elements/1.1/", dr3d:"urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0", draw:"urn:oasis:names:tc:opendocument:xmlns:drawing:1.0", chart:"urn:oasis:names:tc:opendocument:xmlns:chart:1.0", fo:"urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0", form:"urn:oasis:names:tc:opendocument:xmlns:form:1.0", meta:"urn:oasis:names:tc:opendocument:xmlns:meta:1.0", number:"urn:oasis [...]
 +office:"urn:oasis:names:tc:opendocument:xmlns:office:1.0", presentation:"urn:oasis:names:tc:opendocument:xmlns:presentation:1.0", style:"urn:oasis:names:tc:opendocument:xmlns:style:1.0", svg:"urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0", table:"urn:oasis:names:tc:opendocument:xmlns:table:1.0", text:"urn:oasis:names:tc:opendocument:xmlns:text:1.0", xlink:"http://www.w3.org/1999/xlink", xml:"http://www.w3.org/XML/1998/namespace"}, prefixMap:{}, dbns:"urn:oasis:names:tc:opendo [...]
 +dcns:"http://purl.org/dc/elements/1.1/", dr3dns:"urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0", drawns:"urn:oasis:names:tc:opendocument:xmlns:drawing:1.0", chartns:"urn:oasis:names:tc:opendocument:xmlns:chart:1.0", fons:"urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0", formns:"urn:oasis:names:tc:opendocument:xmlns:form:1.0", metans:"urn:oasis:names:tc:opendocument:xmlns:meta:1.0", numberns:"urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0", officens:"urn:oasis:names:tc [...]
 +presentationns:"urn:oasis:names:tc:opendocument:xmlns:presentation:1.0", stylens:"urn:oasis:names:tc:opendocument:xmlns:style:1.0", svgns:"urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0", tablens:"urn:oasis:names:tc:opendocument:xmlns:table:1.0", textns:"urn:oasis:names:tc:opendocument:xmlns:text:1.0", xlinkns:"http://www.w3.org/1999/xlink", xmlns:"http://www.w3.org/XML/1998/namespace"};
 +(function() {
 +  var map = odf.Namespaces.namespaceMap, pmap = odf.Namespaces.prefixMap, prefix;
 +  for(prefix in map) {
 +    if(map.hasOwnProperty(prefix)) {
 +      pmap[map[prefix]] = prefix
 +    }
 +  }
 +})();
 +odf.Namespaces.forEachPrefix = function forEachPrefix(cb) {
 +  var ns = odf.Namespaces.namespaceMap, prefix;
 +  for(prefix in ns) {
 +    if(ns.hasOwnProperty(prefix)) {
 +      cb(prefix, ns[prefix])
 +    }
 +  }
 +};
 +odf.Namespaces.lookupNamespaceURI = function lookupNamespaceURI(prefix) {
 +  var r = null;
 +  if(odf.Namespaces.namespaceMap.hasOwnProperty(prefix)) {
 +    r = (odf.Namespaces.namespaceMap[prefix])
 +  }
 +  return r
 +};
 +odf.Namespaces.lookupPrefix = function lookupPrefix(namespaceURI) {
 +  var map = odf.Namespaces.prefixMap;
 +  return map.hasOwnProperty(namespaceURI) ? map[namespaceURI] : null
 +};
 +odf.Namespaces.lookupNamespaceURI.lookupNamespaceURI = odf.Namespaces.lookupNamespaceURI;
- /*
- 
-  Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
- 
-  @licstart
-  The JavaScript code in this page is free software: you can redistribute it
-  and/or modify it under the terms of the GNU Affero General Public License
-  (GNU AGPL) as published by the Free Software Foundation, either version 3 of
-  the License, or (at your option) any later version.  The code is distributed
-  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
- 
-  You should have received a copy of the GNU Affero General Public License
-  along with this code.  If not, see <http://www.gnu.org/licenses/>.
- 
-  As additional permission under GNU AGPL version 3 section 7, you
-  may distribute non-source (e.g., minimized or compacted) forms of
-  that code without the copy of the GNU GPL normally required by
-  section 4, provided you include this license notice and a URL
-  through which recipients can access the Corresponding Source.
- 
-  As a special exception to the AGPL, any HTML file which merely makes function
-  calls to this code, and for that purpose includes it by reference shall be
-  deemed a separate work for copyright law purposes. In addition, the copyright
-  holders of this code give you permission to combine this code with free
-  software libraries that are released under the GNU LGPL. You may copy and
-  distribute such a system following the terms of the GNU AGPL for this code
-  and the LGPL for the libraries. If you modify this code, you may extend this
-  exception to your version of the code, but you are not obligated to do so.
-  If you do not wish to do so, delete this exception statement from your
-  version.
- 
-  This license applies to this entire compilation.
-  @licend
-  @source: http://www.webodf.org/
-  @source: https://github.com/kogmbh/WebODF/
- */
- runtime.loadClass("core.DomUtils");
- runtime.loadClass("odf.Namespaces");
- odf.OdfUtils = function OdfUtils() {
-   var textns = odf.Namespaces.textns, drawns = odf.Namespaces.drawns, whitespaceOnly = /^\s*$/, domUtils = new core.DomUtils;
-   function isImage(e) {
-     var name = e && e.localName;
-     return name === "image" && e.namespaceURI === drawns
-   }
-   this.isImage = isImage;
-   function isCharacterFrame(e) {
-     return e !== null && (e.nodeType === Node.ELEMENT_NODE && (e.localName === "frame" && (e.namespaceURI === drawns && (e).getAttributeNS(textns, "anchor-type") === "as-char")))
++xmldom.XPathIterator = function XPathIterator() {
++};
++xmldom.XPathIterator.prototype.next = function() {
++};
++xmldom.XPathIterator.prototype.reset = function() {
++};
++xmldom.XPathAtom;
++function createXPathSingleton() {
++  var createXPathPathIterator, parsePredicates;
++  function isSmallestPositive(a, b, c) {
++    return a !== -1 && ((a < b || b === -1) && (a < c || c === -1))
 +  }
-   this.isCharacterFrame = isCharacterFrame;
-   function isAnnotation(e) {
-     var name = e && e.localName;
-     return name === "annotation" && e.namespaceURI === odf.Namespaces.officens
++  function parseXPathStep(xpath, pos, end, steps) {
++    var location = "", predicates = [], brapos = xpath.indexOf("[", pos), slapos = xpath.indexOf("/", pos), eqpos = xpath.indexOf("=", pos);
++    if(isSmallestPositive(slapos, brapos, eqpos)) {
++      location = xpath.substring(pos, slapos);
++      pos = slapos + 1
++    }else {
++      if(isSmallestPositive(brapos, slapos, eqpos)) {
++        location = xpath.substring(pos, brapos);
++        pos = parsePredicates(xpath, brapos, predicates)
++      }else {
++        if(isSmallestPositive(eqpos, slapos, brapos)) {
++          location = xpath.substring(pos, eqpos);
++          pos = eqpos
++        }else {
++          location = xpath.substring(pos, end);
++          pos = end
++        }
++      }
++    }
++    steps.push({location:location, predicates:predicates});
++    return pos
 +  }
-   function isAnnotationWrapper(e) {
-     var name = e && e.localName;
-     return name === "div" && (e).className === "annotationWrapper"
-   }
-   function isInlineRoot(e) {
-     return isAnnotation(e) || isAnnotationWrapper(e)
-   }
-   this.isInlineRoot = isInlineRoot;
-   this.isTextSpan = function(e) {
-     var name = e && e.localName;
-     return name === "span" && e.namespaceURI === textns
-   };
-   function isParagraph(e) {
-     var name = e && e.localName;
-     return(name === "p" || name === "h") && e.namespaceURI === textns
-   }
-   this.isParagraph = isParagraph;
-   function getParagraphElement(node) {
-     while(node && !isParagraph(node)) {
-       node = node.parentNode
++  function parseXPath(xpath) {
++    var steps = [], p = 0, end = xpath.length, value;
++    while(p < end) {
++      p = parseXPathStep(xpath, p, end, steps);
++      if(p < end && xpath[p] === "=") {
++        value = xpath.substring(p + 1, end);
++        if(value.length > 2 && (value[0] === "'" || value[0] === '"')) {
++          value = value.slice(1, value.length - 1)
++        }else {
++          try {
++            value = parseInt(value, 10)
++          }catch(ignore) {
++          }
++        }
++        p = end
++      }
 +    }
-     return node
++    return{steps:steps, value:value}
 +  }
-   this.getParagraphElement = getParagraphElement;
-   this.isWithinTrackedChanges = function(node, container) {
-     while(node && node !== container) {
-       if(node.namespaceURI === textns && node.localName === "tracked-changes") {
-         return true
++  parsePredicates = function parsePredicates(xpath, start, predicates) {
++    var pos = start, l = xpath.length, depth = 0;
++    while(pos < l) {
++      if(xpath[pos] === "]") {
++        depth -= 1;
++        if(depth <= 0) {
++          predicates.push(parseXPath(xpath.substring(start, pos)))
++        }
++      }else {
++        if(xpath[pos] === "[") {
++          if(depth <= 0) {
++            start = pos + 1
++          }
++          depth += 1
++        }
 +      }
-       node = node.parentNode
++      pos += 1
 +    }
-     return false
-   };
-   this.isListItem = function(e) {
-     var name = e && e.localName;
-     return name === "list-item" && e.namespaceURI === textns
-   };
-   this.isLineBreak = function(e) {
-     var name = e && e.localName;
-     return name === "line-break" && e.namespaceURI === textns
++    return pos
 +  };
-   function isODFWhitespace(text) {
-     return/^[ \t\r\n]+$/.test(text)
-   }
-   this.isODFWhitespace = isODFWhitespace;
-   function isGroupingElement(n) {
-     if(n === null || n.nodeType !== Node.ELEMENT_NODE) {
-       return false
++  function XPathNodeIterator() {
++    var node = null, done = false;
++    this.setNode = function setNode(n) {
++      node = n
++    };
++    this.reset = function() {
++      done = false
++    };
++    this.next = function next() {
++      var val = done ? null : node;
++      done = true;
++      return val
 +    }
-     var e = (n), localName = e.localName;
-     return/^(span|p|h|a|meta)$/.test(localName) && e.namespaceURI === textns || localName === "span" && e.className === "annotationHighlight"
 +  }
-   this.isGroupingElement = isGroupingElement;
-   function isCharacterElement(e) {
-     var n = e && e.localName, ns, r = false;
-     if(n) {
-       ns = e.namespaceURI;
-       if(ns === textns) {
-         r = n === "s" || (n === "tab" || n === "line-break")
++  function AttributeIterator(it, namespace, localName) {
++    this.reset = function reset() {
++      it.reset()
++    };
++    this.next = function next() {
++      var node = it.next();
++      while(node) {
++        if(node.nodeType === Node.ELEMENT_NODE) {
++          node = (node).getAttributeNodeNS(namespace, localName)
++        }
++        if(node) {
++          return node
++        }
++        node = it.next()
 +      }
++      return node
 +    }
-     return r
-   }
-   this.isCharacterElement = isCharacterElement;
-   function isAnchoredAsCharacterElement(e) {
-     return isCharacterElement(e) || (isCharacterFrame(e) || isInlineRoot(e))
 +  }
-   this.isAnchoredAsCharacterElement = isAnchoredAsCharacterElement;
-   function isSpaceElement(e) {
-     var n = e && e.localName, ns, r = false;
-     if(n) {
-       ns = e.namespaceURI;
-       if(ns === textns) {
-         r = n === "s"
++  function AllChildElementIterator(it, recurse) {
++    var root = it.next(), node = null;
++    this.reset = function reset() {
++      it.reset();
++      root = it.next();
++      node = null
++    };
++    this.next = function next() {
++      while(root) {
++        if(node) {
++          if(recurse && node.firstChild) {
++            node = node.firstChild
++          }else {
++            while(!node.nextSibling && node !== root) {
++              node = node.parentNode
++            }
++            if(node === root) {
++              root = it.next()
++            }else {
++              node = node.nextSibling
++            }
++          }
++        }else {
++          do {
++            node = root.firstChild;
++            if(!node) {
++              root = it.next()
++            }
++          }while(root && !node)
++        }
++        if(node && node.nodeType === Node.ELEMENT_NODE) {
++          return node
++        }
 +      }
++      return null
 +    }
-     return r
 +  }
-   this.isSpaceElement = isSpaceElement;
-   function firstChild(node) {
-     while(node.firstChild !== null && isGroupingElement(node)) {
-       node = node.firstChild
++  function ConditionIterator(it, condition) {
++    this.reset = function reset() {
++      it.reset()
++    };
++    this.next = function next() {
++      var n = it.next();
++      while(n && !condition(n)) {
++        n = it.next()
++      }
++      return n
 +    }
-     return node
 +  }
-   this.firstChild = firstChild;
-   function lastChild(node) {
-     while(node.lastChild !== null && isGroupingElement(node)) {
-       node = node.lastChild
-     }
-     return node
++  function createNodenameFilter(it, name, namespaceResolver) {
++    var s = name.split(":", 2), namespace = namespaceResolver(s[0]), localName = s[1];
++    return new ConditionIterator(it, function(node) {
++      return node.localName === localName && node.namespaceURI === namespace
++    })
 +  }
-   this.lastChild = lastChild;
-   function previousNode(node) {
-     while(!isParagraph(node) && node.previousSibling === null) {
-       node = (node.parentNode)
++  function createPredicateFilteredIterator(it, p, namespaceResolver) {
++    var nit = new XPathNodeIterator, pit = createXPathPathIterator(nit, p, namespaceResolver), value = p.value;
++    if(value === undefined) {
++      return new ConditionIterator(it, function(node) {
++        nit.setNode(node);
++        pit.reset();
++        return pit.next() !== null
++      })
 +    }
-     return isParagraph(node) ? null : lastChild((node.previousSibling))
++    return new ConditionIterator(it, function(node) {
++      nit.setNode(node);
++      pit.reset();
++      var n = pit.next();
++      return n ? n.nodeValue === value : false
++    })
 +  }
-   this.previousNode = previousNode;
-   function nextNode(node) {
-     while(!isParagraph(node) && node.nextSibling === null) {
-       node = (node.parentNode)
-     }
-     return isParagraph(node) ? null : firstChild((node.nextSibling))
++  function item(p, i) {
++    return p[i]
 +  }
-   this.nextNode = nextNode;
-   function scanLeftForNonSpace(node) {
-     var r = false, text;
-     while(node) {
-       if(node.nodeType === Node.TEXT_NODE) {
-         text = (node);
-         if(text.length === 0) {
-           node = previousNode(text)
-         }else {
-           return!isODFWhitespace(text.data.substr(text.length - 1, 1))
-         }
++  createXPathPathIterator = function createXPathPathIterator(it, xpath, namespaceResolver) {
++    var i, j, step, location, s, p, ns;
++    for(i = 0;i < xpath.steps.length;i += 1) {
++      step = xpath.steps[i];
++      location = step.location;
++      if(location === "") {
++        it = new AllChildElementIterator(it, false)
 +      }else {
-         if(isAnchoredAsCharacterElement(node)) {
-           r = isSpaceElement(node) === false;
-           node = null
++        if(location[0] === "@") {
++          s = location.substr(1).split(":", 2);
++          ns = namespaceResolver(s[0]);
++          if(!ns) {
++            throw"No namespace associated with the prefix " + s[0];
++          }
++          it = new AttributeIterator(it, ns, s[1])
 +        }else {
-           node = previousNode(node)
++          if(location !== ".") {
++            it = new AllChildElementIterator(it, false);
++            if(location.indexOf(":") !== -1) {
++              it = createNodenameFilter(it, location, namespaceResolver)
++            }
++          }
 +        }
 +      }
++      for(j = 0;j < step.predicates.length;j += 1) {
++        p = item(step.predicates, j);
++        it = createPredicateFilteredIterator(it, p, namespaceResolver)
++      }
 +    }
-     return r
-   }
-   this.scanLeftForNonSpace = scanLeftForNonSpace;
-   function lookLeftForCharacter(node) {
-     var text, r = 0, tl = 0;
-     if(node.nodeType === Node.TEXT_NODE) {
-       tl = (node).length
++    return it
++  };
++  function fallback(node, xpath, namespaceResolver) {
++    var it = new XPathNodeIterator, i, nodelist, parsedXPath;
++    it.setNode(node);
++    parsedXPath = parseXPath(xpath);
++    it = createXPathPathIterator(it, parsedXPath, namespaceResolver);
++    nodelist = [];
++    i = it.next();
++    while(i) {
++      nodelist.push(i);
++      i = it.next()
 +    }
-     if(tl > 0) {
-       text = (node).data;
-       if(!isODFWhitespace(text.substr(tl - 1, 1))) {
-         r = 1
-       }else {
-         if(tl === 1) {
-           r = scanLeftForNonSpace(previousNode(node)) ? 2 : 0
-         }else {
-           r = isODFWhitespace(text.substr(tl - 2, 1)) ? 0 : 2
-         }
-       }
++    return nodelist
++  }
++  function getODFElementsWithXPath(node, xpath, namespaceResolver) {
++    var doc = node.ownerDocument, nodes, elements = [], n = null;
++    if(!doc || typeof doc.evaluate !== "function") {
++      elements = fallback(node, xpath, namespaceResolver)
 +    }else {
-       if(isAnchoredAsCharacterElement(node)) {
-         r = 1
++      nodes = doc.evaluate(xpath, node, namespaceResolver, XPathResult.UNORDERED_NODE_ITERATOR_TYPE, null);
++      n = nodes.iterateNext();
++      while(n !== null) {
++        if(n.nodeType === Node.ELEMENT_NODE) {
++          elements.push(n)
++        }
++        n = nodes.iterateNext()
 +      }
 +    }
-     return r
++    return elements
 +  }
-   this.lookLeftForCharacter = lookLeftForCharacter;
-   function lookRightForCharacter(node) {
-     var r = false, l = 0;
-     if(node && node.nodeType === Node.TEXT_NODE) {
-       l = (node).length
-     }
-     if(l > 0) {
-       r = !isODFWhitespace((node).data.substr(0, 1))
-     }else {
-       if(isAnchoredAsCharacterElement(node)) {
-         r = true
-       }
++  return{getODFElementsWithXPath:getODFElementsWithXPath}
++}
++xmldom.XPath = createXPathSingleton();
++/*
++
++ Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
++
++ @licstart
++ The JavaScript code in this page is free software: you can redistribute it
++ and/or modify it under the terms of the GNU Affero General Public License
++ (GNU AGPL) as published by the Free Software Foundation, either version 3 of
++ the License, or (at your option) any later version.  The code is distributed
++ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
++
++ You should have received a copy of the GNU Affero General Public License
++ along with this code.  If not, see <http://www.gnu.org/licenses/>.
++
++ As additional permission under GNU AGPL version 3 section 7, you
++ may distribute non-source (e.g., minimized or compacted) forms of
++ that code without the copy of the GNU GPL normally required by
++ section 4, provided you include this license notice and a URL
++ through which recipients can access the Corresponding Source.
++
++ As a special exception to the AGPL, any HTML file which merely makes function
++ calls to this code, and for that purpose includes it by reference shall be
++ deemed a separate work for copyright law purposes. In addition, the copyright
++ holders of this code give you permission to combine this code with free
++ software libraries that are released under the GNU LGPL. You may copy and
++ distribute such a system following the terms of the GNU AGPL for this code
++ and the LGPL for the libraries. If you modify this code, you may extend this
++ exception to your version of the code, but you are not obligated to do so.
++ If you do not wish to do so, delete this exception statement from your
++ version.
++
++ This license applies to this entire compilation.
++ @licend
++ @source: http://www.webodf.org/
++ @source: https://github.com/kogmbh/WebODF/
++*/
++odf.StyleInfo = function StyleInfo() {
++  var chartns = odf.Namespaces.chartns, dbns = odf.Namespaces.dbns, dr3dns = odf.Namespaces.dr3dns, drawns = odf.Namespaces.drawns, formns = odf.Namespaces.formns, numberns = odf.Namespaces.numberns, officens = odf.Namespaces.officens, presentationns = odf.Namespaces.presentationns, stylens = odf.Namespaces.stylens, tablens = odf.Namespaces.tablens, textns = odf.Namespaces.textns, nsprefixes = {"urn:oasis:names:tc:opendocument:xmlns:chart:1.0":"chart:", "urn:oasis:names:tc:opendocument: [...]
++  "urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0":"dr3d:", "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0":"draw:", "urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0":"fo:", "urn:oasis:names:tc:opendocument:xmlns:form:1.0":"form:", "urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0":"number:", "urn:oasis:names:tc:opendocument:xmlns:office:1.0":"office:", "urn:oasis:names:tc:opendocument:xmlns:presentation:1.0":"presentation:", "urn:oasis:names:tc:opendocument:xmlns:sty [...]
++  "urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0":"svg:", "urn:oasis:names:tc:opendocument:xmlns:table:1.0":"table:", "urn:oasis:names:tc:opendocument:xmlns:text:1.0":"chart:", "http://www.w3.org/XML/1998/namespace":"xml:"}, elementstyles = {"text":[{ens:stylens, en:"tab-stop", ans:stylens, a:"leader-text-style"}, {ens:stylens, en:"drop-cap", ans:stylens, a:"style-name"}, {ens:textns, en:"notes-configuration", ans:textns, a:"citation-body-style-name"}, {ens:textns, en:"notes- [...]
++  ans:textns, a:"citation-style-name"}, {ens:textns, en:"a", ans:textns, a:"style-name"}, {ens:textns, en:"alphabetical-index", ans:textns, a:"style-name"}, {ens:textns, en:"linenumbering-configuration", ans:textns, a:"style-name"}, {ens:textns, en:"list-level-style-number", ans:textns, a:"style-name"}, {ens:textns, en:"ruby-text", ans:textns, a:"style-name"}, {ens:textns, en:"span", ans:textns, a:"style-name"}, {ens:textns, en:"a", ans:textns, a:"visited-style-name"}, {ens:stylens, en: [...]
++  ans:stylens, a:"text-line-through-text-style"}, {ens:textns, en:"alphabetical-index-source", ans:textns, a:"main-entry-style-name"}, {ens:textns, en:"index-entry-bibliography", ans:textns, a:"style-name"}, {ens:textns, en:"index-entry-chapter", ans:textns, a:"style-name"}, {ens:textns, en:"index-entry-link-end", ans:textns, a:"style-name"}, {ens:textns, en:"index-entry-link-start", ans:textns, a:"style-name"}, {ens:textns, en:"index-entry-page-number", ans:textns, a:"style-name"}, {en [...]
++  en:"index-entry-span", ans:textns, a:"style-name"}, {ens:textns, en:"index-entry-tab-stop", ans:textns, a:"style-name"}, {ens:textns, en:"index-entry-text", ans:textns, a:"style-name"}, {ens:textns, en:"index-title-template", ans:textns, a:"style-name"}, {ens:textns, en:"list-level-style-bullet", ans:textns, a:"style-name"}, {ens:textns, en:"outline-level-style", ans:textns, a:"style-name"}], "paragraph":[{ens:drawns, en:"caption", ans:drawns, a:"text-style-name"}, {ens:drawns, en:"ci [...]
++  a:"text-style-name"}, {ens:drawns, en:"connector", ans:drawns, a:"text-style-name"}, {ens:drawns, en:"control", ans:drawns, a:"text-style-name"}, {ens:drawns, en:"custom-shape", ans:drawns, a:"text-style-name"}, {ens:drawns, en:"ellipse", ans:drawns, a:"text-style-name"}, {ens:drawns, en:"frame", ans:drawns, a:"text-style-name"}, {ens:drawns, en:"line", ans:drawns, a:"text-style-name"}, {ens:drawns, en:"measure", ans:drawns, a:"text-style-name"}, {ens:drawns, en:"path", ans:drawns, a: [...]
++  {ens:drawns, en:"polygon", ans:drawns, a:"text-style-name"}, {ens:drawns, en:"polyline", ans:drawns, a:"text-style-name"}, {ens:drawns, en:"rect", ans:drawns, a:"text-style-name"}, {ens:drawns, en:"regular-polygon", ans:drawns, a:"text-style-name"}, {ens:officens, en:"annotation", ans:drawns, a:"text-style-name"}, {ens:formns, en:"column", ans:formns, a:"text-style-name"}, {ens:stylens, en:"style", ans:stylens, a:"next-style-name"}, {ens:tablens, en:"body", ans:tablens, a:"paragraph-s [...]
++  {ens:tablens, en:"even-columns", ans:tablens, a:"paragraph-style-name"}, {ens:tablens, en:"even-rows", ans:tablens, a:"paragraph-style-name"}, {ens:tablens, en:"first-column", ans:tablens, a:"paragraph-style-name"}, {ens:tablens, en:"first-row", ans:tablens, a:"paragraph-style-name"}, {ens:tablens, en:"last-column", ans:tablens, a:"paragraph-style-name"}, {ens:tablens, en:"last-row", ans:tablens, a:"paragraph-style-name"}, {ens:tablens, en:"odd-columns", ans:tablens, a:"paragraph-styl [...]
++  {ens:tablens, en:"odd-rows", ans:tablens, a:"paragraph-style-name"}, {ens:textns, en:"notes-configuration", ans:textns, a:"default-style-name"}, {ens:textns, en:"alphabetical-index-entry-template", ans:textns, a:"style-name"}, {ens:textns, en:"bibliography-entry-template", ans:textns, a:"style-name"}, {ens:textns, en:"h", ans:textns, a:"style-name"}, {ens:textns, en:"illustration-index-entry-template", ans:textns, a:"style-name"}, {ens:textns, en:"index-source-style", ans:textns, a:"s [...]
++  {ens:textns, en:"object-index-entry-template", ans:textns, a:"style-name"}, {ens:textns, en:"p", ans:textns, a:"style-name"}, {ens:textns, en:"table-index-entry-template", ans:textns, a:"style-name"}, {ens:textns, en:"table-of-content-entry-template", ans:textns, a:"style-name"}, {ens:textns, en:"table-index-entry-template", ans:textns, a:"style-name"}, {ens:textns, en:"user-index-entry-template", ans:textns, a:"style-name"}, {ens:stylens, en:"page-layout-properties", ans:stylens, a:" [...]
++  "chart":[{ens:chartns, en:"axis", ans:chartns, a:"style-name"}, {ens:chartns, en:"chart", ans:chartns, a:"style-name"}, {ens:chartns, en:"data-label", ans:chartns, a:"style-name"}, {ens:chartns, en:"data-point", ans:chartns, a:"style-name"}, {ens:chartns, en:"equation", ans:chartns, a:"style-name"}, {ens:chartns, en:"error-indicator", ans:chartns, a:"style-name"}, {ens:chartns, en:"floor", ans:chartns, a:"style-name"}, {ens:chartns, en:"footer", ans:chartns, a:"style-name"}, {ens:char [...]
++  ans:chartns, a:"style-name"}, {ens:chartns, en:"legend", ans:chartns, a:"style-name"}, {ens:chartns, en:"mean-value", ans:chartns, a:"style-name"}, {ens:chartns, en:"plot-area", ans:chartns, a:"style-name"}, {ens:chartns, en:"regression-curve", ans:chartns, a:"style-name"}, {ens:chartns, en:"series", ans:chartns, a:"style-name"}, {ens:chartns, en:"stock-gain-marker", ans:chartns, a:"style-name"}, {ens:chartns, en:"stock-loss-marker", ans:chartns, a:"style-name"}, {ens:chartns, en:"sto [...]
++  ans:chartns, a:"style-name"}, {ens:chartns, en:"subtitle", ans:chartns, a:"style-name"}, {ens:chartns, en:"title", ans:chartns, a:"style-name"}, {ens:chartns, en:"wall", ans:chartns, a:"style-name"}], "section":[{ens:textns, en:"alphabetical-index", ans:textns, a:"style-name"}, {ens:textns, en:"bibliography", ans:textns, a:"style-name"}, {ens:textns, en:"illustration-index", ans:textns, a:"style-name"}, {ens:textns, en:"index-title", ans:textns, a:"style-name"}, {ens:textns, en:"objec [...]
++  ans:textns, a:"style-name"}, {ens:textns, en:"section", ans:textns, a:"style-name"}, {ens:textns, en:"table-of-content", ans:textns, a:"style-name"}, {ens:textns, en:"table-index", ans:textns, a:"style-name"}, {ens:textns, en:"user-index", ans:textns, a:"style-name"}], "ruby":[{ens:textns, en:"ruby", ans:textns, a:"style-name"}], "table":[{ens:dbns, en:"query", ans:dbns, a:"style-name"}, {ens:dbns, en:"table-representation", ans:dbns, a:"style-name"}, {ens:tablens, en:"background", an [...]
++  a:"style-name"}, {ens:tablens, en:"table", ans:tablens, a:"style-name"}], "table-column":[{ens:dbns, en:"column", ans:dbns, a:"style-name"}, {ens:tablens, en:"table-column", ans:tablens, a:"style-name"}], "table-row":[{ens:dbns, en:"query", ans:dbns, a:"default-row-style-name"}, {ens:dbns, en:"table-representation", ans:dbns, a:"default-row-style-name"}, {ens:tablens, en:"table-row", ans:tablens, a:"style-name"}], "table-cell":[{ens:dbns, en:"column", ans:dbns, a:"default-cell-style-n [...]
++  en:"table-column", ans:tablens, a:"default-cell-style-name"}, {ens:tablens, en:"table-row", ans:tablens, a:"default-cell-style-name"}, {ens:tablens, en:"body", ans:tablens, a:"style-name"}, {ens:tablens, en:"covered-table-cell", ans:tablens, a:"style-name"}, {ens:tablens, en:"even-columns", ans:tablens, a:"style-name"}, {ens:tablens, en:"covered-table-cell", ans:tablens, a:"style-name"}, {ens:tablens, en:"even-columns", ans:tablens, a:"style-name"}, {ens:tablens, en:"even-rows", ans:t [...]
++  {ens:tablens, en:"first-column", ans:tablens, a:"style-name"}, {ens:tablens, en:"first-row", ans:tablens, a:"style-name"}, {ens:tablens, en:"last-column", ans:tablens, a:"style-name"}, {ens:tablens, en:"last-row", ans:tablens, a:"style-name"}, {ens:tablens, en:"odd-columns", ans:tablens, a:"style-name"}, {ens:tablens, en:"odd-rows", ans:tablens, a:"style-name"}, {ens:tablens, en:"table-cell", ans:tablens, a:"style-name"}], "graphic":[{ens:dr3dns, en:"cube", ans:drawns, a:"style-name"} [...]
++  en:"extrude", ans:drawns, a:"style-name"}, {ens:dr3dns, en:"rotate", ans:drawns, a:"style-name"}, {ens:dr3dns, en:"scene", ans:drawns, a:"style-name"}, {ens:dr3dns, en:"sphere", ans:drawns, a:"style-name"}, {ens:drawns, en:"caption", ans:drawns, a:"style-name"}, {ens:drawns, en:"circle", ans:drawns, a:"style-name"}, {ens:drawns, en:"connector", ans:drawns, a:"style-name"}, {ens:drawns, en:"control", ans:drawns, a:"style-name"}, {ens:drawns, en:"custom-shape", ans:drawns, a:"style-name [...]
++  en:"ellipse", ans:drawns, a:"style-name"}, {ens:drawns, en:"frame", ans:drawns, a:"style-name"}, {ens:drawns, en:"g", ans:drawns, a:"style-name"}, {ens:drawns, en:"line", ans:drawns, a:"style-name"}, {ens:drawns, en:"measure", ans:drawns, a:"style-name"}, {ens:drawns, en:"page-thumbnail", ans:drawns, a:"style-name"}, {ens:drawns, en:"path", ans:drawns, a:"style-name"}, {ens:drawns, en:"polygon", ans:drawns, a:"style-name"}, {ens:drawns, en:"polyline", ans:drawns, a:"style-name"}, {ens [...]
++  ans:drawns, a:"style-name"}, {ens:drawns, en:"regular-polygon", ans:drawns, a:"style-name"}, {ens:officens, en:"annotation", ans:drawns, a:"style-name"}], "presentation":[{ens:dr3dns, en:"cube", ans:presentationns, a:"style-name"}, {ens:dr3dns, en:"extrude", ans:presentationns, a:"style-name"}, {ens:dr3dns, en:"rotate", ans:presentationns, a:"style-name"}, {ens:dr3dns, en:"scene", ans:presentationns, a:"style-name"}, {ens:dr3dns, en:"sphere", ans:presentationns, a:"style-name"}, {ens: [...]
++  ans:presentationns, a:"style-name"}, {ens:drawns, en:"circle", ans:presentationns, a:"style-name"}, {ens:drawns, en:"connector", ans:presentationns, a:"style-name"}, {ens:drawns, en:"control", ans:presentationns, a:"style-name"}, {ens:drawns, en:"custom-shape", ans:presentationns, a:"style-name"}, {ens:drawns, en:"ellipse", ans:presentationns, a:"style-name"}, {ens:drawns, en:"frame", ans:presentationns, a:"style-name"}, {ens:drawns, en:"g", ans:presentationns, a:"style-name"}, {ens:d [...]
++  ans:presentationns, a:"style-name"}, {ens:drawns, en:"measure", ans:presentationns, a:"style-name"}, {ens:drawns, en:"page-thumbnail", ans:presentationns, a:"style-name"}, {ens:drawns, en:"path", ans:presentationns, a:"style-name"}, {ens:drawns, en:"polygon", ans:presentationns, a:"style-name"}, {ens:drawns, en:"polyline", ans:presentationns, a:"style-name"}, {ens:drawns, en:"rect", ans:presentationns, a:"style-name"}, {ens:drawns, en:"regular-polygon", ans:presentationns, a:"style-na [...]
++  en:"annotation", ans:presentationns, a:"style-name"}], "drawing-page":[{ens:drawns, en:"page", ans:drawns, a:"style-name"}, {ens:presentationns, en:"notes", ans:drawns, a:"style-name"}, {ens:stylens, en:"handout-master", ans:drawns, a:"style-name"}, {ens:stylens, en:"master-page", ans:drawns, a:"style-name"}], "list-style":[{ens:textns, en:"list", ans:textns, a:"style-name"}, {ens:textns, en:"numbered-paragraph", ans:textns, a:"style-name"}, {ens:textns, en:"list-item", ans:textns, a: [...]
++  {ens:stylens, en:"style", ans:stylens, a:"list-style-name"}], "data":[{ens:stylens, en:"style", ans:stylens, a:"data-style-name"}, {ens:stylens, en:"style", ans:stylens, a:"percentage-data-style-name"}, {ens:presentationns, en:"date-time-decl", ans:stylens, a:"data-style-name"}, {ens:textns, en:"creation-date", ans:stylens, a:"data-style-name"}, {ens:textns, en:"creation-time", ans:stylens, a:"data-style-name"}, {ens:textns, en:"database-display", ans:stylens, a:"data-style-name"}, {e [...]
++  en:"date", ans:stylens, a:"data-style-name"}, {ens:textns, en:"editing-duration", ans:stylens, a:"data-style-name"}, {ens:textns, en:"expression", ans:stylens, a:"data-style-name"}, {ens:textns, en:"meta-field", ans:stylens, a:"data-style-name"}, {ens:textns, en:"modification-date", ans:stylens, a:"data-style-name"}, {ens:textns, en:"modification-time", ans:stylens, a:"data-style-name"}, {ens:textns, en:"print-date", ans:stylens, a:"data-style-name"}, {ens:textns, en:"print-time", ans [...]
++  a:"data-style-name"}, {ens:textns, en:"table-formula", ans:stylens, a:"data-style-name"}, {ens:textns, en:"time", ans:stylens, a:"data-style-name"}, {ens:textns, en:"user-defined", ans:stylens, a:"data-style-name"}, {ens:textns, en:"user-field-get", ans:stylens, a:"data-style-name"}, {ens:textns, en:"user-field-input", ans:stylens, a:"data-style-name"}, {ens:textns, en:"variable-get", ans:stylens, a:"data-style-name"}, {ens:textns, en:"variable-input", ans:stylens, a:"data-style-name" [...]
++  en:"variable-set", ans:stylens, a:"data-style-name"}], "page-layout":[{ens:presentationns, en:"notes", ans:stylens, a:"page-layout-name"}, {ens:stylens, en:"handout-master", ans:stylens, a:"page-layout-name"}, {ens:stylens, en:"master-page", ans:stylens, a:"page-layout-name"}]}, elements, xpath = xmldom.XPath;
++  function hasDerivedStyles(odfbody, nsResolver, styleElement) {
++    var nodes, xp, styleName = styleElement.getAttributeNS(stylens, "name"), styleFamily = styleElement.getAttributeNS(stylens, "family");
++    xp = "//style:*[@style:parent-style-name='" + styleName + "'][@style:family='" + styleFamily + "']";
++    nodes = xpath.getODFElementsWithXPath(odfbody, xp, nsResolver);
++    if(nodes.length) {
++      return true
 +    }
-     return r
++    return false
 +  }
-   this.lookRightForCharacter = lookRightForCharacter;
-   function scanLeftForAnyCharacter(node) {
-     var r = false, l;
-     node = node && lastChild(node);
-     while(node) {
-       if(node.nodeType === Node.TEXT_NODE) {
-         l = (node).length
-       }else {
-         l = 0
-       }
-       if(l > 0 && !isODFWhitespace((node).data)) {
-         r = true;
-         break
++  function prefixUsedStyleNames(element, prefix) {
++    var i, stylename, a, e, ns, elname, elns, localName, length = 0;
++    elname = elements[element.localName];
++    if(elname) {
++      elns = elname[element.namespaceURI];
++      if(elns) {
++        length = elns.length
 +      }
-       if(isAnchoredAsCharacterElement(node)) {
-         r = true;
-         break
++    }
++    for(i = 0;i < length;i += 1) {
++      a = (elns[i]);
++      ns = a.ns;
++      localName = a.localname;
++      stylename = element.getAttributeNS(ns, localName);
++      if(stylename) {
++        element.setAttributeNS(ns, nsprefixes[ns] + localName, prefix + stylename)
 +      }
-       node = previousNode(node)
 +    }
-     return r
++    e = element.firstElementChild;
++    while(e) {
++      prefixUsedStyleNames(e, prefix);
++      e = e.nextElementSibling
++    }
 +  }
-   this.scanLeftForAnyCharacter = scanLeftForAnyCharacter;
-   function scanRightForAnyCharacter(node) {
-     var r = false, l;
-     node = node && firstChild(node);
-     while(node) {
-       if(node.nodeType === Node.TEXT_NODE) {
-         l = (node).length
-       }else {
-         l = 0
-       }
-       if(l > 0 && !isODFWhitespace((node).data)) {
-         r = true;
-         break
-       }
-       if(isAnchoredAsCharacterElement(node)) {
-         r = true;
-         break
++  function prefixStyleName(styleElement, prefix) {
++    var stylename = styleElement.getAttributeNS(drawns, "name"), ns;
++    if(stylename) {
++      ns = drawns
++    }else {
++      stylename = styleElement.getAttributeNS(stylens, "name");
++      if(stylename) {
++        ns = stylens
 +      }
-       node = nextNode(node)
 +    }
-     return r
-   }
-   this.scanRightForAnyCharacter = scanRightForAnyCharacter;
-   function isTrailingWhitespace(textnode, offset) {
-     if(!isODFWhitespace(textnode.data.substr(offset))) {
-       return false
++    if(ns) {
++      styleElement.setAttributeNS(ns, nsprefixes[ns] + "name", prefix + stylename)
 +    }
-     return!scanRightForAnyCharacter(nextNode(textnode))
 +  }
-   this.isTrailingWhitespace = isTrailingWhitespace;
-   function isSignificantWhitespace(textNode, offset) {
-     var text = textNode.data, result;
-     if(!isODFWhitespace(text[offset])) {
-       return false
-     }
-     if(isAnchoredAsCharacterElement(textNode.parentNode)) {
-       return false
++  function prefixStyleNames(styleElementsRoot, prefix, styleUsingElementsRoot) {
++    var s;
++    if(styleElementsRoot) {
++      s = styleElementsRoot.firstChild;
++      while(s) {
++        if(s.nodeType === Node.ELEMENT_NODE) {
++          prefixStyleName((s), prefix)
++        }
++        s = s.nextSibling
++      }
++      prefixUsedStyleNames(styleElementsRoot, prefix);
++      if(styleUsingElementsRoot) {
++        prefixUsedStyleNames(styleUsingElementsRoot, prefix)
++      }
 +    }
-     if(offset > 0) {
-       if(!isODFWhitespace(text[offset - 1])) {
-         result = true
++  }
++  function removeRegExpFromUsedStyleNames(element, regExp) {
++    var i, stylename, e, elname, elns, a, ns, localName, length = 0;
++    elname = elements[element.localName];
++    if(elname) {
++      elns = elname[element.namespaceURI];
++      if(elns) {
++        length = elns.length
 +      }
-     }else {
-       if(scanLeftForNonSpace(previousNode(textNode))) {
-         result = true
++    }
++    for(i = 0;i < length;i += 1) {
++      a = (elns[i]);
++      ns = a.ns;
++      localName = a.localname;
++      stylename = element.getAttributeNS(ns, localName);
++      if(stylename) {
++        stylename = stylename.replace(regExp, "");
++        element.setAttributeNS(ns, nsprefixes[ns] + localName, stylename)
 +      }
 +    }
-     if(result === true) {
-       return isTrailingWhitespace(textNode, offset) ? false : true
++    e = element.firstElementChild;
++    while(e) {
++      removeRegExpFromUsedStyleNames(e, regExp);
++      e = e.nextElementSibling
 +    }
-     return false
 +  }
-   this.isSignificantWhitespace = isSignificantWhitespace;
-   this.isDowngradableSpaceElement = function(node) {
-     if(node.namespaceURI === textns && node.localName === "s") {
-       return scanLeftForNonSpace(previousNode(node)) && scanRightForAnyCharacter(nextNode(node))
++  function removeRegExpFromStyleName(styleElement, regExp) {
++    var stylename = styleElement.getAttributeNS(drawns, "name"), ns;
++    if(stylename) {
++      ns = drawns
++    }else {
++      stylename = styleElement.getAttributeNS(stylens, "name");
++      if(stylename) {
++        ns = stylens
++      }
 +    }
-     return false
-   };
-   function getFirstNonWhitespaceChild(node) {
-     var child = node && node.firstChild;
-     while(child && (child.nodeType === Node.TEXT_NODE && whitespaceOnly.test(child.nodeValue))) {
-       child = child.nextSibling
++    if(ns) {
++      stylename = stylename.replace(regExp, "");
++      styleElement.setAttributeNS(ns, nsprefixes[ns] + "name", stylename)
 +    }
-     return child
 +  }
-   this.getFirstNonWhitespaceChild = getFirstNonWhitespaceChild;
-   function parseLength(length) {
-     var re = /(-?[0-9]*[0-9][0-9]*(\.[0-9]*)?|0+\.[0-9]*[1-9][0-9]*|\.[0-9]*[1-9][0-9]*)((cm)|(mm)|(in)|(pt)|(pc)|(px)|(%))/, m = re.exec(length);
-     if(!m) {
-       return null
++  function removePrefixFromStyleNames(styleElementsRoot, prefix, styleUsingElementsRoot) {
++    var s, regExp = new RegExp("^" + prefix);
++    if(styleElementsRoot) {
++      s = styleElementsRoot.firstChild;
++      while(s) {
++        if(s.nodeType === Node.ELEMENT_NODE) {
++          removeRegExpFromStyleName((s), regExp)
++        }
++        s = s.nextSibling
++      }
++      removeRegExpFromUsedStyleNames(styleElementsRoot, regExp);
++      if(styleUsingElementsRoot) {
++        removeRegExpFromUsedStyleNames(styleUsingElementsRoot, regExp)
++      }
 +    }
-     return{value:parseFloat(m[1]), unit:m[3]}
 +  }
-   this.parseLength = parseLength;
-   function parsePositiveLength(length) {
-     var result = parseLength(length);
-     if(result && (result.value <= 0 || result.unit === "%")) {
-       return null
++  function determineStylesForNode(element, usedStyles) {
++    var i, stylename, elname, elns, a, ns, localName, keyname, length = 0, map;
++    elname = elements[element.localName];
++    if(elname) {
++      elns = elname[element.namespaceURI];
++      if(elns) {
++        length = elns.length
++      }
 +    }
-     return result
-   }
-   function parseNonNegativeLength(length) {
-     var result = parseLength(length);
-     if(result && (result.value < 0 || result.unit === "%")) {
-       return null
++    for(i = 0;i < length;i += 1) {
++      a = (elns[i]);
++      ns = a.ns;
++      localName = a.localname;
++      stylename = element.getAttributeNS(ns, localName);
++      if(stylename) {
++        usedStyles = usedStyles || {};
++        keyname = a.keyname;
++        if(usedStyles.hasOwnProperty(keyname)) {
++          usedStyles[keyname][stylename] = 1
++        }else {
++          map = {};
++          map[stylename] = 1;
++          usedStyles[keyname] = map
++        }
++      }
 +    }
-     return result
++    return usedStyles
 +  }
-   this.parseNonNegativeLength = parseNonNegativeLength;
-   function parsePercentage(length) {
-     var result = parseLength(length);
-     if(result && result.unit !== "%") {
-       return null
++  function determineUsedStyles(styleUsingElementsRoot, usedStyles) {
++    var i, e;
++    determineStylesForNode(styleUsingElementsRoot, usedStyles);
++    i = styleUsingElementsRoot.firstChild;
++    while(i) {
++      if(i.nodeType === Node.ELEMENT_NODE) {
++        e = (i);
++        determineUsedStyles(e, usedStyles)
++      }
++      i = i.nextSibling
 +    }
-     return result
 +  }
-   function parseFoFontSize(fontSize) {
-     return parsePositiveLength(fontSize) || parsePercentage(fontSize)
-   }
-   this.parseFoFontSize = parseFoFontSize;
-   function parseFoLineHeight(lineHeight) {
-     return parseNonNegativeLength(lineHeight) || parsePercentage(lineHeight)
-   }
-   this.parseFoLineHeight = parseFoLineHeight;
-   function item(a, i) {
-     return a[i]
++  function StyleDefinition(key, name, family) {
++    this.key = key;
++    this.name = name;
++    this.family = family;
++    this.requires = {}
 +  }
-   function getImpactedParagraphs(range) {
-     var i, l, e, outerContainer = (range.commonAncestorContainer), impactedParagraphs = [], filtered = [];
-     if(outerContainer.nodeType === Node.ELEMENT_NODE) {
-       impactedParagraphs = domUtils.getElementsByTagNameNS(outerContainer, textns, "p").concat(domUtils.getElementsByTagNameNS(outerContainer, textns, "h"))
-     }
-     while(outerContainer && !isParagraph(outerContainer)) {
-       outerContainer = outerContainer.parentNode
-     }
-     if(outerContainer) {
-       impactedParagraphs.push(outerContainer)
-     }
-     l = impactedParagraphs.length;
-     for(i = 0;i < l;i += 1) {
-       e = item(impactedParagraphs, i);
-       if(domUtils.rangeIntersectsNode(range, e)) {
-         filtered.push(e)
-       }
++  function getStyleDefinition(stylename, stylefamily, knownStyles) {
++    var styleKey = stylename + '"' + stylefamily, styleDefinition = knownStyles[styleKey];
++    if(!styleDefinition) {
++      styleDefinition = knownStyles[styleKey] = new StyleDefinition(styleKey, stylename, stylefamily)
 +    }
-     return filtered
++    return styleDefinition
 +  }
-   this.getImpactedParagraphs = getImpactedParagraphs;
-   function isAcceptedNode(node) {
-     switch(node.namespaceURI) {
-       case odf.Namespaces.drawns:
-       ;
-       case odf.Namespaces.svgns:
-       ;
-       case odf.Namespaces.dr3dns:
-         return false;
-       case odf.Namespaces.textns:
-         switch(node.localName) {
-           case "note-body":
-           ;
-           case "ruby-text":
-             return false
-         }
-         break;
-       case odf.Namespaces.officens:
-         switch(node.localName) {
-           case "annotation":
-           ;
-           case "binary-data":
-           ;
-           case "event-listeners":
-             return false
-         }
-         break;
-       default:
-         switch(node.localName) {
-           case "editinfo":
-             return false
-         }
-         break
++  function determineDependentStyles(element, styleScope, knownStyles) {
++    var i, stylename, elname, elns, a, ns, localName, e, referencedStyleFamily, referencedStyleDef, length = 0, newScopeName = element.getAttributeNS(stylens, "name"), newScopeFamily = element.getAttributeNS(stylens, "family");
++    if(newScopeName && newScopeFamily) {
++      styleScope = getStyleDefinition(newScopeName, newScopeFamily, knownStyles)
 +    }
-     return true
-   }
-   function isSignificantTextContent(textNode) {
-     return Boolean(getParagraphElement(textNode) && (!isODFWhitespace(textNode.textContent) || isSignificantWhitespace(textNode, 0)))
-   }
-   function includeNode(range, nodeRange, includePartial) {
-     return includePartial && domUtils.rangesIntersect(range, nodeRange) || domUtils.containsRange(range, nodeRange)
-   }
-   function getTextNodes(range, includePartial) {
-     var document = range.startContainer.ownerDocument, nodeRange = document.createRange(), textNodes;
-     function nodeFilter(node) {
-       nodeRange.selectNodeContents(node);
-       if(node.nodeType === Node.TEXT_NODE) {
-         if(includeNode(range, nodeRange, includePartial)) {
-           return isSignificantTextContent((node)) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT
++    if(styleScope) {
++      elname = elements[element.localName];
++      if(elname) {
++        elns = elname[element.namespaceURI];
++        if(elns) {
++          length = elns.length
 +        }
-       }else {
-         if(domUtils.rangesIntersect(range, nodeRange)) {
-           if(isAcceptedNode(node)) {
-             return NodeFilter.FILTER_SKIP
-           }
++      }
++      for(i = 0;i < length;i += 1) {
++        a = (elns[i]);
++        ns = a.ns;
++        localName = a.localname;
++        stylename = element.getAttributeNS(ns, localName);
++        if(stylename) {
++          referencedStyleFamily = a.keyname;
++          referencedStyleDef = getStyleDefinition(stylename, referencedStyleFamily, knownStyles);
++          styleScope.requires[referencedStyleDef.key] = referencedStyleDef
 +        }
 +      }
-       return NodeFilter.FILTER_REJECT
 +    }
-     textNodes = domUtils.getNodesInRange(range, nodeFilter);
-     nodeRange.detach();
-     return textNodes
++    e = element.firstElementChild;
++    while(e) {
++      determineDependentStyles(e, styleScope, knownStyles);
++      e = e.nextElementSibling
++    }
++    return knownStyles
 +  }
-   this.getTextNodes = getTextNodes;
-   this.getTextElements = function(range, includePartial, includeInsignificantWhitespace) {
-     var document = range.startContainer.ownerDocument, nodeRange = document.createRange(), elements;
-     function nodeFilter(node) {
-       nodeRange.selectNodeContents(node);
-       if(isCharacterElement(node.parentNode)) {
-         return NodeFilter.FILTER_REJECT
-       }
-       if(node.nodeType === Node.TEXT_NODE) {
-         if(includeNode(range, nodeRange, includePartial)) {
-           if(includeInsignificantWhitespace || isSignificantTextContent((node))) {
-             return NodeFilter.FILTER_ACCEPT
-           }
-         }
-       }else {
-         if(isAnchoredAsCharacterElement(node)) {
-           if(includeNode(range, nodeRange, includePartial)) {
-             return NodeFilter.FILTER_ACCEPT
++  function inverse() {
++    var i, l, keyname, list, item, e = {}, map, array, en, ens;
++    for(keyname in elementstyles) {
++      if(elementstyles.hasOwnProperty(keyname)) {
++        list = elementstyles[keyname];
++        l = list.length;
++        for(i = 0;i < l;i += 1) {
++          item = list[i];
++          en = item.en;
++          ens = item.ens;
++          if(e.hasOwnProperty(en)) {
++            map = e[en]
++          }else {
++            e[en] = map = {}
 +          }
-         }else {
-           if(isAcceptedNode(node) || isGroupingElement(node)) {
-             return NodeFilter.FILTER_SKIP
++          if(map.hasOwnProperty(ens)) {
++            array = map[ens]
++          }else {
++            map[ens] = array = []
 +          }
++          array.push({ns:item.ans, localname:item.a, keyname:keyname})
 +        }
 +      }
-       return NodeFilter.FILTER_REJECT
 +    }
-     elements = domUtils.getNodesInRange(range, nodeFilter);
-     nodeRange.detach();
-     return elements
-   };
-   this.getParagraphElements = function(range) {
-     var document = range.startContainer.ownerDocument, nodeRange = document.createRange(), elements;
-     function nodeFilter(node) {
-       nodeRange.selectNodeContents(node);
-       if(isParagraph(node)) {
-         if(domUtils.rangesIntersect(range, nodeRange)) {
-           return NodeFilter.FILTER_ACCEPT
-         }
-       }else {
-         if(isAcceptedNode(node) || isGroupingElement(node)) {
-           return NodeFilter.FILTER_SKIP
-         }
-       }
-       return NodeFilter.FILTER_REJECT
++    return e
++  }
++  function mergeRequiredStyles(styleDependency, usedStyles) {
++    var family = usedStyles[styleDependency.family];
++    if(!family) {
++      family = usedStyles[styleDependency.family] = {}
 +    }
-     elements = domUtils.getNodesInRange(range, nodeFilter);
-     nodeRange.detach();
-     return elements
-   };
-   this.getImageElements = function(range) {
-     var document = range.startContainer.ownerDocument, nodeRange = document.createRange(), elements;
-     function nodeFilter(node) {
-       nodeRange.selectNodeContents(node);
-       if(isImage(node) && domUtils.containsRange(range, nodeRange)) {
-         return NodeFilter.FILTER_ACCEPT
++    family[styleDependency.name] = 1;
++    Object.keys((styleDependency.requires)).forEach(function(requiredStyleKey) {
++      mergeRequiredStyles((styleDependency.requires[requiredStyleKey]), usedStyles)
++    })
++  }
++  function mergeUsedAutomaticStyles(automaticStylesRoot, usedStyles) {
++    var automaticStyles = determineDependentStyles(automaticStylesRoot, null, {});
++    Object.keys(automaticStyles).forEach(function(styleKey) {
++      var automaticStyleDefinition = automaticStyles[styleKey], usedFamily = usedStyles[automaticStyleDefinition.family];
++      if(usedFamily && usedFamily.hasOwnProperty(automaticStyleDefinition.name)) {
++        mergeRequiredStyles(automaticStyleDefinition, usedStyles)
 +      }
-       return NodeFilter.FILTER_SKIP
-     }
-     elements = domUtils.getNodesInRange(range, nodeFilter);
-     nodeRange.detach();
-     return elements
++    })
 +  }
- };
++  function collectUsedFontFaces(usedFontFaceDeclMap, styleElement) {
++    var localNames = ["font-name", "font-name-asian", "font-name-complex"], e, currentElement;
++    function collectByAttribute(localName) {
++      var fontFaceName = currentElement.getAttributeNS(stylens, localName);
++      if(fontFaceName) {
++        usedFontFaceDeclMap[fontFaceName] = true
++      }
++    }
++    e = styleElement && styleElement.firstElementChild;
++    while(e) {
++      currentElement = e;
++      localNames.forEach(collectByAttribute);
++      collectUsedFontFaces(usedFontFaceDeclMap, currentElement);
++      e = e.nextElementSibling
++    }
++  }
++  this.collectUsedFontFaces = collectUsedFontFaces;
++  function changeFontFaceNames(styleElement, fontFaceNameChangeMap) {
++    var localNames = ["font-name", "font-name-asian", "font-name-complex"], e, currentElement;
++    function changeFontFaceNameByAttribute(localName) {
++      var fontFaceName = currentElement.getAttributeNS(stylens, localName);
++      if(fontFaceName && fontFaceNameChangeMap.hasOwnProperty(fontFaceName)) {
++        currentElement.setAttributeNS(stylens, "style:" + localName, fontFaceNameChangeMap[fontFaceName])
++      }
++    }
++    e = styleElement && styleElement.firstElementChild;
++    while(e) {
++      currentElement = e;
++      localNames.forEach(changeFontFaceNameByAttribute);
++      changeFontFaceNames(currentElement, fontFaceNameChangeMap);
++      e = e.nextElementSibling
++    }
++  }
++  this.changeFontFaceNames = changeFontFaceNames;
++  this.UsedStyleList = function(styleUsingElementsRoot, automaticStylesRoot) {
++    var usedStyles = {};
++    this.uses = function(element) {
++      var localName = element.localName, name = element.getAttributeNS(drawns, "name") || element.getAttributeNS(stylens, "name"), keyName, map;
++      if(localName === "style") {
++        keyName = element.getAttributeNS(stylens, "family")
++      }else {
++        if(element.namespaceURI === numberns) {
++          keyName = "data"
++        }else {
++          keyName = localName
++        }
++      }
++      map = usedStyles[keyName];
++      return map ? map[name] > 0 : false
++    };
++    determineUsedStyles(styleUsingElementsRoot, usedStyles);
++    if(automaticStylesRoot) {
++      mergeUsedAutomaticStyles(automaticStylesRoot, usedStyles)
++    }
++  };
++  this.hasDerivedStyles = hasDerivedStyles;
++  this.prefixStyleNames = prefixStyleNames;
++  this.removePrefixFromStyleNames = removePrefixFromStyleNames;
++  this.determineStylesForNode = determineStylesForNode;
++  elements = inverse()
++};
++if(typeof Object.create !== "function") {
++  Object["create"] = function(o) {
++    var F = function() {
++    };
++    F.prototype = o;
++    return new F
++  }
++}
++xmldom.LSSerializer = function LSSerializer() {
++  var self = this;
++  function Namespaces(nsmap) {
++    function invertMap(map) {
++      var m = {}, i;
++      for(i in map) {
++        if(map.hasOwnProperty(i)) {
++          m[map[i]] = i
++        }
++      }
++      return m
++    }
++    var current = nsmap || {}, currentrev = invertMap(nsmap), levels = [current], levelsrev = [currentrev], level = 0;
++    this.push = function() {
++      level += 1;
++      current = levels[level] = Object.create(current);
++      currentrev = levelsrev[level] = Object.create(currentrev)
++    };
++    this.pop = function() {
++      levels.pop();
++      levelsrev.pop();
++      level -= 1;
++      current = levels[level];
++      currentrev = levelsrev[level]
++    };
++    this.getLocalNamespaceDefinitions = function() {
++      return currentrev
++    };
++    this.getQName = function(node) {
++      var ns = node.namespaceURI, i = 0, p;
++      if(!ns) {
++        return node.localName
++      }
++      p = currentrev[ns];
++      if(p) {
++        return p + ":" + node.localName
++      }
++      do {
++        if(p || !node.prefix) {
++          p = "ns" + i;
++          i += 1
++        }else {
++          p = node.prefix
++        }
++        if(current[p] === ns) {
++          break
++        }
++        if(!current[p]) {
++          current[p] = ns;
++          currentrev[ns] = p;
++          break
++        }
++        p = null
++      }while(p === null);
++      return p + ":" + node.localName
++    }
++  }
++  function escapeContent(value) {
++    return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/'/g, "'").replace(/"/g, """)
++  }
++  function serializeAttribute(qname, attr) {
++    var escapedValue = typeof attr.value === "string" ? escapeContent(attr.value) : attr.value, s = qname + '="' + escapedValue + '"';
++    return s
++  }
++  function startElement(ns, qname, element) {
++    var s = "", atts = (element.attributes), length, i, attr, attstr = "", accept, prefix, nsmap;
++    s += "<" + qname;
++    length = atts.length;
++    for(i = 0;i < length;i += 1) {
++      attr = (atts.item(i));
++      if(attr.namespaceURI !== "http://www.w3.org/2000/xmlns/") {
++        accept = self.filter ? self.filter.acceptNode(attr) : NodeFilter.FILTER_ACCEPT;
++        if(accept === NodeFilter.FILTER_ACCEPT) {
++          attstr += " " + serializeAttribute(ns.getQName(attr), attr)
++        }
++      }
++    }
++    nsmap = ns.getLocalNamespaceDefinitions();
++    for(i in nsmap) {
++      if(nsmap.hasOwnProperty(i)) {
++        prefix = nsmap[i];
++        if(!prefix) {
++          s += ' xmlns="' + i + '"'
++        }else {
++          if(prefix !== "xmlns") {
++            s += " xmlns:" + nsmap[i] + '="' + i + '"'
++          }
++        }
++      }
++    }
++    s += attstr + ">";
++    return s
++  }
++  function serializeNode(ns, node) {
++    var s = "", accept = self.filter ? self.filter.acceptNode(node) : NodeFilter.FILTER_ACCEPT, child, qname;
++    if(accept === NodeFilter.FILTER_ACCEPT && node.nodeType === Node.ELEMENT_NODE) {
++      ns.push();
++      qname = ns.getQName(node);
++      s += startElement(ns, qname, node)
++    }
++    if(accept === NodeFilter.FILTER_ACCEPT || accept === NodeFilter.FILTER_SKIP) {
++      child = node.firstChild;
++      while(child) {
++        s += serializeNode(ns, child);
++        child = child.nextSibling
++      }
++      if(node.nodeValue) {
++        s += escapeContent(node.nodeValue)
++      }
++    }
++    if(qname) {
++      s += "</" + qname + ">";
++      ns.pop()
++    }
++    return s
++  }
++  this.filter = null;
++  this.writeToString = function(node, nsmap) {
++    if(!node) {
++      return""
++    }
++    var ns = new Namespaces(nsmap);
++    return serializeNode(ns, node)
++  }
++};
 +/*
 +
-  Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
++ Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- ops.Server = function Server() {
- };
- ops.Server.prototype.connect = function(timeout, cb) {
- };
- ops.Server.prototype.networkStatus = function() {
- };
- ops.Server.prototype.login = function(login, password, successCb, failCb) {
- };
- ops.Server.prototype.joinSession = function(userId, sessionId, successCb, failCb) {
- };
- ops.Server.prototype.leaveSession = function(sessionId, memberId, successCb, failCb) {
- };
- ops.Server.prototype.getGenesisUrl = function(sessionId) {
- };
- xmldom.LSSerializerFilter = function LSSerializerFilter() {
- };
- xmldom.LSSerializerFilter.prototype.acceptNode = function(node) {
- };
- xmldom.XPathIterator = function XPathIterator() {
- };
- xmldom.XPathIterator.prototype.next = function() {
- };
- xmldom.XPathIterator.prototype.reset = function() {
- };
- xmldom.XPathAtom;
- function createXPathSingleton() {
-   var createXPathPathIterator, parsePredicates;
-   function isSmallestPositive(a, b, c) {
-     return a !== -1 && ((a < b || b === -1) && (a < c || c === -1))
-   }
-   function parseXPathStep(xpath, pos, end, steps) {
-     var location = "", predicates = [], brapos = xpath.indexOf("[", pos), slapos = xpath.indexOf("/", pos), eqpos = xpath.indexOf("=", pos);
-     if(isSmallestPositive(slapos, brapos, eqpos)) {
-       location = xpath.substring(pos, slapos);
-       pos = slapos + 1
-     }else {
-       if(isSmallestPositive(brapos, slapos, eqpos)) {
-         location = xpath.substring(pos, brapos);
-         pos = parsePredicates(xpath, brapos, predicates)
-       }else {
-         if(isSmallestPositive(eqpos, slapos, brapos)) {
-           location = xpath.substring(pos, eqpos);
-           pos = eqpos
-         }else {
-           location = xpath.substring(pos, end);
-           pos = end
-         }
++(function() {
++  var styleInfo = new odf.StyleInfo, domUtils = new core.DomUtils, officens = "urn:oasis:names:tc:opendocument:xmlns:office:1.0", manifestns = "urn:oasis:names:tc:opendocument:xmlns:manifest:1.0", webodfns = "urn:webodf:names:scope", stylens = odf.Namespaces.stylens, nodeorder = ["meta", "settings", "scripts", "font-face-decls", "styles", "automatic-styles", "master-styles", "body"], automaticStylePrefix = (new Date).getTime() + "_webodf_", base64 = new core.Base64, documentStylesScope  [...]
++  documentContentScope = "document-content";
++  function getNodePosition(child) {
++    var i, l = nodeorder.length;
++    for(i = 0;i < l;i += 1) {
++      if(child.namespaceURI === officens && child.localName === nodeorder[i]) {
++        return i
 +      }
 +    }
-     steps.push({location:location, predicates:predicates});
-     return pos
++    return-1
 +  }
-   function parseXPath(xpath) {
-     var steps = [], p = 0, end = xpath.length, value;
-     while(p < end) {
-       p = parseXPathStep(xpath, p, end, steps);
-       if(p < end && xpath[p] === "=") {
-         value = xpath.substring(p + 1, end);
-         if(value.length > 2 && (value[0] === "'" || value[0] === '"')) {
-           value = value.slice(1, value.length - 1)
++  function OdfStylesFilter(styleUsingElementsRoot, automaticStyles) {
++    var usedStyleList = new styleInfo.UsedStyleList(styleUsingElementsRoot, automaticStyles), odfNodeFilter = new odf.OdfNodeFilter;
++    this.acceptNode = function(node) {
++      var result = odfNodeFilter.acceptNode(node);
++      if(result === NodeFilter.FILTER_ACCEPT && (node.parentNode === automaticStyles && node.nodeType === Node.ELEMENT_NODE)) {
++        if(usedStyleList.uses((node))) {
++          result = NodeFilter.FILTER_ACCEPT
 +        }else {
-           try {
-             value = parseInt(value, 10)
-           }catch(ignore) {
-           }
++          result = NodeFilter.FILTER_REJECT
 +        }
-         p = end
 +      }
++      return result
 +    }
-     return{steps:steps, value:value}
 +  }
-   parsePredicates = function parsePredicates(xpath, start, predicates) {
-     var pos = start, l = xpath.length, depth = 0;
-     while(pos < l) {
-       if(xpath[pos] === "]") {
-         depth -= 1;
-         if(depth <= 0) {
-           predicates.push(parseXPath(xpath.substring(start, pos)))
-         }
-       }else {
-         if(xpath[pos] === "[") {
-           if(depth <= 0) {
-             start = pos + 1
-           }
-           depth += 1
-         }
++  function OdfContentFilter(styleUsingElementsRoot, automaticStyles) {
++    var odfStylesFilter = new OdfStylesFilter(styleUsingElementsRoot, automaticStyles);
++    this.acceptNode = function(node) {
++      var result = odfStylesFilter.acceptNode(node);
++      if(result === NodeFilter.FILTER_ACCEPT && (node.parentNode && (node.parentNode.namespaceURI === odf.Namespaces.textns && (node.parentNode.localName === "s" || node.parentNode.localName === "tab")))) {
++        result = NodeFilter.FILTER_REJECT
 +      }
-       pos += 1
++      return result
 +    }
-     return pos
-   };
-   function XPathNodeIterator() {
-     var node = null, done = false;
-     this.setNode = function setNode(n) {
-       node = n
-     };
-     this.reset = function() {
-       done = false
-     };
-     this.next = function next() {
-       var val = done ? null : node;
-       done = true;
-       return val
++  }
++  function setChild(node, child) {
++    if(!child) {
++      return
++    }
++    var childpos = getNodePosition(child), pos, c = node.firstChild;
++    if(childpos === -1) {
++      return
++    }
++    while(c) {
++      pos = getNodePosition(c);
++      if(pos !== -1 && pos > childpos) {
++        break
++      }
++      c = c.nextSibling
 +    }
++    node.insertBefore(child, c)
 +  }
-   function AttributeIterator(it, namespace, localName) {
-     this.reset = function reset() {
-       it.reset()
-     };
-     this.next = function next() {
-       var node = it.next();
-       while(node) {
-         if(node.nodeType === Node.ELEMENT_NODE) {
-           node = (node).getAttributeNodeNS(namespace, localName)
++  odf.ODFElement = function ODFElement() {
++  };
++  odf.ODFDocumentElement = function ODFDocumentElement() {
++  };
++  odf.ODFDocumentElement.prototype = new odf.ODFElement;
++  odf.ODFDocumentElement.prototype.constructor = odf.ODFDocumentElement;
++  odf.ODFDocumentElement.prototype.automaticStyles;
++  odf.ODFDocumentElement.prototype.body;
++  odf.ODFDocumentElement.prototype.fontFaceDecls = null;
++  odf.ODFDocumentElement.prototype.manifest = null;
++  odf.ODFDocumentElement.prototype.masterStyles;
++  odf.ODFDocumentElement.prototype.meta;
++  odf.ODFDocumentElement.prototype.settings = null;
++  odf.ODFDocumentElement.prototype.styles;
++  odf.ODFDocumentElement.namespaceURI = officens;
++  odf.ODFDocumentElement.localName = "document";
++  odf.AnnotationElement = function AnnotationElement() {
++  };
++  odf.AnnotationElement.prototype.annotationEndElement;
++  odf.OdfPart = function OdfPart(name, mimetype, container, zip) {
++    var self = this;
++    this.size = 0;
++    this.type = null;
++    this.name = name;
++    this.container = container;
++    this.url = null;
++    this.mimetype = mimetype;
++    this.document = null;
++    this.onstatereadychange = null;
++    this.onchange;
++    this.EMPTY = 0;
++    this.LOADING = 1;
++    this.DONE = 2;
++    this.state = this.EMPTY;
++    this.data = "";
++    this.load = function() {
++      if(zip === null) {
++        return
++      }
++      this.mimetype = mimetype;
++      zip.loadAsDataURL(name, mimetype, function(err, url) {
++        if(err) {
++          runtime.log(err)
 +        }
-         if(node) {
-           return node
++        self.url = url;
++        if(self.onchange) {
++          self.onchange(self)
 +        }
-         node = it.next()
++        if(self.onstatereadychange) {
++          self.onstatereadychange(self)
++        }
++      })
++    }
++  };
++  odf.OdfPart.prototype.load = function() {
++  };
++  odf.OdfPart.prototype.getUrl = function() {
++    if(this.data) {
++      return"data:;base64," + base64.toBase64(this.data)
++    }
++    return null
++  };
++  odf.OdfContainer = function OdfContainer(url, onstatereadychange) {
++    var self = this, zip, partMimetypes = {}, contentElement;
++    this.onstatereadychange = onstatereadychange;
++    this.onchange = null;
++    this.state = null;
++    this.rootElement;
++    function removeProcessingInstructions(element) {
++      var n = element.firstChild, next, e;
++      while(n) {
++        next = n.nextSibling;
++        if(n.nodeType === Node.ELEMENT_NODE) {
++          e = (n);
++          removeProcessingInstructions(e)
++        }else {
++          if(n.nodeType === Node.PROCESSING_INSTRUCTION_NODE) {
++            element.removeChild(n)
++          }
++        }
++        n = next
 +      }
-       return node
 +    }
-   }
-   function AllChildElementIterator(it, recurse) {
-     var root = it.next(), node = null;
-     this.reset = function reset() {
-       it.reset();
-       root = it.next();
-       node = null
-     };
-     this.next = function next() {
-       while(root) {
-         if(node) {
-           if(recurse && node.firstChild) {
-             node = node.firstChild
-           }else {
-             while(!node.nextSibling && node !== root) {
-               node = node.parentNode
++    function linkAnnotationStartAndEndElements(rootElement) {
++      var document = rootElement.ownerDocument, annotationStarts = {}, n, name, annotationStart, nodeIterator = document.createNodeIterator(rootElement, NodeFilter.SHOW_ELEMENT, null, false);
++      n = (nodeIterator.nextNode());
++      while(n) {
++        if(n.namespaceURI === officens) {
++          if(n.localName === "annotation") {
++            name = n.getAttributeNS(officens, "name");
++            if(name) {
++              if(annotationStarts.hasOwnProperty(name)) {
++                runtime.log("Warning: annotation name used more than once with <office:annotation/>: '" + name + "'")
++              }else {
++                annotationStarts[name] = n
++              }
 +            }
-             if(node === root) {
-               root = it.next()
-             }else {
-               node = node.nextSibling
++          }else {
++            if(n.localName === "annotation-end") {
++              name = n.getAttributeNS(officens, "name");
++              if(name) {
++                if(annotationStarts.hasOwnProperty(name)) {
++                  annotationStart = (annotationStarts[name]);
++                  if(!annotationStart.annotationEndElement) {
++                    annotationStart.annotationEndElement = n
++                  }else {
++                    runtime.log("Warning: annotation name used more than once with <office:annotation-end/>: '" + name + "'")
++                  }
++                }else {
++                  runtime.log("Warning: annotation end without an annotation start, name: '" + name + "'")
++                }
++              }else {
++                runtime.log("Warning: annotation end without a name found")
++              }
 +            }
 +          }
-         }else {
-           do {
-             node = root.firstChild;
-             if(!node) {
-               root = it.next()
-             }
-           }while(root && !node)
 +        }
-         if(node && node.nodeType === Node.ELEMENT_NODE) {
-           return node
++        n = (nodeIterator.nextNode())
++      }
++    }
++    function setAutomaticStylesScope(stylesRootElement, scope) {
++      var n = stylesRootElement && stylesRootElement.firstChild;
++      while(n) {
++        if(n.nodeType === Node.ELEMENT_NODE) {
++          (n).setAttributeNS(webodfns, "scope", scope)
 +        }
++        n = n.nextSibling
++      }
++    }
++    function getEnsuredMetaElement() {
++      var root = self.rootElement, meta = root.meta;
++      if(!meta) {
++        root.meta = meta = document.createElementNS(officens, "meta");
++        setChild(root, meta)
++      }
++      return meta
++    }
++    function getMetaData(metadataNs, metadataLocalName) {
++      var node = self.rootElement.meta, textNode;
++      node = node && node.firstChild;
++      while(node && (node.namespaceURI !== metadataNs || node.localName !== metadataLocalName)) {
++        node = node.nextSibling
++      }
++      node = node && node.firstChild;
++      while(node && node.nodeType !== Node.TEXT_NODE) {
++        node = node.nextSibling
++      }
++      if(node) {
++        textNode = (node);
++        return textNode.data
 +      }
 +      return null
 +    }
-   }
-   function ConditionIterator(it, condition) {
-     this.reset = function reset() {
-       it.reset()
-     };
-     this.next = function next() {
-       var n = it.next();
-       while(n && !condition(n)) {
-         n = it.next()
++    function unusedKey(key, map1, map2) {
++      var i = 0, postFixedKey;
++      key = key.replace(/\d+$/, "");
++      postFixedKey = key;
++      while(map1.hasOwnProperty(postFixedKey) || map2.hasOwnProperty(postFixedKey)) {
++        i += 1;
++        postFixedKey = key + i
 +      }
-       return n
++      return postFixedKey
 +    }
-   }
-   function createNodenameFilter(it, name, namespaceResolver) {
-     var s = name.split(":", 2), namespace = namespaceResolver(s[0]), localName = s[1];
-     return new ConditionIterator(it, function(node) {
-       return node.localName === localName && node.namespaceURI === namespace
-     })
-   }
-   function createPredicateFilteredIterator(it, p, namespaceResolver) {
-     var nit = new XPathNodeIterator, pit = createXPathPathIterator(nit, p, namespaceResolver), value = p.value;
-     if(value === undefined) {
-       return new ConditionIterator(it, function(node) {
-         nit.setNode(node);
-         pit.reset();
-         return pit.next() !== null
-       })
++    function mapByFontFaceName(fontFaceDecls) {
++      var fn, result = {}, fontname;
++      fn = fontFaceDecls.firstChild;
++      while(fn) {
++        if(fn.nodeType === Node.ELEMENT_NODE && (fn.namespaceURI === stylens && fn.localName === "font-face")) {
++          fontname = (fn).getAttributeNS(stylens, "name");
++          result[fontname] = fn
++        }
++        fn = fn.nextSibling
++      }
++      return result
 +    }
-     return new ConditionIterator(it, function(node) {
-       nit.setNode(node);
-       pit.reset();
-       var n = pit.next();
-       return n ? n.nodeValue === value : false
-     })
-   }
-   function item(p, i) {
-     return p[i]
-   }
-   createXPathPathIterator = function createXPathPathIterator(it, xpath, namespaceResolver) {
-     var i, j, step, location, s, p, ns;
-     for(i = 0;i < xpath.steps.length;i += 1) {
-       step = xpath.steps[i];
-       location = step.location;
-       if(location === "") {
-         it = new AllChildElementIterator(it, false)
-       }else {
-         if(location[0] === "@") {
-           s = location.substr(1).split(":", 2);
-           ns = namespaceResolver(s[0]);
-           if(!ns) {
-             throw"No namespace associated with the prefix " + s[0];
-           }
-           it = new AttributeIterator(it, ns, s[1])
-         }else {
-           if(location !== ".") {
-             it = new AllChildElementIterator(it, false);
-             if(location.indexOf(":") !== -1) {
-               it = createNodenameFilter(it, location, namespaceResolver)
++    function mergeFontFaceDecls(targetFontFaceDeclsRootElement, sourceFontFaceDeclsRootElement) {
++      var e, s, fontFaceName, newFontFaceName, targetFontFaceDeclsMap, sourceFontFaceDeclsMap, fontFaceNameChangeMap = {};
++      targetFontFaceDeclsMap = mapByFontFaceName(targetFontFaceDeclsRootElement);
++      sourceFontFaceDeclsMap = mapByFontFaceName(sourceFontFaceDeclsRootElement);
++      e = sourceFontFaceDeclsRootElement.firstElementChild;
++      while(e) {
++        s = e.nextElementSibling;
++        if(e.namespaceURI === stylens && e.localName === "font-face") {
++          fontFaceName = e.getAttributeNS(stylens, "name");
++          if(targetFontFaceDeclsMap.hasOwnProperty(fontFaceName)) {
++            if(!e.isEqualNode(targetFontFaceDeclsMap[fontFaceName])) {
++              newFontFaceName = unusedKey(fontFaceName, targetFontFaceDeclsMap, sourceFontFaceDeclsMap);
++              e.setAttributeNS(stylens, "style:name", newFontFaceName);
++              targetFontFaceDeclsRootElement.appendChild(e);
++              targetFontFaceDeclsMap[newFontFaceName] = e;
++              delete sourceFontFaceDeclsMap[fontFaceName];
++              fontFaceNameChangeMap[fontFaceName] = newFontFaceName
 +            }
++          }else {
++            targetFontFaceDeclsRootElement.appendChild(e);
++            targetFontFaceDeclsMap[fontFaceName] = e;
++            delete sourceFontFaceDeclsMap[fontFaceName]
 +          }
 +        }
++        e = s
 +      }
-       for(j = 0;j < step.predicates.length;j += 1) {
-         p = item(step.predicates, j);
-         it = createPredicateFilteredIterator(it, p, namespaceResolver)
-       }
-     }
-     return it
-   };
-   function fallback(node, xpath, namespaceResolver) {
-     var it = new XPathNodeIterator, i, nodelist, parsedXPath;
-     it.setNode(node);
-     parsedXPath = parseXPath(xpath);
-     it = createXPathPathIterator(it, parsedXPath, namespaceResolver);
-     nodelist = [];
-     i = it.next();
-     while(i) {
-       nodelist.push(i);
-       i = it.next()
++      return fontFaceNameChangeMap
 +    }
-     return nodelist
-   }
-   function getODFElementsWithXPath(node, xpath, namespaceResolver) {
-     var doc = node.ownerDocument, nodes, elements = [], n = null;
-     if(!doc || typeof doc.evaluate !== "function") {
-       elements = fallback(node, xpath, namespaceResolver)
-     }else {
-       nodes = doc.evaluate(xpath, node, namespaceResolver, XPathResult.UNORDERED_NODE_ITERATOR_TYPE, null);
-       n = nodes.iterateNext();
-       while(n !== null) {
-         if(n.nodeType === Node.ELEMENT_NODE) {
-           elements.push(n)
++    function cloneStylesInScope(stylesRootElement, scope) {
++      var copy = null, e, s, scopeAttrValue;
++      if(stylesRootElement) {
++        copy = stylesRootElement.cloneNode(true);
++        e = copy.firstElementChild;
++        while(e) {
++          s = e.nextElementSibling;
++          scopeAttrValue = e.getAttributeNS(webodfns, "scope");
++          if(scopeAttrValue && scopeAttrValue !== scope) {
++            copy.removeChild(e)
++          }
++          e = s
 +        }
-         n = nodes.iterateNext()
 +      }
++      return copy
 +    }
-     return elements
-   }
-   return{getODFElementsWithXPath:getODFElementsWithXPath}
- }
- xmldom.XPath = createXPathSingleton();
- runtime.loadClass("core.DomUtils");
- core.Cursor = function Cursor(document, memberId) {
-   var cursorns = "urn:webodf:names:cursor", cursorNode = document.createElementNS(cursorns, "cursor"), anchorNode = document.createElementNS(cursorns, "anchor"), forwardSelection, recentlyModifiedNodes = [], selectedRange = (document.createRange()), isCollapsed, domUtils = new core.DomUtils;
-   function putIntoTextNode(node, container, offset) {
-     runtime.assert(Boolean(container), "putCursorIntoTextNode: invalid container");
-     var parent = container.parentNode;
-     runtime.assert(Boolean(parent), "putCursorIntoTextNode: container without parent");
-     runtime.assert(offset >= 0 && offset <= container.length, "putCursorIntoTextNode: offset is out of bounds");
-     if(offset === 0) {
-       parent.insertBefore(node, container)
-     }else {
-       if(offset === container.length) {
-         parent.insertBefore(node, container.nextSibling)
-       }else {
-         container.splitText(offset);
-         parent.insertBefore(node, container.nextSibling)
++    function cloneFontFaceDeclsUsedInStyles(fontFaceDeclsRootElement, stylesRootElementList) {
++      var e, nextSibling, fontFaceName, copy = null, usedFontFaceDeclMap = {};
++      if(fontFaceDeclsRootElement) {
++        stylesRootElementList.forEach(function(stylesRootElement) {
++          styleInfo.collectUsedFontFaces(usedFontFaceDeclMap, stylesRootElement)
++        });
++        copy = fontFaceDeclsRootElement.cloneNode(true);
++        e = copy.firstElementChild;
++        while(e) {
++          nextSibling = e.nextElementSibling;
++          fontFaceName = e.getAttributeNS(stylens, "name");
++          if(!usedFontFaceDeclMap[fontFaceName]) {
++            copy.removeChild(e)
++          }
++          e = nextSibling
++        }
 +      }
++      return copy
 +    }
-   }
-   function removeNode(node) {
-     if(node.parentNode) {
-       recentlyModifiedNodes.push(node.previousSibling);
-       recentlyModifiedNodes.push(node.nextSibling);
-       node.parentNode.removeChild(node)
++    function importRootNode(xmldoc) {
++      var doc = self.rootElement.ownerDocument, node;
++      if(xmldoc) {
++        removeProcessingInstructions(xmldoc.documentElement);
++        try {
++          node = (doc.importNode(xmldoc.documentElement, true))
++        }catch(ignore) {
++        }
++      }
++      return node
 +    }
-   }
-   function putNode(node, container, offset) {
-     if(container.nodeType === Node.TEXT_NODE) {
-       putIntoTextNode(node, (container), offset)
-     }else {
-       if(container.nodeType === Node.ELEMENT_NODE) {
-         container.insertBefore(node, container.childNodes.item(offset))
++    function setState(state) {
++      self.state = state;
++      if(self.onchange) {
++        self.onchange(self)
++      }
++      if(self.onstatereadychange) {
++        self.onstatereadychange(self)
 +      }
 +    }
-     recentlyModifiedNodes.push(node.previousSibling);
-     recentlyModifiedNodes.push(node.nextSibling)
-   }
-   function getStartNode() {
-     return forwardSelection ? anchorNode : cursorNode
-   }
-   function getEndNode() {
-     return forwardSelection ? cursorNode : anchorNode
-   }
-   this.getNode = function() {
-     return cursorNode
-   };
-   this.getAnchorNode = function() {
-     return anchorNode.parentNode ? anchorNode : cursorNode
-   };
-   this.getSelectedRange = function() {
-     if(isCollapsed) {
-       selectedRange.setStartBefore(cursorNode);
-       selectedRange.collapse(true)
-     }else {
-       selectedRange.setStartAfter(getStartNode());
-       selectedRange.setEndBefore(getEndNode())
++    function setRootElement(root) {
++      contentElement = null;
++      self.rootElement = (root);
++      root.fontFaceDecls = domUtils.getDirectChild(root, officens, "font-face-decls");
++      root.styles = domUtils.getDirectChild(root, officens, "styles");
++      root.automaticStyles = domUtils.getDirectChild(root, officens, "automatic-styles");
++      root.masterStyles = domUtils.getDirectChild(root, officens, "master-styles");
++      root.body = domUtils.getDirectChild(root, officens, "body");
++      root.meta = domUtils.getDirectChild(root, officens, "meta");
++      linkAnnotationStartAndEndElements(root)
 +    }
-     return selectedRange
-   };
-   this.setSelectedRange = function(range, isForwardSelection) {
-     if(selectedRange && selectedRange !== range) {
-       selectedRange.detach()
++    function handleFlatXml(xmldoc) {
++      var root = importRootNode(xmldoc);
++      if(!root || (root.localName !== "document" || root.namespaceURI !== officens)) {
++        setState(OdfContainer.INVALID);
++        return
++      }
++      setRootElement((root));
++      setState(OdfContainer.DONE)
 +    }
-     selectedRange = range;
-     forwardSelection = isForwardSelection !== false;
-     isCollapsed = range.collapsed;
-     if(range.collapsed) {
-       removeNode(anchorNode);
-       removeNode(cursorNode);
-       putNode(cursorNode, (range.startContainer), range.startOffset)
-     }else {
-       removeNode(anchorNode);
-       removeNode(cursorNode);
-       putNode(getEndNode(), (range.endContainer), range.endOffset);
-       putNode(getStartNode(), (range.startContainer), range.startOffset)
++    function handleStylesXml(xmldoc) {
++      var node = importRootNode(xmldoc), root = self.rootElement, n;
++      if(!node || (node.localName !== "document-styles" || node.namespaceURI !== officens)) {
++        setState(OdfContainer.INVALID);
++        return
++      }
++      root.fontFaceDecls = domUtils.getDirectChild(node, officens, "font-face-decls");
++      setChild(root, root.fontFaceDecls);
++      n = domUtils.getDirectChild(node, officens, "styles");
++      root.styles = n || xmldoc.createElementNS(officens, "styles");
++      setChild(root, root.styles);
++      n = domUtils.getDirectChild(node, officens, "automatic-styles");
++      root.automaticStyles = n || xmldoc.createElementNS(officens, "automatic-styles");
++      setAutomaticStylesScope(root.automaticStyles, documentStylesScope);
++      setChild(root, root.automaticStyles);
++      node = domUtils.getDirectChild(node, officens, "master-styles");
++      root.masterStyles = node || xmldoc.createElementNS(officens, "master-styles");
++      setChild(root, root.masterStyles);
++      styleInfo.prefixStyleNames(root.automaticStyles, automaticStylePrefix, root.masterStyles)
 +    }
-     recentlyModifiedNodes.forEach(domUtils.normalizeTextNodes);
-     recentlyModifiedNodes.length = 0
-   };
-   this.hasForwardSelection = function() {
-     return forwardSelection
-   };
-   this.remove = function() {
-     removeNode(cursorNode);
-     recentlyModifiedNodes.forEach(domUtils.normalizeTextNodes);
-     recentlyModifiedNodes.length = 0
-   };
-   function init() {
-     cursorNode.setAttributeNS(cursorns, "memberId", memberId);
-     anchorNode.setAttributeNS(cursorns, "memberId", memberId)
-   }
-   init()
- };
- runtime.loadClass("core.PositionIterator");
- core.PositionFilter = function PositionFilter() {
- };
- core.PositionFilter.FilterResult = {FILTER_ACCEPT:1, FILTER_REJECT:2, FILTER_SKIP:3};
- core.PositionFilter.prototype.acceptPosition = function(point) {
- };
- (function() {
-   return core.PositionFilter
- })();
- runtime.loadClass("core.PositionFilter");
- core.PositionFilterChain = function PositionFilterChain() {
-   var filterChain = {}, FILTER_ACCEPT = core.PositionFilter.FilterResult.FILTER_ACCEPT, FILTER_REJECT = core.PositionFilter.FilterResult.FILTER_REJECT;
-   this.acceptPosition = function(iterator) {
-     var filterName;
-     for(filterName in filterChain) {
-       if(filterChain.hasOwnProperty(filterName)) {
-         if(filterChain[filterName].acceptPosition(iterator) === FILTER_REJECT) {
-           return FILTER_REJECT
++    function handleContentXml(xmldoc) {
++      var node = importRootNode(xmldoc), root, automaticStyles, fontFaceDecls, fontFaceNameChangeMap, c;
++      if(!node || (node.localName !== "document-content" || node.namespaceURI !== officens)) {
++        setState(OdfContainer.INVALID);
++        return
++      }
++      root = self.rootElement;
++      fontFaceDecls = domUtils.getDirectChild(node, officens, "font-face-decls");
++      if(root.fontFaceDecls && fontFaceDecls) {
++        fontFaceNameChangeMap = mergeFontFaceDecls(root.fontFaceDecls, fontFaceDecls)
++      }else {
++        if(fontFaceDecls) {
++          root.fontFaceDecls = fontFaceDecls;
++          setChild(root, fontFaceDecls)
++        }
++      }
++      automaticStyles = domUtils.getDirectChild(node, officens, "automatic-styles");
++      setAutomaticStylesScope(automaticStyles, documentContentScope);
++      if(fontFaceNameChangeMap) {
++        styleInfo.changeFontFaceNames(automaticStyles, fontFaceNameChangeMap)
++      }
++      if(root.automaticStyles && automaticStyles) {
++        c = automaticStyles.firstChild;
++        while(c) {
++          root.automaticStyles.appendChild(c);
++          c = automaticStyles.firstChild
++        }
++      }else {
++        if(automaticStyles) {
++          root.automaticStyles = automaticStyles;
++          setChild(root, automaticStyles)
 +        }
 +      }
++      node = domUtils.getDirectChild(node, officens, "body");
++      if(node === null) {
++        throw"<office:body/> tag is mising.";
++      }
++      root.body = node;
++      setChild(root, root.body)
 +    }
-     return FILTER_ACCEPT
-   };
-   this.addFilter = function(filterName, filterInstance) {
-     filterChain[filterName] = filterInstance
-   };
-   this.removeFilter = function(filterName) {
-     delete filterChain[filterName]
-   }
- };
- /*
- 
-  Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
- 
-  @licstart
-  The JavaScript code in this page is free software: you can redistribute it
-  and/or modify it under the terms of the GNU Affero General Public License
-  (GNU AGPL) as published by the Free Software Foundation, either version 3 of
-  the License, or (at your option) any later version.  The code is distributed
-  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
- 
-  You should have received a copy of the GNU Affero General Public License
-  along with this code.  If not, see <http://www.gnu.org/licenses/>.
- 
-  As additional permission under GNU AGPL version 3 section 7, you
-  may distribute non-source (e.g., minimized or compacted) forms of
-  that code without the copy of the GNU GPL normally required by
-  section 4, provided you include this license notice and a URL
-  through which recipients can access the Corresponding Source.
- 
-  As a special exception to the AGPL, any HTML file which merely makes function
-  calls to this code, and for that purpose includes it by reference shall be
-  deemed a separate work for copyright law purposes. In addition, the copyright
-  holders of this code give you permission to combine this code with free
-  software libraries that are released under the GNU LGPL. You may copy and
-  distribute such a system following the terms of the GNU AGPL for this code
-  and the LGPL for the libraries. If you modify this code, you may extend this
-  exception to your version of the code, but you are not obligated to do so.
-  If you do not wish to do so, delete this exception statement from your
-  version.
- 
-  This license applies to this entire compilation.
-  @licend
-  @source: http://www.webodf.org/
-  @source: https://github.com/kogmbh/WebODF/
- */
- gui.AnnotatableCanvas = function AnnotatableCanvas() {
- };
- gui.AnnotatableCanvas.prototype.refreshSize = function() {
- };
- gui.AnnotatableCanvas.prototype.getZoomLevel = function() {
- };
- gui.AnnotatableCanvas.prototype.getSizer = function() {
- };
- gui.AnnotationViewManager = function AnnotationViewManager(canvas, odfFragment, annotationsPane) {
-   var annotations = [], doc = odfFragment.ownerDocument, odfUtils = new odf.OdfUtils, CONNECTOR_MARGIN = 30, NOTE_MARGIN = 20, window = runtime.getWindow();
-   runtime.assert(Boolean(window), "Expected to be run in an environment which has a global window, like a browser.");
-   function wrapAnnotation(annotation) {
-     var annotationWrapper = doc.createElement("div"), annotationNote = doc.createElement("div"), connectorHorizontal = doc.createElement("div"), connectorAngular = doc.createElement("div"), removeButton = doc.createElement("div"), annotationNode = annotation.node;
-     annotationWrapper.className = "annotationWrapper";
-     annotationNode.parentNode.insertBefore(annotationWrapper, annotationNode);
-     annotationNote.className = "annotationNote";
-     annotationNote.appendChild(annotationNode);
-     removeButton.className = "annotationRemoveButton";
-     annotationNote.appendChild(removeButton);
-     connectorHorizontal.className = "annotationConnector horizontal";
-     connectorAngular.className = "annotationConnector angular";
-     annotationWrapper.appendChild(annotationNote);
-     annotationWrapper.appendChild(connectorHorizontal);
-     annotationWrapper.appendChild(connectorAngular)
-   }
-   function unwrapAnnotation(annotation) {
-     var annotationNode = annotation.node, annotationWrapper = annotationNode.parentNode.parentNode;
-     if(annotationWrapper.localName === "div") {
-       annotationWrapper.parentNode.insertBefore(annotationNode, annotationWrapper);
-       annotationWrapper.parentNode.removeChild(annotationWrapper)
++    function handleMetaXml(xmldoc) {
++      var node = importRootNode(xmldoc), root;
++      if(!node || (node.localName !== "document-meta" || node.namespaceURI !== officens)) {
++        return
++      }
++      root = self.rootElement;
++      root.meta = domUtils.getDirectChild(node, officens, "meta");
++      setChild(root, root.meta)
 +    }
-   }
-   function highlightAnnotation(annotation) {
-     var annotationNode = annotation.node, annotationEnd = annotation.end, range = doc.createRange(), textNodes;
-     if(annotationEnd) {
-       range.setStart(annotationNode, annotationNode.childNodes.length);
-       range.setEnd(annotationEnd, 0);
-       textNodes = odfUtils.getTextNodes(range, false);
-       textNodes.forEach(function(n) {
-         var container = doc.createElement("span"), v = annotationNode.getAttributeNS(odf.Namespaces.officens, "name");
-         container.className = "annotationHighlight";
-         container.setAttribute("annotation", v);
-         n.parentNode.insertBefore(container, n);
-         container.appendChild(n)
-       })
++    function handleSettingsXml(xmldoc) {
++      var node = importRootNode(xmldoc), root;
++      if(!node || (node.localName !== "document-settings" || node.namespaceURI !== officens)) {
++        return
++      }
++      root = self.rootElement;
++      root.settings = domUtils.getDirectChild(node, officens, "settings");
++      setChild(root, root.settings)
 +    }
-     range.detach()
-   }
-   function unhighlightAnnotation(annotation) {
-     var annotationName = annotation.node.getAttributeNS(odf.Namespaces.officens, "name"), highlightSpans = doc.querySelectorAll('span.annotationHighlight[annotation="' + annotationName + '"]'), i, container;
-     for(i = 0;i < highlightSpans.length;i += 1) {
-       container = highlightSpans.item(i);
-       while(container.firstChild) {
-         container.parentNode.insertBefore(container.firstChild, container)
++    function handleManifestXml(xmldoc) {
++      var node = importRootNode(xmldoc), root, e;
++      if(!node || (node.localName !== "manifest" || node.namespaceURI !== manifestns)) {
++        return
++      }
++      root = self.rootElement;
++      root.manifest = (node);
++      e = root.manifest.firstElementChild;
++      while(e) {
++        if(e.localName === "file-entry" && e.namespaceURI === manifestns) {
++          partMimetypes[e.getAttributeNS(manifestns, "full-path")] = e.getAttributeNS(manifestns, "media-type")
++        }
++        e = e.nextElementSibling
 +      }
-       container.parentNode.removeChild(container)
 +    }
-   }
-   function lineDistance(point1, point2) {
-     var xs = 0, ys = 0;
-     xs = point2.x - point1.x;
-     xs = xs * xs;
-     ys = point2.y - point1.y;
-     ys = ys * ys;
-     return Math.sqrt(xs + ys)
-   }
-   function renderAnnotation(annotation) {
-     var annotationNote = annotation.node.parentElement, connectorHorizontal = annotationNote.nextElementSibling, connectorAngular = connectorHorizontal.nextElementSibling, annotationWrapper = annotationNote.parentElement, connectorAngle = 0, previousAnnotation = annotations[annotations.indexOf(annotation) - 1], previousRect, zoomLevel = canvas.getZoomLevel();
-     annotationNote.style.left = (annotationsPane.getBoundingClientRect().left - annotationWrapper.getBoundingClientRect().left) / zoomLevel + "px";
-     annotationNote.style.width = annotationsPane.getBoundingClientRect().width / zoomLevel + "px";
-     connectorHorizontal.style.width = parseFloat(annotationNote.style.left) - CONNECTOR_MARGIN + "px";
-     if(previousAnnotation) {
-       previousRect = previousAnnotation.node.parentElement.getBoundingClientRect();
-       if((annotationWrapper.getBoundingClientRect().top - previousRect.bottom) / zoomLevel <= NOTE_MARGIN) {
-         annotationNote.style.top = Math.abs(annotationWrapper.getBoundingClientRect().top - previousRect.bottom) / zoomLevel + NOTE_MARGIN + "px"
++    function loadNextComponent(remainingComponents) {
++      var component = remainingComponents.shift();
++      if(component) {
++        zip.loadAsDOM(component.path, function(err, xmldoc) {
++          component.handler(xmldoc);
++          if(err || self.state === OdfContainer.INVALID) {
++            return
++          }
++          loadNextComponent(remainingComponents)
++        })
 +      }else {
-         annotationNote.style.top = "0px"
++        linkAnnotationStartAndEndElements(self.rootElement);
++        setState(OdfContainer.DONE)
 +      }
 +    }
-     connectorAngular.style.left = connectorHorizontal.getBoundingClientRect().width / zoomLevel + "px";
-     connectorAngular.style.width = lineDistance({x:connectorAngular.getBoundingClientRect().left / zoomLevel, y:connectorAngular.getBoundingClientRect().top / zoomLevel}, {x:annotationNote.getBoundingClientRect().left / zoomLevel, y:annotationNote.getBoundingClientRect().top / zoomLevel}) + "px";
-     connectorAngle = Math.asin((annotationNote.getBoundingClientRect().top - connectorAngular.getBoundingClientRect().top) / (zoomLevel * parseFloat(connectorAngular.style.width)));
-     connectorAngular.style.transform = "rotate(" + connectorAngle + "rad)";
-     connectorAngular.style.MozTransform = "rotate(" + connectorAngle + "rad)";
-     connectorAngular.style.WebkitTransform = "rotate(" + connectorAngle + "rad)";
-     connectorAngular.style.msTransform = "rotate(" + connectorAngle + "rad)"
-   }
-   function showAnnotationsPane(show) {
-     var sizer = canvas.getSizer();
-     if(show) {
-       annotationsPane.style.display = "inline-block";
-       sizer.style.paddingRight = window.getComputedStyle(annotationsPane).width
-     }else {
-       annotationsPane.style.display = "none";
-       sizer.style.paddingRight = 0
++    function loadComponents() {
++      var componentOrder = [{path:"styles.xml", handler:handleStylesXml}, {path:"content.xml", handler:handleContentXml}, {path:"meta.xml", handler:handleMetaXml}, {path:"settings.xml", handler:handleSettingsXml}, {path:"META-INF/manifest.xml", handler:handleManifestXml}];
++      loadNextComponent(componentOrder)
 +    }
-     canvas.refreshSize()
-   }
-   function sortAnnotations() {
-     annotations.sort(function(a, b) {
-       if(a.node.compareDocumentPosition(b.node) === Node.DOCUMENT_POSITION_FOLLOWING) {
-         return-1
++    function createDocumentElement(name) {
++      var s = "";
++      function defineNamespace(prefix, ns) {
++        s += " xmlns:" + prefix + '="' + ns + '"'
 +      }
-       return 1
-     })
-   }
-   function rerenderAnnotations() {
-     var i;
-     for(i = 0;i < annotations.length;i += 1) {
-       renderAnnotation(annotations[i])
++      odf.Namespaces.forEachPrefix(defineNamespace);
++      return'<?xml version="1.0" encoding="UTF-8"?><office:' + name + " " + s + ' office:version="1.2">'
 +    }
-   }
-   this.rerenderAnnotations = rerenderAnnotations;
-   function addAnnotation(annotation) {
-     showAnnotationsPane(true);
-     annotations.push({node:annotation.node, end:annotation.end});
-     sortAnnotations();
-     wrapAnnotation(annotation);
-     if(annotation.end) {
-       highlightAnnotation(annotation)
++    function serializeMetaXml() {
++      var serializer = new xmldom.LSSerializer, s = createDocumentElement("document-meta");
++      serializer.filter = new odf.OdfNodeFilter;
++      s += serializer.writeToString(self.rootElement.meta, odf.Namespaces.namespaceMap);
++      s += "</office:document-meta>";
++      return s
 +    }
-     rerenderAnnotations()
-   }
-   this.addAnnotation = addAnnotation;
-   function forgetAnnotation(annotation) {
-     var index = annotations.indexOf(annotation);
-     unwrapAnnotation(annotation);
-     unhighlightAnnotation(annotation);
-     if(index !== -1) {
-       annotations.splice(index, 1)
++    function createManifestEntry(fullPath, mediaType) {
++      var element = document.createElementNS(manifestns, "manifest:file-entry");
++      element.setAttributeNS(manifestns, "manifest:full-path", fullPath);
++      element.setAttributeNS(manifestns, "manifest:media-type", mediaType);
++      return element
 +    }
-     if(annotations.length === 0) {
-       showAnnotationsPane(false)
++    function serializeManifestXml() {
++      var header = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n', xml = '<manifest:manifest xmlns:manifest="' + manifestns + '" manifest:version="1.2"></manifest:manifest>', manifest = (runtime.parseXML(xml)), manifestRoot = manifest.documentElement, serializer = new xmldom.LSSerializer, fullPath;
++      for(fullPath in partMimetypes) {
++        if(partMimetypes.hasOwnProperty(fullPath)) {
++          manifestRoot.appendChild(createManifestEntry(fullPath, partMimetypes[fullPath]))
++        }
++      }
++      serializer.filter = new odf.OdfNodeFilter;
++      return header + serializer.writeToString(manifest, odf.Namespaces.namespaceMap)
 +    }
-   }
-   function forgetAnnotations() {
-     while(annotations.length) {
-       forgetAnnotation(annotations[0])
++    function serializeSettingsXml() {
++      var serializer = new xmldom.LSSerializer, s = createDocumentElement("document-settings");
++      serializer.filter = new odf.OdfNodeFilter;
++      if(self.rootElement.settings.firstElementChild) {
++        s += serializer.writeToString(self.rootElement.settings, odf.Namespaces.namespaceMap)
++      }
++      s += "</office:document-settings>";
++      return s
 +    }
-   }
-   this.forgetAnnotations = forgetAnnotations
- };
++    function serializeStylesXml() {
++      var fontFaceDecls, automaticStyles, masterStyles, nsmap = odf.Namespaces.namespaceMap, serializer = new xmldom.LSSerializer, s = createDocumentElement("document-styles");
++      automaticStyles = cloneStylesInScope(self.rootElement.automaticStyles, documentStylesScope);
++      masterStyles = (self.rootElement.masterStyles.cloneNode(true));
++      fontFaceDecls = cloneFontFaceDeclsUsedInStyles(self.rootElement.fontFaceDecls, [masterStyles, self.rootElement.styles, automaticStyles]);
++      styleInfo.removePrefixFromStyleNames(automaticStyles, automaticStylePrefix, masterStyles);
++      serializer.filter = new OdfStylesFilter(masterStyles, automaticStyles);
++      s += serializer.writeToString(fontFaceDecls, nsmap);
++      s += serializer.writeToString(self.rootElement.styles, nsmap);
++      s += serializer.writeToString(automaticStyles, nsmap);
++      s += serializer.writeToString(masterStyles, nsmap);
++      s += "</office:document-styles>";
++      return s
++    }
++    function serializeContentXml() {
++      var fontFaceDecls, automaticStyles, nsmap = odf.Namespaces.namespaceMap, serializer = new xmldom.LSSerializer, s = createDocumentElement("document-content");
++      automaticStyles = cloneStylesInScope(self.rootElement.automaticStyles, documentContentScope);
++      fontFaceDecls = cloneFontFaceDeclsUsedInStyles(self.rootElement.fontFaceDecls, [automaticStyles]);
++      serializer.filter = new OdfContentFilter(self.rootElement.body, automaticStyles);
++      s += serializer.writeToString(fontFaceDecls, nsmap);
++      s += serializer.writeToString(automaticStyles, nsmap);
++      s += serializer.writeToString(self.rootElement.body, nsmap);
++      s += "</office:document-content>";
++      return s
++    }
++    function createElement(type) {
++      var original = document.createElementNS(type.namespaceURI, type.localName), method, iface = new type.Type;
++      for(method in iface) {
++        if(iface.hasOwnProperty(method)) {
++          original[method] = iface[method]
++        }
++      }
++      return original
++    }
++    function loadFromXML(url, callback) {
++      runtime.loadXML(url, function(err, dom) {
++        if(err) {
++          callback(err)
++        }else {
++          handleFlatXml(dom)
++        }
++      })
++    }
++    this.setRootElement = setRootElement;
++    this.getContentElement = function() {
++      var body;
++      if(!contentElement) {
++        body = self.rootElement.body;
++        contentElement = domUtils.getDirectChild(body, officens, "text") || (domUtils.getDirectChild(body, officens, "presentation") || domUtils.getDirectChild(body, officens, "spreadsheet"))
++      }
++      if(!contentElement) {
++        throw"Could not find content element in <office:body/>.";
++      }
++      return contentElement
++    };
++    this.getDocumentType = function() {
++      var content = self.getContentElement();
++      return content && content.localName
++    };
++    this.getPart = function(partname) {
++      return new odf.OdfPart(partname, partMimetypes[partname], self, zip)
++    };
++    this.getPartData = function(url, callback) {
++      zip.load(url, callback)
++    };
++    function setMetadata(setProperties, removedPropertyNames) {
++      var metaElement = getEnsuredMetaElement();
++      if(setProperties) {
++        domUtils.mapKeyValObjOntoNode(metaElement, setProperties, odf.Namespaces.lookupNamespaceURI)
++      }
++      if(removedPropertyNames) {
++        domUtils.removeKeyElementsFromNode(metaElement, removedPropertyNames, odf.Namespaces.lookupNamespaceURI)
++      }
++    }
++    this.setMetadata = setMetadata;
++    this.incrementEditingCycles = function() {
++      var currentValueString = getMetaData(odf.Namespaces.metans, "editing-cycles"), currentCycles = currentValueString ? parseInt(currentValueString, 10) : 0;
++      if(isNaN(currentCycles)) {
++        currentCycles = 0
++      }
++      setMetadata({"meta:editing-cycles":currentCycles + 1}, null)
++    };
++    function updateMetadataForSaving() {
++      var generatorString, window = runtime.getWindow();
++      generatorString = "WebODF/" + (String(typeof webodf_version) !== "undefined" ? webodf_version : "FromSource");
++      if(window) {
++        generatorString = generatorString + " " + window.navigator.userAgent
++      }
++      setMetadata({"meta:generator":generatorString}, null)
++    }
++    function createEmptyTextDocument() {
++      var emptyzip = new core.Zip("", null), data = runtime.byteArrayFromString("application/vnd.oasis.opendocument.text", "utf8"), root = self.rootElement, text = document.createElementNS(officens, "text");
++      emptyzip.save("mimetype", data, false, new Date);
++      function addToplevelElement(memberName, realLocalName) {
++        var element;
++        if(!realLocalName) {
++          realLocalName = memberName
++        }
++        element = document.createElementNS(officens, realLocalName);
++        root[memberName] = element;
++        root.appendChild(element)
++      }
++      addToplevelElement("meta");
++      addToplevelElement("settings");
++      addToplevelElement("scripts");
++      addToplevelElement("fontFaceDecls", "font-face-decls");
++      addToplevelElement("styles");
++      addToplevelElement("automaticStyles", "automatic-styles");
++      addToplevelElement("masterStyles", "master-styles");
++      addToplevelElement("body");
++      root.body.appendChild(text);
++      partMimetypes["/"] = "application/vnd.oasis.opendocument.text";
++      partMimetypes["settings.xml"] = "text/xml";
++      partMimetypes["meta.xml"] = "text/xml";
++      partMimetypes["styles.xml"] = "text/xml";
++      partMimetypes["content.xml"] = "text/xml";
++      setState(OdfContainer.DONE);
++      return emptyzip
++    }
++    function fillZip() {
++      var data, date = new Date;
++      updateMetadataForSaving();
++      data = runtime.byteArrayFromString(serializeSettingsXml(), "utf8");
++      zip.save("settings.xml", data, true, date);
++      data = runtime.byteArrayFromString(serializeMetaXml(), "utf8");
++      zip.save("meta.xml", data, true, date);
++      data = runtime.byteArrayFromString(serializeStylesXml(), "utf8");
++      zip.save("styles.xml", data, true, date);
++      data = runtime.byteArrayFromString(serializeContentXml(), "utf8");
++      zip.save("content.xml", data, true, date);
++      data = runtime.byteArrayFromString(serializeManifestXml(), "utf8");
++      zip.save("META-INF/manifest.xml", data, true, date)
++    }
++    function createByteArray(successCallback, errorCallback) {
++      fillZip();
++      zip.createByteArray(successCallback, errorCallback)
++    }
++    this.createByteArray = createByteArray;
++    function saveAs(newurl, callback) {
++      fillZip();
++      zip.writeAs(newurl, function(err) {
++        callback(err)
++      })
++    }
++    this.saveAs = saveAs;
++    this.save = function(callback) {
++      saveAs(url, callback)
++    };
++    this.getUrl = function() {
++      return url
++    };
++    this.setBlob = function(filename, mimetype, content) {
++      var data = base64.convertBase64ToByteArray(content), date = new Date;
++      zip.save(filename, data, false, date);
++      if(partMimetypes.hasOwnProperty(filename)) {
++        runtime.log(filename + " has been overwritten.")
++      }
++      partMimetypes[filename] = mimetype
++    };
++    this.removeBlob = function(filename) {
++      var foundAndRemoved = zip.remove(filename);
++      runtime.assert(foundAndRemoved, "file is not found: " + filename);
++      delete partMimetypes[filename]
++    };
++    this.state = OdfContainer.LOADING;
++    this.rootElement = (createElement({Type:odf.ODFDocumentElement, namespaceURI:odf.ODFDocumentElement.namespaceURI, localName:odf.ODFDocumentElement.localName}));
++    if(url) {
++      zip = new core.Zip(url, function(err, zipobject) {
++        zip = zipobject;
++        if(err) {
++          loadFromXML(url, function(xmlerr) {
++            if(err) {
++              zip.error = err + "\n" + xmlerr;
++              setState(OdfContainer.INVALID)
++            }
++          })
++        }else {
++          loadComponents()
++        }
++      })
++    }else {
++      zip = createEmptyTextDocument()
++    }
++  };
++  odf.OdfContainer.EMPTY = 0;
++  odf.OdfContainer.LOADING = 1;
++  odf.OdfContainer.DONE = 2;
++  odf.OdfContainer.INVALID = 3;
++  odf.OdfContainer.SAVING = 4;
++  odf.OdfContainer.MODIFIED = 5;
++  odf.OdfContainer.getContainer = function(url) {
++    return new odf.OdfContainer(url, null)
++  };
++  return odf.OdfContainer
++})();
 +/*
 +
 + Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("core.Cursor");
- runtime.loadClass("core.DomUtils");
- runtime.loadClass("core.PositionIterator");
- runtime.loadClass("core.PositionFilter");
- runtime.loadClass("core.LoopWatchDog");
- runtime.loadClass("odf.OdfUtils");
- gui.SelectionMover = function SelectionMover(cursor, rootNode) {
-   var odfUtils = new odf.OdfUtils, domUtils = new core.DomUtils, positionIterator, cachedXOffset, timeoutHandle, FILTER_ACCEPT = core.PositionFilter.FilterResult.FILTER_ACCEPT;
-   function getIteratorAtCursor() {
-     positionIterator.setUnfilteredPosition(cursor.getNode(), 0);
-     return positionIterator
++odf.OdfUtils = function OdfUtils() {
++  var textns = odf.Namespaces.textns, drawns = odf.Namespaces.drawns, xlinkns = odf.Namespaces.xlinkns, whitespaceOnly = /^\s*$/, domUtils = new core.DomUtils;
++  function isImage(e) {
++    var name = e && e.localName;
++    return name === "image" && e.namespaceURI === drawns
 +  }
-   function getMaximumNodePosition(node) {
-     return node.nodeType === Node.TEXT_NODE ? node.textContent.length : node.childNodes.length
++  this.isImage = isImage;
++  function isCharacterFrame(e) {
++    return e !== null && (e.nodeType === Node.ELEMENT_NODE && (e.localName === "frame" && (e.namespaceURI === drawns && (e).getAttributeNS(textns, "anchor-type") === "as-char")))
 +  }
-   function getClientRect(clientRectangles, useRightEdge) {
-     var rectangle, simplifiedRectangle = null;
-     if(clientRectangles && clientRectangles.length > 0) {
-       rectangle = useRightEdge ? clientRectangles.item(clientRectangles.length - 1) : clientRectangles.item(0)
-     }
-     if(rectangle) {
-       simplifiedRectangle = {top:rectangle.top, left:useRightEdge ? rectangle.right : rectangle.left, bottom:rectangle.bottom}
-     }
-     return simplifiedRectangle
++  this.isCharacterFrame = isCharacterFrame;
++  function isAnnotation(e) {
++    var name = e && e.localName;
++    return name === "annotation" && e.namespaceURI === odf.Namespaces.officens
 +  }
-   function getVisibleRect(container, offset, range, useRightEdge) {
-     var rectangle, nodeType = container.nodeType;
-     range.setStart(container, offset);
-     range.collapse(!useRightEdge);
-     rectangle = getClientRect(range.getClientRects(), useRightEdge === true);
-     if(!rectangle && offset > 0) {
-       range.setStart(container, offset - 1);
-       range.setEnd(container, offset);
-       rectangle = getClientRect(range.getClientRects(), true)
-     }
-     if(!rectangle) {
-       if(nodeType === Node.ELEMENT_NODE && (offset > 0 && (container).childNodes.length >= offset)) {
-         rectangle = getVisibleRect(container, offset - 1, range, true)
-       }else {
-         if(container.nodeType === Node.TEXT_NODE && offset > 0) {
-           rectangle = getVisibleRect(container, offset - 1, range, true)
-         }else {
-           if(container.previousSibling) {
-             rectangle = getVisibleRect(container.previousSibling, getMaximumNodePosition(container.previousSibling), range, true)
-           }else {
-             if(container.parentNode && container.parentNode !== rootNode) {
-               rectangle = getVisibleRect(container.parentNode, 0, range, false)
-             }else {
-               range.selectNode(rootNode);
-               rectangle = getClientRect(range.getClientRects(), false)
-             }
-           }
-         }
-       }
-     }
-     runtime.assert(Boolean(rectangle), "No visible rectangle found");
-     return(rectangle)
++  function isAnnotationWrapper(e) {
++    var name = e && e.localName;
++    return name === "div" && (e).className === "annotationWrapper"
 +  }
-   function doMove(positions, extend, move) {
-     var left = positions, iterator = getIteratorAtCursor(), initialRect, range = (rootNode.ownerDocument.createRange()), selectionRange = cursor.getSelectedRange().cloneRange(), newRect, horizontalMovement, o, c, isForwardSelection;
-     initialRect = getVisibleRect(iterator.container(), iterator.unfilteredDomOffset(), range);
-     while(left > 0 && move()) {
-       left -= 1
-     }
-     if(extend) {
-       c = iterator.container();
-       o = iterator.unfilteredDomOffset();
-       if(domUtils.comparePoints((selectionRange.startContainer), selectionRange.startOffset, c, o) === -1) {
-         selectionRange.setStart(c, o);
-         isForwardSelection = false
-       }else {
-         selectionRange.setEnd(c, o)
-       }
-     }else {
-       selectionRange.setStart(iterator.container(), iterator.unfilteredDomOffset());
-       selectionRange.collapse(true)
-     }
-     cursor.setSelectedRange(selectionRange, isForwardSelection);
-     iterator = getIteratorAtCursor();
-     newRect = getVisibleRect(iterator.container(), iterator.unfilteredDomOffset(), range);
-     horizontalMovement = newRect.top === initialRect.top ? true : false;
-     if(horizontalMovement || cachedXOffset === undefined) {
-       cachedXOffset = newRect.left
-     }
-     runtime.clearTimeout(timeoutHandle);
-     timeoutHandle = runtime.setTimeout(function() {
-       cachedXOffset = undefined
-     }, 2E3);
-     range.detach();
-     return positions - left
++  function isInlineRoot(e) {
++    return isAnnotation(e) || isAnnotationWrapper(e)
 +  }
-   this.movePointForward = function(positions, extend) {
-     return doMove(positions, extend || false, positionIterator.nextPosition)
++  this.isInlineRoot = isInlineRoot;
++  this.isTextSpan = function(e) {
++    var name = e && e.localName;
++    return name === "span" && e.namespaceURI === textns
 +  };
-   this.movePointBackward = function(positions, extend) {
-     return doMove(positions, extend || false, positionIterator.previousPosition)
++  function isHyperlink(node) {
++    var name = node && node.localName;
++    return name === "a" && node.namespaceURI === textns
++  }
++  this.isHyperlink = isHyperlink;
++  this.getHyperlinkTarget = function(element) {
++    return element.getAttributeNS(xlinkns, "href")
 +  };
-   function isPositionWalkable(filter) {
-     var iterator = getIteratorAtCursor();
-     if(filter.acceptPosition(iterator) === FILTER_ACCEPT) {
-       iterator.setUnfilteredPosition(cursor.getAnchorNode(), 0);
-       if(filter.acceptPosition(iterator) === FILTER_ACCEPT) {
-         return true
-       }
++  function isParagraph(e) {
++    var name = e && e.localName;
++    return(name === "p" || name === "h") && e.namespaceURI === textns
++  }
++  this.isParagraph = isParagraph;
++  function getParagraphElement(node) {
++    while(node && !isParagraph(node)) {
++      node = node.parentNode
 +    }
-     return false
++    return(node)
 +  }
-   function countSteps(iterator, steps, filter) {
-     var watch = new core.LoopWatchDog(1E4), positions = 0, positionsCount = 0, increment = steps >= 0 ? 1 : -1, delegate = (steps >= 0 ? iterator.nextPosition : iterator.previousPosition);
-     while(steps !== 0 && delegate()) {
-       watch.check();
-       positionsCount += increment;
-       if(filter.acceptPosition(iterator) === FILTER_ACCEPT) {
-         steps -= increment;
-         positions += positionsCount;
-         positionsCount = 0
++  this.getParagraphElement = getParagraphElement;
++  this.isWithinTrackedChanges = function(node, container) {
++    while(node && node !== container) {
++      if(node.namespaceURI === textns && node.localName === "tracked-changes") {
++        return true
 +      }
++      node = node.parentNode
 +    }
-     return positions
++    return false
++  };
++  this.isListItem = function(e) {
++    var name = e && e.localName;
++    return name === "list-item" && e.namespaceURI === textns
++  };
++  this.isLineBreak = function(e) {
++    var name = e && e.localName;
++    return name === "line-break" && e.namespaceURI === textns
++  };
++  function isODFWhitespace(text) {
++    return/^[ \t\r\n]+$/.test(text)
 +  }
-   function convertForwardStepsBetweenFilters(stepsFilter1, filter1, filter2) {
-     var iterator = getIteratorAtCursor(), watch = new core.LoopWatchDog(1E4), pendingStepsFilter2 = 0, stepsFilter2 = 0;
-     while(stepsFilter1 > 0 && iterator.nextPosition()) {
-       watch.check();
-       if(filter2.acceptPosition(iterator) === FILTER_ACCEPT) {
-         pendingStepsFilter2 += 1;
-         if(filter1.acceptPosition(iterator) === FILTER_ACCEPT) {
-           stepsFilter2 += pendingStepsFilter2;
-           pendingStepsFilter2 = 0;
-           stepsFilter1 -= 1
-         }
-       }
++  this.isODFWhitespace = isODFWhitespace;
++  function isGroupingElement(n) {
++    if(n === null || n.nodeType !== Node.ELEMENT_NODE) {
++      return false
 +    }
-     return stepsFilter2
++    var e = (n), localName = e.localName;
++    return/^(span|p|h|a|meta)$/.test(localName) && e.namespaceURI === textns || localName === "span" && e.className === "annotationHighlight"
 +  }
-   function convertBackwardStepsBetweenFilters(stepsFilter1, filter1, filter2) {
-     var iterator = getIteratorAtCursor(), watch = new core.LoopWatchDog(1E4), pendingStepsFilter2 = 0, stepsFilter2 = 0;
-     while(stepsFilter1 > 0 && iterator.previousPosition()) {
-       watch.check();
-       if(filter2.acceptPosition(iterator) === FILTER_ACCEPT) {
-         pendingStepsFilter2 += 1;
-         if(filter1.acceptPosition(iterator) === FILTER_ACCEPT) {
-           stepsFilter2 += pendingStepsFilter2;
-           pendingStepsFilter2 = 0;
-           stepsFilter1 -= 1
-         }
++  this.isGroupingElement = isGroupingElement;
++  function isCharacterElement(e) {
++    var n = e && e.localName, ns, r = false;
++    if(n) {
++      ns = e.namespaceURI;
++      if(ns === textns) {
++        r = n === "s" || (n === "tab" || n === "line-break")
 +      }
 +    }
-     return stepsFilter2
++    return r
 +  }
-   function countStepsPublic(steps, filter) {
-     var iterator = getIteratorAtCursor();
-     return countSteps(iterator, steps, filter)
++  this.isCharacterElement = isCharacterElement;
++  function isAnchoredAsCharacterElement(e) {
++    return isCharacterElement(e) || (isCharacterFrame(e) || isInlineRoot(e))
 +  }
-   function countPositionsToClosestStep(container, offset, filter) {
-     var iterator = getIteratorAtCursor(), paragraphNode = odfUtils.getParagraphElement(iterator.getCurrentNode()), count = 0;
-     iterator.setUnfilteredPosition(container, offset);
-     if(filter.acceptPosition(iterator) !== FILTER_ACCEPT) {
-       count = countSteps(iterator, -1, filter);
-       if(count === 0 || paragraphNode && paragraphNode !== odfUtils.getParagraphElement(iterator.getCurrentNode())) {
-         iterator.setUnfilteredPosition(container, offset);
-         count = countSteps(iterator, 1, filter)
++  this.isAnchoredAsCharacterElement = isAnchoredAsCharacterElement;
++  function isSpaceElement(e) {
++    var n = e && e.localName, ns, r = false;
++    if(n) {
++      ns = e.namespaceURI;
++      if(ns === textns) {
++        r = n === "s"
 +      }
 +    }
-     return count
++    return r
 +  }
-   function countLineSteps(filter, direction, iterator) {
-     var c = iterator.container(), steps = 0, bestContainer = null, bestOffset, bestXDiff = 10, xDiff, bestCount = 0, top, left, lastTop, rect, range = (rootNode.ownerDocument.createRange()), watch = new core.LoopWatchDog(1E4);
-     rect = getVisibleRect(c, iterator.unfilteredDomOffset(), range);
-     top = rect.top;
-     if(cachedXOffset === undefined) {
-       left = rect.left
-     }else {
-       left = cachedXOffset
-     }
-     lastTop = top;
-     while((direction < 0 ? iterator.previousPosition() : iterator.nextPosition()) === true) {
-       watch.check();
-       if(filter.acceptPosition(iterator) === FILTER_ACCEPT) {
-         steps += 1;
-         c = iterator.container();
-         rect = getVisibleRect(c, iterator.unfilteredDomOffset(), range);
-         if(rect.top !== top) {
-           if(rect.top !== lastTop && lastTop !== top) {
-             break
-           }
-           lastTop = rect.top;
-           xDiff = Math.abs(left - rect.left);
-           if(bestContainer === null || xDiff < bestXDiff) {
-             bestContainer = c;
-             bestOffset = iterator.unfilteredDomOffset();
-             bestXDiff = xDiff;
-             bestCount = steps
-           }
-         }
-       }
++  this.isSpaceElement = isSpaceElement;
++  function firstChild(node) {
++    while(node.firstChild !== null && isGroupingElement(node)) {
++      node = node.firstChild
 +    }
-     if(bestContainer !== null) {
-       iterator.setUnfilteredPosition(bestContainer, (bestOffset));
-       steps = bestCount
-     }else {
-       steps = 0
++    return node
++  }
++  this.firstChild = firstChild;
++  function lastChild(node) {
++    while(node.lastChild !== null && isGroupingElement(node)) {
++      node = node.lastChild
 +    }
-     range.detach();
-     return steps
++    return node
 +  }
-   function countLinesSteps(lines, filter) {
-     var iterator = getIteratorAtCursor(), stepCount = 0, steps = 0, direction = lines < 0 ? -1 : 1;
-     lines = Math.abs(lines);
-     while(lines > 0) {
-       stepCount += countLineSteps(filter, direction, iterator);
-       if(stepCount === 0) {
-         break
-       }
-       steps += stepCount;
-       lines -= 1
++  this.lastChild = lastChild;
++  function previousNode(node) {
++    while(!isParagraph(node) && node.previousSibling === null) {
++      node = (node.parentNode)
 +    }
-     return steps * direction
++    return isParagraph(node) ? null : lastChild((node.previousSibling))
 +  }
-   function countStepsToLineBoundary(direction, filter) {
-     var fnNextPos, increment, lastRect, rect, onSameLine, iterator = getIteratorAtCursor(), paragraphNode = odfUtils.getParagraphElement(iterator.getCurrentNode()), steps = 0, range = (rootNode.ownerDocument.createRange());
-     if(direction < 0) {
-       fnNextPos = iterator.previousPosition;
-       increment = -1
-     }else {
-       fnNextPos = iterator.nextPosition;
-       increment = 1
++  this.previousNode = previousNode;
++  function nextNode(node) {
++    while(!isParagraph(node) && node.nextSibling === null) {
++      node = (node.parentNode)
 +    }
-     lastRect = getVisibleRect(iterator.container(), iterator.unfilteredDomOffset(), range);
-     while(fnNextPos.call(iterator)) {
-       if(filter.acceptPosition(iterator) === FILTER_ACCEPT) {
-         if(odfUtils.getParagraphElement(iterator.getCurrentNode()) !== paragraphNode) {
-           break
++    return isParagraph(node) ? null : firstChild((node.nextSibling))
++  }
++  this.nextNode = nextNode;
++  function scanLeftForNonSpace(node) {
++    var r = false, text;
++    while(node) {
++      if(node.nodeType === Node.TEXT_NODE) {
++        text = (node);
++        if(text.length === 0) {
++          node = previousNode(text)
++        }else {
++          return!isODFWhitespace(text.data.substr(text.length - 1, 1))
 +        }
-         rect = getVisibleRect(iterator.container(), iterator.unfilteredDomOffset(), range);
-         if(rect.bottom !== lastRect.bottom) {
-           onSameLine = rect.top >= lastRect.top && rect.bottom < lastRect.bottom || rect.top <= lastRect.top && rect.bottom > lastRect.bottom;
-           if(!onSameLine) {
-             break
-           }
++      }else {
++        if(isAnchoredAsCharacterElement(node)) {
++          r = isSpaceElement(node) === false;
++          node = null
++        }else {
++          node = previousNode(node)
 +        }
-         steps += increment;
-         lastRect = rect
 +      }
 +    }
-     range.detach();
-     return steps
++    return r
 +  }
-   function countStepsToPosition(targetNode, targetOffset, filter) {
-     runtime.assert(targetNode !== null, "SelectionMover.countStepsToPosition called with element===null");
-     var iterator = getIteratorAtCursor(), c = iterator.container(), o = iterator.unfilteredDomOffset(), steps = 0, watch = new core.LoopWatchDog(1E4), comparison;
-     iterator.setUnfilteredPosition(targetNode, targetOffset);
-     while(filter.acceptPosition(iterator) !== FILTER_ACCEPT && iterator.previousPosition()) {
-       watch.check()
-     }
-     targetNode = iterator.container();
-     runtime.assert(Boolean(targetNode), "SelectionMover.countStepsToPosition: positionIterator.container() returned null");
-     targetOffset = iterator.unfilteredDomOffset();
-     iterator.setUnfilteredPosition(c, o);
-     while(filter.acceptPosition(iterator) !== FILTER_ACCEPT && iterator.previousPosition()) {
-       watch.check()
-     }
-     comparison = domUtils.comparePoints(targetNode, targetOffset, iterator.container(), iterator.unfilteredDomOffset());
-     if(comparison < 0) {
-       while(iterator.nextPosition()) {
-         watch.check();
-         if(filter.acceptPosition(iterator) === FILTER_ACCEPT) {
-           steps += 1
-         }
-         if(iterator.container() === targetNode && iterator.unfilteredDomOffset() === targetOffset) {
-           return steps
++  this.scanLeftForNonSpace = scanLeftForNonSpace;
++  function lookLeftForCharacter(node) {
++    var text, r = 0, tl = 0;
++    if(node.nodeType === Node.TEXT_NODE) {
++      tl = (node).length
++    }
++    if(tl > 0) {
++      text = (node).data;
++      if(!isODFWhitespace(text.substr(tl - 1, 1))) {
++        r = 1
++      }else {
++        if(tl === 1) {
++          r = scanLeftForNonSpace(previousNode(node)) ? 2 : 0
++        }else {
++          r = isODFWhitespace(text.substr(tl - 2, 1)) ? 0 : 2
 +        }
 +      }
 +    }else {
-       if(comparison > 0) {
-         while(iterator.previousPosition()) {
-           watch.check();
-           if(filter.acceptPosition(iterator) === FILTER_ACCEPT) {
-             steps -= 1;
-             if(iterator.container() === targetNode && iterator.unfilteredDomOffset() === targetOffset) {
-               break
-             }
-           }
-         }
++      if(isAnchoredAsCharacterElement(node)) {
++        r = 1
 +      }
 +    }
-     return steps
-   }
-   this.getStepCounter = function() {
-     return{countSteps:countStepsPublic, convertForwardStepsBetweenFilters:convertForwardStepsBetweenFilters, convertBackwardStepsBetweenFilters:convertBackwardStepsBetweenFilters, countLinesSteps:countLinesSteps, countStepsToLineBoundary:countStepsToLineBoundary, countStepsToPosition:countStepsToPosition, isPositionWalkable:isPositionWalkable, countPositionsToNearestStep:countPositionsToClosestStep}
-   };
-   function init() {
-     positionIterator = gui.SelectionMover.createPositionIterator(rootNode);
-     var range = rootNode.ownerDocument.createRange();
-     range.setStart(positionIterator.container(), positionIterator.unfilteredDomOffset());
-     range.collapse(true);
-     cursor.setSelectedRange(range)
++    return r
 +  }
-   init()
- };
- gui.SelectionMover.createPositionIterator = function(rootNode) {
-   function CursorFilter() {
-     this.acceptNode = function(node) {
-       if(!node || (node.namespaceURI === "urn:webodf:names:cursor" || node.namespaceURI === "urn:webodf:names:editinfo")) {
-         return NodeFilter.FILTER_REJECT
++  this.lookLeftForCharacter = lookLeftForCharacter;
++  function lookRightForCharacter(node) {
++    var r = false, l = 0;
++    if(node && node.nodeType === Node.TEXT_NODE) {
++      l = (node).length
++    }
++    if(l > 0) {
++      r = !isODFWhitespace((node).data.substr(0, 1))
++    }else {
++      if(isAnchoredAsCharacterElement(node)) {
++        r = true
 +      }
-       return NodeFilter.FILTER_ACCEPT
 +    }
++    return r
 +  }
-   var filter = new CursorFilter;
-   return new core.PositionIterator(rootNode, 5, filter, false)
- };
- (function() {
-   return gui.SelectionMover
- })();
- /*
- 
-  Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
- 
-  @licstart
-  The JavaScript code in this page is free software: you can redistribute it
-  and/or modify it under the terms of the GNU Affero General Public License
-  (GNU AGPL) as published by the Free Software Foundation, either version 3 of
-  the License, or (at your option) any later version.  The code is distributed
-  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
- 
-  You should have received a copy of the GNU Affero General Public License
-  along with this code.  If not, see <http://www.gnu.org/licenses/>.
- 
-  As additional permission under GNU AGPL version 3 section 7, you
-  may distribute non-source (e.g., minimized or compacted) forms of
-  that code without the copy of the GNU GPL normally required by
-  section 4, provided you include this license notice and a URL
-  through which recipients can access the Corresponding Source.
- 
-  As a special exception to the AGPL, any HTML file which merely makes function
-  calls to this code, and for that purpose includes it by reference shall be
-  deemed a separate work for copyright law purposes. In addition, the copyright
-  holders of this code give you permission to combine this code with free
-  software libraries that are released under the GNU LGPL. You may copy and
-  distribute such a system following the terms of the GNU AGPL for this code
-  and the LGPL for the libraries. If you modify this code, you may extend this
-  exception to your version of the code, but you are not obligated to do so.
-  If you do not wish to do so, delete this exception statement from your
-  version.
- 
-  This license applies to this entire compilation.
-  @licend
-  @source: http://www.webodf.org/
-  @source: https://github.com/kogmbh/WebODF/
- */
- odf.OdfNodeFilter = function OdfNodeFilter() {
-   this.acceptNode = function(node) {
-     var result;
-     if(node.namespaceURI === "http://www.w3.org/1999/xhtml") {
-       result = NodeFilter.FILTER_SKIP
-     }else {
-       if(node.namespaceURI && node.namespaceURI.match(/^urn:webodf:/)) {
-         result = NodeFilter.FILTER_REJECT
++  this.lookRightForCharacter = lookRightForCharacter;
++  function scanLeftForAnyCharacter(node) {
++    var r = false, l;
++    node = node && lastChild(node);
++    while(node) {
++      if(node.nodeType === Node.TEXT_NODE) {
++        l = (node).length
 +      }else {
-         result = NodeFilter.FILTER_ACCEPT
++        l = 0
++      }
++      if(l > 0 && !isODFWhitespace((node).data)) {
++        r = true;
++        break
++      }
++      if(isAnchoredAsCharacterElement(node)) {
++        r = true;
++        break
 +      }
++      node = previousNode(node)
 +    }
-     return result
++    return r
 +  }
- };
- /*
- 
-  Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
- 
-  @licstart
-  The JavaScript code in this page is free software: you can redistribute it
-  and/or modify it under the terms of the GNU Affero General Public License
-  (GNU AGPL) as published by the Free Software Foundation, either version 3 of
-  the License, or (at your option) any later version.  The code is distributed
-  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
- 
-  You should have received a copy of the GNU Affero General Public License
-  along with this code.  If not, see <http://www.gnu.org/licenses/>.
- 
-  As additional permission under GNU AGPL version 3 section 7, you
-  may distribute non-source (e.g., minimized or compacted) forms of
-  that code without the copy of the GNU GPL normally required by
-  section 4, provided you include this license notice and a URL
-  through which recipients can access the Corresponding Source.
- 
-  As a special exception to the AGPL, any HTML file which merely makes function
-  calls to this code, and for that purpose includes it by reference shall be
-  deemed a separate work for copyright law purposes. In addition, the copyright
-  holders of this code give you permission to combine this code with free
-  software libraries that are released under the GNU LGPL. You may copy and
-  distribute such a system following the terms of the GNU AGPL for this code
-  and the LGPL for the libraries. If you modify this code, you may extend this
-  exception to your version of the code, but you are not obligated to do so.
-  If you do not wish to do so, delete this exception statement from your
-  version.
- 
-  This license applies to this entire compilation.
-  @licend
-  @source: http://www.webodf.org/
-  @source: https://github.com/kogmbh/WebODF/
- */
- runtime.loadClass("odf.Namespaces");
- runtime.loadClass("odf.OdfUtils");
- runtime.loadClass("xmldom.XPath");
- runtime.loadClass("core.CSSUnits");
- odf.StyleTreeNode = function StyleTreeNode(element) {
-   this.derivedStyles = {};
-   this.element = element
- };
- odf.Style2CSS = function Style2CSS() {
-   var drawns = odf.Namespaces.drawns, fons = odf.Namespaces.fons, officens = odf.Namespaces.officens, stylens = odf.Namespaces.stylens, svgns = odf.Namespaces.svgns, tablens = odf.Namespaces.tablens, textns = odf.Namespaces.textns, xlinkns = odf.Namespaces.xlinkns, presentationns = odf.Namespaces.presentationns, familynamespaceprefixes = {"graphic":"draw", "drawing-page":"draw", "paragraph":"text", "presentation":"presentation", "ruby":"text", "section":"text", "table":"table", "table-c [...]
-   "table-column":"table", "table-row":"table", "text":"text", "list":"text", "page":"office"}, familytagnames = {"graphic":["circle", "connected", "control", "custom-shape", "ellipse", "frame", "g", "line", "measure", "page", "page-thumbnail", "path", "polygon", "polyline", "rect", "regular-polygon"], "paragraph":["alphabetical-index-entry-template", "h", "illustration-index-entry-template", "index-source-style", "object-index-entry-template", "p", "table-index-entry-template", "table-o [...]
-   "user-index-entry-template"], "presentation":["caption", "circle", "connector", "control", "custom-shape", "ellipse", "frame", "g", "line", "measure", "page-thumbnail", "path", "polygon", "polyline", "rect", "regular-polygon"], "drawing-page":["caption", "circle", "connector", "control", "page", "custom-shape", "ellipse", "frame", "g", "line", "measure", "page-thumbnail", "path", "polygon", "polyline", "rect", "regular-polygon"], "ruby":["ruby", "ruby-text"], "section":["alphabetical- [...]
-   "illustration-index", "index-title", "object-index", "section", "table-of-content", "table-index", "user-index"], "table":["background", "table"], "table-cell":["body", "covered-table-cell", "even-columns", "even-rows", "first-column", "first-row", "last-column", "last-row", "odd-columns", "odd-rows", "table-cell"], "table-column":["table-column"], "table-row":["table-row"], "text":["a", "index-entry-chapter", "index-entry-link-end", "index-entry-link-start", "index-entry-page-number" [...]
-   "index-entry-tab-stop", "index-entry-text", "index-title-template", "linenumbering-configuration", "list-level-style-number", "list-level-style-bullet", "outline-level-style", "span"], "list":["list-item"]}, textPropertySimpleMapping = [[fons, "color", "color"], [fons, "background-color", "background-color"], [fons, "font-weight", "font-weight"], [fons, "font-style", "font-style"]], bgImageSimpleMapping = [[stylens, "repeat", "background-repeat"]], paragraphPropertySimpleMapping = [[f [...]
-   "background-color"], [fons, "text-align", "text-align"], [fons, "text-indent", "text-indent"], [fons, "padding", "padding"], [fons, "padding-left", "padding-left"], [fons, "padding-right", "padding-right"], [fons, "padding-top", "padding-top"], [fons, "padding-bottom", "padding-bottom"], [fons, "border-left", "border-left"], [fons, "border-right", "border-right"], [fons, "border-top", "border-top"], [fons, "border-bottom", "border-bottom"], [fons, "margin", "margin"], [fons, "margin-l [...]
-   [fons, "margin-right", "margin-right"], [fons, "margin-top", "margin-top"], [fons, "margin-bottom", "margin-bottom"], [fons, "border", "border"]], graphicPropertySimpleMapping = [[fons, "background-color", "background-color"], [fons, "min-height", "min-height"], [drawns, "stroke", "border"], [svgns, "stroke-color", "border-color"], [svgns, "stroke-width", "border-width"], [fons, "border", "border"], [fons, "border-left", "border-left"], [fons, "border-right", "border-right"], [fons, " [...]
-   "border-top"], [fons, "border-bottom", "border-bottom"]], tablecellPropertySimpleMapping = [[fons, "background-color", "background-color"], [fons, "border-left", "border-left"], [fons, "border-right", "border-right"], [fons, "border-top", "border-top"], [fons, "border-bottom", "border-bottom"], [fons, "border", "border"]], tablecolumnPropertySimpleMapping = [[stylens, "column-width", "width"]], tablerowPropertySimpleMapping = [[stylens, "row-height", "height"], [fons, "keep-together", [...]
-   [[stylens, "width", "width"], [fons, "margin-left", "margin-left"], [fons, "margin-right", "margin-right"], [fons, "margin-top", "margin-top"], [fons, "margin-bottom", "margin-bottom"]], pageContentPropertySimpleMapping = [[fons, "background-color", "background-color"], [fons, "padding", "padding"], [fons, "padding-left", "padding-left"], [fons, "padding-right", "padding-right"], [fons, "padding-top", "padding-top"], [fons, "padding-bottom", "padding-bottom"], [fons, "border", "border [...]
-   "border-left", "border-left"], [fons, "border-right", "border-right"], [fons, "border-top", "border-top"], [fons, "border-bottom", "border-bottom"], [fons, "margin", "margin"], [fons, "margin-left", "margin-left"], [fons, "margin-right", "margin-right"], [fons, "margin-top", "margin-top"], [fons, "margin-bottom", "margin-bottom"]], pageSizePropertySimpleMapping = [[fons, "page-width", "width"], [fons, "page-height", "height"]], borderPropertyMap = {"border":true, "border-left":true, " [...]
-   "border-top":true, "border-bottom":true, "stroke-width":true}, fontFaceDeclsMap = {}, utils = new odf.OdfUtils, documentType, odfRoot, defaultFontSize, xpath = xmldom.XPath, cssUnits = new core.CSSUnits;
-   function getStyleMap(stylesnode) {
-     var node, name, family, style, stylemap = {};
-     if(!stylesnode) {
-       return stylemap
-     }
-     node = stylesnode.firstElementChild;
++  this.scanLeftForAnyCharacter = scanLeftForAnyCharacter;
++  function scanRightForAnyCharacter(node) {
++    var r = false, l;
++    node = node && firstChild(node);
 +    while(node) {
-       if(node.namespaceURI === stylens && (node.localName === "style" || node.localName === "default-style")) {
-         family = node.getAttributeNS(stylens, "family")
++      if(node.nodeType === Node.TEXT_NODE) {
++        l = (node).length
 +      }else {
-         if(node.namespaceURI === textns && node.localName === "list-style") {
-           family = "list"
-         }else {
-           if(node.namespaceURI === stylens && (node.localName === "page-layout" || node.localName === "default-page-layout")) {
-             family = "page"
-           }else {
-             family = undefined
-           }
-         }
++        l = 0
 +      }
-       if(family) {
-         name = node.getAttributeNS(stylens, "name");
-         if(!name) {
-           name = ""
-         }
-         if(stylemap.hasOwnProperty(family)) {
-           style = stylemap[family]
-         }else {
-           stylemap[family] = style = {}
-         }
-         style[name] = node
++      if(l > 0 && !isODFWhitespace((node).data)) {
++        r = true;
++        break
 +      }
-       node = node.nextElementSibling
++      if(isAnchoredAsCharacterElement(node)) {
++        r = true;
++        break
++      }
++      node = nextNode(node)
 +    }
-     return stylemap
++    return r
 +  }
-   function findStyle(stylestree, name) {
-     if(stylestree.hasOwnProperty(name)) {
-       return stylestree[name]
-     }
-     var n, style = null;
-     for(n in stylestree) {
-       if(stylestree.hasOwnProperty(n)) {
-         style = findStyle(stylestree[n].derivedStyles, name);
-         if(style) {
-           break
-         }
-       }
++  this.scanRightForAnyCharacter = scanRightForAnyCharacter;
++  function isTrailingWhitespace(textnode, offset) {
++    if(!isODFWhitespace(textnode.data.substr(offset))) {
++      return false
 +    }
-     return style
++    return!scanRightForAnyCharacter(nextNode(textnode))
 +  }
-   function addStyleToStyleTree(stylename, stylesmap, stylestree) {
-     var style, parentname, parentstyle;
-     if(!stylesmap.hasOwnProperty(stylename)) {
-       return null
++  this.isTrailingWhitespace = isTrailingWhitespace;
++  function isSignificantWhitespace(textNode, offset) {
++    var text = textNode.data, result;
++    if(!isODFWhitespace(text[offset])) {
++      return false
 +    }
-     style = new odf.StyleTreeNode(stylesmap[stylename]);
-     parentname = style.element.getAttributeNS(stylens, "parent-style-name");
-     parentstyle = null;
-     if(parentname) {
-       parentstyle = findStyle(stylestree, parentname) || addStyleToStyleTree(parentname, stylesmap, stylestree)
++    if(isAnchoredAsCharacterElement(textNode.parentNode)) {
++      return false
 +    }
-     if(parentstyle) {
-       parentstyle.derivedStyles[stylename] = style
++    if(offset > 0) {
++      if(!isODFWhitespace(text[offset - 1])) {
++        result = true
++      }
 +    }else {
-       stylestree[stylename] = style
++      if(scanLeftForNonSpace(previousNode(textNode))) {
++        result = true
++      }
 +    }
-     delete stylesmap[stylename];
-     return style
++    if(result === true) {
++      return isTrailingWhitespace(textNode, offset) ? false : true
++    }
++    return false
 +  }
-   function addStyleMapToStyleTree(stylesmap, stylestree) {
-     var name;
-     for(name in stylesmap) {
-       if(stylesmap.hasOwnProperty(name)) {
-         addStyleToStyleTree(name, stylesmap, stylestree)
-       }
++  this.isSignificantWhitespace = isSignificantWhitespace;
++  this.isDowngradableSpaceElement = function(node) {
++    if(node.namespaceURI === textns && node.localName === "s") {
++      return scanLeftForNonSpace(previousNode(node)) && scanRightForAnyCharacter(nextNode(node))
++    }
++    return false
++  };
++  function getFirstNonWhitespaceChild(node) {
++    var child = node && node.firstChild;
++    while(child && (child.nodeType === Node.TEXT_NODE && whitespaceOnly.test(child.nodeValue))) {
++      child = child.nextSibling
 +    }
++    return child
 +  }
-   function createSelector(family, name) {
-     var prefix = familynamespaceprefixes[family], namepart, selector;
-     if(prefix === undefined) {
++  this.getFirstNonWhitespaceChild = getFirstNonWhitespaceChild;
++  function parseLength(length) {
++    var re = /(-?[0-9]*[0-9][0-9]*(\.[0-9]*)?|0+\.[0-9]*[1-9][0-9]*|\.[0-9]*[1-9][0-9]*)((cm)|(mm)|(in)|(pt)|(pc)|(px)|(%))/, m = re.exec(length);
++    if(!m) {
 +      return null
 +    }
-     if(name) {
-       namepart = "[" + prefix + '|style-name="' + name + '"]'
-     }else {
-       namepart = ""
-     }
-     if(prefix === "presentation") {
-       prefix = "draw";
-       if(name) {
-         namepart = '[presentation|style-name="' + name + '"]'
-       }else {
-         namepart = ""
-       }
++    return{value:parseFloat(m[1]), unit:m[3]}
++  }
++  this.parseLength = parseLength;
++  function parsePositiveLength(length) {
++    var result = parseLength(length);
++    if(result && (result.value <= 0 || result.unit === "%")) {
++      return null
 +    }
-     selector = prefix + "|" + familytagnames[family].join(namepart + "," + prefix + "|") + namepart;
-     return selector
++    return result
 +  }
-   function getSelectors(family, name, node) {
-     var selectors = [], ss, derivedStyles = node.derivedStyles, n;
-     ss = createSelector(family, name);
-     if(ss !== null) {
-       selectors.push(ss)
++  function parseNonNegativeLength(length) {
++    var result = parseLength(length);
++    if(result && (result.value < 0 || result.unit === "%")) {
++      return null
 +    }
-     for(n in derivedStyles) {
-       if(derivedStyles.hasOwnProperty(n)) {
-         ss = getSelectors(family, n, derivedStyles[n]);
-         selectors = selectors.concat(ss)
-       }
++    return result
++  }
++  this.parseNonNegativeLength = parseNonNegativeLength;
++  function parsePercentage(length) {
++    var result = parseLength(length);
++    if(result && result.unit !== "%") {
++      return null
 +    }
-     return selectors
++    return result
 +  }
-   function getDirectChild(node, ns, name) {
-     var e = node && node.firstElementChild;
-     while(e) {
-       if(e.namespaceURI === ns && e.localName === name) {
++  function parseFoFontSize(fontSize) {
++    return parsePositiveLength(fontSize) || parsePercentage(fontSize)
++  }
++  this.parseFoFontSize = parseFoFontSize;
++  function parseFoLineHeight(lineHeight) {
++    return parseNonNegativeLength(lineHeight) || parsePercentage(lineHeight)
++  }
++  this.parseFoLineHeight = parseFoLineHeight;
++  function isTextContentContainingNode(node) {
++    switch(node.namespaceURI) {
++      case odf.Namespaces.drawns:
++      ;
++      case odf.Namespaces.svgns:
++      ;
++      case odf.Namespaces.dr3dns:
++        return false;
++      case odf.Namespaces.textns:
++        switch(node.localName) {
++          case "note-body":
++          ;
++          case "ruby-text":
++            return false
++        }
++        break;
++      case odf.Namespaces.officens:
++        switch(node.localName) {
++          case "annotation":
++          ;
++          case "binary-data":
++          ;
++          case "event-listeners":
++            return false
++        }
++        break;
++      default:
++        switch(node.localName) {
++          case "cursor":
++          ;
++          case "editinfo":
++            return false
++        }
 +        break
-       }
-       e = e.nextElementSibling
 +    }
-     return e
++    return true
 +  }
-   function fixBorderWidth(value) {
-     var index = value.indexOf(" "), width, theRestOfBorderAttributes;
-     if(index !== -1) {
-       width = value.substring(0, index);
-       theRestOfBorderAttributes = value.substring(index)
-     }else {
-       width = value;
-       theRestOfBorderAttributes = ""
++  this.isTextContentContainingNode = isTextContentContainingNode;
++  function isSignificantTextContent(textNode) {
++    return Boolean(getParagraphElement(textNode) && (!isODFWhitespace(textNode.textContent) || isSignificantWhitespace(textNode, 0)))
++  }
++  function removePartiallyContainedNodes(range, nodes) {
++    while(nodes.length > 0 && !domUtils.rangeContainsNode(range, (nodes[0]))) {
++      nodes.shift()
 +    }
-     width = utils.parseLength(width);
-     if(width && (width.unit === "pt" && width.value < 0.75)) {
-       value = "0.75pt" + theRestOfBorderAttributes
++    while(nodes.length > 0 && !domUtils.rangeContainsNode(range, (nodes[nodes.length - 1]))) {
++      nodes.pop()
 +    }
-     return value
 +  }
-   function applySimpleMapping(props, mapping) {
-     var rule = "", i, r, value;
-     for(i = 0;i < mapping.length;i += 1) {
-       r = mapping[i];
-       value = props.getAttributeNS(r[0], r[1]);
-       if(value) {
-         value = value.trim();
-         if(borderPropertyMap.hasOwnProperty(r[1])) {
-           value = fixBorderWidth(value)
++  function getTextNodes(range, includePartial) {
++    var textNodes;
++    function nodeFilter(node) {
++      var result = NodeFilter.FILTER_REJECT;
++      if(node.nodeType === Node.TEXT_NODE) {
++        if(isSignificantTextContent((node))) {
++          result = NodeFilter.FILTER_ACCEPT
 +        }
-         if(r[2]) {
-           rule += r[2] + ":" + value + ";"
++      }else {
++        if(isTextContentContainingNode(node)) {
++          result = NodeFilter.FILTER_SKIP
 +        }
 +      }
++      return result
 +    }
-     return rule
-   }
-   function getFontSize(styleNode) {
-     var props = getDirectChild(styleNode, stylens, "text-properties");
-     if(props) {
-       return utils.parseFoFontSize(props.getAttributeNS(fons, "font-size"))
++    textNodes = domUtils.getNodesInRange(range, nodeFilter, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT);
++    if(!includePartial) {
++      removePartiallyContainedNodes(range, textNodes)
 +    }
-     return null
++    return textNodes
 +  }
-   function getParentStyleNode(styleNode) {
-     var parentStyleName = "", parentStyleFamily = "", parentStyleNode = null, xp;
-     if(styleNode.localName === "default-style") {
-       return null
++  this.getTextNodes = getTextNodes;
++  function getTextElements(range, includePartial, includeInsignificantWhitespace) {
++    var elements;
++    function nodeFilter(node) {
++      var result = NodeFilter.FILTER_REJECT;
++      if(isCharacterElement(node.parentNode) || isInlineRoot(node)) {
++        result = NodeFilter.FILTER_REJECT
++      }else {
++        if(node.nodeType === Node.TEXT_NODE) {
++          if(includeInsignificantWhitespace || isSignificantTextContent((node))) {
++            result = NodeFilter.FILTER_ACCEPT
++          }
++        }else {
++          if(isAnchoredAsCharacterElement(node)) {
++            result = NodeFilter.FILTER_ACCEPT
++          }else {
++            if(isTextContentContainingNode(node) || isGroupingElement(node)) {
++              result = NodeFilter.FILTER_SKIP
++            }
++          }
++        }
++      }
++      return result
 +    }
-     parentStyleName = styleNode.getAttributeNS(stylens, "parent-style-name");
-     parentStyleFamily = styleNode.getAttributeNS(stylens, "family");
-     if(parentStyleName) {
-       xp = "//style:*[@style:name='" + parentStyleName + "'][@style:family='" + parentStyleFamily + "']"
-     }else {
-       xp = "//style:default-style[@style:family='" + parentStyleFamily + "']"
++    elements = domUtils.getNodesInRange(range, nodeFilter, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT);
++    if(!includePartial) {
++      removePartiallyContainedNodes(range, elements)
 +    }
-     parentStyleNode = xpath.getODFElementsWithXPath((odfRoot), xp, odf.Namespaces.lookupNamespaceURI)[0];
-     return parentStyleNode
++    return elements
 +  }
-   function getTextProperties(props) {
-     var rule = "", fontName, fontSize, value, textDecoration = "", fontSizeRule = "", sizeMultiplier = 1, parentStyle;
-     rule += applySimpleMapping(props, textPropertySimpleMapping);
-     value = props.getAttributeNS(stylens, "text-underline-style");
-     if(value === "solid") {
-       textDecoration += " underline"
-     }
-     value = props.getAttributeNS(stylens, "text-line-through-style");
-     if(value === "solid") {
-       textDecoration += " line-through"
-     }
-     if(textDecoration.length) {
-       textDecoration = "text-decoration:" + textDecoration + ";";
-       rule += textDecoration
++  this.getTextElements = getTextElements;
++  function prependParentContainers(startContainer, elements, filter) {
++    var container = startContainer;
++    while(container) {
++      if(filter(container)) {
++        if(elements[0] !== container) {
++          elements.unshift(container)
++        }
++        break
++      }
++      if(isInlineRoot(container)) {
++        break
++      }
++      container = container.parentNode
 +    }
-     fontName = props.getAttributeNS(stylens, "font-name") || props.getAttributeNS(fons, "font-family");
-     if(fontName) {
-       value = fontFaceDeclsMap[fontName];
-       rule += "font-family: " + (value || fontName) + ";"
++  }
++  this.getParagraphElements = function(range) {
++    var elements;
++    function nodeFilter(node) {
++      var result = NodeFilter.FILTER_REJECT;
++      if(isParagraph(node)) {
++        result = NodeFilter.FILTER_ACCEPT
++      }else {
++        if(isTextContentContainingNode(node) || isGroupingElement(node)) {
++          result = NodeFilter.FILTER_SKIP
++        }
++      }
++      return result
 +    }
-     parentStyle = props.parentElement;
-     fontSize = getFontSize(parentStyle);
-     if(!fontSize) {
-       return rule
++    elements = domUtils.getNodesInRange(range, nodeFilter, NodeFilter.SHOW_ELEMENT);
++    prependParentContainers((range.startContainer), elements, isParagraph);
++    return elements
++  };
++  this.getImageElements = function(range) {
++    var elements;
++    function nodeFilter(node) {
++      var result = NodeFilter.FILTER_SKIP;
++      if(isImage(node)) {
++        result = NodeFilter.FILTER_ACCEPT
++      }
++      return result
 +    }
-     while(parentStyle) {
-       fontSize = getFontSize(parentStyle);
-       if(fontSize) {
-         if(fontSize.unit !== "%") {
-           fontSizeRule = "font-size: " + fontSize.value * sizeMultiplier + fontSize.unit + ";";
-           break
-         }
-         sizeMultiplier *= fontSize.value / 100
++    elements = domUtils.getNodesInRange(range, nodeFilter, NodeFilter.SHOW_ELEMENT);
++    prependParentContainers((range.startContainer), elements, isImage);
++    return elements
++  };
++  function getRightNode(container, offset) {
++    var node = container;
++    if(offset < node.childNodes.length - 1) {
++      node = (node.childNodes[offset + 1])
++    }else {
++      while(!node.nextSibling) {
++        node = node.parentNode
 +      }
-       parentStyle = getParentStyleNode(parentStyle)
++      node = node.nextSibling
 +    }
-     if(!fontSizeRule) {
-       fontSizeRule = "font-size: " + parseFloat(defaultFontSize) * sizeMultiplier + cssUnits.getUnits(defaultFontSize) + ";"
++    while(node.firstChild) {
++      node = node.firstChild
 +    }
-     rule += fontSizeRule;
-     return rule
++    return node
 +  }
-   function getParagraphProperties(props) {
-     var rule = "", bgimage, url, lineHeight;
-     rule += applySimpleMapping(props, paragraphPropertySimpleMapping);
-     bgimage = getDirectChild(props, stylens, "background-image");
-     if(bgimage) {
-       url = bgimage.getAttributeNS(xlinkns, "href");
-       if(url) {
-         rule += "background-image: url('odfkit:" + url + "');";
-         rule += applySimpleMapping(bgimage, bgImageSimpleMapping)
++  this.getHyperlinkElements = function(range) {
++    var links = [], newRange = (range.cloneRange()), node, textNodes;
++    if(range.collapsed && range.endContainer.nodeType === Node.ELEMENT_NODE) {
++      node = getRightNode(range.endContainer, range.endOffset);
++      if(node.nodeType === Node.TEXT_NODE) {
++        newRange.setEnd(node, 1)
 +      }
 +    }
-     lineHeight = props.getAttributeNS(fons, "line-height");
-     if(lineHeight && lineHeight !== "normal") {
-       lineHeight = utils.parseFoLineHeight(lineHeight);
-       if(lineHeight.unit !== "%") {
-         rule += "line-height: " + lineHeight.value + lineHeight.unit + ";"
-       }else {
-         rule += "line-height: " + lineHeight.value / 100 + ";"
++    textNodes = getTextElements(newRange, true, false);
++    textNodes.forEach(function(node) {
++      var parent = node.parentNode;
++      while(!isParagraph(parent)) {
++        if(isHyperlink(parent) && links.indexOf(parent) === -1) {
++          links.push(parent);
++          break
++        }
++        parent = parent.parentNode
 +      }
-     }
-     return rule
-   }
-   function matchToRgb(m, r, g, b) {
-     return r + r + g + g + b + b
-   }
-   function hexToRgb(hex) {
-     var result, shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
-     hex = hex.replace(shorthandRegex, matchToRgb);
-     result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
-     return result ? {r:parseInt(result[1], 16), g:parseInt(result[2], 16), b:parseInt(result[3], 16)} : null
-   }
-   function isNumber(n) {
-     return!isNaN(parseFloat(n))
++    });
++    newRange.detach();
++    return links
 +  }
-   function getGraphicProperties(props) {
-     var rule = "", alpha, bgcolor, fill;
-     rule += applySimpleMapping(props, graphicPropertySimpleMapping);
-     alpha = props.getAttributeNS(drawns, "opacity");
-     fill = props.getAttributeNS(drawns, "fill");
-     bgcolor = props.getAttributeNS(drawns, "fill-color");
-     if(fill === "solid" || fill === "hatch") {
-       if(bgcolor && bgcolor !== "none") {
-         alpha = isNumber(alpha) ? parseFloat(alpha) / 100 : 1;
-         bgcolor = hexToRgb(bgcolor);
-         if(bgcolor) {
-           rule += "background-color: rgba(" + bgcolor.r + "," + bgcolor.g + "," + bgcolor.b + "," + alpha + ");"
-         }
-       }else {
-         rule += "background: none;"
-       }
-     }else {
-       if(fill === "none") {
-         rule += "background: none;"
-       }
++};
++/*
++
++ Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
++
++ @licstart
++ The JavaScript code in this page is free software: you can redistribute it
++ and/or modify it under the terms of the GNU Affero General Public License
++ (GNU AGPL) as published by the Free Software Foundation, either version 3 of
++ the License, or (at your option) any later version.  The code is distributed
++ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
++
++ You should have received a copy of the GNU Affero General Public License
++ along with this code.  If not, see <http://www.gnu.org/licenses/>.
++
++ As additional permission under GNU AGPL version 3 section 7, you
++ may distribute non-source (e.g., minimized or compacted) forms of
++ that code without the copy of the GNU GPL normally required by
++ section 4, provided you include this license notice and a URL
++ through which recipients can access the Corresponding Source.
++
++ As a special exception to the AGPL, any HTML file which merely makes function
++ calls to this code, and for that purpose includes it by reference shall be
++ deemed a separate work for copyright law purposes. In addition, the copyright
++ holders of this code give you permission to combine this code with free
++ software libraries that are released under the GNU LGPL. You may copy and
++ distribute such a system following the terms of the GNU AGPL for this code
++ and the LGPL for the libraries. If you modify this code, you may extend this
++ exception to your version of the code, but you are not obligated to do so.
++ If you do not wish to do so, delete this exception statement from your
++ version.
++
++ This license applies to this entire compilation.
++ @licend
++ @source: http://www.webodf.org/
++ @source: https://github.com/kogmbh/WebODF/
++*/
++gui.AnnotatableCanvas = function AnnotatableCanvas() {
++};
++gui.AnnotatableCanvas.prototype.refreshSize = function() {
++};
++gui.AnnotatableCanvas.prototype.getZoomLevel = function() {
++};
++gui.AnnotatableCanvas.prototype.getSizer = function() {
++};
++gui.AnnotationViewManager = function AnnotationViewManager(canvas, odfFragment, annotationsPane, showAnnotationRemoveButton) {
++  var annotations = [], doc = odfFragment.ownerDocument, odfUtils = new odf.OdfUtils, CONNECTOR_MARGIN = 30, NOTE_MARGIN = 20, window = runtime.getWindow();
++  runtime.assert(Boolean(window), "Expected to be run in an environment which has a global window, like a browser.");
++  function wrapAnnotation(annotation) {
++    var annotationWrapper = doc.createElement("div"), annotationNote = doc.createElement("div"), connectorHorizontal = doc.createElement("div"), connectorAngular = doc.createElement("div"), removeButton;
++    annotationWrapper.className = "annotationWrapper";
++    annotation.parentNode.insertBefore(annotationWrapper, annotation);
++    annotationNote.className = "annotationNote";
++    annotationNote.appendChild(annotation);
++    if(showAnnotationRemoveButton) {
++      removeButton = doc.createElement("div");
++      removeButton.className = "annotationRemoveButton";
++      annotationNote.appendChild(removeButton)
 +    }
-     return rule
++    connectorHorizontal.className = "annotationConnector horizontal";
++    connectorAngular.className = "annotationConnector angular";
++    annotationWrapper.appendChild(annotationNote);
++    annotationWrapper.appendChild(connectorHorizontal);
++    annotationWrapper.appendChild(connectorAngular)
 +  }
-   function getDrawingPageProperties(props) {
-     var rule = "";
-     rule += applySimpleMapping(props, graphicPropertySimpleMapping);
-     if(props.getAttributeNS(presentationns, "background-visible") === "true") {
-       rule += "background: none;"
++  function unwrapAnnotation(annotation) {
++    var annotationWrapper = annotation.parentNode.parentNode;
++    if(annotationWrapper.localName === "div") {
++      annotationWrapper.parentNode.insertBefore(annotation, annotationWrapper);
++      annotationWrapper.parentNode.removeChild(annotationWrapper)
 +    }
-     return rule
 +  }
-   function getTableCellProperties(props) {
-     var rule = "";
-     rule += applySimpleMapping(props, tablecellPropertySimpleMapping);
-     return rule
++  function highlightAnnotation(annotation) {
++    var annotationEnd = annotation.annotationEndElement, range = doc.createRange(), annotationName = annotation.getAttributeNS(odf.Namespaces.officens, "name"), textNodes;
++    if(annotationEnd) {
++      range.setStart(annotation, annotation.childNodes.length);
++      range.setEnd(annotationEnd, 0);
++      textNodes = odfUtils.getTextNodes(range, false);
++      textNodes.forEach(function(n) {
++        var container = doc.createElement("span");
++        container.className = "annotationHighlight";
++        container.setAttribute("annotation", annotationName);
++        n.parentNode.insertBefore(container, n);
++        container.appendChild(n)
++      })
++    }
++    range.detach()
 +  }
-   function getTableRowProperties(props) {
-     var rule = "";
-     rule += applySimpleMapping(props, tablerowPropertySimpleMapping);
-     return rule
++  function unhighlightAnnotation(annotation) {
++    var annotationName = annotation.getAttributeNS(odf.Namespaces.officens, "name"), highlightSpans = doc.querySelectorAll('span.annotationHighlight[annotation="' + annotationName + '"]'), i, container;
++    for(i = 0;i < highlightSpans.length;i += 1) {
++      container = highlightSpans.item(i);
++      while(container.firstChild) {
++        container.parentNode.insertBefore(container.firstChild, container)
++      }
++      container.parentNode.removeChild(container)
++    }
 +  }
-   function getTableColumnProperties(props) {
-     var rule = "";
-     rule += applySimpleMapping(props, tablecolumnPropertySimpleMapping);
-     return rule
++  function lineDistance(point1, point2) {
++    var xs = 0, ys = 0;
++    xs = point2.x - point1.x;
++    xs = xs * xs;
++    ys = point2.y - point1.y;
++    ys = ys * ys;
++    return Math.sqrt(xs + ys)
 +  }
-   function getTableProperties(props) {
-     var rule = "", borderModel;
-     rule += applySimpleMapping(props, tablePropertySimpleMapping);
-     borderModel = props.getAttributeNS(tablens, "border-model");
-     if(borderModel === "collapsing") {
-       rule += "border-collapse:collapse;"
-     }else {
-       if(borderModel === "separating") {
-         rule += "border-collapse:separate;"
++  function renderAnnotation(annotation) {
++    var annotationNote = (annotation.parentNode), connectorHorizontal = annotationNote.nextElementSibling, connectorAngular = connectorHorizontal.nextElementSibling, annotationWrapper = (annotationNote.parentNode), connectorAngle = 0, previousAnnotation = annotations[annotations.indexOf(annotation) - 1], previousRect, zoomLevel = canvas.getZoomLevel();
++    annotationNote.style.left = (annotationsPane.getBoundingClientRect().left - annotationWrapper.getBoundingClientRect().left) / zoomLevel + "px";
++    annotationNote.style.width = annotationsPane.getBoundingClientRect().width / zoomLevel + "px";
++    connectorHorizontal.style.width = parseFloat(annotationNote.style.left) - CONNECTOR_MARGIN + "px";
++    if(previousAnnotation) {
++      previousRect = (previousAnnotation.parentNode).getBoundingClientRect();
++      if((annotationWrapper.getBoundingClientRect().top - previousRect.bottom) / zoomLevel <= NOTE_MARGIN) {
++        annotationNote.style.top = Math.abs(annotationWrapper.getBoundingClientRect().top - previousRect.bottom) / zoomLevel + NOTE_MARGIN + "px"
++      }else {
++        annotationNote.style.top = "0px"
 +      }
 +    }
-     return rule
++    connectorAngular.style.left = connectorHorizontal.getBoundingClientRect().width / zoomLevel + "px";
++    connectorAngular.style.width = lineDistance({x:connectorAngular.getBoundingClientRect().left / zoomLevel, y:connectorAngular.getBoundingClientRect().top / zoomLevel}, {x:annotationNote.getBoundingClientRect().left / zoomLevel, y:annotationNote.getBoundingClientRect().top / zoomLevel}) + "px";
++    connectorAngle = Math.asin((annotationNote.getBoundingClientRect().top - connectorAngular.getBoundingClientRect().top) / (zoomLevel * parseFloat(connectorAngular.style.width)));
++    connectorAngular.style.transform = "rotate(" + connectorAngle + "rad)";
++    connectorAngular.style.MozTransform = "rotate(" + connectorAngle + "rad)";
++    connectorAngular.style.WebkitTransform = "rotate(" + connectorAngle + "rad)";
++    connectorAngular.style.msTransform = "rotate(" + connectorAngle + "rad)"
 +  }
-   function addStyleRule(sheet, family, name, node) {
-     var selectors = getSelectors(family, name, node), selector = selectors.join(","), rule = "", properties;
-     properties = getDirectChild(node.element, stylens, "text-properties");
-     if(properties) {
-       rule += getTextProperties(properties)
-     }
-     properties = getDirectChild(node.element, stylens, "paragraph-properties");
-     if(properties) {
-       rule += getParagraphProperties(properties)
-     }
-     properties = getDirectChild(node.element, stylens, "graphic-properties");
-     if(properties) {
-       rule += getGraphicProperties(properties)
-     }
-     properties = getDirectChild(node.element, stylens, "drawing-page-properties");
-     if(properties) {
-       rule += getDrawingPageProperties(properties)
-     }
-     properties = getDirectChild(node.element, stylens, "table-cell-properties");
-     if(properties) {
-       rule += getTableCellProperties(properties)
-     }
-     properties = getDirectChild(node.element, stylens, "table-row-properties");
-     if(properties) {
-       rule += getTableRowProperties(properties)
-     }
-     properties = getDirectChild(node.element, stylens, "table-column-properties");
-     if(properties) {
-       rule += getTableColumnProperties(properties)
-     }
-     properties = getDirectChild(node.element, stylens, "table-properties");
-     if(properties) {
-       rule += getTableProperties(properties)
-     }
-     if(rule.length === 0) {
-       return
-     }
-     rule = selector + "{" + rule + "}";
-     try {
-       sheet.insertRule(rule, sheet.cssRules.length)
-     }catch(e) {
-       throw e;
++  function showAnnotationsPane(show) {
++    var sizer = canvas.getSizer();
++    if(show) {
++      annotationsPane.style.display = "inline-block";
++      sizer.style.paddingRight = window.getComputedStyle(annotationsPane).width
++    }else {
++      annotationsPane.style.display = "none";
++      sizer.style.paddingRight = 0
 +    }
++    canvas.refreshSize()
 +  }
-   function getNumberRule(node) {
-     var style = node.getAttributeNS(stylens, "num-format"), suffix = node.getAttributeNS(stylens, "num-suffix") || "", prefix = node.getAttributeNS(stylens, "num-prefix") || "", stylemap = {1:"decimal", "a":"lower-latin", "A":"upper-latin", "i":"lower-roman", "I":"upper-roman"}, content = "";
-     if(prefix) {
-       content += ' "' + prefix + '"'
-     }
-     if(stylemap.hasOwnProperty(style)) {
-       content += " counter(list, " + stylemap[style] + ")"
-     }else {
-       if(style) {
-         content += ' "' + style + '"'
-       }else {
-         content += " ''"
++  function sortAnnotations() {
++    annotations.sort(function(a, b) {
++      if((a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_FOLLOWING) !== 0) {
++        return-1
 +      }
-     }
-     return"content:" + content + ' "' + suffix + '"'
++      return 1
++    })
 +  }
-   function getImageRule() {
-     return"content: none;"
++  function rerenderAnnotations() {
++    var i;
++    for(i = 0;i < annotations.length;i += 1) {
++      renderAnnotation(annotations[i])
++    }
 +  }
-   function getBulletRule(node) {
-     var bulletChar = node.getAttributeNS(textns, "bullet-char");
-     return"content: '" + bulletChar + "';"
++  this.rerenderAnnotations = rerenderAnnotations;
++  function getMinimumHeightForAnnotationPane() {
++    if(annotationsPane.style.display !== "none" && annotations.length > 0) {
++      return((annotations[annotations.length - 1].parentNode).getBoundingClientRect().bottom - annotationsPane.getBoundingClientRect().top) / canvas.getZoomLevel() + "px"
++    }
++    return null
 +  }
-   function addListStyleRule(sheet, name, node, itemrule) {
-     var selector = 'text|list[text|style-name="' + name + '"]', level = node.getAttributeNS(textns, "level"), itemSelector, listItemRule, listLevelProps = getDirectChild(node, stylens, "list-level-properties"), listLevelLabelAlign = getDirectChild(listLevelProps, stylens, "list-level-label-alignment"), bulletIndent, listIndent, bulletWidth, rule;
-     if(listLevelLabelAlign) {
-       bulletIndent = listLevelLabelAlign.getAttributeNS(fons, "text-indent");
-       listIndent = listLevelLabelAlign.getAttributeNS(fons, "margin-left")
++  this.getMinimumHeightForAnnotationPane = getMinimumHeightForAnnotationPane;
++  function addAnnotation(annotation) {
++    showAnnotationsPane(true);
++    annotations.push(annotation);
++    sortAnnotations();
++    wrapAnnotation(annotation);
++    if(annotation.annotationEndElement) {
++      highlightAnnotation(annotation)
 +    }
-     if(!bulletIndent) {
-       bulletIndent = "-0.6cm"
++    rerenderAnnotations()
++  }
++  this.addAnnotation = addAnnotation;
++  function forgetAnnotation(annotation) {
++    var index = annotations.indexOf(annotation);
++    unwrapAnnotation(annotation);
++    unhighlightAnnotation(annotation);
++    if(index !== -1) {
++      annotations.splice(index, 1)
 +    }
-     if(bulletIndent.charAt(0) === "-") {
-       bulletWidth = bulletIndent.substring(1)
-     }else {
-       bulletWidth = "-" + bulletIndent
++    if(annotations.length === 0) {
++      showAnnotationsPane(false)
 +    }
-     level = level && parseInt(level, 10);
-     while(level > 1) {
-       selector += " > text|list-item > text|list";
-       level -= 1
++  }
++  function forgetAnnotations() {
++    while(annotations.length) {
++      forgetAnnotation(annotations[0])
 +    }
-     if(listIndent) {
-       itemSelector = selector;
-       itemSelector += " > text|list-item > *:not(text|list):first-child";
-       listItemRule = itemSelector + "{";
-       listItemRule += "margin-left:" + listIndent + ";";
-       listItemRule += "}";
-       try {
-         sheet.insertRule(listItemRule, sheet.cssRules.length)
-       }catch(e1) {
-         runtime.log("cannot load rule: " + listItemRule)
++  }
++  this.forgetAnnotations = forgetAnnotations
++};
++/*
++
++ Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
++
++ @licstart
++ The JavaScript code in this page is free software: you can redistribute it
++ and/or modify it under the terms of the GNU Affero General Public License
++ (GNU AGPL) as published by the Free Software Foundation, either version 3 of
++ the License, or (at your option) any later version.  The code is distributed
++ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
++
++ You should have received a copy of the GNU Affero General Public License
++ along with this code.  If not, see <http://www.gnu.org/licenses/>.
++
++ As additional permission under GNU AGPL version 3 section 7, you
++ may distribute non-source (e.g., minimized or compacted) forms of
++ that code without the copy of the GNU GPL normally required by
++ section 4, provided you include this license notice and a URL
++ through which recipients can access the Corresponding Source.
++
++ As a special exception to the AGPL, any HTML file which merely makes function
++ calls to this code, and for that purpose includes it by reference shall be
++ deemed a separate work for copyright law purposes. In addition, the copyright
++ holders of this code give you permission to combine this code with free
++ software libraries that are released under the GNU LGPL. You may copy and
++ distribute such a system following the terms of the GNU AGPL for this code
++ and the LGPL for the libraries. If you modify this code, you may extend this
++ exception to your version of the code, but you are not obligated to do so.
++ If you do not wish to do so, delete this exception statement from your
++ version.
++
++ This license applies to this entire compilation.
++ @licend
++ @source: http://www.webodf.org/
++ @source: https://github.com/kogmbh/WebODF/
++*/
++(function() {
++  var xpath = xmldom.XPath, base64 = new core.Base64;
++  function getEmbeddedFontDeclarations(fontFaceDecls) {
++    var decls = {}, fonts, i, font, name, uris, href, family;
++    if(!fontFaceDecls) {
++      return decls
++    }
++    fonts = xpath.getODFElementsWithXPath(fontFaceDecls, "style:font-face[svg:font-face-src]", odf.Namespaces.lookupNamespaceURI);
++    for(i = 0;i < fonts.length;i += 1) {
++      font = fonts[i];
++      name = font.getAttributeNS(odf.Namespaces.stylens, "name");
++      family = font.getAttributeNS(odf.Namespaces.svgns, "font-family");
++      uris = xpath.getODFElementsWithXPath(font, "svg:font-face-src/svg:font-face-uri", odf.Namespaces.lookupNamespaceURI);
++      if(uris.length > 0) {
++        href = uris[0].getAttributeNS(odf.Namespaces.xlinkns, "href");
++        decls[name] = {href:href, family:family}
 +      }
 +    }
-     selector += " > text|list-item > *:not(text|list):first-child:before";
-     rule = selector + "{" + itemrule + ";";
-     rule += "counter-increment:list;";
-     rule += "margin-left:" + bulletIndent + ";";
-     rule += "width:" + bulletWidth + ";";
-     rule += "display:inline-block}";
++    return decls
++  }
++  function addFontToCSS(name, font, fontdata, stylesheet) {
++    var cssFamily = font.family || name, rule = "@font-face { font-family: '" + cssFamily + "'; src: " + "url(data:application/x-font-ttf;charset=binary;base64," + base64.convertUTF8ArrayToBase64(fontdata) + ') format("truetype"); }';
 +    try {
-       sheet.insertRule(rule, sheet.cssRules.length)
-     }catch(e2) {
-       runtime.log("cannot load rule: " + rule)
++      stylesheet.insertRule(rule, stylesheet.cssRules.length)
++    }catch(e) {
++      runtime.log("Problem inserting rule in CSS: " + runtime.toJson(e) + "\nRule: " + rule)
 +    }
 +  }
-   function addPageStyleRules(sheet, node) {
-     var rule = "", imageProps, url, contentLayoutRule = "", pageSizeRule = "", props = getDirectChild(node, stylens, "page-layout-properties"), stylename, masterStyles, e, masterStyleName;
-     if(!props) {
-       return
-     }
-     stylename = node.getAttributeNS(stylens, "name");
-     rule += applySimpleMapping(props, pageContentPropertySimpleMapping);
-     imageProps = getDirectChild(props, stylens, "background-image");
-     if(imageProps) {
-       url = imageProps.getAttributeNS(xlinkns, "href");
-       if(url) {
-         rule += "background-image: url('odfkit:" + url + "');";
-         rule += applySimpleMapping(imageProps, bgImageSimpleMapping)
-       }
-     }
-     if(documentType === "presentation") {
-       masterStyles = getDirectChild(node.parentNode.parentElement, officens, "master-styles");
-       e = masterStyles && masterStyles.firstElementChild;
-       while(e) {
-         if(e.namespaceURI === stylens && (e.localName === "master-page" && e.getAttributeNS(stylens, "page-layout-name") === stylename)) {
-           masterStyleName = e.getAttributeNS(stylens, "name");
-           contentLayoutRule = "draw|page[draw|master-page-name=" + masterStyleName + "] {" + rule + "}";
-           pageSizeRule = "office|body, draw|page[draw|master-page-name=" + masterStyleName + "] {" + applySimpleMapping(props, pageSizePropertySimpleMapping) + " }";
-           try {
-             sheet.insertRule(contentLayoutRule, sheet.cssRules.length);
-             sheet.insertRule(pageSizeRule, sheet.cssRules.length)
-           }catch(e1) {
-             throw e1;
-           }
-         }
-         e = e.nextElementSibling
-       }
-     }else {
-       if(documentType === "text") {
-         contentLayoutRule = "office|text {" + rule + "}";
-         rule = "";
-         pageSizeRule = "office|body {" + "width: " + props.getAttributeNS(fons, "page-width") + ";" + "}";
-         try {
-           sheet.insertRule(contentLayoutRule, sheet.cssRules.length);
-           sheet.insertRule(pageSizeRule, sheet.cssRules.length)
-         }catch(e2) {
-           throw e2;
++  function loadFontIntoCSS(embeddedFontDeclarations, odfContainer, pos, stylesheet, callback) {
++    var name, i = 0, n;
++    for(n in embeddedFontDeclarations) {
++      if(embeddedFontDeclarations.hasOwnProperty(n)) {
++        if(i === pos) {
++          name = n;
++          break
 +        }
++        i += 1
 +      }
 +    }
-   }
-   function addListStyleRules(sheet, name, node) {
-     var n = node.firstChild, e, itemrule;
-     while(n) {
-       if(n.namespaceURI === textns) {
-         e = (n);
-         if(n.localName === "list-level-style-number") {
-           itemrule = getNumberRule(e);
-           addListStyleRule(sheet, name, e, itemrule)
-         }else {
-           if(n.localName === "list-level-style-image") {
-             itemrule = getImageRule();
-             addListStyleRule(sheet, name, e, itemrule)
-           }else {
-             if(n.localName === "list-level-style-bullet") {
-               itemrule = getBulletRule(e);
-               addListStyleRule(sheet, name, e, itemrule)
-             }
-           }
-         }
++    if(!name) {
++      if(callback) {
++        callback()
 +      }
-       n = n.nextSibling
++      return
 +    }
-   }
-   function addRule(sheet, family, name, node) {
-     if(family === "list") {
-       addListStyleRules(sheet, name, node.element)
-     }else {
-       if(family === "page") {
-         addPageStyleRules(sheet, node.element)
++    odfContainer.getPartData(embeddedFontDeclarations[name].href, function(err, fontdata) {
++      if(err) {
++        runtime.log(err)
 +      }else {
-         addStyleRule(sheet, family, name, node)
++        if(!fontdata) {
++          runtime.log("missing font data for " + embeddedFontDeclarations[name].href)
++        }else {
++          addFontToCSS(name, embeddedFontDeclarations[name], fontdata, stylesheet)
++        }
 +      }
-     }
++      loadFontIntoCSS(embeddedFontDeclarations, odfContainer, pos + 1, stylesheet, callback)
++    })
 +  }
-   function addRules(sheet, family, name, node) {
-     addRule(sheet, family, name, node);
-     var n;
-     for(n in node.derivedStyles) {
-       if(node.derivedStyles.hasOwnProperty(n)) {
-         addRules(sheet, family, n, node.derivedStyles[n])
-       }
-     }
++  function loadFontsIntoCSS(embeddedFontDeclarations, odfContainer, stylesheet) {
++    loadFontIntoCSS(embeddedFontDeclarations, odfContainer, 0, stylesheet)
 +  }
-   this.style2css = function(doctype, stylesheet, fontFaceMap, styles, autostyles) {
-     var doc, styletree, tree, rule, name, family, stylenodes, styleautonodes;
-     while(stylesheet.cssRules.length) {
-       stylesheet.deleteRule(stylesheet.cssRules.length - 1)
-     }
-     doc = null;
-     if(styles) {
-       doc = styles.ownerDocument;
-       odfRoot = styles.parentNode
-     }
-     if(autostyles) {
-       doc = autostyles.ownerDocument;
-       odfRoot = autostyles.parentNode
-     }
-     if(!doc) {
-       return
-     }
-     odf.Namespaces.forEachPrefix(function(prefix, ns) {
-       rule = "@namespace " + prefix + " url(" + ns + ");";
-       try {
-         stylesheet.insertRule(rule, stylesheet.cssRules.length)
-       }catch(ignore) {
++  odf.FontLoader = function FontLoader() {
++    this.loadFonts = function(odfContainer, stylesheet) {
++      var embeddedFontDeclarations, fontFaceDecls = odfContainer.rootElement.fontFaceDecls;
++      while(stylesheet.cssRules.length) {
++        stylesheet.deleteRule(stylesheet.cssRules.length - 1)
 +      }
-     });
-     fontFaceDeclsMap = fontFaceMap;
-     documentType = doctype;
-     defaultFontSize = runtime.getWindow().getComputedStyle(document.body, null).getPropertyValue("font-size") || "12pt";
-     stylenodes = getStyleMap(styles);
-     styleautonodes = getStyleMap(autostyles);
-     styletree = {};
-     for(family in familynamespaceprefixes) {
-       if(familynamespaceprefixes.hasOwnProperty(family)) {
-         tree = styletree[family] = {};
-         addStyleMapToStyleTree(stylenodes[family], tree);
-         addStyleMapToStyleTree(styleautonodes[family], tree);
-         for(name in tree) {
-           if(tree.hasOwnProperty(name)) {
-             addRules(stylesheet, family, name, tree[name])
-           }
-         }
++      if(fontFaceDecls) {
++        embeddedFontDeclarations = getEmbeddedFontDeclarations(fontFaceDecls);
++        loadFontsIntoCSS(embeddedFontDeclarations, odfContainer, stylesheet)
 +      }
 +    }
-   }
- };
++  };
++  return odf.FontLoader
++})();
 +/*
 +
 + Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("xmldom.XPath");
- runtime.loadClass("odf.Namespaces");
- odf.StyleInfo = function StyleInfo() {
-   var chartns = odf.Namespaces.chartns, dbns = odf.Namespaces.dbns, dr3dns = odf.Namespaces.dr3dns, drawns = odf.Namespaces.drawns, formns = odf.Namespaces.formns, numberns = odf.Namespaces.numberns, officens = odf.Namespaces.officens, presentationns = odf.Namespaces.presentationns, stylens = odf.Namespaces.stylens, tablens = odf.Namespaces.tablens, textns = odf.Namespaces.textns, nsprefixes = {"urn:oasis:names:tc:opendocument:xmlns:chart:1.0":"chart:", "urn:oasis:names:tc:opendocument: [...]
-   "urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0":"dr3d:", "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0":"draw:", "urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0":"fo:", "urn:oasis:names:tc:opendocument:xmlns:form:1.0":"form:", "urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0":"number:", "urn:oasis:names:tc:opendocument:xmlns:office:1.0":"office:", "urn:oasis:names:tc:opendocument:xmlns:presentation:1.0":"presentation:", "urn:oasis:names:tc:opendocument:xmlns:sty [...]
-   "urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0":"svg:", "urn:oasis:names:tc:opendocument:xmlns:table:1.0":"table:", "urn:oasis:names:tc:opendocument:xmlns:text:1.0":"chart:", "http://www.w3.org/XML/1998/namespace":"xml:"}, elementstyles = {"text":[{ens:stylens, en:"tab-stop", ans:stylens, a:"leader-text-style"}, {ens:stylens, en:"drop-cap", ans:stylens, a:"style-name"}, {ens:textns, en:"notes-configuration", ans:textns, a:"citation-body-style-name"}, {ens:textns, en:"notes- [...]
-   ans:textns, a:"citation-style-name"}, {ens:textns, en:"a", ans:textns, a:"style-name"}, {ens:textns, en:"alphabetical-index", ans:textns, a:"style-name"}, {ens:textns, en:"linenumbering-configuration", ans:textns, a:"style-name"}, {ens:textns, en:"list-level-style-number", ans:textns, a:"style-name"}, {ens:textns, en:"ruby-text", ans:textns, a:"style-name"}, {ens:textns, en:"span", ans:textns, a:"style-name"}, {ens:textns, en:"a", ans:textns, a:"visited-style-name"}, {ens:stylens, en: [...]
-   ans:stylens, a:"text-line-through-text-style"}, {ens:textns, en:"alphabetical-index-source", ans:textns, a:"main-entry-style-name"}, {ens:textns, en:"index-entry-bibliography", ans:textns, a:"style-name"}, {ens:textns, en:"index-entry-chapter", ans:textns, a:"style-name"}, {ens:textns, en:"index-entry-link-end", ans:textns, a:"style-name"}, {ens:textns, en:"index-entry-link-start", ans:textns, a:"style-name"}, {ens:textns, en:"index-entry-page-number", ans:textns, a:"style-name"}, {en [...]
-   en:"index-entry-span", ans:textns, a:"style-name"}, {ens:textns, en:"index-entry-tab-stop", ans:textns, a:"style-name"}, {ens:textns, en:"index-entry-text", ans:textns, a:"style-name"}, {ens:textns, en:"index-title-template", ans:textns, a:"style-name"}, {ens:textns, en:"list-level-style-bullet", ans:textns, a:"style-name"}, {ens:textns, en:"outline-level-style", ans:textns, a:"style-name"}], "paragraph":[{ens:drawns, en:"caption", ans:drawns, a:"text-style-name"}, {ens:drawns, en:"ci [...]
-   a:"text-style-name"}, {ens:drawns, en:"connector", ans:drawns, a:"text-style-name"}, {ens:drawns, en:"control", ans:drawns, a:"text-style-name"}, {ens:drawns, en:"custom-shape", ans:drawns, a:"text-style-name"}, {ens:drawns, en:"ellipse", ans:drawns, a:"text-style-name"}, {ens:drawns, en:"frame", ans:drawns, a:"text-style-name"}, {ens:drawns, en:"line", ans:drawns, a:"text-style-name"}, {ens:drawns, en:"measure", ans:drawns, a:"text-style-name"}, {ens:drawns, en:"path", ans:drawns, a: [...]
-   {ens:drawns, en:"polygon", ans:drawns, a:"text-style-name"}, {ens:drawns, en:"polyline", ans:drawns, a:"text-style-name"}, {ens:drawns, en:"rect", ans:drawns, a:"text-style-name"}, {ens:drawns, en:"regular-polygon", ans:drawns, a:"text-style-name"}, {ens:officens, en:"annotation", ans:drawns, a:"text-style-name"}, {ens:formns, en:"column", ans:formns, a:"text-style-name"}, {ens:stylens, en:"style", ans:stylens, a:"next-style-name"}, {ens:tablens, en:"body", ans:tablens, a:"paragraph-s [...]
-   {ens:tablens, en:"even-columns", ans:tablens, a:"paragraph-style-name"}, {ens:tablens, en:"even-rows", ans:tablens, a:"paragraph-style-name"}, {ens:tablens, en:"first-column", ans:tablens, a:"paragraph-style-name"}, {ens:tablens, en:"first-row", ans:tablens, a:"paragraph-style-name"}, {ens:tablens, en:"last-column", ans:tablens, a:"paragraph-style-name"}, {ens:tablens, en:"last-row", ans:tablens, a:"paragraph-style-name"}, {ens:tablens, en:"odd-columns", ans:tablens, a:"paragraph-styl [...]
-   {ens:tablens, en:"odd-rows", ans:tablens, a:"paragraph-style-name"}, {ens:textns, en:"notes-configuration", ans:textns, a:"default-style-name"}, {ens:textns, en:"alphabetical-index-entry-template", ans:textns, a:"style-name"}, {ens:textns, en:"bibliography-entry-template", ans:textns, a:"style-name"}, {ens:textns, en:"h", ans:textns, a:"style-name"}, {ens:textns, en:"illustration-index-entry-template", ans:textns, a:"style-name"}, {ens:textns, en:"index-source-style", ans:textns, a:"s [...]
-   {ens:textns, en:"object-index-entry-template", ans:textns, a:"style-name"}, {ens:textns, en:"p", ans:textns, a:"style-name"}, {ens:textns, en:"table-index-entry-template", ans:textns, a:"style-name"}, {ens:textns, en:"table-of-content-entry-template", ans:textns, a:"style-name"}, {ens:textns, en:"table-index-entry-template", ans:textns, a:"style-name"}, {ens:textns, en:"user-index-entry-template", ans:textns, a:"style-name"}, {ens:stylens, en:"page-layout-properties", ans:stylens, a:" [...]
-   "chart":[{ens:chartns, en:"axis", ans:chartns, a:"style-name"}, {ens:chartns, en:"chart", ans:chartns, a:"style-name"}, {ens:chartns, en:"data-label", ans:chartns, a:"style-name"}, {ens:chartns, en:"data-point", ans:chartns, a:"style-name"}, {ens:chartns, en:"equation", ans:chartns, a:"style-name"}, {ens:chartns, en:"error-indicator", ans:chartns, a:"style-name"}, {ens:chartns, en:"floor", ans:chartns, a:"style-name"}, {ens:chartns, en:"footer", ans:chartns, a:"style-name"}, {ens:char [...]
-   ans:chartns, a:"style-name"}, {ens:chartns, en:"legend", ans:chartns, a:"style-name"}, {ens:chartns, en:"mean-value", ans:chartns, a:"style-name"}, {ens:chartns, en:"plot-area", ans:chartns, a:"style-name"}, {ens:chartns, en:"regression-curve", ans:chartns, a:"style-name"}, {ens:chartns, en:"series", ans:chartns, a:"style-name"}, {ens:chartns, en:"stock-gain-marker", ans:chartns, a:"style-name"}, {ens:chartns, en:"stock-loss-marker", ans:chartns, a:"style-name"}, {ens:chartns, en:"sto [...]
-   ans:chartns, a:"style-name"}, {ens:chartns, en:"subtitle", ans:chartns, a:"style-name"}, {ens:chartns, en:"title", ans:chartns, a:"style-name"}, {ens:chartns, en:"wall", ans:chartns, a:"style-name"}], "section":[{ens:textns, en:"alphabetical-index", ans:textns, a:"style-name"}, {ens:textns, en:"bibliography", ans:textns, a:"style-name"}, {ens:textns, en:"illustration-index", ans:textns, a:"style-name"}, {ens:textns, en:"index-title", ans:textns, a:"style-name"}, {ens:textns, en:"objec [...]
-   ans:textns, a:"style-name"}, {ens:textns, en:"section", ans:textns, a:"style-name"}, {ens:textns, en:"table-of-content", ans:textns, a:"style-name"}, {ens:textns, en:"table-index", ans:textns, a:"style-name"}, {ens:textns, en:"user-index", ans:textns, a:"style-name"}], "ruby":[{ens:textns, en:"ruby", ans:textns, a:"style-name"}], "table":[{ens:dbns, en:"query", ans:dbns, a:"style-name"}, {ens:dbns, en:"table-representation", ans:dbns, a:"style-name"}, {ens:tablens, en:"background", an [...]
-   a:"style-name"}, {ens:tablens, en:"table", ans:tablens, a:"style-name"}], "table-column":[{ens:dbns, en:"column", ans:dbns, a:"style-name"}, {ens:tablens, en:"table-column", ans:tablens, a:"style-name"}], "table-row":[{ens:dbns, en:"query", ans:dbns, a:"default-row-style-name"}, {ens:dbns, en:"table-representation", ans:dbns, a:"default-row-style-name"}, {ens:tablens, en:"table-row", ans:tablens, a:"style-name"}], "table-cell":[{ens:dbns, en:"column", ans:dbns, a:"default-cell-style-n [...]
-   en:"table-column", ans:tablens, a:"default-cell-style-name"}, {ens:tablens, en:"table-row", ans:tablens, a:"default-cell-style-name"}, {ens:tablens, en:"body", ans:tablens, a:"style-name"}, {ens:tablens, en:"covered-table-cell", ans:tablens, a:"style-name"}, {ens:tablens, en:"even-columns", ans:tablens, a:"style-name"}, {ens:tablens, en:"covered-table-cell", ans:tablens, a:"style-name"}, {ens:tablens, en:"even-columns", ans:tablens, a:"style-name"}, {ens:tablens, en:"even-rows", ans:t [...]
-   {ens:tablens, en:"first-column", ans:tablens, a:"style-name"}, {ens:tablens, en:"first-row", ans:tablens, a:"style-name"}, {ens:tablens, en:"last-column", ans:tablens, a:"style-name"}, {ens:tablens, en:"last-row", ans:tablens, a:"style-name"}, {ens:tablens, en:"odd-columns", ans:tablens, a:"style-name"}, {ens:tablens, en:"odd-rows", ans:tablens, a:"style-name"}, {ens:tablens, en:"table-cell", ans:tablens, a:"style-name"}], "graphic":[{ens:dr3dns, en:"cube", ans:drawns, a:"style-name"} [...]
-   en:"extrude", ans:drawns, a:"style-name"}, {ens:dr3dns, en:"rotate", ans:drawns, a:"style-name"}, {ens:dr3dns, en:"scene", ans:drawns, a:"style-name"}, {ens:dr3dns, en:"sphere", ans:drawns, a:"style-name"}, {ens:drawns, en:"caption", ans:drawns, a:"style-name"}, {ens:drawns, en:"circle", ans:drawns, a:"style-name"}, {ens:drawns, en:"connector", ans:drawns, a:"style-name"}, {ens:drawns, en:"control", ans:drawns, a:"style-name"}, {ens:drawns, en:"custom-shape", ans:drawns, a:"style-name [...]
-   en:"ellipse", ans:drawns, a:"style-name"}, {ens:drawns, en:"frame", ans:drawns, a:"style-name"}, {ens:drawns, en:"g", ans:drawns, a:"style-name"}, {ens:drawns, en:"line", ans:drawns, a:"style-name"}, {ens:drawns, en:"measure", ans:drawns, a:"style-name"}, {ens:drawns, en:"page-thumbnail", ans:drawns, a:"style-name"}, {ens:drawns, en:"path", ans:drawns, a:"style-name"}, {ens:drawns, en:"polygon", ans:drawns, a:"style-name"}, {ens:drawns, en:"polyline", ans:drawns, a:"style-name"}, {ens [...]
-   ans:drawns, a:"style-name"}, {ens:drawns, en:"regular-polygon", ans:drawns, a:"style-name"}, {ens:officens, en:"annotation", ans:drawns, a:"style-name"}], "presentation":[{ens:dr3dns, en:"cube", ans:presentationns, a:"style-name"}, {ens:dr3dns, en:"extrude", ans:presentationns, a:"style-name"}, {ens:dr3dns, en:"rotate", ans:presentationns, a:"style-name"}, {ens:dr3dns, en:"scene", ans:presentationns, a:"style-name"}, {ens:dr3dns, en:"sphere", ans:presentationns, a:"style-name"}, {ens: [...]
-   ans:presentationns, a:"style-name"}, {ens:drawns, en:"circle", ans:presentationns, a:"style-name"}, {ens:drawns, en:"connector", ans:presentationns, a:"style-name"}, {ens:drawns, en:"control", ans:presentationns, a:"style-name"}, {ens:drawns, en:"custom-shape", ans:presentationns, a:"style-name"}, {ens:drawns, en:"ellipse", ans:presentationns, a:"style-name"}, {ens:drawns, en:"frame", ans:presentationns, a:"style-name"}, {ens:drawns, en:"g", ans:presentationns, a:"style-name"}, {ens:d [...]
-   ans:presentationns, a:"style-name"}, {ens:drawns, en:"measure", ans:presentationns, a:"style-name"}, {ens:drawns, en:"page-thumbnail", ans:presentationns, a:"style-name"}, {ens:drawns, en:"path", ans:presentationns, a:"style-name"}, {ens:drawns, en:"polygon", ans:presentationns, a:"style-name"}, {ens:drawns, en:"polyline", ans:presentationns, a:"style-name"}, {ens:drawns, en:"rect", ans:presentationns, a:"style-name"}, {ens:drawns, en:"regular-polygon", ans:presentationns, a:"style-na [...]
-   en:"annotation", ans:presentationns, a:"style-name"}], "drawing-page":[{ens:drawns, en:"page", ans:drawns, a:"style-name"}, {ens:presentationns, en:"notes", ans:drawns, a:"style-name"}, {ens:stylens, en:"handout-master", ans:drawns, a:"style-name"}, {ens:stylens, en:"master-page", ans:drawns, a:"style-name"}], "list-style":[{ens:textns, en:"list", ans:textns, a:"style-name"}, {ens:textns, en:"numbered-paragraph", ans:textns, a:"style-name"}, {ens:textns, en:"list-item", ans:textns, a: [...]
-   {ens:stylens, en:"style", ans:stylens, a:"list-style-name"}], "data":[{ens:stylens, en:"style", ans:stylens, a:"data-style-name"}, {ens:stylens, en:"style", ans:stylens, a:"percentage-data-style-name"}, {ens:presentationns, en:"date-time-decl", ans:stylens, a:"data-style-name"}, {ens:textns, en:"creation-date", ans:stylens, a:"data-style-name"}, {ens:textns, en:"creation-time", ans:stylens, a:"data-style-name"}, {ens:textns, en:"database-display", ans:stylens, a:"data-style-name"}, {e [...]
-   en:"date", ans:stylens, a:"data-style-name"}, {ens:textns, en:"editing-duration", ans:stylens, a:"data-style-name"}, {ens:textns, en:"expression", ans:stylens, a:"data-style-name"}, {ens:textns, en:"meta-field", ans:stylens, a:"data-style-name"}, {ens:textns, en:"modification-date", ans:stylens, a:"data-style-name"}, {ens:textns, en:"modification-time", ans:stylens, a:"data-style-name"}, {ens:textns, en:"print-date", ans:stylens, a:"data-style-name"}, {ens:textns, en:"print-time", ans [...]
-   a:"data-style-name"}, {ens:textns, en:"table-formula", ans:stylens, a:"data-style-name"}, {ens:textns, en:"time", ans:stylens, a:"data-style-name"}, {ens:textns, en:"user-defined", ans:stylens, a:"data-style-name"}, {ens:textns, en:"user-field-get", ans:stylens, a:"data-style-name"}, {ens:textns, en:"user-field-input", ans:stylens, a:"data-style-name"}, {ens:textns, en:"variable-get", ans:stylens, a:"data-style-name"}, {ens:textns, en:"variable-input", ans:stylens, a:"data-style-name" [...]
-   en:"variable-set", ans:stylens, a:"data-style-name"}], "page-layout":[{ens:presentationns, en:"notes", ans:stylens, a:"page-layout-name"}, {ens:stylens, en:"handout-master", ans:stylens, a:"page-layout-name"}, {ens:stylens, en:"master-page", ans:stylens, a:"page-layout-name"}]}, elements, xpath = xmldom.XPath;
-   function hasDerivedStyles(odfbody, nsResolver, styleElement) {
-     var nodes, xp, styleName = styleElement.getAttributeNS(stylens, "name"), styleFamily = styleElement.getAttributeNS(stylens, "family");
-     xp = "//style:*[@style:parent-style-name='" + styleName + "'][@style:family='" + styleFamily + "']";
-     nodes = xpath.getODFElementsWithXPath(odfbody, xp, nsResolver);
-     if(nodes.length) {
-       return true
++odf.Formatting = function Formatting() {
++  var odfContainer, styleInfo = new odf.StyleInfo, svgns = odf.Namespaces.svgns, stylens = odf.Namespaces.stylens, textns = odf.Namespaces.textns, numberns = odf.Namespaces.numberns, fons = odf.Namespaces.fons, odfUtils = new odf.OdfUtils, domUtils = new core.DomUtils, utils = new core.Utils, builtInDefaultStyleAttributesByFamily = {"paragraph":{"style:paragraph-properties":{"fo:text-align":"left"}}}, defaultPageFormatSettings = {width:21.001, height:29.7, margin:2, padding:0};
++  function getSystemDefaultStyleAttributes(styleFamily) {
++    var result, builtInDefaultStyleAttributes = builtInDefaultStyleAttributesByFamily[styleFamily];
++    if(builtInDefaultStyleAttributes) {
++      result = utils.mergeObjects({}, builtInDefaultStyleAttributes)
++    }else {
++      result = {}
 +    }
-     return false
++    return result
 +  }
-   function prefixUsedStyleNames(element, prefix) {
-     var i, stylename, a, e, ns, elname, elns, localName, length = 0;
-     elname = elements[element.localName];
-     if(elname) {
-       elns = elname[element.namespaceURI];
-       if(elns) {
-         length = elns.length
++  this.getSystemDefaultStyleAttributes = getSystemDefaultStyleAttributes;
++  this.setOdfContainer = function(odfcontainer) {
++    odfContainer = odfcontainer
++  };
++  function getFontMap() {
++    var fontFaceDecls = odfContainer.rootElement.fontFaceDecls, fontFaceDeclsMap = {}, node, name, family;
++    node = fontFaceDecls && fontFaceDecls.firstElementChild;
++    while(node) {
++      name = node.getAttributeNS(stylens, "name");
++      if(name) {
++        family = node.getAttributeNS(svgns, "font-family");
++        if(family || node.getElementsByTagNameNS(svgns, "font-face-uri").length > 0) {
++          fontFaceDeclsMap[name] = family
++        }
 +      }
++      node = node.nextElementSibling
 +    }
-     for(i = 0;i < length;i += 1) {
-       a = (elns[i]);
-       ns = a.ns;
-       localName = a.localname;
-       stylename = element.getAttributeNS(ns, localName);
-       if(stylename) {
-         element.setAttributeNS(ns, nsprefixes[ns] + localName, prefix + stylename)
++    return fontFaceDeclsMap
++  }
++  this.getFontMap = getFontMap;
++  this.getAvailableParagraphStyles = function() {
++    var node = odfContainer.rootElement.styles, p_family, p_name, p_displayName, paragraphStyles = [];
++    node = node && node.firstElementChild;
++    while(node) {
++      if(node.localName === "style" && node.namespaceURI === stylens) {
++        p_family = node.getAttributeNS(stylens, "family");
++        if(p_family === "paragraph") {
++          p_name = node.getAttributeNS(stylens, "name");
++          p_displayName = node.getAttributeNS(stylens, "display-name") || p_name;
++          if(p_name && p_displayName) {
++            paragraphStyles.push({name:p_name, displayName:p_displayName})
++          }
++        }
 +      }
++      node = node.nextElementSibling
 +    }
-     e = element.firstElementChild;
-     while(e) {
-       prefixUsedStyleNames(e, prefix);
-       e = e.nextElementSibling
++    return paragraphStyles
++  };
++  this.isStyleUsed = function(styleElement) {
++    var hasDerivedStyles, isUsed, root = odfContainer.rootElement;
++    hasDerivedStyles = styleInfo.hasDerivedStyles(root, odf.Namespaces.lookupNamespaceURI, styleElement);
++    isUsed = (new styleInfo.UsedStyleList(root.styles)).uses(styleElement) || ((new styleInfo.UsedStyleList(root.automaticStyles)).uses(styleElement) || (new styleInfo.UsedStyleList(root.body)).uses(styleElement));
++    return hasDerivedStyles || isUsed
++  };
++  function getDefaultStyleElement(family) {
++    var node = odfContainer.rootElement.styles.firstElementChild;
++    while(node) {
++      if(node.namespaceURI === stylens && (node.localName === "default-style" && node.getAttributeNS(stylens, "family") === family)) {
++        return node
++      }
++      node = node.nextElementSibling
 +    }
++    return null
 +  }
-   function prefixStyleName(styleElement, prefix) {
-     var stylename = styleElement.getAttributeNS(drawns, "name"), ns;
-     if(stylename) {
-       ns = drawns
-     }else {
-       stylename = styleElement.getAttributeNS(stylens, "name");
-       if(stylename) {
-         ns = stylens
++  this.getDefaultStyleElement = getDefaultStyleElement;
++  function getStyleElement(styleName, family, styleElements) {
++    var node, nodeStyleName, styleListElement, i;
++    styleElements = styleElements || [odfContainer.rootElement.automaticStyles, odfContainer.rootElement.styles];
++    for(i = 0;i < styleElements.length;i += 1) {
++      styleListElement = (styleElements[i]);
++      node = styleListElement.firstElementChild;
++      while(node) {
++        nodeStyleName = node.getAttributeNS(stylens, "name");
++        if(node.namespaceURI === stylens && (node.localName === "style" && (node.getAttributeNS(stylens, "family") === family && nodeStyleName === styleName))) {
++          return node
++        }
++        if(family === "list-style" && (node.namespaceURI === textns && (node.localName === "list-style" && nodeStyleName === styleName))) {
++          return node
++        }
++        if(family === "data" && (node.namespaceURI === numberns && nodeStyleName === styleName)) {
++          return node
++        }
++        node = node.nextElementSibling
 +      }
 +    }
-     if(ns) {
-       styleElement.setAttributeNS(ns, nsprefixes[ns] + "name", prefix + stylename)
-     }
++    return null
 +  }
-   function prefixStyleNames(styleElementsRoot, prefix, styleUsingElementsRoot) {
-     var s;
-     if(styleElementsRoot) {
-       s = styleElementsRoot.firstChild;
-       while(s) {
-         if(s.nodeType === Node.ELEMENT_NODE) {
-           prefixStyleName((s), prefix)
++  this.getStyleElement = getStyleElement;
++  function getStyleAttributes(styleNode) {
++    var i, a, map, ai, propertiesMap = {}, propertiesNode = styleNode.firstElementChild;
++    while(propertiesNode) {
++      if(propertiesNode.namespaceURI === stylens) {
++        map = propertiesMap[propertiesNode.nodeName] = {};
++        a = propertiesNode.attributes;
++        for(i = 0;i < a.length;i += 1) {
++          ai = (a.item(i));
++          map[ai.name] = ai.value
 +        }
-         s = s.nextSibling
-       }
-       prefixUsedStyleNames(styleElementsRoot, prefix);
-       if(styleUsingElementsRoot) {
-         prefixUsedStyleNames(styleUsingElementsRoot, prefix)
 +      }
++      propertiesNode = propertiesNode.nextElementSibling
++    }
++    a = styleNode.attributes;
++    for(i = 0;i < a.length;i += 1) {
++      ai = (a.item(i));
++      propertiesMap[ai.name] = ai.value
 +    }
++    return propertiesMap
 +  }
-   function removeRegExpFromUsedStyleNames(element, regExp) {
-     var i, stylename, e, elname, elns, a, ns, localName, length = 0;
-     elname = elements[element.localName];
-     if(elname) {
-       elns = elname[element.namespaceURI];
-       if(elns) {
-         length = elns.length
++  this.getStyleAttributes = getStyleAttributes;
++  function getInheritedStyleAttributes(styleNode, includeSystemDefault) {
++    var styleListElement = odfContainer.rootElement.styles, parentStyleName, propertiesMap, inheritedPropertiesMap = {}, styleFamily = styleNode.getAttributeNS(stylens, "family"), node = styleNode;
++    while(node) {
++      propertiesMap = getStyleAttributes(node);
++      inheritedPropertiesMap = utils.mergeObjects(propertiesMap, inheritedPropertiesMap);
++      parentStyleName = node.getAttributeNS(stylens, "parent-style-name");
++      if(parentStyleName) {
++        node = getStyleElement(parentStyleName, styleFamily, [styleListElement])
++      }else {
++        node = null
 +      }
 +    }
-     for(i = 0;i < length;i += 1) {
-       a = (elns[i]);
-       ns = a.ns;
-       localName = a.localname;
-       stylename = element.getAttributeNS(ns, localName);
-       if(stylename) {
-         stylename = stylename.replace(regExp, "");
-         element.setAttributeNS(ns, nsprefixes[ns] + localName, stylename)
-       }
++    node = getDefaultStyleElement(styleFamily);
++    if(node) {
++      propertiesMap = getStyleAttributes(node);
++      inheritedPropertiesMap = utils.mergeObjects(propertiesMap, inheritedPropertiesMap)
 +    }
-     e = element.firstElementChild;
-     while(e) {
-       removeRegExpFromUsedStyleNames(e, regExp);
-       e = e.nextElementSibling
++    if(includeSystemDefault !== false) {
++      propertiesMap = getSystemDefaultStyleAttributes(styleFamily);
++      inheritedPropertiesMap = utils.mergeObjects(propertiesMap, inheritedPropertiesMap)
 +    }
++    return inheritedPropertiesMap
 +  }
-   function removeRegExpFromStyleName(styleElement, regExp) {
-     var stylename = styleElement.getAttributeNS(drawns, "name"), ns;
-     if(stylename) {
-       ns = drawns
-     }else {
-       stylename = styleElement.getAttributeNS(stylens, "name");
-       if(stylename) {
-         ns = stylens
-       }
++  this.getInheritedStyleAttributes = getInheritedStyleAttributes;
++  this.getFirstCommonParentStyleNameOrSelf = function(styleName) {
++    var automaticStyleElementList = odfContainer.rootElement.automaticStyles, styleElementList = odfContainer.rootElement.styles, styleElement;
++    styleElement = getStyleElement(styleName, "paragraph", [automaticStyleElementList]);
++    while(styleElement) {
++      styleName = styleElement.getAttributeNS(stylens, "parent-style-name");
++      styleElement = getStyleElement(styleName, "paragraph", [automaticStyleElementList])
 +    }
-     if(ns) {
-       stylename = stylename.replace(regExp, "");
-       styleElement.setAttributeNS(ns, nsprefixes[ns] + "name", stylename)
++    styleElement = getStyleElement(styleName, "paragraph", [styleElementList]);
++    if(!styleElement) {
++      return null
 +    }
-   }
-   function removePrefixFromStyleNames(styleElementsRoot, prefix, styleUsingElementsRoot) {
-     var s, regExp = new RegExp("^" + prefix);
-     if(styleElementsRoot) {
-       s = styleElementsRoot.firstChild;
-       while(s) {
-         if(s.nodeType === Node.ELEMENT_NODE) {
-           removeRegExpFromStyleName((s), regExp)
-         }
-         s = s.nextSibling
++    return styleName
++  };
++  this.hasParagraphStyle = function(styleName) {
++    return Boolean(getStyleElement(styleName, "paragraph"))
++  };
++  function buildStyleChain(node, collectedChains) {
++    var parent = (node.nodeType === Node.TEXT_NODE ? node.parentNode : node), nodeStyles, appliedStyles = [], chainKey = "", foundContainer = false;
++    while(parent) {
++      if(!foundContainer && odfUtils.isGroupingElement(parent)) {
++        foundContainer = true
 +      }
-       removeRegExpFromUsedStyleNames(styleElementsRoot, regExp);
-       if(styleUsingElementsRoot) {
-         removeRegExpFromUsedStyleNames(styleUsingElementsRoot, regExp)
++      nodeStyles = styleInfo.determineStylesForNode(parent);
++      if(nodeStyles) {
++        appliedStyles.push(nodeStyles)
 +      }
++      parent = (parent.parentNode)
 +    }
-   }
-   function determineStylesForNode(element, usedStyles) {
-     var i, stylename, elname, elns, a, ns, localName, keyname, length = 0, map;
-     elname = elements[element.localName];
-     if(elname) {
-       elns = elname[element.namespaceURI];
-       if(elns) {
-         length = elns.length
++    function chainStyles(usedStyleMap) {
++      Object.keys(usedStyleMap).forEach(function(styleFamily) {
++        Object.keys(usedStyleMap[styleFamily]).forEach(function(styleName) {
++          chainKey += "|" + styleFamily + ":" + styleName + "|"
++        })
++      })
++    }
++    if(foundContainer) {
++      appliedStyles.forEach(chainStyles);
++      if(collectedChains) {
++        collectedChains[chainKey] = appliedStyles
 +      }
 +    }
-     for(i = 0;i < length;i += 1) {
-       a = (elns[i]);
-       ns = a.ns;
-       localName = a.localname;
-       stylename = element.getAttributeNS(ns, localName);
-       if(stylename) {
-         usedStyles = usedStyles || {};
-         keyname = a.keyname;
-         if(usedStyles.hasOwnProperty(keyname)) {
-           usedStyles[keyname][stylename] = 1
++    return foundContainer ? appliedStyles : undefined
++  }
++  function isCommonStyleElement(styleNode) {
++    return styleNode.parentNode === odfContainer.rootElement.styles
++  }
++  function calculateAppliedStyle(styleChain) {
++    var mergedChildStyle = {orderedStyles:[]};
++    styleChain.forEach(function(elementStyleSet) {
++      Object.keys((elementStyleSet)).forEach(function(styleFamily) {
++        var styleName = Object.keys(elementStyleSet[styleFamily])[0], styleSummary = {name:styleName, family:styleFamily, displayName:undefined, isCommonStyle:false}, styleElement, parentStyle;
++        styleElement = getStyleElement(styleName, styleFamily);
++        if(styleElement) {
++          parentStyle = getInheritedStyleAttributes((styleElement));
++          mergedChildStyle = utils.mergeObjects(parentStyle, mergedChildStyle);
++          styleSummary.displayName = styleElement.getAttributeNS(stylens, "display-name");
++          styleSummary.isCommonStyle = isCommonStyleElement(styleElement)
 +        }else {
-           map = {};
-           map[stylename] = 1;
-           usedStyles[keyname] = map
++          runtime.log("No style element found for '" + styleName + "' of family '" + styleFamily + "'")
 +        }
-       }
-     }
-     return usedStyles
++        mergedChildStyle.orderedStyles.push(styleSummary)
++      })
++    });
++    return mergedChildStyle
 +  }
-   function determineUsedStyles(styleUsingElementsRoot, usedStyles) {
-     var i, e;
-     determineStylesForNode(styleUsingElementsRoot, usedStyles);
-     i = styleUsingElementsRoot.firstChild;
-     while(i) {
-       if(i.nodeType === Node.ELEMENT_NODE) {
-         e = (i);
-         determineUsedStyles(e, usedStyles)
-       }
-       i = i.nextSibling
++  function getAppliedStyles(nodes, calculatedStylesCache) {
++    var styleChains = {}, styles = [];
++    if(!calculatedStylesCache) {
++      calculatedStylesCache = {}
 +    }
++    nodes.forEach(function(n) {
++      buildStyleChain(n, styleChains)
++    });
++    Object.keys(styleChains).forEach(function(key) {
++      if(!calculatedStylesCache[key]) {
++        calculatedStylesCache[key] = calculateAppliedStyle(styleChains[key])
++      }
++      styles.push(calculatedStylesCache[key])
++    });
++    return styles
 +  }
-   function StyleDefinition(key, name, family) {
-     this.key = key;
-     this.name = name;
-     this.family = family;
-     this.requires = {}
-   }
-   function getStyleDefinition(stylename, stylefamily, knownStyles) {
-     var styleKey = stylename + '"' + stylefamily, styleDefinition = knownStyles[styleKey];
-     if(!styleDefinition) {
-       styleDefinition = knownStyles[styleKey] = new StyleDefinition(styleKey, stylename, stylefamily)
++  this.getAppliedStyles = getAppliedStyles;
++  this.getAppliedStylesForElement = function(node, calculatedStylesCache) {
++    return getAppliedStyles([node], calculatedStylesCache)[0]
++  };
++  this.updateStyle = function(styleNode, properties) {
++    var fontName, fontFaceNode;
++    domUtils.mapObjOntoNode(styleNode, properties, odf.Namespaces.lookupNamespaceURI);
++    fontName = properties["style:text-properties"] && properties["style:text-properties"]["style:font-name"];
++    if(fontName && !getFontMap().hasOwnProperty(fontName)) {
++      fontFaceNode = styleNode.ownerDocument.createElementNS(stylens, "style:font-face");
++      fontFaceNode.setAttributeNS(stylens, "style:name", fontName);
++      fontFaceNode.setAttributeNS(svgns, "svg:font-family", fontName);
++      odfContainer.rootElement.fontFaceDecls.appendChild(fontFaceNode)
 +    }
-     return styleDefinition
-   }
-   function determineDependentStyles(element, styleScope, knownStyles) {
-     var i, stylename, elname, elns, a, ns, localName, e, referencedStyleFamily, referencedStyleDef, length = 0, newScopeName = element.getAttributeNS(stylens, "name"), newScopeFamily = element.getAttributeNS(stylens, "family");
-     if(newScopeName && newScopeFamily) {
-       styleScope = getStyleDefinition(newScopeName, newScopeFamily, knownStyles)
++  };
++  this.createDerivedStyleObject = function(parentStyleName, family, overrides) {
++    var originalStyleElement = (getStyleElement(parentStyleName, family)), newStyleObject;
++    runtime.assert(Boolean(originalStyleElement), "No style element found for '" + parentStyleName + "' of family '" + family + "'");
++    if(isCommonStyleElement(originalStyleElement)) {
++      newStyleObject = {"style:parent-style-name":parentStyleName}
++    }else {
++      newStyleObject = getStyleAttributes(originalStyleElement)
 +    }
-     if(styleScope) {
-       elname = elements[element.localName];
-       if(elname) {
-         elns = elname[element.namespaceURI];
-         if(elns) {
-           length = elns.length
++    newStyleObject["style:family"] = family;
++    utils.mergeObjects(newStyleObject, overrides);
++    return newStyleObject
++  };
++  this.getDefaultTabStopDistance = function() {
++    var defaultParagraph = getDefaultStyleElement("paragraph"), paragraphProperties = defaultParagraph && defaultParagraph.firstElementChild, tabStopDistance;
++    while(paragraphProperties) {
++      if(paragraphProperties.namespaceURI === stylens && paragraphProperties.localName === "paragraph-properties") {
++        tabStopDistance = paragraphProperties.getAttributeNS(stylens, "tab-stop-distance")
++      }
++      paragraphProperties = paragraphProperties.nextElementSibling
++    }
++    if(!tabStopDistance) {
++      tabStopDistance = "1.25cm"
++    }
++    return odfUtils.parseNonNegativeLength(tabStopDistance)
++  };
++  function getPageLayoutStyleElement(styleName, styleFamily) {
++    var masterPageName, layoutName, pageLayoutElements, node, i, styleElement = getStyleElement(styleName, styleFamily);
++    runtime.assert(styleFamily === "paragraph" || styleFamily === "table", "styleFamily has to be either paragraph or table");
++    if(styleElement) {
++      masterPageName = styleElement.getAttributeNS(stylens, "master-page-name") || "Standard";
++      node = odfContainer.rootElement.masterStyles.lastElementChild;
++      while(node) {
++        if(node.getAttributeNS(stylens, "name") === masterPageName) {
++          break
 +        }
++        node = node.previousElementSibling
 +      }
-       for(i = 0;i < length;i += 1) {
-         a = (elns[i]);
-         ns = a.ns;
-         localName = a.localname;
-         stylename = element.getAttributeNS(ns, localName);
-         if(stylename) {
-           referencedStyleFamily = a.keyname;
-           referencedStyleDef = getStyleDefinition(stylename, referencedStyleFamily, knownStyles);
-           styleScope.requires[referencedStyleDef.key] = referencedStyleDef
++      layoutName = node.getAttributeNS(stylens, "page-layout-name");
++      pageLayoutElements = domUtils.getElementsByTagNameNS(odfContainer.rootElement.automaticStyles, stylens, "page-layout");
++      for(i = 0;i < pageLayoutElements.length;i += 1) {
++        node = pageLayoutElements[i];
++        if(node.getAttributeNS(stylens, "name") === layoutName) {
++          return(node)
 +        }
 +      }
 +    }
-     e = element.firstElementChild;
-     while(e) {
-       determineDependentStyles(e, styleScope, knownStyles);
-       e = e.nextElementSibling
-     }
-     return knownStyles
++    return null
 +  }
-   function inverse() {
-     var i, l, keyname, list, item, e = {}, map, array, en, ens;
-     for(keyname in elementstyles) {
-       if(elementstyles.hasOwnProperty(keyname)) {
-         list = elementstyles[keyname];
-         l = list.length;
-         for(i = 0;i < l;i += 1) {
-           item = list[i];
-           en = item.en;
-           ens = item.ens;
-           if(e.hasOwnProperty(en)) {
-             map = e[en]
-           }else {
-             e[en] = map = {}
-           }
-           if(map.hasOwnProperty(ens)) {
-             array = map[ens]
-           }else {
-             map[ens] = array = []
-           }
-           array.push({ns:item.ans, localname:item.a, keyname:keyname})
-         }
++  function lengthInCm(length, defaultValue) {
++    var result = odfUtils.parseLength(length), value = defaultValue;
++    if(result) {
++      switch(result.unit) {
++        case "cm":
++          value = result.value;
++          break;
++        case "mm":
++          value = result.value * 0.1;
++          break;
++        case "in":
++          value = result.value * 2.54;
++          break;
++        case "pt":
++          value = result.value * 0.035277778;
++          break;
++        case "pc":
++        ;
++        case "px":
++        ;
++        case "em":
++          break;
++        default:
++          runtime.log("Unit identifier: " + result.unit + " is not supported.");
++          break
 +      }
 +    }
-     return e
++    return value
 +  }
-   function mergeRequiredStyles(styleDependency, usedStyles) {
-     var family = usedStyles[styleDependency.family];
-     if(!family) {
-       family = usedStyles[styleDependency.family] = {}
++  this.getContentSize = function(styleName, styleFamily) {
++    var pageLayoutElement, props, printOrientation, defaultOrientedPageWidth, defaultOrientedPageHeight, pageWidth, pageHeight, margin, marginLeft, marginRight, marginTop, marginBottom, padding, paddingLeft, paddingRight, paddingTop, paddingBottom;
++    pageLayoutElement = getPageLayoutStyleElement(styleName, styleFamily);
++    if(!pageLayoutElement) {
++      pageLayoutElement = domUtils.getDirectChild(odfContainer.rootElement.styles, stylens, "default-page-layout")
 +    }
-     family[styleDependency.name] = 1;
-     Object.keys((styleDependency.requires)).forEach(function(requiredStyleKey) {
-       mergeRequiredStyles((styleDependency.requires[requiredStyleKey]), usedStyles)
-     })
-   }
-   function mergeUsedAutomaticStyles(automaticStylesRoot, usedStyles) {
-     var automaticStyles = determineDependentStyles(automaticStylesRoot, null, {});
-     Object.keys(automaticStyles).forEach(function(styleKey) {
-       var automaticStyleDefinition = automaticStyles[styleKey], usedFamily = usedStyles[automaticStyleDefinition.family];
-       if(usedFamily && usedFamily.hasOwnProperty(automaticStyleDefinition.name)) {
-         mergeRequiredStyles(automaticStyleDefinition, usedStyles)
++    props = domUtils.getDirectChild(pageLayoutElement, stylens, "page-layout-properties");
++    if(props) {
++      printOrientation = props.getAttributeNS(stylens, "print-orientation") || "portrait";
++      if(printOrientation === "portrait") {
++        defaultOrientedPageWidth = defaultPageFormatSettings.width;
++        defaultOrientedPageHeight = defaultPageFormatSettings.height
++      }else {
++        defaultOrientedPageWidth = defaultPageFormatSettings.height;
++        defaultOrientedPageHeight = defaultPageFormatSettings.width
 +      }
-     })
-   }
-   function collectUsedFontFaces(usedFontFaceDeclMap, styleElement) {
-     var localNames = ["font-name", "font-name-asian", "font-name-complex"], e, currentElement;
-     function collectByAttribute(localName) {
-       var fontFaceName = currentElement.getAttributeNS(stylens, localName);
-       if(fontFaceName) {
-         usedFontFaceDeclMap[fontFaceName] = true
++      pageWidth = lengthInCm(props.getAttributeNS(fons, "page-width"), defaultOrientedPageWidth);
++      pageHeight = lengthInCm(props.getAttributeNS(fons, "page-height"), defaultOrientedPageHeight);
++      margin = lengthInCm(props.getAttributeNS(fons, "margin"), null);
++      if(margin === null) {
++        marginLeft = lengthInCm(props.getAttributeNS(fons, "margin-left"), defaultPageFormatSettings.margin);
++        marginRight = lengthInCm(props.getAttributeNS(fons, "margin-right"), defaultPageFormatSettings.margin);
++        marginTop = lengthInCm(props.getAttributeNS(fons, "margin-top"), defaultPageFormatSettings.margin);
++        marginBottom = lengthInCm(props.getAttributeNS(fons, "margin-bottom"), defaultPageFormatSettings.margin)
++      }else {
++        marginLeft = marginRight = marginTop = marginBottom = margin
 +      }
-     }
-     e = styleElement && styleElement.firstElementChild;
-     while(e) {
-       currentElement = e;
-       localNames.forEach(collectByAttribute);
-       collectUsedFontFaces(usedFontFaceDeclMap, currentElement);
-       e = e.nextElementSibling
-     }
-   }
-   this.collectUsedFontFaces = collectUsedFontFaces;
-   function changeFontFaceNames(styleElement, fontFaceNameChangeMap) {
-     var localNames = ["font-name", "font-name-asian", "font-name-complex"], e, currentElement;
-     function changeFontFaceNameByAttribute(localName) {
-       var fontFaceName = currentElement.getAttributeNS(stylens, localName);
-       if(fontFaceName && fontFaceNameChangeMap.hasOwnProperty(fontFaceName)) {
-         currentElement.setAttributeNS(stylens, "style:" + localName, fontFaceNameChangeMap[fontFaceName])
++      padding = lengthInCm(props.getAttributeNS(fons, "padding"), null);
++      if(padding === null) {
++        paddingLeft = lengthInCm(props.getAttributeNS(fons, "padding-left"), defaultPageFormatSettings.padding);
++        paddingRight = lengthInCm(props.getAttributeNS(fons, "padding-right"), defaultPageFormatSettings.padding);
++        paddingTop = lengthInCm(props.getAttributeNS(fons, "padding-top"), defaultPageFormatSettings.padding);
++        paddingBottom = lengthInCm(props.getAttributeNS(fons, "padding-bottom"), defaultPageFormatSettings.padding)
++      }else {
++        paddingLeft = paddingRight = paddingTop = paddingBottom = padding
 +      }
 +    }
-     e = styleElement && styleElement.firstElementChild;
-     while(e) {
-       currentElement = e;
-       localNames.forEach(changeFontFaceNameByAttribute);
-       changeFontFaceNames(currentElement, fontFaceNameChangeMap);
-       e = e.nextElementSibling
-     }
++    return{width:pageWidth - marginLeft - marginRight - paddingLeft - paddingRight, height:pageHeight - marginTop - marginBottom - paddingTop - paddingBottom}
 +  }
-   this.changeFontFaceNames = changeFontFaceNames;
-   this.UsedStyleList = function(styleUsingElementsRoot, automaticStylesRoot) {
-     var usedStyles = {};
-     this.uses = function(element) {
-       var localName = element.localName, name = element.getAttributeNS(drawns, "name") || element.getAttributeNS(stylens, "name"), keyName, map;
-       if(localName === "style") {
-         keyName = element.getAttributeNS(stylens, "family")
-       }else {
-         if(element.namespaceURI === numberns) {
-           keyName = "data"
-         }else {
-           keyName = localName
-         }
-       }
-       map = usedStyles[keyName];
-       return map ? map[name] > 0 : false
-     };
-     determineUsedStyles(styleUsingElementsRoot, usedStyles);
-     if(automaticStylesRoot) {
-       mergeUsedAutomaticStyles(automaticStylesRoot, usedStyles)
-     }
-   };
-   this.hasDerivedStyles = hasDerivedStyles;
-   this.prefixStyleNames = prefixStyleNames;
-   this.removePrefixFromStyleNames = removePrefixFromStyleNames;
-   this.determineStylesForNode = determineStylesForNode;
-   elements = inverse()
 +};
 +/*
 +
-  Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
++ Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("odf.OdfUtils");
- odf.TextSerializer = function TextSerializer() {
-   var self = this, odfUtils = new odf.OdfUtils;
-   function serializeNode(node) {
-     var s = "", accept = self.filter ? self.filter.acceptNode(node) : NodeFilter.FILTER_ACCEPT, nodeType = node.nodeType, child;
-     if(accept === NodeFilter.FILTER_ACCEPT || accept === NodeFilter.FILTER_SKIP) {
-       child = node.firstChild;
-       while(child) {
-         s += serializeNode(child);
-         child = child.nextSibling
-       }
++odf.StyleTreeNode = function StyleTreeNode(element) {
++  this.derivedStyles = {};
++  this.element = element
++};
++odf.Style2CSS = function Style2CSS() {
++  var drawns = odf.Namespaces.drawns, fons = odf.Namespaces.fons, officens = odf.Namespaces.officens, stylens = odf.Namespaces.stylens, svgns = odf.Namespaces.svgns, tablens = odf.Namespaces.tablens, textns = odf.Namespaces.textns, xlinkns = odf.Namespaces.xlinkns, presentationns = odf.Namespaces.presentationns, domUtils = new core.DomUtils, familynamespaceprefixes = {"graphic":"draw", "drawing-page":"draw", "paragraph":"text", "presentation":"presentation", "ruby":"text", "section":"te [...]
++  "table-cell":"table", "table-column":"table", "table-row":"table", "text":"text", "list":"text", "page":"office"}, familytagnames = {"graphic":["circle", "connected", "control", "custom-shape", "ellipse", "frame", "g", "line", "measure", "page", "page-thumbnail", "path", "polygon", "polyline", "rect", "regular-polygon"], "paragraph":["alphabetical-index-entry-template", "h", "illustration-index-entry-template", "index-source-style", "object-index-entry-template", "p", "table-index-ent [...]
++  "table-of-content-entry-template", "user-index-entry-template"], "presentation":["caption", "circle", "connector", "control", "custom-shape", "ellipse", "frame", "g", "line", "measure", "page-thumbnail", "path", "polygon", "polyline", "rect", "regular-polygon"], "drawing-page":["caption", "circle", "connector", "control", "page", "custom-shape", "ellipse", "frame", "g", "line", "measure", "page-thumbnail", "path", "polygon", "polyline", "rect", "regular-polygon"], "ruby":["ruby", "rub [...]
++  "section":["alphabetical-index", "bibliography", "illustration-index", "index-title", "object-index", "section", "table-of-content", "table-index", "user-index"], "table":["background", "table"], "table-cell":["body", "covered-table-cell", "even-columns", "even-rows", "first-column", "first-row", "last-column", "last-row", "odd-columns", "odd-rows", "table-cell"], "table-column":["table-column"], "table-row":["table-row"], "text":["a", "index-entry-chapter", "index-entry-link-end", "i [...]
++  "index-entry-page-number", "index-entry-span", "index-entry-tab-stop", "index-entry-text", "index-title-template", "linenumbering-configuration", "list-level-style-number", "list-level-style-bullet", "outline-level-style", "span"], "list":["list-item"]}, textPropertySimpleMapping = [[fons, "color", "color"], [fons, "background-color", "background-color"], [fons, "font-weight", "font-weight"], [fons, "font-style", "font-style"]], bgImageSimpleMapping = [[stylens, "repeat", "background- [...]
++  paragraphPropertySimpleMapping = [[fons, "background-color", "background-color"], [fons, "text-align", "text-align"], [fons, "text-indent", "text-indent"], [fons, "padding", "padding"], [fons, "padding-left", "padding-left"], [fons, "padding-right", "padding-right"], [fons, "padding-top", "padding-top"], [fons, "padding-bottom", "padding-bottom"], [fons, "border-left", "border-left"], [fons, "border-right", "border-right"], [fons, "border-top", "border-top"], [fons, "border-bottom", " [...]
++  [fons, "margin", "margin"], [fons, "margin-left", "margin-left"], [fons, "margin-right", "margin-right"], [fons, "margin-top", "margin-top"], [fons, "margin-bottom", "margin-bottom"], [fons, "border", "border"]], graphicPropertySimpleMapping = [[fons, "background-color", "background-color"], [fons, "min-height", "min-height"], [drawns, "stroke", "border"], [svgns, "stroke-color", "border-color"], [svgns, "stroke-width", "border-width"], [fons, "border", "border"], [fons, "border-left" [...]
++  [fons, "border-right", "border-right"], [fons, "border-top", "border-top"], [fons, "border-bottom", "border-bottom"]], tablecellPropertySimpleMapping = [[fons, "background-color", "background-color"], [fons, "border-left", "border-left"], [fons, "border-right", "border-right"], [fons, "border-top", "border-top"], [fons, "border-bottom", "border-bottom"], [fons, "border", "border"]], tablecolumnPropertySimpleMapping = [[stylens, "column-width", "width"]], tablerowPropertySimpleMapping  [...]
++  "row-height", "height"], [fons, "keep-together", null]], tablePropertySimpleMapping = [[stylens, "width", "width"], [fons, "margin-left", "margin-left"], [fons, "margin-right", "margin-right"], [fons, "margin-top", "margin-top"], [fons, "margin-bottom", "margin-bottom"]], pageContentPropertySimpleMapping = [[fons, "background-color", "background-color"], [fons, "padding", "padding"], [fons, "padding-left", "padding-left"], [fons, "padding-right", "padding-right"], [fons, "padding-top" [...]
++  [fons, "padding-bottom", "padding-bottom"], [fons, "border", "border"], [fons, "border-left", "border-left"], [fons, "border-right", "border-right"], [fons, "border-top", "border-top"], [fons, "border-bottom", "border-bottom"], [fons, "margin", "margin"], [fons, "margin-left", "margin-left"], [fons, "margin-right", "margin-right"], [fons, "margin-top", "margin-top"], [fons, "margin-bottom", "margin-bottom"]], pageSizePropertySimpleMapping = [[fons, "page-width", "width"], [fons, "page [...]
++  "height"]], borderPropertyMap = {"border":true, "border-left":true, "border-right":true, "border-top":true, "border-bottom":true, "stroke-width":true}, fontFaceDeclsMap = {}, utils = new odf.OdfUtils, documentType, odfRoot, defaultFontSize, xpath = xmldom.XPath, cssUnits = new core.CSSUnits;
++  function getStyleMap(stylesnode) {
++    var node, name, family, style, stylemap = {};
++    if(!stylesnode) {
++      return stylemap
 +    }
-     if(accept === NodeFilter.FILTER_ACCEPT) {
-       if(nodeType === Node.ELEMENT_NODE && odfUtils.isParagraph(node)) {
-         s += "\n"
++    node = stylesnode.firstElementChild;
++    while(node) {
++      if(node.namespaceURI === stylens && (node.localName === "style" || node.localName === "default-style")) {
++        family = node.getAttributeNS(stylens, "family")
 +      }else {
-         if(nodeType === Node.TEXT_NODE && node.textContent) {
-           s += node.textContent
++        if(node.namespaceURI === textns && node.localName === "list-style") {
++          family = "list"
++        }else {
++          if(node.namespaceURI === stylens && (node.localName === "page-layout" || node.localName === "default-page-layout")) {
++            family = "page"
++          }else {
++            family = undefined
++          }
++        }
++      }
++      if(family) {
++        name = node.getAttributeNS(stylens, "name");
++        if(!name) {
++          name = ""
++        }
++        if(stylemap.hasOwnProperty(family)) {
++          style = stylemap[family]
++        }else {
++          stylemap[family] = style = {}
 +        }
++        style[name] = node
 +      }
++      node = node.nextElementSibling
 +    }
-     return s
++    return stylemap
 +  }
-   this.filter = null;
-   this.writeToString = function(node) {
-     var plainText;
-     if(!node) {
-       return""
++  function findStyle(stylestree, name) {
++    if(stylestree.hasOwnProperty(name)) {
++      return stylestree[name]
 +    }
-     plainText = serializeNode(node);
-     if(plainText[plainText.length - 1] === "\n") {
-       plainText = plainText.substr(0, plainText.length - 1)
++    var n, style = null;
++    for(n in stylestree) {
++      if(stylestree.hasOwnProperty(n)) {
++        style = findStyle(stylestree[n].derivedStyles, name);
++        if(style) {
++          break
++        }
++      }
 +    }
-     return plainText
++    return style
 +  }
- };
- /*
- 
-  Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
- 
-  @licstart
-  The JavaScript code in this page is free software: you can redistribute it
-  and/or modify it under the terms of the GNU Affero General Public License
-  (GNU AGPL) as published by the Free Software Foundation, either version 3 of
-  the License, or (at your option) any later version.  The code is distributed
-  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
- 
-  You should have received a copy of the GNU Affero General Public License
-  along with this code.  If not, see <http://www.gnu.org/licenses/>.
- 
-  As additional permission under GNU AGPL version 3 section 7, you
-  may distribute non-source (e.g., minimized or compacted) forms of
-  that code without the copy of the GNU GPL normally required by
-  section 4, provided you include this license notice and a URL
-  through which recipients can access the Corresponding Source.
- 
-  As a special exception to the AGPL, any HTML file which merely makes function
-  calls to this code, and for that purpose includes it by reference shall be
-  deemed a separate work for copyright law purposes. In addition, the copyright
-  holders of this code give you permission to combine this code with free
-  software libraries that are released under the GNU LGPL. You may copy and
-  distribute such a system following the terms of the GNU AGPL for this code
-  and the LGPL for the libraries. If you modify this code, you may extend this
-  exception to your version of the code, but you are not obligated to do so.
-  If you do not wish to do so, delete this exception statement from your
-  version.
- 
-  This license applies to this entire compilation.
-  @licend
-  @source: http://www.webodf.org/
-  @source: https://github.com/kogmbh/WebODF/
- */
- runtime.loadClass("core.PositionFilter");
- runtime.loadClass("odf.OdfUtils");
- ops.TextPositionFilter = function TextPositionFilter(getRootNode) {
-   var odfUtils = new odf.OdfUtils, ELEMENT_NODE = Node.ELEMENT_NODE, TEXT_NODE = Node.TEXT_NODE, FILTER_ACCEPT = core.PositionFilter.FilterResult.FILTER_ACCEPT, FILTER_REJECT = core.PositionFilter.FilterResult.FILTER_REJECT;
-   function checkLeftRight(container, leftNode, rightNode) {
-     var r, firstPos, rightOfChar;
-     if(leftNode) {
-       if(odfUtils.isInlineRoot(leftNode) && odfUtils.isGroupingElement(rightNode)) {
-         return FILTER_REJECT
-       }
-       r = odfUtils.lookLeftForCharacter(leftNode);
-       if(r === 1) {
-         return FILTER_ACCEPT
-       }
-       if(r === 2 && (odfUtils.scanRightForAnyCharacter(rightNode) || odfUtils.scanRightForAnyCharacter(odfUtils.nextNode(container)))) {
-         return FILTER_ACCEPT
-       }
++  function addStyleToStyleTree(stylename, stylesmap, stylestree) {
++    var style, parentname, parentstyle;
++    if(!stylesmap.hasOwnProperty(stylename)) {
++      return null
 +    }
-     firstPos = leftNode === null && odfUtils.isParagraph(container);
-     rightOfChar = odfUtils.lookRightForCharacter(rightNode);
-     if(firstPos) {
-       if(rightOfChar) {
-         return FILTER_ACCEPT
-       }
-       return odfUtils.scanRightForAnyCharacter(rightNode) ? FILTER_REJECT : FILTER_ACCEPT
++    style = new odf.StyleTreeNode(stylesmap[stylename]);
++    parentname = style.element.getAttributeNS(stylens, "parent-style-name");
++    parentstyle = null;
++    if(parentname) {
++      parentstyle = findStyle(stylestree, parentname) || addStyleToStyleTree(parentname, stylesmap, stylestree)
 +    }
-     if(!rightOfChar) {
-       return FILTER_REJECT
++    if(parentstyle) {
++      parentstyle.derivedStyles[stylename] = style
++    }else {
++      stylestree[stylename] = style
 +    }
-     leftNode = leftNode || odfUtils.previousNode(container);
-     return odfUtils.scanLeftForAnyCharacter(leftNode) ? FILTER_REJECT : FILTER_ACCEPT
++    delete stylesmap[stylename];
++    return style
 +  }
-   this.acceptPosition = function(iterator) {
-     var container = iterator.container(), nodeType = container.nodeType, offset, text, leftChar, rightChar, leftNode, rightNode, r;
-     if(nodeType !== ELEMENT_NODE && nodeType !== TEXT_NODE) {
-       return FILTER_REJECT
-     }
-     if(nodeType === TEXT_NODE) {
-       if(!odfUtils.isGroupingElement(container.parentNode) || odfUtils.isWithinTrackedChanges(container.parentNode, getRootNode())) {
-         return FILTER_REJECT
-       }
-       offset = iterator.unfilteredDomOffset();
-       text = container.data;
-       runtime.assert(offset !== text.length, "Unexpected offset.");
-       if(offset > 0) {
-         leftChar = (text[offset - 1]);
-         if(!odfUtils.isODFWhitespace(leftChar)) {
-           return FILTER_ACCEPT
-         }
-         if(offset > 1) {
-           leftChar = (text[offset - 2]);
-           if(!odfUtils.isODFWhitespace(leftChar)) {
-             r = FILTER_ACCEPT
-           }else {
-             if(!odfUtils.isODFWhitespace(text.substr(0, offset))) {
-               return FILTER_REJECT
-             }
-           }
-         }else {
-           leftNode = odfUtils.previousNode(container);
-           if(odfUtils.scanLeftForNonSpace(leftNode)) {
-             r = FILTER_ACCEPT
-           }
-         }
-         if(r === FILTER_ACCEPT) {
-           return odfUtils.isTrailingWhitespace((container), offset) ? FILTER_REJECT : FILTER_ACCEPT
-         }
-         rightChar = (text[offset]);
-         if(odfUtils.isODFWhitespace(rightChar)) {
-           return FILTER_REJECT
-         }
-         return odfUtils.scanLeftForAnyCharacter(odfUtils.previousNode(container)) ? FILTER_REJECT : FILTER_ACCEPT
++  function addStyleMapToStyleTree(stylesmap, stylestree) {
++    var name;
++    for(name in stylesmap) {
++      if(stylesmap.hasOwnProperty(name)) {
++        addStyleToStyleTree(name, stylesmap, stylestree)
 +      }
-       leftNode = iterator.leftNode();
-       rightNode = container;
-       container = (container.parentNode);
-       r = checkLeftRight(container, leftNode, rightNode)
++    }
++  }
++  function createSelector(family, name) {
++    var prefix = familynamespaceprefixes[family], namepart, selector;
++    if(prefix === undefined) {
++      return null
++    }
++    if(name) {
++      namepart = "[" + prefix + '|style-name="' + name + '"]'
 +    }else {
-       if(!odfUtils.isGroupingElement(container) || odfUtils.isWithinTrackedChanges(container, getRootNode())) {
-         r = FILTER_REJECT
++      namepart = ""
++    }
++    if(prefix === "presentation") {
++      prefix = "draw";
++      if(name) {
++        namepart = '[presentation|style-name="' + name + '"]'
 +      }else {
-         leftNode = iterator.leftNode();
-         rightNode = iterator.rightNode();
-         r = checkLeftRight(container, leftNode, rightNode)
++        namepart = ""
 +      }
 +    }
-     return r
++    selector = prefix + "|" + familytagnames[family].join(namepart + "," + prefix + "|") + namepart;
++    return selector
 +  }
- };
- if(typeof Object.create !== "function") {
-   Object["create"] = function(o) {
-     var F = function() {
-     };
-     F.prototype = o;
-     return new F
-   }
- }
- xmldom.LSSerializer = function LSSerializer() {
-   var self = this;
-   function Namespaces(nsmap) {
-     function invertMap(map) {
-       var m = {}, i;
-       for(i in map) {
-         if(map.hasOwnProperty(i)) {
-           m[map[i]] = i
-         }
-       }
-       return m
++  function getSelectors(family, name, node) {
++    var selectors = [], ss, derivedStyles = node.derivedStyles, n;
++    ss = createSelector(family, name);
++    if(ss !== null) {
++      selectors.push(ss)
 +    }
-     var current = nsmap || {}, currentrev = invertMap(nsmap), levels = [current], levelsrev = [currentrev], level = 0;
-     this.push = function() {
-       level += 1;
-       current = levels[level] = Object.create(current);
-       currentrev = levelsrev[level] = Object.create(currentrev)
-     };
-     this.pop = function() {
-       levels.pop();
-       levelsrev.pop();
-       level -= 1;
-       current = levels[level];
-       currentrev = levelsrev[level]
-     };
-     this.getLocalNamespaceDefinitions = function() {
-       return currentrev
-     };
-     this.getQName = function(node) {
-       var ns = node.namespaceURI, i = 0, p;
-       if(!ns) {
-         return node.localName
-       }
-       p = currentrev[ns];
-       if(p) {
-         return p + ":" + node.localName
++    for(n in derivedStyles) {
++      if(derivedStyles.hasOwnProperty(n)) {
++        ss = getSelectors(family, n, derivedStyles[n]);
++        selectors = selectors.concat(ss)
 +      }
-       do {
-         if(p || !node.prefix) {
-           p = "ns" + i;
-           i += 1
-         }else {
-           p = node.prefix
-         }
-         if(current[p] === ns) {
-           break
++    }
++    return selectors
++  }
++  function fixBorderWidth(value) {
++    var index = value.indexOf(" "), width, theRestOfBorderAttributes;
++    if(index !== -1) {
++      width = value.substring(0, index);
++      theRestOfBorderAttributes = value.substring(index)
++    }else {
++      width = value;
++      theRestOfBorderAttributes = ""
++    }
++    width = utils.parseLength(width);
++    if(width && (width.unit === "pt" && width.value < 0.75)) {
++      value = "0.75pt" + theRestOfBorderAttributes
++    }
++    return value
++  }
++  function applySimpleMapping(props, mapping) {
++    var rule = "", i, r, value;
++    for(i = 0;i < mapping.length;i += 1) {
++      r = mapping[i];
++      value = props.getAttributeNS(r[0], r[1]);
++      if(value) {
++        value = value.trim();
++        if(borderPropertyMap.hasOwnProperty(r[1])) {
++          value = fixBorderWidth(value)
 +        }
-         if(!current[p]) {
-           current[p] = ns;
-           currentrev[ns] = p;
-           break
++        if(r[2]) {
++          rule += r[2] + ":" + value + ";"
 +        }
-         p = null
-       }while(p === null);
-       return p + ":" + node.localName
++      }
 +    }
++    return rule
 +  }
-   function escapeContent(value) {
-     return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/'/g, "'").replace(/"/g, """)
++  function getFontSize(styleNode) {
++    var props = domUtils.getDirectChild(styleNode, stylens, "text-properties");
++    if(props) {
++      return utils.parseFoFontSize(props.getAttributeNS(fons, "font-size"))
++    }
++    return null
 +  }
-   function serializeAttribute(qname, attr) {
-     var escapedValue = typeof attr.value === "string" ? escapeContent(attr.value) : attr.value, s = qname + '="' + escapedValue + '"';
-     return s
++  function getParentStyleNode(styleNode) {
++    var parentStyleName = "", parentStyleFamily = "", parentStyleNode = null, xp;
++    if(styleNode.localName === "default-style") {
++      return null
++    }
++    parentStyleName = styleNode.getAttributeNS(stylens, "parent-style-name");
++    parentStyleFamily = styleNode.getAttributeNS(stylens, "family");
++    if(parentStyleName) {
++      xp = "//style:*[@style:name='" + parentStyleName + "'][@style:family='" + parentStyleFamily + "']"
++    }else {
++      xp = "//style:default-style[@style:family='" + parentStyleFamily + "']"
++    }
++    parentStyleNode = xpath.getODFElementsWithXPath((odfRoot), xp, odf.Namespaces.lookupNamespaceURI)[0];
++    return parentStyleNode
 +  }
-   function startElement(ns, qname, element) {
-     var s = "", atts = (element.attributes), length, i, attr, attstr = "", accept, prefix, nsmap;
-     s += "<" + qname;
-     length = atts.length;
-     for(i = 0;i < length;i += 1) {
-       attr = (atts.item(i));
-       if(attr.namespaceURI !== "http://www.w3.org/2000/xmlns/") {
-         accept = self.filter ? self.filter.acceptNode(attr) : NodeFilter.FILTER_ACCEPT;
-         if(accept === NodeFilter.FILTER_ACCEPT) {
-           attstr += " " + serializeAttribute(ns.getQName(attr), attr)
-         }
-       }
++  function getTextProperties(props) {
++    var rule = "", fontName, fontSize, value, textDecoration = "", fontSizeRule = "", sizeMultiplier = 1, parentStyle;
++    rule += applySimpleMapping(props, textPropertySimpleMapping);
++    value = props.getAttributeNS(stylens, "text-underline-style");
++    if(value === "solid") {
++      textDecoration += " underline"
 +    }
-     nsmap = ns.getLocalNamespaceDefinitions();
-     for(i in nsmap) {
-       if(nsmap.hasOwnProperty(i)) {
-         prefix = nsmap[i];
-         if(!prefix) {
-           s += ' xmlns="' + i + '"'
-         }else {
-           if(prefix !== "xmlns") {
-             s += " xmlns:" + nsmap[i] + '="' + i + '"'
-           }
++    value = props.getAttributeNS(stylens, "text-line-through-style");
++    if(value === "solid") {
++      textDecoration += " line-through"
++    }
++    if(textDecoration.length) {
++      textDecoration = "text-decoration:" + textDecoration + ";";
++      rule += textDecoration
++    }
++    fontName = props.getAttributeNS(stylens, "font-name") || props.getAttributeNS(fons, "font-family");
++    if(fontName) {
++      value = fontFaceDeclsMap[fontName];
++      rule += "font-family: " + (value || fontName) + ";"
++    }
++    parentStyle = (props.parentNode);
++    fontSize = getFontSize(parentStyle);
++    if(!fontSize) {
++      return rule
++    }
++    while(parentStyle) {
++      fontSize = getFontSize(parentStyle);
++      if(fontSize) {
++        if(fontSize.unit !== "%") {
++          fontSizeRule = "font-size: " + fontSize.value * sizeMultiplier + fontSize.unit + ";";
++          break
 +        }
++        sizeMultiplier *= fontSize.value / 100
 +      }
++      parentStyle = getParentStyleNode(parentStyle)
 +    }
-     s += attstr + ">";
-     return s
-   }
-   function serializeNode(ns, node) {
-     var s = "", accept = self.filter ? self.filter.acceptNode(node) : NodeFilter.FILTER_ACCEPT, child, qname;
-     if(accept === NodeFilter.FILTER_ACCEPT && node.nodeType === Node.ELEMENT_NODE) {
-       ns.push();
-       qname = ns.getQName(node);
-       s += startElement(ns, qname, node)
++    if(!fontSizeRule) {
++      fontSizeRule = "font-size: " + parseFloat(defaultFontSize) * sizeMultiplier + cssUnits.getUnits(defaultFontSize) + ";"
 +    }
-     if(accept === NodeFilter.FILTER_ACCEPT || accept === NodeFilter.FILTER_SKIP) {
-       child = node.firstChild;
-       while(child) {
-         s += serializeNode(ns, child);
-         child = child.nextSibling
-       }
-       if(node.nodeValue) {
-         s += escapeContent(node.nodeValue)
++    rule += fontSizeRule;
++    return rule
++  }
++  function getParagraphProperties(props) {
++    var rule = "", bgimage, url, lineHeight;
++    rule += applySimpleMapping(props, paragraphPropertySimpleMapping);
++    bgimage = domUtils.getDirectChild(props, stylens, "background-image");
++    if(bgimage) {
++      url = bgimage.getAttributeNS(xlinkns, "href");
++      if(url) {
++        rule += "background-image: url('odfkit:" + url + "');";
++        rule += applySimpleMapping(bgimage, bgImageSimpleMapping)
 +      }
 +    }
-     if(qname) {
-       s += "</" + qname + ">";
-       ns.pop()
++    lineHeight = props.getAttributeNS(fons, "line-height");
++    if(lineHeight && lineHeight !== "normal") {
++      lineHeight = utils.parseFoLineHeight(lineHeight);
++      if(lineHeight.unit !== "%") {
++        rule += "line-height: " + lineHeight.value + lineHeight.unit + ";"
++      }else {
++        rule += "line-height: " + lineHeight.value / 100 + ";"
++      }
 +    }
-     return s
++    return rule
 +  }
-   this.filter = null;
-   this.writeToString = function(node, nsmap) {
-     if(!node) {
-       return""
-     }
-     var ns = new Namespaces(nsmap);
-     return serializeNode(ns, node)
++  function matchToRgb(m, r, g, b) {
++    return r + r + g + g + b + b
 +  }
- };
- /*
- 
-  Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
- 
-  @licstart
-  The JavaScript code in this page is free software: you can redistribute it
-  and/or modify it under the terms of the GNU Affero General Public License
-  (GNU AGPL) as published by the Free Software Foundation, either version 3 of
-  the License, or (at your option) any later version.  The code is distributed
-  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
- 
-  You should have received a copy of the GNU Affero General Public License
-  along with this code.  If not, see <http://www.gnu.org/licenses/>.
- 
-  As additional permission under GNU AGPL version 3 section 7, you
-  may distribute non-source (e.g., minimized or compacted) forms of
-  that code without the copy of the GNU GPL normally required by
-  section 4, provided you include this license notice and a URL
-  through which recipients can access the Corresponding Source.
- 
-  As a special exception to the AGPL, any HTML file which merely makes function
-  calls to this code, and for that purpose includes it by reference shall be
-  deemed a separate work for copyright law purposes. In addition, the copyright
-  holders of this code give you permission to combine this code with free
-  software libraries that are released under the GNU LGPL. You may copy and
-  distribute such a system following the terms of the GNU AGPL for this code
-  and the LGPL for the libraries. If you modify this code, you may extend this
-  exception to your version of the code, but you are not obligated to do so.
-  If you do not wish to do so, delete this exception statement from your
-  version.
- 
-  This license applies to this entire compilation.
-  @licend
-  @source: http://www.webodf.org/
-  @source: https://github.com/kogmbh/WebODF/
- */
- runtime.loadClass("odf.Namespaces");
- runtime.loadClass("xmldom.LSSerializer");
- runtime.loadClass("odf.OdfNodeFilter");
- runtime.loadClass("odf.TextSerializer");
- gui.Clipboard = function Clipboard() {
-   var xmlSerializer, textSerializer, filter;
-   this.setDataFromRange = function(e, range) {
-     var result = true, setDataResult, clipboard = e.clipboardData, window = runtime.getWindow(), document = range.startContainer.ownerDocument, fragmentContainer;
-     if(!clipboard && window) {
-       clipboard = window.clipboardData
-     }
-     if(clipboard) {
-       fragmentContainer = document.createElement("span");
-       fragmentContainer.appendChild(range.cloneContents());
-       setDataResult = clipboard.setData("text/plain", textSerializer.writeToString(fragmentContainer));
-       result = result && setDataResult;
-       setDataResult = clipboard.setData("text/html", xmlSerializer.writeToString(fragmentContainer, odf.Namespaces.namespaceMap));
-       result = result && setDataResult;
-       e.preventDefault()
++  function hexToRgb(hex) {
++    var result, shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
++    hex = hex.replace(shorthandRegex, matchToRgb);
++    result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
++    return result ? {r:parseInt(result[1], 16), g:parseInt(result[2], 16), b:parseInt(result[3], 16)} : null
++  }
++  function isNumber(n) {
++    return!isNaN(parseFloat(n))
++  }
++  function getGraphicProperties(props) {
++    var rule = "", alpha, bgcolor, fill;
++    rule += applySimpleMapping(props, graphicPropertySimpleMapping);
++    alpha = props.getAttributeNS(drawns, "opacity");
++    fill = props.getAttributeNS(drawns, "fill");
++    bgcolor = props.getAttributeNS(drawns, "fill-color");
++    if(fill === "solid" || fill === "hatch") {
++      if(bgcolor && bgcolor !== "none") {
++        alpha = isNumber(alpha) ? parseFloat(alpha) / 100 : 1;
++        bgcolor = hexToRgb(bgcolor);
++        if(bgcolor) {
++          rule += "background-color: rgba(" + bgcolor.r + "," + bgcolor.g + "," + bgcolor.b + "," + alpha + ");"
++        }
++      }else {
++        rule += "background: none;"
++      }
 +    }else {
-       result = false
++      if(fill === "none") {
++        rule += "background: none;"
++      }
 +    }
-     return result
-   };
-   function init() {
-     xmlSerializer = new xmldom.LSSerializer;
-     textSerializer = new odf.TextSerializer;
-     filter = new odf.OdfNodeFilter;
-     xmlSerializer.filter = filter;
-     textSerializer.filter = filter
++    return rule
 +  }
-   init()
- };
- /*
- 
-  Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
- 
-  @licstart
-  The JavaScript code in this page is free software: you can redistribute it
-  and/or modify it under the terms of the GNU Affero General Public License
-  (GNU AGPL) as published by the Free Software Foundation, either version 3 of
-  the License, or (at your option) any later version.  The code is distributed
-  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
- 
-  You should have received a copy of the GNU Affero General Public License
-  along with this code.  If not, see <http://www.gnu.org/licenses/>.
- 
-  As additional permission under GNU AGPL version 3 section 7, you
-  may distribute non-source (e.g., minimized or compacted) forms of
-  that code without the copy of the GNU GPL normally required by
-  section 4, provided you include this license notice and a URL
-  through which recipients can access the Corresponding Source.
- 
-  As a special exception to the AGPL, any HTML file which merely makes function
-  calls to this code, and for that purpose includes it by reference shall be
-  deemed a separate work for copyright law purposes. In addition, the copyright
-  holders of this code give you permission to combine this code with free
-  software libraries that are released under the GNU LGPL. You may copy and
-  distribute such a system following the terms of the GNU AGPL for this code
-  and the LGPL for the libraries. If you modify this code, you may extend this
-  exception to your version of the code, but you are not obligated to do so.
-  If you do not wish to do so, delete this exception statement from your
-  version.
- 
-  This license applies to this entire compilation.
-  @licend
-  @source: http://www.webodf.org/
-  @source: https://github.com/kogmbh/WebODF/
- */
- runtime.loadClass("core.Base64");
- runtime.loadClass("core.Zip");
- runtime.loadClass("core.DomUtils");
- runtime.loadClass("xmldom.LSSerializer");
- runtime.loadClass("odf.StyleInfo");
- runtime.loadClass("odf.Namespaces");
- runtime.loadClass("odf.OdfNodeFilter");
- (function() {
-   var styleInfo = new odf.StyleInfo, domUtils = new core.DomUtils, officens = "urn:oasis:names:tc:opendocument:xmlns:office:1.0", manifestns = "urn:oasis:names:tc:opendocument:xmlns:manifest:1.0", webodfns = "urn:webodf:names:scope", stylens = odf.Namespaces.stylens, nodeorder = ["meta", "settings", "scripts", "font-face-decls", "styles", "automatic-styles", "master-styles", "body"], automaticStylePrefix = (new Date).getTime() + "_webodf_", base64 = new core.Base64, documentStylesScope  [...]
-   documentContentScope = "document-content";
-   function getDirectChild(node, ns, name) {
-     node = node ? node.firstChild : null;
-     while(node) {
-       if(node.localName === name && node.namespaceURI === ns) {
-         return(node)
-       }
-       node = node.nextSibling
++  function getDrawingPageProperties(props) {
++    var rule = "";
++    rule += applySimpleMapping(props, graphicPropertySimpleMapping);
++    if(props.getAttributeNS(presentationns, "background-visible") === "true") {
++      rule += "background: none;"
 +    }
-     return null
++    return rule
 +  }
-   function getNodePosition(child) {
-     var i, l = nodeorder.length;
-     for(i = 0;i < l;i += 1) {
-       if(child.namespaceURI === officens && child.localName === nodeorder[i]) {
-         return i
++  function getTableCellProperties(props) {
++    var rule = "";
++    rule += applySimpleMapping(props, tablecellPropertySimpleMapping);
++    return rule
++  }
++  function getTableRowProperties(props) {
++    var rule = "";
++    rule += applySimpleMapping(props, tablerowPropertySimpleMapping);
++    return rule
++  }
++  function getTableColumnProperties(props) {
++    var rule = "";
++    rule += applySimpleMapping(props, tablecolumnPropertySimpleMapping);
++    return rule
++  }
++  function getTableProperties(props) {
++    var rule = "", borderModel;
++    rule += applySimpleMapping(props, tablePropertySimpleMapping);
++    borderModel = props.getAttributeNS(tablens, "border-model");
++    if(borderModel === "collapsing") {
++      rule += "border-collapse:collapse;"
++    }else {
++      if(borderModel === "separating") {
++        rule += "border-collapse:separate;"
 +      }
 +    }
-     return-1
++    return rule
 +  }
-   function OdfStylesFilter(styleUsingElementsRoot, automaticStyles) {
-     var usedStyleList = new styleInfo.UsedStyleList(styleUsingElementsRoot, automaticStyles), odfNodeFilter = new odf.OdfNodeFilter;
-     this.acceptNode = function(node) {
-       var result = odfNodeFilter.acceptNode(node);
-       if(result === NodeFilter.FILTER_ACCEPT && (node.parentNode === automaticStyles && node.nodeType === Node.ELEMENT_NODE)) {
-         if(usedStyleList.uses((node))) {
-           result = NodeFilter.FILTER_ACCEPT
-         }else {
-           result = NodeFilter.FILTER_REJECT
-         }
-       }
-       return result
++  function addStyleRule(sheet, family, name, node) {
++    var selectors = getSelectors(family, name, node), selector = selectors.join(","), rule = "", properties;
++    properties = domUtils.getDirectChild(node.element, stylens, "text-properties");
++    if(properties) {
++      rule += getTextProperties(properties)
++    }
++    properties = domUtils.getDirectChild(node.element, stylens, "paragraph-properties");
++    if(properties) {
++      rule += getParagraphProperties(properties)
++    }
++    properties = domUtils.getDirectChild(node.element, stylens, "graphic-properties");
++    if(properties) {
++      rule += getGraphicProperties(properties)
++    }
++    properties = domUtils.getDirectChild(node.element, stylens, "drawing-page-properties");
++    if(properties) {
++      rule += getDrawingPageProperties(properties)
++    }
++    properties = domUtils.getDirectChild(node.element, stylens, "table-cell-properties");
++    if(properties) {
++      rule += getTableCellProperties(properties)
++    }
++    properties = domUtils.getDirectChild(node.element, stylens, "table-row-properties");
++    if(properties) {
++      rule += getTableRowProperties(properties)
++    }
++    properties = domUtils.getDirectChild(node.element, stylens, "table-column-properties");
++    if(properties) {
++      rule += getTableColumnProperties(properties)
++    }
++    properties = domUtils.getDirectChild(node.element, stylens, "table-properties");
++    if(properties) {
++      rule += getTableProperties(properties)
++    }
++    if(rule.length === 0) {
++      return
++    }
++    rule = selector + "{" + rule + "}";
++    try {
++      sheet.insertRule(rule, sheet.cssRules.length)
++    }catch(e) {
++      throw e;
 +    }
 +  }
-   function OdfContentFilter(styleUsingElementsRoot, automaticStyles) {
-     var odfStylesFilter = new OdfStylesFilter(styleUsingElementsRoot, automaticStyles);
-     this.acceptNode = function(node) {
-       var result = odfStylesFilter.acceptNode(node);
-       if(result === NodeFilter.FILTER_ACCEPT && (node.parentNode && (node.parentNode.namespaceURI === odf.Namespaces.textns && (node.parentNode.localName === "s" || node.parentNode.localName === "tab")))) {
-         result = NodeFilter.FILTER_REJECT
++  function getNumberRule(node) {
++    var style = node.getAttributeNS(stylens, "num-format"), suffix = node.getAttributeNS(stylens, "num-suffix") || "", prefix = node.getAttributeNS(stylens, "num-prefix") || "", stylemap = {1:"decimal", "a":"lower-latin", "A":"upper-latin", "i":"lower-roman", "I":"upper-roman"}, content = "";
++    if(prefix) {
++      content += ' "' + prefix + '"'
++    }
++    if(stylemap.hasOwnProperty(style)) {
++      content += " counter(list, " + stylemap[style] + ")"
++    }else {
++      if(style) {
++        content += ' "' + style + '"'
++      }else {
++        content += " ''"
 +      }
-       return result
 +    }
++    return"content:" + content + ' "' + suffix + '"'
 +  }
-   function setChild(node, child) {
-     if(!child) {
-       return
++  function getImageRule() {
++    return"content: none;"
++  }
++  function getBulletRule(node) {
++    var bulletChar = node.getAttributeNS(textns, "bullet-char");
++    return"content: '" + bulletChar + "';"
++  }
++  function addListStyleRule(sheet, name, node, itemrule) {
++    var selector = 'text|list[text|style-name="' + name + '"]', level = node.getAttributeNS(textns, "level"), itemSelector, listItemRule, listLevelProps = domUtils.getDirectChild(node, stylens, "list-level-properties"), listLevelLabelAlign = domUtils.getDirectChild(listLevelProps, stylens, "list-level-label-alignment"), bulletIndent, listIndent, bulletWidth, rule;
++    if(listLevelLabelAlign) {
++      bulletIndent = listLevelLabelAlign.getAttributeNS(fons, "text-indent");
++      listIndent = listLevelLabelAlign.getAttributeNS(fons, "margin-left")
 +    }
-     var childpos = getNodePosition(child), pos, c = node.firstChild;
-     if(childpos === -1) {
-       return
++    if(!bulletIndent) {
++      bulletIndent = "-0.6cm"
 +    }
-     while(c) {
-       pos = getNodePosition(c);
-       if(pos !== -1 && pos > childpos) {
-         break
++    if(bulletIndent.charAt(0) === "-") {
++      bulletWidth = bulletIndent.substring(1)
++    }else {
++      bulletWidth = "-" + bulletIndent
++    }
++    level = level && parseInt(level, 10);
++    while(level > 1) {
++      selector += " > text|list-item > text|list";
++      level -= 1
++    }
++    if(listIndent) {
++      itemSelector = selector;
++      itemSelector += " > text|list-item > *:not(text|list):first-child";
++      listItemRule = itemSelector + "{";
++      listItemRule += "margin-left:" + listIndent + ";";
++      listItemRule += "}";
++      try {
++        sheet.insertRule(listItemRule, sheet.cssRules.length)
++      }catch(e1) {
++        runtime.log("cannot load rule: " + listItemRule)
 +      }
-       c = c.nextSibling
 +    }
-     node.insertBefore(child, c)
-   }
-   odf.ODFElement = function ODFElement() {
-   };
-   odf.ODFDocumentElement = function ODFDocumentElement() {
-   };
-   odf.ODFDocumentElement.prototype = new odf.ODFElement;
-   odf.ODFDocumentElement.prototype.constructor = odf.ODFDocumentElement;
-   odf.ODFDocumentElement.prototype.automaticStyles;
-   odf.ODFDocumentElement.prototype.body;
-   odf.ODFDocumentElement.prototype.fontFaceDecls = null;
-   odf.ODFDocumentElement.prototype.manifest = null;
-   odf.ODFDocumentElement.prototype.masterStyles;
-   odf.ODFDocumentElement.prototype.meta;
-   odf.ODFDocumentElement.prototype.settings = null;
-   odf.ODFDocumentElement.prototype.styles;
-   odf.ODFDocumentElement.namespaceURI = officens;
-   odf.ODFDocumentElement.localName = "document";
-   odf.OdfPart = function OdfPart(name, mimetype, container, zip) {
-     var self = this;
-     this.size = 0;
-     this.type = null;
-     this.name = name;
-     this.container = container;
-     this.url = null;
-     this.mimetype = mimetype;
-     this.document = null;
-     this.onstatereadychange = null;
-     this.onchange;
-     this.EMPTY = 0;
-     this.LOADING = 1;
-     this.DONE = 2;
-     this.state = this.EMPTY;
-     this.data = "";
-     this.load = function() {
-       if(zip === null) {
-         return
++    selector += " > text|list-item > *:not(text|list):first-child:before";
++    rule = selector + "{" + itemrule + ";";
++    rule += "counter-increment:list;";
++    rule += "margin-left:" + bulletIndent + ";";
++    rule += "width:" + bulletWidth + ";";
++    rule += "display:inline-block}";
++    try {
++      sheet.insertRule(rule, sheet.cssRules.length)
++    }catch(e2) {
++      runtime.log("cannot load rule: " + rule)
++    }
++  }
++  function addPageStyleRules(sheet, node) {
++    var rule = "", imageProps, url, contentLayoutRule = "", pageSizeRule = "", props = domUtils.getDirectChild(node, stylens, "page-layout-properties"), stylename, masterStyles, e, masterStyleName;
++    if(!props) {
++      return
++    }
++    stylename = node.getAttributeNS(stylens, "name");
++    rule += applySimpleMapping(props, pageContentPropertySimpleMapping);
++    imageProps = domUtils.getDirectChild(props, stylens, "background-image");
++    if(imageProps) {
++      url = imageProps.getAttributeNS(xlinkns, "href");
++      if(url) {
++        rule += "background-image: url('odfkit:" + url + "');";
++        rule += applySimpleMapping(imageProps, bgImageSimpleMapping)
 +      }
-       this.mimetype = mimetype;
-       zip.loadAsDataURL(name, mimetype, function(err, url) {
-         if(err) {
-           runtime.log(err)
-         }
-         self.url = url;
-         if(self.onchange) {
-           self.onchange(self)
++    }
++    if(documentType === "presentation") {
++      masterStyles = domUtils.getDirectChild((node.parentNode.parentNode), officens, "master-styles");
++      e = masterStyles && masterStyles.firstElementChild;
++      while(e) {
++        if(e.namespaceURI === stylens && (e.localName === "master-page" && e.getAttributeNS(stylens, "page-layout-name") === stylename)) {
++          masterStyleName = e.getAttributeNS(stylens, "name");
++          contentLayoutRule = "draw|page[draw|master-page-name=" + masterStyleName + "] {" + rule + "}";
++          pageSizeRule = "office|body, draw|page[draw|master-page-name=" + masterStyleName + "] {" + applySimpleMapping(props, pageSizePropertySimpleMapping) + " }";
++          try {
++            sheet.insertRule(contentLayoutRule, sheet.cssRules.length);
++            sheet.insertRule(pageSizeRule, sheet.cssRules.length)
++          }catch(e1) {
++            throw e1;
++          }
 +        }
-         if(self.onstatereadychange) {
-           self.onstatereadychange(self)
++        e = e.nextElementSibling
++      }
++    }else {
++      if(documentType === "text") {
++        contentLayoutRule = "office|text {" + rule + "}";
++        rule = "";
++        pageSizeRule = "office|body {" + "width: " + props.getAttributeNS(fons, "page-width") + ";" + "}";
++        try {
++          sheet.insertRule(contentLayoutRule, sheet.cssRules.length);
++          sheet.insertRule(pageSizeRule, sheet.cssRules.length)
++        }catch(e2) {
++          throw e2;
 +        }
-       })
-     }
-   };
-   odf.OdfPart.prototype.load = function() {
-   };
-   odf.OdfPart.prototype.getUrl = function() {
-     if(this.data) {
-       return"data:;base64," + base64.toBase64(this.data)
++      }
 +    }
-     return null
-   };
-   odf.OdfContainer = function OdfContainer(url, onstatereadychange) {
-     var self = this, zip, partMimetypes = {}, contentElement;
-     this.onstatereadychange = onstatereadychange;
-     this.onchange = null;
-     this.state = null;
-     this.rootElement;
-     function removeProcessingInstructions(element) {
-       var n = element.firstChild, next, e;
-       while(n) {
-         next = n.nextSibling;
-         if(n.nodeType === Node.ELEMENT_NODE) {
-           e = (n);
-           removeProcessingInstructions(e)
++  }
++  function addListStyleRules(sheet, name, node) {
++    var n = node.firstChild, e, itemrule;
++    while(n) {
++      if(n.namespaceURI === textns) {
++        e = (n);
++        if(n.localName === "list-level-style-number") {
++          itemrule = getNumberRule(e);
++          addListStyleRule(sheet, name, e, itemrule)
 +        }else {
-           if(n.nodeType === Node.PROCESSING_INSTRUCTION_NODE) {
-             element.removeChild(n)
++          if(n.localName === "list-level-style-image") {
++            itemrule = getImageRule();
++            addListStyleRule(sheet, name, e, itemrule)
++          }else {
++            if(n.localName === "list-level-style-bullet") {
++              itemrule = getBulletRule(e);
++              addListStyleRule(sheet, name, e, itemrule)
++            }
 +          }
 +        }
-         n = next
 +      }
++      n = n.nextSibling
 +    }
-     function setAutomaticStylesScope(stylesRootElement, scope) {
-       var n = stylesRootElement && stylesRootElement.firstChild;
-       while(n) {
-         if(n.nodeType === Node.ELEMENT_NODE) {
-           (n).setAttributeNS(webodfns, "scope", scope)
-         }
-         n = n.nextSibling
++  }
++  function addRule(sheet, family, name, node) {
++    if(family === "list") {
++      addListStyleRules(sheet, name, node.element)
++    }else {
++      if(family === "page") {
++        addPageStyleRules(sheet, node.element)
++      }else {
++        addStyleRule(sheet, family, name, node)
 +      }
 +    }
-     function getEnsuredMetaElement() {
-       var root = self.rootElement, meta = root.meta;
-       if(!meta) {
-         root.meta = meta = document.createElementNS(officens, "meta");
-         setChild(root, meta)
++  }
++  function addRules(sheet, family, name, node) {
++    addRule(sheet, family, name, node);
++    var n;
++    for(n in node.derivedStyles) {
++      if(node.derivedStyles.hasOwnProperty(n)) {
++        addRules(sheet, family, n, node.derivedStyles[n])
 +      }
-       return meta
 +    }
-     function getMetaData(metadataNs, metadataLocalName) {
-       var node = self.rootElement.meta, textNode;
-       node = node && node.firstChild;
-       while(node && (node.namespaceURI !== metadataNs || node.localName !== metadataLocalName)) {
-         node = node.nextSibling
-       }
-       node = node && node.firstChild;
-       while(node && node.nodeType !== Node.TEXT_NODE) {
-         node = node.nextSibling
-       }
-       if(node) {
-         textNode = (node);
-         return textNode.data
-       }
-       return null
++  }
++  this.style2css = function(doctype, stylesheet, fontFaceMap, styles, autostyles) {
++    var doc, styletree, tree, rule, name, family, stylenodes, styleautonodes;
++    while(stylesheet.cssRules.length) {
++      stylesheet.deleteRule(stylesheet.cssRules.length - 1)
 +    }
-     function unusedKey(key, map1, map2) {
-       var i = 0, postFixedKey;
-       key = key.replace(/\d+$/, "");
-       postFixedKey = key;
-       while(map1.hasOwnProperty(postFixedKey) || map2.hasOwnProperty(postFixedKey)) {
-         i += 1;
-         postFixedKey = key + i
-       }
-       return postFixedKey
++    doc = null;
++    if(styles) {
++      doc = styles.ownerDocument;
++      odfRoot = styles.parentNode
 +    }
-     function mapByFontFaceName(fontFaceDecls) {
-       var fn, result = {}, fontname;
-       fn = fontFaceDecls.firstChild;
-       while(fn) {
-         if(fn.nodeType === Node.ELEMENT_NODE && (fn.namespaceURI === stylens && fn.localName === "font-face")) {
-           fontname = (fn).getAttributeNS(stylens, "name");
-           result[fontname] = fn
-         }
-         fn = fn.nextSibling
-       }
-       return result
++    if(autostyles) {
++      doc = autostyles.ownerDocument;
++      odfRoot = autostyles.parentNode
 +    }
-     function mergeFontFaceDecls(targetFontFaceDeclsRootElement, sourceFontFaceDeclsRootElement) {
-       var e, s, fontFaceName, newFontFaceName, targetFontFaceDeclsMap, sourceFontFaceDeclsMap, fontFaceNameChangeMap = {};
-       targetFontFaceDeclsMap = mapByFontFaceName(targetFontFaceDeclsRootElement);
-       sourceFontFaceDeclsMap = mapByFontFaceName(sourceFontFaceDeclsRootElement);
-       e = sourceFontFaceDeclsRootElement.firstElementChild;
-       while(e) {
-         s = e.nextElementSibling;
-         if(e.namespaceURI === stylens && e.localName === "font-face") {
-           fontFaceName = e.getAttributeNS(stylens, "name");
-           if(targetFontFaceDeclsMap.hasOwnProperty(fontFaceName)) {
-             if(!e.isEqualNode(targetFontFaceDeclsMap[fontFaceName])) {
-               newFontFaceName = unusedKey(fontFaceName, targetFontFaceDeclsMap, sourceFontFaceDeclsMap);
-               e.setAttributeNS(stylens, "style:name", newFontFaceName);
-               targetFontFaceDeclsRootElement.appendChild(e);
-               targetFontFaceDeclsMap[newFontFaceName] = e;
-               delete sourceFontFaceDeclsMap[fontFaceName];
-               fontFaceNameChangeMap[fontFaceName] = newFontFaceName
-             }
-           }else {
-             targetFontFaceDeclsRootElement.appendChild(e);
-             targetFontFaceDeclsMap[fontFaceName] = e;
-             delete sourceFontFaceDeclsMap[fontFaceName]
++    if(!doc) {
++      return
++    }
++    odf.Namespaces.forEachPrefix(function(prefix, ns) {
++      rule = "@namespace " + prefix + " url(" + ns + ");";
++      try {
++        stylesheet.insertRule(rule, stylesheet.cssRules.length)
++      }catch(ignore) {
++      }
++    });
++    fontFaceDeclsMap = fontFaceMap;
++    documentType = doctype;
++    defaultFontSize = runtime.getWindow().getComputedStyle(document.body, null).getPropertyValue("font-size") || "12pt";
++    stylenodes = getStyleMap(styles);
++    styleautonodes = getStyleMap(autostyles);
++    styletree = {};
++    for(family in familynamespaceprefixes) {
++      if(familynamespaceprefixes.hasOwnProperty(family)) {
++        tree = styletree[family] = {};
++        addStyleMapToStyleTree(stylenodes[family], tree);
++        addStyleMapToStyleTree(styleautonodes[family], tree);
++        for(name in tree) {
++          if(tree.hasOwnProperty(name)) {
++            addRules(stylesheet, family, name, tree[name])
 +          }
 +        }
-         e = s
 +      }
-       return fontFaceNameChangeMap
 +    }
-     function cloneStylesInScope(stylesRootElement, scope) {
-       var copy = null, e, s, scopeAttrValue;
-       if(stylesRootElement) {
-         copy = stylesRootElement.cloneNode(true);
-         e = copy.firstElementChild;
-         while(e) {
-           s = e.nextElementSibling;
-           scopeAttrValue = e.getAttributeNS(webodfns, "scope");
-           if(scopeAttrValue && scopeAttrValue !== scope) {
-             copy.removeChild(e)
-           }
-           e = s
-         }
-       }
-       return copy
-     }
-     function cloneFontFaceDeclsUsedInStyles(fontFaceDeclsRootElement, stylesRootElementList) {
-       var e, nextSibling, fontFaceName, copy = null, usedFontFaceDeclMap = {};
-       if(fontFaceDeclsRootElement) {
-         stylesRootElementList.forEach(function(stylesRootElement) {
-           styleInfo.collectUsedFontFaces(usedFontFaceDeclMap, stylesRootElement)
-         });
-         copy = fontFaceDeclsRootElement.cloneNode(true);
-         e = copy.firstElementChild;
-         while(e) {
-           nextSibling = e.nextElementSibling;
-           fontFaceName = e.getAttributeNS(stylens, "name");
-           if(!usedFontFaceDeclMap[fontFaceName]) {
-             copy.removeChild(e)
-           }
-           e = nextSibling
-         }
-       }
-       return copy
++  }
++};
++/*
++
++ Copyright (C) 2014 KO GmbH <copyright at kogmbh.com>
++
++ @licstart
++ This file is part of WebODF.
++
++ WebODF is free software: you can redistribute it and/or modify it
++ under the terms of the GNU Affero General Public License (GNU AGPL)
++ as published by the Free Software Foundation, either version 3 of
++ the License, or (at your option) any later version.
++
++ WebODF is distributed in the hope that it will be useful, but
++ WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ GNU Affero General Public License for more details.
++
++ You should have received a copy of the GNU Affero General Public License
++ along with WebODF.  If not, see <http://www.gnu.org/licenses/>.
++ @licend
++
++ @source: http://www.webodf.org/
++ @source: https://github.com/kogmbh/WebODF/
++*/
++(function() {
++  function Point(x, y) {
++    var self = this;
++    this.getDistance = function(point) {
++      var xOffset = self.x - point.x, yOffset = self.y - point.y;
++      return Math.sqrt(xOffset * xOffset + yOffset * yOffset)
++    };
++    this.getCenter = function(point) {
++      return new Point((self.x + point.x) / 2, (self.y + point.y) / 2)
++    };
++    this.x;
++    this.y;
++    function init() {
++      self.x = x;
++      self.y = y
 +    }
-     function importRootNode(xmldoc) {
-       var doc = self.rootElement.ownerDocument, node;
-       if(xmldoc) {
-         removeProcessingInstructions(xmldoc.documentElement);
-         try {
-           node = doc.importNode(xmldoc.documentElement, true)
-         }catch(ignore) {
-         }
++    init()
++  }
++  gui.ZoomHelper = function() {
++    var zoomableElement, panPoint, previousPanPoint, firstPinchDistance, zoom, previousZoom, maxZoom = 4, offsetParent, events = new core.EventNotifier([gui.ZoomHelper.signalZoomChanged]), gestures = {NONE:0, SCROLL:1, PINCH:2}, currentGesture = gestures.NONE, requiresCustomScrollBars = runtime.getWindow().hasOwnProperty("ontouchstart");
++    function applyCSSTransform(x, y, scale, is3D) {
++      var transformCommand;
++      if(is3D) {
++        transformCommand = "translate3d(" + x + "px, " + y + "px, 0) scale3d(" + scale + ", " + scale + ", 1)"
++      }else {
++        transformCommand = "translate(" + x + "px, " + y + "px) scale(" + scale + ")"
 +      }
-       return node
++      zoomableElement.style.WebkitTransform = transformCommand;
++      zoomableElement.style.MozTransform = transformCommand;
++      zoomableElement.style.msTransform = transformCommand;
++      zoomableElement.style.OTransform = transformCommand;
++      zoomableElement.style.transform = transformCommand
 +    }
-     function setState(state) {
-       self.state = state;
-       if(self.onchange) {
-         self.onchange(self)
-       }
-       if(self.onstatereadychange) {
-         self.onstatereadychange(self)
++    function applyTransform(is3D) {
++      if(is3D) {
++        applyCSSTransform(-panPoint.x, -panPoint.y, zoom, true)
++      }else {
++        applyCSSTransform(0, 0, zoom, true);
++        applyCSSTransform(0, 0, zoom, false)
 +      }
 +    }
-     function setRootElement(root) {
-       contentElement = null;
-       self.rootElement = (root);
-       root.fontFaceDecls = getDirectChild(root, officens, "font-face-decls");
-       root.styles = getDirectChild(root, officens, "styles");
-       root.automaticStyles = getDirectChild(root, officens, "automatic-styles");
-       root.masterStyles = getDirectChild(root, officens, "master-styles");
-       root.body = getDirectChild(root, officens, "body");
-       root.meta = getDirectChild(root, officens, "meta")
++    function applyFastTransform() {
++      applyTransform(true)
 +    }
-     function handleFlatXml(xmldoc) {
-       var root = importRootNode(xmldoc);
-       if(!root || (root.localName !== "document" || root.namespaceURI !== officens)) {
-         setState(OdfContainer.INVALID);
-         return
-       }
-       setRootElement((root));
-       setState(OdfContainer.DONE)
++    function applyDetailedTransform() {
++      applyTransform(false)
 +    }
-     function handleStylesXml(xmldoc) {
-       var node = importRootNode(xmldoc), root = self.rootElement, n;
-       if(!node || (node.localName !== "document-styles" || node.namespaceURI !== officens)) {
-         setState(OdfContainer.INVALID);
++    function enableScrollBars(enable) {
++      if(!offsetParent || !requiresCustomScrollBars) {
 +        return
 +      }
-       root.fontFaceDecls = getDirectChild(node, officens, "font-face-decls");
-       setChild(root, root.fontFaceDecls);
-       n = getDirectChild(node, officens, "styles");
-       root.styles = n || xmldoc.createElementNS(officens, "styles");
-       setChild(root, root.styles);
-       n = getDirectChild(node, officens, "automatic-styles");
-       root.automaticStyles = n || xmldoc.createElementNS(officens, "automatic-styles");
-       setAutomaticStylesScope(root.automaticStyles, documentStylesScope);
-       setChild(root, root.automaticStyles);
-       node = getDirectChild(node, officens, "master-styles");
-       root.masterStyles = node || xmldoc.createElementNS(officens, "master-styles");
-       setChild(root, root.masterStyles);
-       styleInfo.prefixStyleNames(root.automaticStyles, automaticStylePrefix, root.masterStyles)
-     }
-     function handleContentXml(xmldoc) {
-       var node = importRootNode(xmldoc), root, automaticStyles, fontFaceDecls, fontFaceNameChangeMap, c;
-       if(!node || (node.localName !== "document-content" || node.namespaceURI !== officens)) {
-         setState(OdfContainer.INVALID);
++      var initialOverflow = offsetParent.style.overflow, enabled = offsetParent.classList.contains("customScrollbars");
++      if(enable && enabled || !enable && !enabled) {
 +        return
 +      }
-       root = self.rootElement;
-       fontFaceDecls = getDirectChild(node, officens, "font-face-decls");
-       if(root.fontFaceDecls && fontFaceDecls) {
-         fontFaceNameChangeMap = mergeFontFaceDecls(root.fontFaceDecls, fontFaceDecls)
++      if(enable) {
++        offsetParent.classList.add("customScrollbars");
++        offsetParent.style.overflow = "hidden";
++        runtime.requestAnimationFrame(function() {
++          offsetParent.style.overflow = initialOverflow
++        })
 +      }else {
-         if(fontFaceDecls) {
-           root.fontFaceDecls = fontFaceDecls;
-           setChild(root, fontFaceDecls)
-         }
-       }
-       automaticStyles = getDirectChild(node, officens, "automatic-styles");
-       setAutomaticStylesScope(automaticStyles, documentContentScope);
-       if(fontFaceNameChangeMap) {
-         styleInfo.changeFontFaceNames(automaticStyles, fontFaceNameChangeMap)
-       }
-       if(root.automaticStyles && automaticStyles) {
-         c = automaticStyles.firstChild;
-         while(c) {
-           root.automaticStyles.appendChild(c);
-           c = automaticStyles.firstChild
-         }
++        offsetParent.classList.remove("customScrollbars")
++      }
++    }
++    function removeScroll() {
++      applyCSSTransform(-panPoint.x, -panPoint.y, zoom, true);
++      offsetParent.scrollLeft = 0;
++      offsetParent.scrollTop = 0;
++      enableScrollBars(false)
++    }
++    function restoreScroll() {
++      applyCSSTransform(0, 0, zoom, true);
++      offsetParent.scrollLeft = panPoint.x;
++      offsetParent.scrollTop = panPoint.y;
++      enableScrollBars(true)
++    }
++    function getPoint(touch) {
++      return new Point(touch.pageX - zoomableElement.offsetLeft, touch.pageY - zoomableElement.offsetTop)
++    }
++    function sanitizePointForPan(point) {
++      return new Point(Math.min(Math.max(point.x, zoomableElement.offsetLeft), (zoomableElement.offsetLeft + zoomableElement.offsetWidth) * zoom - offsetParent.clientWidth), Math.min(Math.max(point.y, zoomableElement.offsetTop), (zoomableElement.offsetTop + zoomableElement.offsetHeight) * zoom - offsetParent.clientHeight))
++    }
++    function processPan(point) {
++      if(previousPanPoint) {
++        panPoint.x -= point.x - previousPanPoint.x;
++        panPoint.y -= point.y - previousPanPoint.y;
++        panPoint = sanitizePointForPan(panPoint)
++      }
++      previousPanPoint = point
++    }
++    function processZoom(zoomPoint, incrementalZoom) {
++      var originalZoom = zoom, actuallyIncrementedZoom, minZoom = Math.min(maxZoom, zoomableElement.offsetParent.clientWidth / zoomableElement.offsetWidth);
++      zoom = previousZoom * incrementalZoom;
++      zoom = Math.min(Math.max(zoom, minZoom), maxZoom);
++      actuallyIncrementedZoom = zoom / originalZoom;
++      panPoint.x += (actuallyIncrementedZoom - 1) * (zoomPoint.x + panPoint.x);
++      panPoint.y += (actuallyIncrementedZoom - 1) * (zoomPoint.y + panPoint.y)
++    }
++    function processPinch(point1, point2) {
++      var zoomPoint = point1.getCenter(point2), pinchDistance = point1.getDistance(point2), incrementalZoom = pinchDistance / firstPinchDistance;
++      processPan(zoomPoint);
++      processZoom(zoomPoint, incrementalZoom)
++    }
++    function prepareGesture(event) {
++      var fingers = event.touches.length, point1 = fingers > 0 ? getPoint(event.touches[0]) : null, point2 = fingers > 1 ? getPoint(event.touches[1]) : null;
++      if(point1 && point2) {
++        firstPinchDistance = point1.getDistance(point2);
++        previousZoom = zoom;
++        previousPanPoint = point1.getCenter(point2);
++        removeScroll();
++        currentGesture = gestures.PINCH
 +      }else {
-         if(automaticStyles) {
-           root.automaticStyles = automaticStyles;
-           setChild(root, automaticStyles)
++        if(point1) {
++          previousPanPoint = point1;
++          currentGesture = gestures.SCROLL
 +        }
 +      }
-       node = getDirectChild(node, officens, "body");
-       if(node === null) {
-         throw"<office:body/> tag is mising.";
-       }
-       root.body = node;
-       setChild(root, root.body)
-     }
-     function handleMetaXml(xmldoc) {
-       var node = importRootNode(xmldoc), root;
-       if(!node || (node.localName !== "document-meta" || node.namespaceURI !== officens)) {
-         return
-       }
-       root = self.rootElement;
-       root.meta = getDirectChild(node, officens, "meta");
-       setChild(root, root.meta)
-     }
-     function handleSettingsXml(xmldoc) {
-       var node = importRootNode(xmldoc), root;
-       if(!node || (node.localName !== "document-settings" || node.namespaceURI !== officens)) {
-         return
-       }
-       root = self.rootElement;
-       root.settings = getDirectChild(node, officens, "settings");
-       setChild(root, root.settings)
 +    }
-     function handleManifestXml(xmldoc) {
-       var node = importRootNode(xmldoc), root, e;
-       if(!node || (node.localName !== "manifest" || node.namespaceURI !== manifestns)) {
-         return
-       }
-       root = self.rootElement;
-       root.manifest = (node);
-       e = root.manifest.firstElementChild;
-       while(e) {
-         if(e.localName === "file-entry" && e.namespaceURI === manifestns) {
-           partMimetypes[e.getAttributeNS(manifestns, "full-path")] = e.getAttributeNS(manifestns, "media-type")
++    function processGesture(event) {
++      var fingers = event.touches.length, point1 = fingers > 0 ? getPoint(event.touches[0]) : null, point2 = fingers > 1 ? getPoint(event.touches[1]) : null;
++      if(point1 && point2) {
++        event.preventDefault();
++        if(currentGesture === gestures.SCROLL) {
++          currentGesture = gestures.PINCH;
++          removeScroll();
++          firstPinchDistance = point1.getDistance(point2);
++          return
 +        }
-         e = e.nextElementSibling
-       }
-     }
-     function loadNextComponent(remainingComponents) {
-       var component = remainingComponents.shift();
-       if(component) {
-         zip.loadAsDOM(component.path, function(err, xmldoc) {
-           component.handler(xmldoc);
-           if(err || self.state === OdfContainer.INVALID) {
++        processPinch(point1, point2);
++        applyFastTransform()
++      }else {
++        if(point1) {
++          if(currentGesture === gestures.PINCH) {
++            currentGesture = gestures.SCROLL;
++            restoreScroll();
 +            return
 +          }
-           loadNextComponent(remainingComponents)
-         })
-       }else {
-         setState(OdfContainer.DONE)
++          processPan(point1)
++        }
 +      }
 +    }
-     function loadComponents() {
-       var componentOrder = [{path:"styles.xml", handler:handleStylesXml}, {path:"content.xml", handler:handleContentXml}, {path:"meta.xml", handler:handleMetaXml}, {path:"settings.xml", handler:handleSettingsXml}, {path:"META-INF/manifest.xml", handler:handleManifestXml}];
-       loadNextComponent(componentOrder)
-     }
-     function createDocumentElement(name) {
-       var s = "";
-       function defineNamespace(prefix, ns) {
-         s += " xmlns:" + prefix + '="' + ns + '"'
++    function sanitizeGesture() {
++      if(currentGesture === gestures.PINCH) {
++        events.emit(gui.ZoomHelper.signalZoomChanged, zoom);
++        restoreScroll();
++        applyDetailedTransform()
 +      }
-       odf.Namespaces.forEachPrefix(defineNamespace);
-       return'<?xml version="1.0" encoding="UTF-8"?><office:' + name + " " + s + ' office:version="1.2">'
++      currentGesture = gestures.NONE
 +    }
-     function serializeMetaXml() {
-       var serializer = new xmldom.LSSerializer, s = createDocumentElement("document-meta");
-       serializer.filter = new odf.OdfNodeFilter;
-       s += serializer.writeToString(self.rootElement.meta, odf.Namespaces.namespaceMap);
-       s += "</office:document-meta>";
-       return s
-     }
-     function createManifestEntry(fullPath, mediaType) {
-       var element = document.createElementNS(manifestns, "manifest:file-entry");
-       element.setAttributeNS(manifestns, "manifest:full-path", fullPath);
-       element.setAttributeNS(manifestns, "manifest:media-type", mediaType);
-       return element
-     }
-     function serializeManifestXml() {
-       var header = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n', xml = '<manifest:manifest xmlns:manifest="' + manifestns + '" manifest:version="1.2"></manifest:manifest>', manifest = (runtime.parseXML(xml)), manifestRoot = getDirectChild(manifest, manifestns, "manifest"), serializer = new xmldom.LSSerializer, fullPath;
-       for(fullPath in partMimetypes) {
-         if(partMimetypes.hasOwnProperty(fullPath)) {
-           manifestRoot.appendChild(createManifestEntry(fullPath, partMimetypes[fullPath]))
-         }
++    this.subscribe = function(eventid, cb) {
++      events.subscribe(eventid, cb)
++    };
++    this.unsubscribe = function(eventid, cb) {
++      events.unsubscribe(eventid, cb)
++    };
++    this.getZoomLevel = function() {
++      return zoom
++    };
++    this.setZoomLevel = function(zoomLevel) {
++      if(zoomableElement) {
++        zoom = zoomLevel;
++        applyDetailedTransform();
++        events.emit(gui.ZoomHelper.signalZoomChanged, zoom)
++      }
++    };
++    function registerGestureListeners() {
++      if(offsetParent) {
++        offsetParent.addEventListener("touchstart", (prepareGesture), false);
++        offsetParent.addEventListener("touchmove", (processGesture), false);
++        offsetParent.addEventListener("touchend", (sanitizeGesture), false)
 +      }
-       serializer.filter = new odf.OdfNodeFilter;
-       return header + serializer.writeToString(manifest, odf.Namespaces.namespaceMap)
-     }
-     function serializeSettingsXml() {
-       var serializer = new xmldom.LSSerializer, s = createDocumentElement("document-settings");
-       serializer.filter = new odf.OdfNodeFilter;
-       s += serializer.writeToString(self.rootElement.settings, odf.Namespaces.namespaceMap);
-       s += "</office:document-settings>";
-       return s
-     }
-     function serializeStylesXml() {
-       var fontFaceDecls, automaticStyles, masterStyles, nsmap = odf.Namespaces.namespaceMap, serializer = new xmldom.LSSerializer, s = createDocumentElement("document-styles");
-       automaticStyles = cloneStylesInScope(self.rootElement.automaticStyles, documentStylesScope);
-       masterStyles = (self.rootElement.masterStyles.cloneNode(true));
-       fontFaceDecls = cloneFontFaceDeclsUsedInStyles(self.rootElement.fontFaceDecls, [masterStyles, self.rootElement.styles, automaticStyles]);
-       styleInfo.removePrefixFromStyleNames(automaticStyles, automaticStylePrefix, masterStyles);
-       serializer.filter = new OdfStylesFilter(masterStyles, automaticStyles);
-       s += serializer.writeToString(fontFaceDecls, nsmap);
-       s += serializer.writeToString(self.rootElement.styles, nsmap);
-       s += serializer.writeToString(automaticStyles, nsmap);
-       s += serializer.writeToString(masterStyles, nsmap);
-       s += "</office:document-styles>";
-       return s
-     }
-     function serializeContentXml() {
-       var fontFaceDecls, automaticStyles, nsmap = odf.Namespaces.namespaceMap, serializer = new xmldom.LSSerializer, s = createDocumentElement("document-content");
-       automaticStyles = cloneStylesInScope(self.rootElement.automaticStyles, documentContentScope);
-       fontFaceDecls = cloneFontFaceDeclsUsedInStyles(self.rootElement.fontFaceDecls, [automaticStyles]);
-       serializer.filter = new OdfContentFilter(self.rootElement.body, automaticStyles);
-       s += serializer.writeToString(fontFaceDecls, nsmap);
-       s += serializer.writeToString(automaticStyles, nsmap);
-       s += serializer.writeToString(self.rootElement.body, nsmap);
-       s += "</office:document-content>";
-       return s
 +    }
-     function createElement(type) {
-       var original = document.createElementNS(type.namespaceURI, type.localName), method, iface = new type.Type;
-       for(method in iface) {
-         if(iface.hasOwnProperty(method)) {
-           original[method] = iface[method]
-         }
++    function unregisterGestureListeners() {
++      if(offsetParent) {
++        offsetParent.removeEventListener("touchstart", (prepareGesture), false);
++        offsetParent.removeEventListener("touchmove", (processGesture), false);
++        offsetParent.removeEventListener("touchend", (sanitizeGesture), false)
 +      }
-       return original
 +    }
-     function loadFromXML(url, callback) {
-       runtime.loadXML(url, function(err, dom) {
-         if(err) {
-           callback(err)
-         }else {
-           handleFlatXml(dom)
-         }
-       })
-     }
-     this.setRootElement = setRootElement;
-     this.getContentElement = function() {
-       var body;
-       if(!contentElement) {
-         body = self.rootElement.body;
-         contentElement = getDirectChild(body, officens, "text") || (getDirectChild(body, officens, "presentation") || getDirectChild(body, officens, "spreadsheet"))
-       }
-       if(!contentElement) {
-         throw"Could not find content element in <office:body/>.";
-       }
-       return contentElement
-     };
-     this.getDocumentType = function() {
-       var content = self.getContentElement();
-       return content && content.localName
-     };
-     this.getPart = function(partname) {
-       return new odf.OdfPart(partname, partMimetypes[partname], self, zip)
-     };
-     this.getPartData = function(url, callback) {
-       zip.load(url, callback)
-     };
-     function setMetadata(setProperties, removedPropertyNames) {
-       var metaElement = getEnsuredMetaElement();
-       if(setProperties) {
-         domUtils.mapKeyValObjOntoNode(metaElement, setProperties, odf.Namespaces.lookupNamespaceURI)
-       }
-       if(removedPropertyNames) {
-         domUtils.removeKeyElementsFromNode(metaElement, removedPropertyNames, odf.Namespaces.lookupNamespaceURI)
-       }
-     }
-     this.setMetadata = setMetadata;
-     this.incrementEditingCycles = function() {
-       var currentValueString = getMetaData(odf.Namespaces.metans, "editing-cycles"), currentCycles = currentValueString ? parseInt(currentValueString, 10) : 0;
-       if(isNaN(currentCycles)) {
-         currentCycles = 0
-       }
-       setMetadata({"meta:editing-cycles":currentCycles + 1}, null)
-     };
-     function updateMetadataForSaving() {
-       var generatorString, window = runtime.getWindow();
-       generatorString = "WebODF/" + (String(typeof webodf_version) !== "undefined" ? webodf_version : "FromSource");
-       if(window) {
-         generatorString = generatorString + " " + window.navigator.userAgent
-       }
-       setMetadata({"meta:generator":generatorString}, null)
-     }
-     function createEmptyTextDocument() {
-       var emptyzip = new core.Zip("", null), data = runtime.byteArrayFromString("application/vnd.oasis.opendocument.text", "utf8"), root = self.rootElement, text = document.createElementNS(officens, "text");
-       emptyzip.save("mimetype", data, false, new Date);
-       function addToplevelElement(memberName, realLocalName) {
-         var element;
-         if(!realLocalName) {
-           realLocalName = memberName
-         }
-         element = document.createElementNS(officens, realLocalName);
-         root[memberName] = element;
-         root.appendChild(element)
-       }
-       addToplevelElement("meta");
-       addToplevelElement("settings");
-       addToplevelElement("scripts");
-       addToplevelElement("fontFaceDecls", "font-face-decls");
-       addToplevelElement("styles");
-       addToplevelElement("automaticStyles", "automatic-styles");
-       addToplevelElement("masterStyles", "master-styles");
-       addToplevelElement("body");
-       root.body.appendChild(text);
-       setState(OdfContainer.DONE);
-       return emptyzip
-     }
-     function fillZip() {
-       var data, date = new Date;
-       updateMetadataForSaving();
-       data = runtime.byteArrayFromString(serializeSettingsXml(), "utf8");
-       zip.save("settings.xml", data, true, date);
-       data = runtime.byteArrayFromString(serializeMetaXml(), "utf8");
-       zip.save("meta.xml", data, true, date);
-       data = runtime.byteArrayFromString(serializeStylesXml(), "utf8");
-       zip.save("styles.xml", data, true, date);
-       data = runtime.byteArrayFromString(serializeContentXml(), "utf8");
-       zip.save("content.xml", data, true, date);
-       data = runtime.byteArrayFromString(serializeManifestXml(), "utf8");
-       zip.save("META-INF/manifest.xml", data, true, date)
-     }
-     function createByteArray(successCallback, errorCallback) {
-       fillZip();
-       zip.createByteArray(successCallback, errorCallback)
-     }
-     this.createByteArray = createByteArray;
-     function saveAs(newurl, callback) {
-       fillZip();
-       zip.writeAs(newurl, function(err) {
-         callback(err)
-       })
-     }
-     this.saveAs = saveAs;
-     this.save = function(callback) {
-       saveAs(url, callback)
-     };
-     this.getUrl = function() {
-       return url
-     };
-     this.setBlob = function(filename, mimetype, content) {
-       var data = base64.convertBase64ToByteArray(content), date = new Date;
-       zip.save(filename, data, false, date);
-       if(partMimetypes.hasOwnProperty(filename)) {
-         runtime.log(filename + " has been overwritten.")
-       }
-       partMimetypes[filename] = mimetype
++    this.destroy = function(callback) {
++      unregisterGestureListeners();
++      enableScrollBars(false);
++      callback()
 +    };
-     this.removeBlob = function(filename) {
-       var foundAndRemoved = zip.remove(filename);
-       runtime.assert(foundAndRemoved, "file is not found: " + filename);
-       delete partMimetypes[filename]
++    this.setZoomableElement = function(element) {
++      unregisterGestureListeners();
++      zoomableElement = element;
++      offsetParent = (zoomableElement.offsetParent);
++      applyDetailedTransform();
++      registerGestureListeners();
++      enableScrollBars(true)
 +    };
-     this.state = OdfContainer.LOADING;
-     this.rootElement = (createElement({Type:odf.ODFDocumentElement, namespaceURI:odf.ODFDocumentElement.namespaceURI, localName:odf.ODFDocumentElement.localName}));
-     if(url) {
-       zip = new core.Zip(url, function(err, zipobject) {
-         zip = zipobject;
-         if(err) {
-           loadFromXML(url, function(xmlerr) {
-             if(err) {
-               zip.error = err + "\n" + xmlerr;
-               setState(OdfContainer.INVALID)
-             }
-           })
-         }else {
-           loadComponents()
-         }
-       })
-     }else {
-       zip = createEmptyTextDocument()
++    function init() {
++      zoom = 1;
++      previousZoom = 1;
++      panPoint = new Point(0, 0)
 +    }
++    init()
 +  };
-   odf.OdfContainer.EMPTY = 0;
-   odf.OdfContainer.LOADING = 1;
-   odf.OdfContainer.DONE = 2;
-   odf.OdfContainer.INVALID = 3;
-   odf.OdfContainer.SAVING = 4;
-   odf.OdfContainer.MODIFIED = 5;
-   odf.OdfContainer.getContainer = function(url) {
-     return new odf.OdfContainer(url, null)
-   };
-   return odf.OdfContainer
++  gui.ZoomHelper.signalZoomChanged = "zoomChanged"
 +})();
 +/*
 +
 + Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("core.Base64");
- runtime.loadClass("xmldom.XPath");
- runtime.loadClass("odf.OdfContainer");
- (function() {
-   var xpath = xmldom.XPath, base64 = new core.Base64;
-   function getEmbeddedFontDeclarations(fontFaceDecls) {
-     var decls = {}, fonts, i, font, name, uris, href, family;
-     if(!fontFaceDecls) {
-       return decls
-     }
-     fonts = xpath.getODFElementsWithXPath(fontFaceDecls, "style:font-face[svg:font-face-src]", odf.Namespaces.lookupNamespaceURI);
-     for(i = 0;i < fonts.length;i += 1) {
-       font = fonts[i];
-       name = font.getAttributeNS(odf.Namespaces.stylens, "name");
-       family = font.getAttributeNS(odf.Namespaces.svgns, "font-family");
-       uris = xpath.getODFElementsWithXPath(font, "svg:font-face-src/svg:font-face-uri", odf.Namespaces.lookupNamespaceURI);
-       if(uris.length > 0) {
-         href = uris[0].getAttributeNS(odf.Namespaces.xlinkns, "href");
-         decls[name] = {href:href, family:family}
-       }
-     }
-     return decls
-   }
-   function addFontToCSS(name, font, fontdata, stylesheet) {
-     var cssFamily = font.family || name, rule = "@font-face { font-family: '" + cssFamily + "'; src: " + "url(data:application/x-font-ttf;charset=binary;base64," + base64.convertUTF8ArrayToBase64(fontdata) + ') format("truetype"); }';
-     try {
-       stylesheet.insertRule(rule, stylesheet.cssRules.length)
-     }catch(e) {
-       runtime.log("Problem inserting rule in CSS: " + runtime.toJson(e) + "\nRule: " + rule)
-     }
-   }
-   function loadFontIntoCSS(embeddedFontDeclarations, odfContainer, pos, stylesheet, callback) {
-     var name, i = 0, n;
-     for(n in embeddedFontDeclarations) {
-       if(embeddedFontDeclarations.hasOwnProperty(n)) {
-         if(i === pos) {
-           name = n;
-           break
-         }
-         i += 1
-       }
-     }
-     if(!name) {
-       if(callback) {
-         callback()
-       }
-       return
-     }
-     odfContainer.getPartData(embeddedFontDeclarations[name].href, function(err, fontdata) {
-       if(err) {
-         runtime.log(err)
-       }else {
-         if(!fontdata) {
-           runtime.log("missing font data for " + embeddedFontDeclarations[name].href)
-         }else {
-           addFontToCSS(name, embeddedFontDeclarations[name], fontdata, stylesheet)
-         }
-       }
-       loadFontIntoCSS(embeddedFontDeclarations, odfContainer, pos + 1, stylesheet, callback)
-     })
-   }
-   function loadFontsIntoCSS(embeddedFontDeclarations, odfContainer, stylesheet) {
-     loadFontIntoCSS(embeddedFontDeclarations, odfContainer, 0, stylesheet)
-   }
-   odf.FontLoader = function FontLoader() {
-     this.loadFonts = function(odfContainer, stylesheet) {
-       var embeddedFontDeclarations, fontFaceDecls = odfContainer.rootElement.fontFaceDecls;
-       while(stylesheet.cssRules.length) {
-         stylesheet.deleteRule(stylesheet.cssRules.length - 1)
-       }
-       if(fontFaceDecls) {
-         embeddedFontDeclarations = getEmbeddedFontDeclarations(fontFaceDecls);
-         loadFontsIntoCSS(embeddedFontDeclarations, odfContainer, stylesheet)
-       }
-     }
-   };
-   return odf.FontLoader
- })();
++ops.Canvas = function Canvas() {
++};
++ops.Canvas.prototype.getZoomLevel = function() {
++};
++ops.Canvas.prototype.getElement = function() {
++};
++ops.Canvas.prototype.getZoomHelper = function() {
++};
 +/*
 +
 + Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("core.DomUtils");
- runtime.loadClass("core.Utils");
- odf.ObjectNameGenerator = function ObjectNameGenerator(odfContainer, memberId) {
-   var stylens = odf.Namespaces.stylens, drawns = odf.Namespaces.drawns, xlinkns = odf.Namespaces.xlinkns, domUtils = new core.DomUtils, utils = new core.Utils, memberIdHash = utils.hashString(memberId), styleNameGenerator = null, frameNameGenerator = null, imageNameGenerator = null, existingFrameNames = {}, existingImageNames = {};
-   function NameGenerator(prefix, findExistingNames) {
-     var reportedNames = {};
-     this.generateName = function() {
-       var existingNames = findExistingNames(), startIndex = 0, name;
-       do {
-         name = prefix + startIndex;
-         startIndex += 1
-       }while(reportedNames[name] || existingNames[name]);
-       reportedNames[name] = true;
-       return name
-     }
-   }
-   function getAllStyleNames() {
-     var styleElements = [odfContainer.rootElement.automaticStyles, odfContainer.rootElement.styles], styleNames = {};
-     function getStyleNames(styleListElement) {
-       var e = styleListElement.firstElementChild;
-       while(e) {
-         if(e.namespaceURI === stylens && e.localName === "style") {
-           styleNames[e.getAttributeNS(stylens, "name")] = true
-         }
-         e = e.nextElementSibling
++(function() {
++  function LoadingQueue() {
++    var queue = [], taskRunning = false;
++    function run(task) {
++      taskRunning = true;
++      runtime.setTimeout(function() {
++        try {
++          task()
++        }catch(e) {
++          runtime.log(String(e))
++        }
++        taskRunning = false;
++        if(queue.length > 0) {
++          run(queue.pop())
++        }
++      }, 10)
++    }
++    this.clearQueue = function() {
++      queue.length = 0
++    };
++    this.addToQueue = function(loadingTask) {
++      if(queue.length === 0 && !taskRunning) {
++        return run(loadingTask)
 +      }
++      queue.push(loadingTask)
 +    }
-     styleElements.forEach(getStyleNames);
-     return styleNames
 +  }
-   this.generateStyleName = function() {
-     if(styleNameGenerator === null) {
-       styleNameGenerator = new NameGenerator("auto" + memberIdHash + "_", function() {
-         return getAllStyleNames()
-       })
-     }
-     return styleNameGenerator.generateName()
-   };
-   this.generateFrameName = function() {
-     if(frameNameGenerator === null) {
-       var nodes = domUtils.getElementsByTagNameNS(odfContainer.rootElement.body, drawns, "frame");
-       nodes.forEach(function(frame) {
-         existingFrameNames[frame.getAttributeNS(drawns, "name")] = true
-       });
-       frameNameGenerator = new NameGenerator("fr" + memberIdHash + "_", function() {
-         return existingFrameNames
-       })
++  function PageSwitcher(css) {
++    var sheet = (css.sheet), position = 1;
++    function updateCSS() {
++      while(sheet.cssRules.length > 0) {
++        sheet.deleteRule(0)
++      }
++      sheet.insertRule("#shadowContent draw|page {display:none;}", 0);
++      sheet.insertRule("office|presentation draw|page {display:none;}", 1);
++      sheet.insertRule("#shadowContent draw|page:nth-of-type(" + position + ") {display:block;}", 2);
++      sheet.insertRule("office|presentation draw|page:nth-of-type(" + position + ") {display:block;}", 3)
 +    }
-     return frameNameGenerator.generateName()
-   };
-   this.generateImageName = function() {
-     if(imageNameGenerator === null) {
-       var nodes = domUtils.getElementsByTagNameNS(odfContainer.rootElement.body, drawns, "image");
-       nodes.forEach(function(image) {
-         var path = image.getAttributeNS(xlinkns, "href");
-         path = path.substring("Pictures/".length, path.lastIndexOf("."));
-         existingImageNames[path] = true
-       });
-       imageNameGenerator = new NameGenerator("img" + memberIdHash + "_", function() {
-         return existingImageNames
-       })
++    this.showFirstPage = function() {
++      position = 1;
++      updateCSS()
++    };
++    this.showNextPage = function() {
++      position += 1;
++      updateCSS()
++    };
++    this.showPreviousPage = function() {
++      if(position > 1) {
++        position -= 1;
++        updateCSS()
++      }
++    };
++    this.showPage = function(n) {
++      if(n > 0) {
++        position = n;
++        updateCSS()
++      }
++    };
++    this.css = css;
++    this.destroy = function(callback) {
++      css.parentNode.removeChild(css);
++      callback()
 +    }
-     return imageNameGenerator.generateName()
 +  }
- };
- /*
- 
-  Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
- 
-  @licstart
-  The JavaScript code in this page is free software: you can redistribute it
-  and/or modify it under the terms of the GNU Affero General Public License
-  (GNU AGPL) as published by the Free Software Foundation, either version 3 of
-  the License, or (at your option) any later version.  The code is distributed
-  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
- 
-  You should have received a copy of the GNU Affero General Public License
-  along with this code.  If not, see <http://www.gnu.org/licenses/>.
- 
-  As additional permission under GNU AGPL version 3 section 7, you
-  may distribute non-source (e.g., minimized or compacted) forms of
-  that code without the copy of the GNU GPL normally required by
-  section 4, provided you include this license notice and a URL
-  through which recipients can access the Corresponding Source.
- 
-  As a special exception to the AGPL, any HTML file which merely makes function
-  calls to this code, and for that purpose includes it by reference shall be
-  deemed a separate work for copyright law purposes. In addition, the copyright
-  holders of this code give you permission to combine this code with free
-  software libraries that are released under the GNU LGPL. You may copy and
-  distribute such a system following the terms of the GNU AGPL for this code
-  and the LGPL for the libraries. If you modify this code, you may extend this
-  exception to your version of the code, but you are not obligated to do so.
-  If you do not wish to do so, delete this exception statement from your
-  version.
- 
-  This license applies to this entire compilation.
-  @licend
-  @source: http://www.webodf.org/
-  @source: https://github.com/kogmbh/WebODF/
- */
- runtime.loadClass("core.Utils");
- runtime.loadClass("odf.ObjectNameGenerator");
- runtime.loadClass("odf.Namespaces");
- runtime.loadClass("odf.OdfContainer");
- runtime.loadClass("odf.StyleInfo");
- runtime.loadClass("odf.OdfUtils");
- odf.Formatting = function Formatting() {
-   var odfContainer, styleInfo = new odf.StyleInfo, svgns = odf.Namespaces.svgns, stylens = odf.Namespaces.stylens, textns = odf.Namespaces.textns, numberns = odf.Namespaces.numberns, fons = odf.Namespaces.fons, odfUtils = new odf.OdfUtils, domUtils = new core.DomUtils, utils = new core.Utils, builtInDefaultStyleAttributesByFamily = {"paragraph":{"style:paragraph-properties":{"fo:text-align":"left"}}}, defaultPageFormatSettings = {width:21.001, height:29.7, margin:2, padding:0};
-   function getSystemDefaultStyleAttributes(styleFamily) {
-     var result, builtInDefaultStyleAttributes = builtInDefaultStyleAttributesByFamily[styleFamily];
-     if(builtInDefaultStyleAttributes) {
-       result = utils.mergeObjects({}, builtInDefaultStyleAttributes)
++  function listenEvent(eventTarget, eventType, eventHandler) {
++    if(eventTarget.addEventListener) {
++      eventTarget.addEventListener(eventType, eventHandler, false)
 +    }else {
-       result = {}
++      if(eventTarget.attachEvent) {
++        eventType = "on" + eventType;
++        eventTarget.attachEvent(eventType, eventHandler)
++      }else {
++        eventTarget["on" + eventType] = eventHandler
++      }
 +    }
-     return result
 +  }
-   this.getSystemDefaultStyleAttributes = getSystemDefaultStyleAttributes;
-   this.setOdfContainer = function(odfcontainer) {
-     odfContainer = odfcontainer
-   };
-   function getDirectChild(node, ns, name) {
-     var e = node && node.firstElementChild;
-     while(e) {
-       if(e.namespaceURI === ns && e.localName === name) {
-         break
-       }
-       e = e.nextElementSibling
++  var drawns = odf.Namespaces.drawns, fons = odf.Namespaces.fons, officens = odf.Namespaces.officens, stylens = odf.Namespaces.stylens, svgns = odf.Namespaces.svgns, tablens = odf.Namespaces.tablens, textns = odf.Namespaces.textns, xlinkns = odf.Namespaces.xlinkns, xmlns = odf.Namespaces.xmlns, presentationns = odf.Namespaces.presentationns, webodfhelperns = "urn:webodf:names:helper", window = runtime.getWindow(), xpath = xmldom.XPath, odfUtils = new odf.OdfUtils, domUtils = new core.DomUtils;
++  function clear(element) {
++    while(element.firstChild) {
++      element.removeChild(element.firstChild)
 +    }
-     return e
 +  }
-   function getFontMap() {
-     var fontFaceDecls = odfContainer.rootElement.fontFaceDecls, fontFaceDeclsMap = {}, node, name, family;
-     node = fontFaceDecls && fontFaceDecls.firstElementChild;
-     while(node) {
-       name = node.getAttributeNS(stylens, "name");
-       if(name) {
-         family = node.getAttributeNS(svgns, "font-family");
-         if(family || node.getElementsByTagNameNS(svgns, "font-face-uri").length > 0) {
-           fontFaceDeclsMap[name] = family
-         }
-       }
-       node = node.nextElementSibling
++  function clearCSSStyleSheet(style) {
++    var stylesheet = (style.sheet), cssRules = stylesheet.cssRules;
++    while(cssRules.length) {
++      stylesheet.deleteRule(cssRules.length - 1)
 +    }
-     return fontFaceDeclsMap
 +  }
-   this.getFontMap = getFontMap;
-   this.getAvailableParagraphStyles = function() {
-     var node = odfContainer.rootElement.styles, p_family, p_name, p_displayName, paragraphStyles = [];
-     node = node && node.firstElementChild;
-     while(node) {
-       if(node.localName === "style" && node.namespaceURI === stylens) {
-         p_family = node.getAttributeNS(stylens, "family");
-         if(p_family === "paragraph") {
-           p_name = node.getAttributeNS(stylens, "name");
-           p_displayName = node.getAttributeNS(stylens, "display-name") || p_name;
-           if(p_name && p_displayName) {
-             paragraphStyles.push({name:p_name, displayName:p_displayName})
-           }
-         }
++  function handleStyles(odfcontainer, formatting, stylesxmlcss) {
++    var style2css = new odf.Style2CSS;
++    style2css.style2css(odfcontainer.getDocumentType(), (stylesxmlcss.sheet), formatting.getFontMap(), odfcontainer.rootElement.styles, odfcontainer.rootElement.automaticStyles)
++  }
++  function handleFonts(odfContainer, fontcss) {
++    var fontLoader = new odf.FontLoader;
++    fontLoader.loadFonts(odfContainer, (fontcss.sheet))
++  }
++  function getMasterPageElement(odfContainer, masterPageName) {
++    if(!masterPageName) {
++      return null
++    }
++    var masterStyles = odfContainer.rootElement.masterStyles, masterStylesChild = masterStyles.firstElementChild;
++    while(masterStylesChild) {
++      if(masterStylesChild.getAttributeNS(stylens, "name") === masterPageName && (masterStylesChild.localName === "master-page" && masterStylesChild.namespaceURI === stylens)) {
++        break
 +      }
-       node = node.nextElementSibling
++      masterStylesChild = masterStylesChild.nextElementSibling
 +    }
-     return paragraphStyles
-   };
-   this.isStyleUsed = function(styleElement) {
-     var hasDerivedStyles, isUsed, root = odfContainer.rootElement;
-     hasDerivedStyles = styleInfo.hasDerivedStyles(root, odf.Namespaces.lookupNamespaceURI, styleElement);
-     isUsed = (new styleInfo.UsedStyleList(root.styles)).uses(styleElement) || ((new styleInfo.UsedStyleList(root.automaticStyles)).uses(styleElement) || (new styleInfo.UsedStyleList(root.body)).uses(styleElement));
-     return hasDerivedStyles || isUsed
-   };
-   function getDefaultStyleElement(family) {
-     var node = odfContainer.rootElement.styles.firstElementChild;
-     while(node) {
-       if(node.namespaceURI === stylens && (node.localName === "default-style" && node.getAttributeNS(stylens, "family") === family)) {
-         return node
++    return masterStylesChild
++  }
++  function dropTemplateDrawFrames(clonedNode) {
++    var i, element, presentationClass, clonedDrawFrameElements = clonedNode.getElementsByTagNameNS(drawns, "frame");
++    for(i = 0;i < clonedDrawFrameElements.length;i += 1) {
++      element = (clonedDrawFrameElements[i]);
++      presentationClass = element.getAttributeNS(presentationns, "class");
++      if(presentationClass && !/^(date-time|footer|header|page-number)$/.test(presentationClass)) {
++        element.parentNode.removeChild(element)
 +      }
-       node = node.nextElementSibling
 +    }
-     return null
 +  }
-   this.getDefaultStyleElement = getDefaultStyleElement;
-   function getStyleElement(styleName, family, styleElements) {
-     var node, nodeStyleName, styleListElement, i;
-     styleElements = styleElements || [odfContainer.rootElement.automaticStyles, odfContainer.rootElement.styles];
-     for(i = 0;i < styleElements.length;i += 1) {
-       styleListElement = (styleElements[i]);
-       node = styleListElement.firstElementChild;
-       while(node) {
-         nodeStyleName = node.getAttributeNS(stylens, "name");
-         if(node.namespaceURI === stylens && (node.localName === "style" && (node.getAttributeNS(stylens, "family") === family && nodeStyleName === styleName))) {
-           return node
-         }
-         if(family === "list-style" && (node.namespaceURI === textns && (node.localName === "list-style" && nodeStyleName === styleName))) {
-           return node
-         }
-         if(family === "data" && (node.namespaceURI === numberns && nodeStyleName === styleName)) {
-           return node
++  function getHeaderFooter(odfContainer, frame, headerFooterId) {
++    var headerFooter = null, i, declElements = odfContainer.rootElement.body.getElementsByTagNameNS(presentationns, headerFooterId + "-decl"), headerFooterName = frame.getAttributeNS(presentationns, "use-" + headerFooterId + "-name"), element;
++    if(headerFooterName && declElements.length > 0) {
++      for(i = 0;i < declElements.length;i += 1) {
++        element = (declElements[i]);
++        if(element.getAttributeNS(presentationns, "name") === headerFooterName) {
++          headerFooter = element.textContent;
++          break
 +        }
-         node = node.nextElementSibling
 +      }
 +    }
-     return null
++    return headerFooter
 +  }
-   this.getStyleElement = getStyleElement;
-   function getStyleAttributes(styleNode) {
-     var i, a, map, ai, propertiesMap = {}, propertiesNode = styleNode.firstElementChild;
-     while(propertiesNode) {
-       if(propertiesNode.namespaceURI === stylens) {
-         map = propertiesMap[propertiesNode.nodeName] = {};
-         a = propertiesNode.attributes;
-         for(i = 0;i < a.length;i += 1) {
-           ai = (a.item(i));
-           map[ai.name] = ai.value
-         }
++  function setContainerValue(rootElement, ns, localName, value) {
++    var i, containerList, document = rootElement.ownerDocument, e;
++    containerList = rootElement.getElementsByTagNameNS(ns, localName);
++    for(i = 0;i < containerList.length;i += 1) {
++      clear(containerList[i]);
++      if(value) {
++        e = (containerList[i]);
++        e.appendChild(document.createTextNode(value))
 +      }
-       propertiesNode = propertiesNode.nextElementSibling
-     }
-     a = styleNode.attributes;
-     for(i = 0;i < a.length;i += 1) {
-       ai = (a.item(i));
-       propertiesMap[ai.name] = ai.value
 +    }
-     return propertiesMap
 +  }
-   this.getStyleAttributes = getStyleAttributes;
-   function getInheritedStyleAttributes(styleNode, includeSystemDefault) {
-     var styleListElement = odfContainer.rootElement.styles, parentStyleName, propertiesMap, inheritedPropertiesMap = {}, styleFamily = styleNode.getAttributeNS(stylens, "family"), node = styleNode;
-     while(node) {
-       propertiesMap = getStyleAttributes(node);
-       inheritedPropertiesMap = utils.mergeObjects(propertiesMap, inheritedPropertiesMap);
-       parentStyleName = node.getAttributeNS(stylens, "parent-style-name");
-       if(parentStyleName) {
-         node = getStyleElement(parentStyleName, styleFamily, [styleListElement])
++  function setDrawElementPosition(styleid, frame, stylesheet) {
++    frame.setAttributeNS(webodfhelperns, "styleid", styleid);
++    var rule, anchor = frame.getAttributeNS(textns, "anchor-type"), x = frame.getAttributeNS(svgns, "x"), y = frame.getAttributeNS(svgns, "y"), width = frame.getAttributeNS(svgns, "width"), height = frame.getAttributeNS(svgns, "height"), minheight = frame.getAttributeNS(fons, "min-height"), minwidth = frame.getAttributeNS(fons, "min-width");
++    if(anchor === "as-char") {
++      rule = "display: inline-block;"
++    }else {
++      if(anchor || (x || y)) {
++        rule = "position: absolute;"
 +      }else {
-         node = null
++        if(width || (height || (minheight || minwidth))) {
++          rule = "display: block;"
++        }
 +      }
 +    }
-     node = getDefaultStyleElement(styleFamily);
-     if(node) {
-       propertiesMap = getStyleAttributes(node);
-       inheritedPropertiesMap = utils.mergeObjects(propertiesMap, inheritedPropertiesMap)
++    if(x) {
++      rule += "left: " + x + ";"
 +    }
-     if(includeSystemDefault) {
-       propertiesMap = getSystemDefaultStyleAttributes(styleFamily);
-       if(propertiesMap) {
-         inheritedPropertiesMap = utils.mergeObjects(propertiesMap, inheritedPropertiesMap)
-       }
++    if(y) {
++      rule += "top: " + y + ";"
 +    }
-     return inheritedPropertiesMap
-   }
-   this.getInheritedStyleAttributes = getInheritedStyleAttributes;
-   this.getFirstCommonParentStyleNameOrSelf = function(styleName) {
-     var automaticStyleElementList = odfContainer.rootElement.automaticStyles, styleElementList = odfContainer.rootElement.styles, styleElement;
-     styleElement = getStyleElement(styleName, "paragraph", [automaticStyleElementList]);
-     while(styleElement) {
-       styleName = styleElement.getAttributeNS(stylens, "parent-style-name");
-       styleElement = getStyleElement(styleName, "paragraph", [automaticStyleElementList])
++    if(width) {
++      rule += "width: " + width + ";"
 +    }
-     styleElement = getStyleElement(styleName, "paragraph", [styleElementList]);
-     if(!styleElement) {
-       return null
++    if(height) {
++      rule += "height: " + height + ";"
 +    }
-     return styleName
-   };
-   this.hasParagraphStyle = function(styleName) {
-     return Boolean(getStyleElement(styleName, "paragraph"))
-   };
-   function buildStyleChain(node, collectedChains) {
-     var parent = (node.nodeType === Node.TEXT_NODE ? node.parentNode : node), nodeStyles, appliedStyles = [], chainKey = "", foundContainer = false;
-     while(parent) {
-       if(!foundContainer && odfUtils.isGroupingElement(parent)) {
-         foundContainer = true
++    if(minheight) {
++      rule += "min-height: " + minheight + ";"
++    }
++    if(minwidth) {
++      rule += "min-width: " + minwidth + ";"
++    }
++    if(rule) {
++      rule = "draw|" + frame.localName + '[webodfhelper|styleid="' + styleid + '"] {' + rule + "}";
++      stylesheet.insertRule(rule, stylesheet.cssRules.length)
++    }
++  }
++  function getUrlFromBinaryDataElement(image) {
++    var node = image.firstChild;
++    while(node) {
++      if(node.namespaceURI === officens && node.localName === "binary-data") {
++        return"data:image/png;base64," + node.textContent.replace(/[\r\n\s]/g, "")
 +      }
-       nodeStyles = styleInfo.determineStylesForNode(parent);
-       if(nodeStyles) {
-         appliedStyles.push(nodeStyles)
++      node = node.nextSibling
++    }
++    return""
++  }
++  function setImage(id, container, image, stylesheet) {
++    image.setAttributeNS(webodfhelperns, "styleid", id);
++    var url = image.getAttributeNS(xlinkns, "href"), part;
++    function callback(url) {
++      var rule;
++      if(url) {
++        rule = "background-image: url(" + url + ");";
++        rule = 'draw|image[webodfhelper|styleid="' + id + '"] {' + rule + "}";
++        stylesheet.insertRule(rule, stylesheet.cssRules.length)
 +      }
-       parent = parent.parentElement
 +    }
-     function chainStyles(usedStyleMap) {
-       Object.keys(usedStyleMap).forEach(function(styleFamily) {
-         Object.keys(usedStyleMap[styleFamily]).forEach(function(styleName) {
-           chainKey += "|" + styleFamily + ":" + styleName + "|"
-         })
-       })
++    function onchange(p) {
++      callback(p.url)
 +    }
-     if(foundContainer) {
-       appliedStyles.forEach(chainStyles);
-       if(collectedChains) {
-         collectedChains[chainKey] = appliedStyles
++    if(url) {
++      try {
++        part = container.getPart(url);
++        part.onchange = onchange;
++        part.load()
++      }catch(e) {
++        runtime.log("slight problem: " + String(e))
 +      }
++    }else {
++      url = getUrlFromBinaryDataElement(image);
++      callback(url)
 +    }
-     return foundContainer ? appliedStyles : undefined
-   }
-   function calculateAppliedStyle(styleChain) {
-     var mergedChildStyle = {orderedStyles:[]};
-     styleChain.forEach(function(elementStyleSet) {
-       Object.keys((elementStyleSet)).forEach(function(styleFamily) {
-         var styleName = Object.keys(elementStyleSet[styleFamily])[0], styleElement, parentStyle, displayName;
-         styleElement = getStyleElement(styleName, styleFamily);
-         if(styleElement) {
-           parentStyle = getInheritedStyleAttributes((styleElement));
-           mergedChildStyle = utils.mergeObjects(parentStyle, mergedChildStyle);
-           displayName = styleElement.getAttributeNS(stylens, "display-name")
-         }else {
-           runtime.log("No style element found for '" + styleName + "' of family '" + styleFamily + "'")
-         }
-         mergedChildStyle.orderedStyles.push({name:styleName, family:styleFamily, displayName:displayName})
-       })
-     });
-     return mergedChildStyle
 +  }
-   this.getAppliedStyles = function(textNodes) {
-     var styleChains = {}, styles = [];
-     textNodes.forEach(function(n) {
-       buildStyleChain(n, styleChains)
-     });
-     Object.keys(styleChains).forEach(function(key) {
-       styles.push(calculateAppliedStyle(styleChains[key]))
-     });
-     return styles
-   };
-   this.getAppliedStylesForElement = function(node) {
-     var styleChain;
-     styleChain = buildStyleChain(node);
-     return styleChain ? calculateAppliedStyle(styleChain) : undefined
-   };
-   this.updateStyle = function(styleNode, properties) {
-     var fontName, fontFaceNode;
-     domUtils.mapObjOntoNode(styleNode, properties, odf.Namespaces.lookupNamespaceURI);
-     fontName = properties["style:text-properties"] && properties["style:text-properties"]["style:font-name"];
-     if(fontName && !getFontMap().hasOwnProperty(fontName)) {
-       fontFaceNode = styleNode.ownerDocument.createElementNS(stylens, "style:font-face");
-       fontFaceNode.setAttributeNS(stylens, "style:name", fontName);
-       fontFaceNode.setAttributeNS(svgns, "svg:font-family", fontName);
-       odfContainer.rootElement.fontFaceDecls.appendChild(fontFaceNode)
++  function formatParagraphAnchors(odfbody) {
++    var n, i, nodes = xpath.getODFElementsWithXPath(odfbody, ".//*[*[@text:anchor-type='paragraph']]", odf.Namespaces.lookupNamespaceURI);
++    for(i = 0;i < nodes.length;i += 1) {
++      n = nodes[i];
++      if(n.setAttributeNS) {
++        n.setAttributeNS(webodfhelperns, "containsparagraphanchor", true)
++      }
 +    }
-   };
-   function isAutomaticStyleElement(styleNode) {
-     return styleNode.parentNode === odfContainer.rootElement.automaticStyles
 +  }
-   this.createDerivedStyleObject = function(parentStyleName, family, overrides) {
-     var originalStyleElement = (getStyleElement(parentStyleName, family)), newStyleObject;
-     runtime.assert(Boolean(originalStyleElement), "No style element found for '" + parentStyleName + "' of family '" + family + "'");
-     if(isAutomaticStyleElement(originalStyleElement)) {
-       newStyleObject = getStyleAttributes(originalStyleElement)
-     }else {
-       newStyleObject = {"style:parent-style-name":parentStyleName}
-     }
-     newStyleObject["style:family"] = family;
-     utils.mergeObjects(newStyleObject, overrides);
-     return newStyleObject
-   };
-   this.getDefaultTabStopDistance = function() {
-     var defaultParagraph = getDefaultStyleElement("paragraph"), paragraphProperties = defaultParagraph && defaultParagraph.firstElementChild, tabStopDistance;
-     while(paragraphProperties) {
-       if(paragraphProperties.namespaceURI === stylens && paragraphProperties.localName === "paragraph-properties") {
-         tabStopDistance = paragraphProperties.getAttributeNS(stylens, "tab-stop-distance")
++  function modifyTables(odffragment, documentns) {
++    var i, tableCells, node;
++    function modifyTableCell(node) {
++      if(node.hasAttributeNS(tablens, "number-columns-spanned")) {
++        node.setAttributeNS(documentns, "colspan", node.getAttributeNS(tablens, "number-columns-spanned"))
++      }
++      if(node.hasAttributeNS(tablens, "number-rows-spanned")) {
++        node.setAttributeNS(documentns, "rowspan", node.getAttributeNS(tablens, "number-rows-spanned"))
 +      }
-       paragraphProperties = paragraphProperties.nextElementSibling
 +    }
-     if(!tabStopDistance) {
-       tabStopDistance = "1.25cm"
++    tableCells = odffragment.getElementsByTagNameNS(tablens, "table-cell");
++    for(i = 0;i < tableCells.length;i += 1) {
++      node = (tableCells.item(i));
++      modifyTableCell(node)
 +    }
-     return odfUtils.parseNonNegativeLength(tabStopDistance)
-   };
-   function getPageLayoutStyleElement(styleName, styleFamily) {
-     var masterPageName, layoutName, pageLayoutElements, node, i, styleElement = getStyleElement(styleName, styleFamily);
-     runtime.assert(styleFamily === "paragraph" || styleFamily === "table", "styleFamily has to be either paragraph or table");
-     if(styleElement) {
-       masterPageName = styleElement.getAttributeNS(stylens, "master-page-name") || "Standard";
-       node = odfContainer.rootElement.masterStyles.lastElementChild;
-       while(node) {
-         if(node.getAttributeNS(stylens, "name") === masterPageName) {
-           break
-         }
-         node = node.previousElementSibling
++  }
++  function modifyLineBreakElements(odffragment) {
++    var document = odffragment.ownerDocument, lineBreakElements = domUtils.getElementsByTagNameNS(odffragment, textns, "line-break");
++    lineBreakElements.forEach(function(lineBreak) {
++      if(!lineBreak.hasChildNodes()) {
++        lineBreak.appendChild(document.createElement("br"))
 +      }
-       layoutName = node.getAttributeNS(stylens, "page-layout-name");
-       pageLayoutElements = domUtils.getElementsByTagNameNS(odfContainer.rootElement.automaticStyles, stylens, "page-layout");
-       for(i = 0;i < pageLayoutElements.length;i += 1) {
-         node = pageLayoutElements[i];
-         if(node.getAttributeNS(stylens, "name") === layoutName) {
-           return(node)
++    })
++  }
++  function expandSpaceElements(odffragment) {
++    var spaces, doc = odffragment.ownerDocument;
++    function expandSpaceElement(space) {
++      var j, count;
++      while(space.firstChild) {
++        space.removeChild(space.firstChild)
++      }
++      space.appendChild(doc.createTextNode(" "));
++      count = parseInt(space.getAttributeNS(textns, "c"), 10);
++      if(count > 1) {
++        space.removeAttributeNS(textns, "c");
++        for(j = 1;j < count;j += 1) {
++          space.parentNode.insertBefore(space.cloneNode(true), space)
 +        }
 +      }
 +    }
-     return null
++    spaces = domUtils.getElementsByTagNameNS(odffragment, textns, "s");
++    spaces.forEach(expandSpaceElement)
 +  }
-   function lengthInCm(length, defaultValue) {
-     var result = odfUtils.parseLength(length), value = defaultValue;
-     if(result) {
-       switch(result.unit) {
-         case "cm":
-           value = result.value;
-           break;
-         case "mm":
-           value = result.value * 0.1;
-           break;
-         case "in":
-           value = result.value * 2.54;
-           break;
-         case "pt":
-           value = result.value * 0.035277778;
-           break;
-         case "pc":
-         ;
-         case "px":
-         ;
-         case "em":
-           break;
-         default:
-           runtime.log("Unit identifier: " + result.unit + " is not supported.");
-           break
-       }
-     }
-     return value
++  function expandTabElements(odffragment) {
++    var tabs;
++    tabs = domUtils.getElementsByTagNameNS(odffragment, textns, "tab");
++    tabs.forEach(function(tab) {
++      tab.textContent = "\t"
++    })
 +  }
-   this.getContentSize = function(styleName, styleFamily) {
-     var pageLayoutElement, props, printOrientation, defaultOrientedPageWidth, defaultOrientedPageHeight, pageWidth, pageHeight, margin, marginLeft, marginRight, marginTop, marginBottom, padding, paddingLeft, paddingRight, paddingTop, paddingBottom;
-     pageLayoutElement = getPageLayoutStyleElement(styleName, styleFamily);
-     if(!pageLayoutElement) {
-       pageLayoutElement = getDirectChild(odfContainer.rootElement.styles, stylens, "default-page-layout")
-     }
-     props = getDirectChild(pageLayoutElement, stylens, "page-layout-properties");
-     if(props) {
-       printOrientation = props.getAttributeNS(stylens, "print-orientation") || "portrait";
-       if(printOrientation === "portrait") {
-         defaultOrientedPageWidth = defaultPageFormatSettings.width;
-         defaultOrientedPageHeight = defaultPageFormatSettings.height
-       }else {
-         defaultOrientedPageWidth = defaultPageFormatSettings.height;
-         defaultOrientedPageHeight = defaultPageFormatSettings.width
-       }
-       pageWidth = lengthInCm(props.getAttributeNS(fons, "page-width"), defaultOrientedPageWidth);
-       pageHeight = lengthInCm(props.getAttributeNS(fons, "page-height"), defaultOrientedPageHeight);
-       margin = lengthInCm(props.getAttributeNS(fons, "margin"), null);
-       if(margin === null) {
-         marginLeft = lengthInCm(props.getAttributeNS(fons, "margin-left"), defaultPageFormatSettings.margin);
-         marginRight = lengthInCm(props.getAttributeNS(fons, "margin-right"), defaultPageFormatSettings.margin);
-         marginTop = lengthInCm(props.getAttributeNS(fons, "margin-top"), defaultPageFormatSettings.margin);
-         marginBottom = lengthInCm(props.getAttributeNS(fons, "margin-bottom"), defaultPageFormatSettings.margin)
-       }else {
-         marginLeft = marginRight = marginTop = marginBottom = margin
++  function modifyDrawElements(odfbody, stylesheet) {
++    var node, drawElements = [], i;
++    node = odfbody.firstElementChild;
++    while(node && node !== odfbody) {
++      if(node.namespaceURI === drawns) {
++        drawElements[drawElements.length] = node
 +      }
-       padding = lengthInCm(props.getAttributeNS(fons, "padding"), null);
-       if(padding === null) {
-         paddingLeft = lengthInCm(props.getAttributeNS(fons, "padding-left"), defaultPageFormatSettings.padding);
-         paddingRight = lengthInCm(props.getAttributeNS(fons, "padding-right"), defaultPageFormatSettings.padding);
-         paddingTop = lengthInCm(props.getAttributeNS(fons, "padding-top"), defaultPageFormatSettings.padding);
-         paddingBottom = lengthInCm(props.getAttributeNS(fons, "padding-bottom"), defaultPageFormatSettings.padding)
++      if(node.firstElementChild) {
++        node = node.firstElementChild
 +      }else {
-         paddingLeft = paddingRight = paddingTop = paddingBottom = padding
++        while(node && (node !== odfbody && !node.nextElementSibling)) {
++          node = (node.parentNode)
++        }
++        if(node && node.nextElementSibling) {
++          node = node.nextElementSibling
++        }
 +      }
 +    }
-     return{width:pageWidth - marginLeft - marginRight - paddingLeft - paddingRight, height:pageHeight - marginTop - marginBottom - paddingTop - paddingBottom}
++    for(i = 0;i < drawElements.length;i += 1) {
++      node = drawElements[i];
++      setDrawElementPosition("frame" + String(i), node, stylesheet)
++    }
++    formatParagraphAnchors(odfbody)
 +  }
- };
- /*
- 
-  Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
- 
-  @licstart
-  The JavaScript code in this page is free software: you can redistribute it
-  and/or modify it under the terms of the GNU Affero General Public License
-  (GNU AGPL) as published by the Free Software Foundation, either version 3 of
-  the License, or (at your option) any later version.  The code is distributed
-  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
- 
-  You should have received a copy of the GNU Affero General Public License
-  along with this code.  If not, see <http://www.gnu.org/licenses/>.
- 
-  As additional permission under GNU AGPL version 3 section 7, you
-  may distribute non-source (e.g., minimized or compacted) forms of
-  that code without the copy of the GNU GPL normally required by
-  section 4, provided you include this license notice and a URL
-  through which recipients can access the Corresponding Source.
- 
-  As a special exception to the AGPL, any HTML file which merely makes function
-  calls to this code, and for that purpose includes it by reference shall be
-  deemed a separate work for copyright law purposes. In addition, the copyright
-  holders of this code give you permission to combine this code with free
-  software libraries that are released under the GNU LGPL. You may copy and
-  distribute such a system following the terms of the GNU AGPL for this code
-  and the LGPL for the libraries. If you modify this code, you may extend this
-  exception to your version of the code, but you are not obligated to do so.
-  If you do not wish to do so, delete this exception statement from your
-  version.
- 
-  This license applies to this entire compilation.
-  @licend
-  @source: http://www.webodf.org/
-  @source: https://github.com/kogmbh/WebODF/
- */
- runtime.loadClass("core.DomUtils");
- runtime.loadClass("odf.OdfContainer");
- runtime.loadClass("odf.Formatting");
- runtime.loadClass("xmldom.XPath");
- runtime.loadClass("odf.FontLoader");
- runtime.loadClass("odf.Style2CSS");
- runtime.loadClass("odf.OdfUtils");
- runtime.loadClass("gui.AnnotationViewManager");
- (function() {
-   function LoadingQueue() {
-     var queue = [], taskRunning = false;
-     function run(task) {
-       taskRunning = true;
-       runtime.setTimeout(function() {
-         try {
-           task()
-         }catch(e) {
-           runtime.log(String(e))
-         }
-         taskRunning = false;
-         if(queue.length > 0) {
-           run(queue.pop())
-         }
-       }, 10)
++  function cloneMasterPages(odfContainer, shadowContent, odfbody, stylesheet) {
++    var masterPageName, masterPageElement, styleId, clonedPageElement, clonedElement, pageNumber = 0, i, element, elementToClone, document = odfContainer.rootElement.ownerDocument;
++    element = odfbody.firstElementChild;
++    if(!(element && (element.namespaceURI === officens && (element.localName === "presentation" || element.localName === "drawing")))) {
++      return
 +    }
-     this.clearQueue = function() {
-       queue.length = 0
-     };
-     this.addToQueue = function(loadingTask) {
-       if(queue.length === 0 && !taskRunning) {
-         return run(loadingTask)
++    element = element.firstElementChild;
++    while(element) {
++      masterPageName = element.getAttributeNS(drawns, "master-page-name");
++      masterPageElement = getMasterPageElement(odfContainer, masterPageName);
++      if(masterPageElement) {
++        styleId = element.getAttributeNS(webodfhelperns, "styleid");
++        clonedPageElement = document.createElementNS(drawns, "draw:page");
++        elementToClone = masterPageElement.firstElementChild;
++        i = 0;
++        while(elementToClone) {
++          if(elementToClone.getAttributeNS(presentationns, "placeholder") !== "true") {
++            clonedElement = (elementToClone.cloneNode(true));
++            clonedPageElement.appendChild(clonedElement);
++            setDrawElementPosition(styleId + "_" + i, clonedElement, stylesheet)
++          }
++          elementToClone = elementToClone.nextElementSibling;
++          i += 1
++        }
++        dropTemplateDrawFrames(clonedPageElement);
++        shadowContent.appendChild(clonedPageElement);
++        pageNumber = String(shadowContent.getElementsByTagNameNS(drawns, "page").length);
++        setContainerValue(clonedPageElement, textns, "page-number", pageNumber);
++        setContainerValue(clonedPageElement, presentationns, "header", getHeaderFooter(odfContainer, (element), "header"));
++        setContainerValue(clonedPageElement, presentationns, "footer", getHeaderFooter(odfContainer, (element), "footer"));
++        setDrawElementPosition(styleId, clonedPageElement, stylesheet);
++        clonedPageElement.setAttributeNS(drawns, "draw:master-page-name", masterPageElement.getAttributeNS(stylens, "name"))
 +      }
-       queue.push(loadingTask)
++      element = element.nextElementSibling
 +    }
 +  }
-   function PageSwitcher(css) {
-     var sheet = (css.sheet), position = 1;
-     function updateCSS() {
-       while(sheet.cssRules.length > 0) {
-         sheet.deleteRule(0)
++  function setVideo(container, plugin) {
++    var video, source, url, doc = plugin.ownerDocument, part;
++    url = plugin.getAttributeNS(xlinkns, "href");
++    function callback(url, mimetype) {
++      var ns = doc.documentElement.namespaceURI;
++      if(mimetype.substr(0, 6) === "video/") {
++        video = doc.createElementNS(ns, "video");
++        video.setAttribute("controls", "controls");
++        source = doc.createElementNS(ns, "source");
++        if(url) {
++          source.setAttribute("src", url)
++        }
++        source.setAttribute("type", mimetype);
++        video.appendChild(source);
++        plugin.parentNode.appendChild(video)
++      }else {
++        plugin.innerHtml = "Unrecognised Plugin"
 +      }
-       sheet.insertRule("#shadowContent draw|page {display:none;}", 0);
-       sheet.insertRule("office|presentation draw|page {display:none;}", 1);
-       sheet.insertRule("#shadowContent draw|page:nth-of-type(" + position + ") {display:block;}", 2);
-       sheet.insertRule("office|presentation draw|page:nth-of-type(" + position + ") {display:block;}", 3)
 +    }
-     this.showFirstPage = function() {
-       position = 1;
-       updateCSS()
-     };
-     this.showNextPage = function() {
-       position += 1;
-       updateCSS()
-     };
-     this.showPreviousPage = function() {
-       if(position > 1) {
-         position -= 1;
-         updateCSS()
-       }
-     };
-     this.showPage = function(n) {
-       if(n > 0) {
-         position = n;
-         updateCSS()
++    function onchange(p) {
++      callback(p.url, p.mimetype)
++    }
++    if(url) {
++      try {
++        part = container.getPart(url);
++        part.onchange = onchange;
++        part.load()
++      }catch(e) {
++        runtime.log("slight problem: " + String(e))
 +      }
-     };
-     this.css = css;
-     this.destroy = function(callback) {
-       css.parentNode.removeChild(css);
-       callback()
++    }else {
++      runtime.log("using MP4 data fallback");
++      url = getUrlFromBinaryDataElement(plugin);
++      callback(url, "video/mp4")
 +    }
 +  }
-   function listenEvent(eventTarget, eventType, eventHandler) {
-     if(eventTarget.addEventListener) {
-       eventTarget.addEventListener(eventType, eventHandler, false)
++  function getNumberRule(node) {
++    var style = node.getAttributeNS(stylens, "num-format"), suffix = node.getAttributeNS(stylens, "num-suffix") || "", prefix = node.getAttributeNS(stylens, "num-prefix") || "", rule = "", stylemap = {1:"decimal", "a":"lower-latin", "A":"upper-latin", "i":"lower-roman", "I":"upper-roman"}, content;
++    content = prefix;
++    if(stylemap.hasOwnProperty(style)) {
++      content += " counter(list, " + stylemap[style] + ")"
 +    }else {
-       if(eventTarget.attachEvent) {
-         eventType = "on" + eventType;
-         eventTarget.attachEvent(eventType, eventHandler)
++      if(style) {
++        content += "'" + style + "';"
 +      }else {
-         eventTarget["on" + eventType] = eventHandler
++        content += " ''"
 +      }
 +    }
-   }
-   var drawns = odf.Namespaces.drawns, fons = odf.Namespaces.fons, officens = odf.Namespaces.officens, stylens = odf.Namespaces.stylens, svgns = odf.Namespaces.svgns, tablens = odf.Namespaces.tablens, textns = odf.Namespaces.textns, xlinkns = odf.Namespaces.xlinkns, xmlns = odf.Namespaces.xmlns, presentationns = odf.Namespaces.presentationns, webodfhelperns = "urn:webodf:names:helper", window = runtime.getWindow(), xpath = xmldom.XPath, odfUtils = new odf.OdfUtils, domUtils = new core.DomUtils;
-   function clear(element) {
-     while(element.firstChild) {
-       element.removeChild(element.firstChild)
++    if(suffix) {
++      content += " '" + suffix + "'"
 +    }
++    rule = "content: " + content + ";";
++    return rule
 +  }
-   function handleStyles(odfcontainer, formatting, stylesxmlcss) {
-     var style2css = new odf.Style2CSS;
-     style2css.style2css(odfcontainer.getDocumentType(), (stylesxmlcss.sheet), formatting.getFontMap(), odfcontainer.rootElement.styles, odfcontainer.rootElement.automaticStyles)
++  function getImageRule() {
++    var rule = "content: none;";
++    return rule
 +  }
-   function handleFonts(odfContainer, fontcss) {
-     var fontLoader = new odf.FontLoader;
-     fontLoader.loadFonts(odfContainer, (fontcss.sheet))
++  function getBulletRule(node) {
++    var bulletChar = node.getAttributeNS(textns, "bullet-char");
++    return"content: '" + bulletChar + "';"
 +  }
-   function getMasterPageElement(odfContainer, masterPageName) {
-     if(!masterPageName) {
-       return null
-     }
-     var masterStyles = odfContainer.rootElement.masterStyles, masterPageElement = masterStyles.firstElementChild;
-     while(masterPageElement) {
-       if(masterPageElement.getAttributeNS(stylens, "name") === masterPageName && (masterPageElement.localName === "master-page" && masterPageElement.namespaceURI === stylens)) {
-         break
++  function getBulletsRule(node) {
++    var itemrule;
++    if(node) {
++      if(node.localName === "list-level-style-number") {
++        itemrule = getNumberRule(node)
++      }else {
++        if(node.localName === "list-level-style-image") {
++          itemrule = getImageRule()
++        }else {
++          if(node.localName === "list-level-style-bullet") {
++            itemrule = getBulletRule(node)
++          }
++        }
 +      }
 +    }
-     return masterPageElement
++    return itemrule
 +  }
-   function dropTemplateDrawFrames(clonedNode) {
-     var i, element, presentationClass, clonedDrawFrameElements = clonedNode.getElementsByTagNameNS(drawns, "frame");
-     for(i = 0;i < clonedDrawFrameElements.length;i += 1) {
-       element = (clonedDrawFrameElements[i]);
-       presentationClass = element.getAttributeNS(presentationns, "class");
-       if(presentationClass && !/^(date-time|footer|header|page-number')$/.test(presentationClass)) {
-         element.parentNode.removeChild(element)
++  function loadLists(odffragment, stylesheet, documentns) {
++    var i, lists, node, id, continueList, styleName, rule, listMap = {}, parentList, listStyles, listStyleMap = {}, bulletRule;
++    listStyles = window.document.getElementsByTagNameNS(textns, "list-style");
++    for(i = 0;i < listStyles.length;i += 1) {
++      node = (listStyles.item(i));
++      styleName = node.getAttributeNS(stylens, "name");
++      if(styleName) {
++        listStyleMap[styleName] = node
 +      }
 +    }
-   }
-   function getHeaderFooter(odfContainer, frame, headerFooterId) {
-     var headerFooter = null, i, declElements = odfContainer.rootElement.body.getElementsByTagNameNS(presentationns, headerFooterId + "-decl"), headerFooterName = frame.getAttributeNS(presentationns, "use-" + headerFooterId + "-name"), element;
-     if(headerFooterName && declElements.length > 0) {
-       for(i = 0;i < declElements.length;i += 1) {
-         element = (declElements[i]);
-         if(element.getAttributeNS(presentationns, "name") === headerFooterName) {
-           headerFooter = element.textContent;
-           break
++    lists = odffragment.getElementsByTagNameNS(textns, "list");
++    for(i = 0;i < lists.length;i += 1) {
++      node = (lists.item(i));
++      id = node.getAttributeNS(xmlns, "id");
++      if(id) {
++        continueList = node.getAttributeNS(textns, "continue-list");
++        node.setAttributeNS(documentns, "id", id);
++        rule = "text|list#" + id + " > text|list-item > *:first-child:before {";
++        styleName = node.getAttributeNS(textns, "style-name");
++        if(styleName) {
++          node = listStyleMap[styleName];
++          bulletRule = getBulletsRule((odfUtils.getFirstNonWhitespaceChild(node)))
++        }
++        if(continueList) {
++          parentList = listMap[continueList];
++          while(parentList) {
++            parentList = listMap[parentList]
++          }
++          rule += "counter-increment:" + continueList + ";";
++          if(bulletRule) {
++            bulletRule = bulletRule.replace("list", continueList);
++            rule += bulletRule
++          }else {
++            rule += "content:counter(" + continueList + ");"
++          }
++        }else {
++          continueList = "";
++          if(bulletRule) {
++            bulletRule = bulletRule.replace("list", id);
++            rule += bulletRule
++          }else {
++            rule += "content: counter(" + id + ");"
++          }
++          rule += "counter-increment:" + id + ";";
++          stylesheet.insertRule("text|list#" + id + " {counter-reset:" + id + "}", stylesheet.cssRules.length)
++        }
++        rule += "}";
++        listMap[id] = continueList;
++        if(rule) {
++          stylesheet.insertRule(rule, stylesheet.cssRules.length)
 +        }
 +      }
 +    }
-     return headerFooter
 +  }
-   function setContainerValue(rootElement, ns, localName, value) {
-     var i, containerList, document = rootElement.ownerDocument, e;
-     containerList = rootElement.getElementsByTagNameNS(ns, localName);
-     for(i = 0;i < containerList.length;i += 1) {
-       clear(containerList[i]);
-       if(value) {
-         e = (containerList[i]);
-         e.appendChild(document.createTextNode(value))
-       }
++  function findWebODFStyleSheet(head) {
++    var style = head.firstElementChild;
++    while(style && !(style.localName === "style" && style.hasAttribute("webodfcss"))) {
++      style = style.nextElementSibling
 +    }
++    return(style)
 +  }
-   function setDrawElementPosition(styleid, frame, stylesheet) {
-     frame.setAttributeNS(webodfhelperns, "styleid", styleid);
-     var rule, anchor = frame.getAttributeNS(textns, "anchor-type"), x = frame.getAttributeNS(svgns, "x"), y = frame.getAttributeNS(svgns, "y"), width = frame.getAttributeNS(svgns, "width"), height = frame.getAttributeNS(svgns, "height"), minheight = frame.getAttributeNS(fons, "min-height"), minwidth = frame.getAttributeNS(fons, "min-width");
-     if(anchor === "as-char") {
-       rule = "display: inline-block;"
++  function addWebODFStyleSheet(document) {
++    var head = (document.getElementsByTagName("head")[0]), css, style, href, count = document.styleSheets.length;
++    style = findWebODFStyleSheet(head);
++    if(style) {
++      count = parseInt(style.getAttribute("webodfcss"), 10);
++      style.setAttribute("webodfcss", count + 1);
++      return style
++    }
++    if(String(typeof webodf_css) === "string") {
++      css = (webodf_css)
 +    }else {
-       if(anchor || (x || y)) {
-         rule = "position: absolute;"
-       }else {
-         if(width || (height || (minheight || minwidth))) {
-           rule = "display: block;"
++      href = "webodf.css";
++      if(runtime.currentDirectory) {
++        href = runtime.currentDirectory();
++        if(href.length > 0 && href.substr(-1) !== "/") {
++          href += "/"
 +        }
++        href += "../webodf.css"
 +      }
++      css = (runtime.readFileSync(href, "utf-8"))
 +    }
-     if(x) {
-       rule += "left: " + x + ";"
-     }
-     if(y) {
-       rule += "top: " + y + ";"
-     }
-     if(width) {
-       rule += "width: " + width + ";"
-     }
-     if(height) {
-       rule += "height: " + height + ";"
-     }
-     if(minheight) {
-       rule += "min-height: " + minheight + ";"
-     }
-     if(minwidth) {
-       rule += "min-width: " + minwidth + ";"
-     }
-     if(rule) {
-       rule = "draw|" + frame.localName + '[webodfhelper|styleid="' + styleid + '"] {' + rule + "}";
-       stylesheet.insertRule(rule, stylesheet.cssRules.length)
-     }
++    style = (document.createElementNS(head.namespaceURI, "style"));
++    style.setAttribute("media", "screen, print, handheld, projection");
++    style.setAttribute("type", "text/css");
++    style.setAttribute("webodfcss", "1");
++    style.appendChild(document.createTextNode(css));
++    head.appendChild(style);
++    return style
 +  }
-   function getUrlFromBinaryDataElement(image) {
-     var node = image.firstChild;
-     while(node) {
-       if(node.namespaceURI === officens && node.localName === "binary-data") {
-         return"data:image/png;base64," + node.textContent.replace(/[\r\n\s]/g, "")
-       }
-       node = node.nextSibling
++  function removeWebODFStyleSheet(webodfcss) {
++    var count = parseInt(webodfcss.getAttribute("webodfcss"), 10);
++    if(count === 1) {
++      webodfcss.parentNode.removeChild(webodfcss)
++    }else {
++      webodfcss.setAttribute("count", count - 1)
 +    }
-     return""
 +  }
-   function setImage(id, container, image, stylesheet) {
-     image.setAttributeNS(webodfhelperns, "styleid", id);
-     var url = image.getAttributeNS(xlinkns, "href"), part;
-     function callback(url) {
-       var rule;
-       if(url) {
-         rule = "background-image: url(" + url + ");";
-         rule = 'draw|image[webodfhelper|styleid="' + id + '"] {' + rule + "}";
-         stylesheet.insertRule(rule, stylesheet.cssRules.length)
++  function addStyleSheet(document) {
++    var head = (document.getElementsByTagName("head")[0]), style = document.createElementNS(head.namespaceURI, "style"), text = "";
++    style.setAttribute("type", "text/css");
++    style.setAttribute("media", "screen, print, handheld, projection");
++    odf.Namespaces.forEachPrefix(function(prefix, ns) {
++      text += "@namespace " + prefix + " url(" + ns + ");\n"
++    });
++    text += "@namespace webodfhelper url(" + webodfhelperns + ");\n";
++    style.appendChild(document.createTextNode(text));
++    head.appendChild(style);
++    return(style)
++  }
++  odf.OdfCanvas = function OdfCanvas(element) {
++    runtime.assert(element !== null && element !== undefined, "odf.OdfCanvas constructor needs DOM element");
++    runtime.assert(element.ownerDocument !== null && element.ownerDocument !== undefined, "odf.OdfCanvas constructor needs DOM");
++    var self = this, doc = (element.ownerDocument), async = new core.Async, odfcontainer, formatting = new odf.Formatting, pageSwitcher, sizer = null, annotationsPane = null, allowAnnotations = false, showAnnotationRemoveButton = false, annotationViewManager = null, webodfcss, fontcss, stylesxmlcss, positioncss, shadowContent, eventHandlers = {}, waitingForDoneTimeoutId, redrawContainerTask, shouldRefreshCss = false, shouldRerenderAnnotations = false, loadingQueue = new LoadingQueue, zo [...]
++    new gui.ZoomHelper;
++    function loadImages(container, odffragment, stylesheet) {
++      var i, images, node;
++      function loadImage(name, container, node, stylesheet) {
++        loadingQueue.addToQueue(function() {
++          setImage(name, container, node, stylesheet)
++        })
 +      }
-     }
-     function onchange(p) {
-       callback(p.url)
-     }
-     if(url) {
-       try {
-         part = container.getPart(url);
-         part.onchange = onchange;
-         part.load()
-       }catch(e) {
-         runtime.log("slight problem: " + String(e))
++      images = odffragment.getElementsByTagNameNS(drawns, "image");
++      for(i = 0;i < images.length;i += 1) {
++        node = (images.item(i));
++        loadImage("image" + String(i), container, node, stylesheet)
 +      }
-     }else {
-       url = getUrlFromBinaryDataElement(image);
-       callback(url)
 +    }
-   }
-   function formatParagraphAnchors(odfbody) {
-     var n, i, nodes = xpath.getODFElementsWithXPath(odfbody, ".//*[*[@text:anchor-type='paragraph']]", odf.Namespaces.lookupNamespaceURI);
-     for(i = 0;i < nodes.length;i += 1) {
-       n = nodes[i];
-       if(n.setAttributeNS) {
-         n.setAttributeNS(webodfhelperns, "containsparagraphanchor", true)
++    function loadVideos(container, odffragment) {
++      var i, plugins, node;
++      function loadVideo(container, node) {
++        loadingQueue.addToQueue(function() {
++          setVideo(container, node)
++        })
++      }
++      plugins = odffragment.getElementsByTagNameNS(drawns, "plugin");
++      for(i = 0;i < plugins.length;i += 1) {
++        node = (plugins.item(i));
++        loadVideo(container, node)
 +      }
 +    }
-   }
-   function modifyTables(odffragment, documentns) {
-     var i, tableCells, node;
-     function modifyTableCell(node) {
-       if(node.hasAttributeNS(tablens, "number-columns-spanned")) {
-         node.setAttributeNS(documentns, "colspan", node.getAttributeNS(tablens, "number-columns-spanned"))
++    function addEventListener(eventType, eventHandler) {
++      var handlers;
++      if(eventHandlers.hasOwnProperty(eventType)) {
++        handlers = eventHandlers[eventType]
++      }else {
++        handlers = eventHandlers[eventType] = []
 +      }
-       if(node.hasAttributeNS(tablens, "number-rows-spanned")) {
-         node.setAttributeNS(documentns, "rowspan", node.getAttributeNS(tablens, "number-rows-spanned"))
++      if(eventHandler && handlers.indexOf(eventHandler) === -1) {
++        handlers.push(eventHandler)
 +      }
 +    }
-     tableCells = odffragment.getElementsByTagNameNS(tablens, "table-cell");
-     for(i = 0;i < tableCells.length;i += 1) {
-       node = (tableCells.item(i));
-       modifyTableCell(node)
++    function fireEvent(eventType, args) {
++      if(!eventHandlers.hasOwnProperty(eventType)) {
++        return
++      }
++      var handlers = eventHandlers[eventType], i;
++      for(i = 0;i < handlers.length;i += 1) {
++        handlers[i].apply(null, args)
++      }
 +    }
-   }
-   function modifyLinks(odffragment) {
-     var i, links, node;
-     function modifyLink(node) {
-       var url, clickHandler;
-       if(!node.hasAttributeNS(xlinkns, "href")) {
++    function fixContainerSize() {
++      var minHeight, odfdoc = sizer.firstChild, zoomLevel = zoomHelper.getZoomLevel();
++      if(!odfdoc) {
 +        return
 +      }
-       url = node.getAttributeNS(xlinkns, "href");
-       if(url[0] === "#") {
-         url = url.substring(1);
-         clickHandler = function() {
-           var bookmarks = xpath.getODFElementsWithXPath(odffragment, "//text:bookmark-start[@text:name='" + url + "']", odf.Namespaces.lookupNamespaceURI);
-           if(bookmarks.length === 0) {
-             bookmarks = xpath.getODFElementsWithXPath(odffragment, "//text:bookmark[@text:name='" + url + "']", odf.Namespaces.lookupNamespaceURI)
-           }
-           if(bookmarks.length > 0) {
-             bookmarks[0].scrollIntoView(true)
-           }
-           return false
-         }
-       }else {
-         clickHandler = function() {
-           window.open(url)
-         }
-       }
-       node.onclick = clickHandler
-     }
-     links = odffragment.getElementsByTagNameNS(textns, "a");
-     for(i = 0;i < links.length;i += 1) {
-       node = (links.item(i));
-       modifyLink(node)
-     }
-   }
-   function modifyLineBreakElements(odffragment) {
-     var document = odffragment.ownerDocument, lineBreakElements = domUtils.getElementsByTagNameNS(odffragment, textns, "line-break");
-     lineBreakElements.forEach(function(lineBreak) {
-       if(!lineBreak.hasChildNodes()) {
-         lineBreak.appendChild(document.createElement("br"))
-       }
-     })
-   }
-   function expandSpaceElements(odffragment) {
-     var spaces, doc = odffragment.ownerDocument;
-     function expandSpaceElement(space) {
-       var j, count;
-       while(space.firstChild) {
-         space.removeChild(space.firstChild)
-       }
-       space.appendChild(doc.createTextNode(" "));
-       count = parseInt(space.getAttributeNS(textns, "c"), 10);
-       if(count > 1) {
-         space.removeAttributeNS(textns, "c");
-         for(j = 1;j < count;j += 1) {
-           space.parentNode.insertBefore(space.cloneNode(true), space)
++      sizer.style.WebkitTransformOrigin = "0% 0%";
++      sizer.style.MozTransformOrigin = "0% 0%";
++      sizer.style.msTransformOrigin = "0% 0%";
++      sizer.style.OTransformOrigin = "0% 0%";
++      sizer.style.transformOrigin = "0% 0%";
++      if(annotationViewManager) {
++        minHeight = annotationViewManager.getMinimumHeightForAnnotationPane();
++        if(minHeight) {
++          sizer.style.minHeight = minHeight
++        }else {
++          sizer.style.removeProperty("min-height")
 +        }
 +      }
++      element.style.width = Math.round(zoomLevel * sizer.offsetWidth) + "px";
++      element.style.height = Math.round(zoomLevel * sizer.offsetHeight) + "px"
 +    }
-     spaces = domUtils.getElementsByTagNameNS(odffragment, textns, "s");
-     spaces.forEach(expandSpaceElement)
-   }
-   function expandTabElements(odffragment) {
-     var tabs;
-     tabs = domUtils.getElementsByTagNameNS(odffragment, textns, "tab");
-     tabs.forEach(function(tab) {
-       tab.textContent = "\t"
-     })
-   }
-   function modifyDrawElements(odfbody, stylesheet) {
-     var node, drawElements = [], i;
-     node = odfbody.firstElementChild;
-     while(node && node !== odfbody) {
-       if(node.namespaceURI === drawns) {
-         drawElements[drawElements.length] = node
++    function redrawContainer() {
++      if(shouldRefreshCss) {
++        handleStyles(odfcontainer, formatting, stylesxmlcss);
++        shouldRefreshCss = false
 +      }
-       if(node.firstElementChild) {
-         node = node.firstElementChild
-       }else {
-         while(node && (node !== odfbody && !node.nextElementSibling)) {
-           node = node.parentElement
-         }
-         if(node && node.nextElementSibling) {
-           node = node.nextElementSibling
++      if(shouldRerenderAnnotations) {
++        if(annotationViewManager) {
++          annotationViewManager.rerenderAnnotations()
 +        }
++        shouldRerenderAnnotations = false
 +      }
++      fixContainerSize()
 +    }
-     for(i = 0;i < drawElements.length;i += 1) {
-       node = drawElements[i];
-       setDrawElementPosition("frame" + String(i), node, stylesheet)
++    function handleContent(container, odfnode) {
++      var css = (positioncss.sheet);
++      clear(element);
++      sizer = (doc.createElementNS(element.namespaceURI, "div"));
++      sizer.style.display = "inline-block";
++      sizer.style.background = "white";
++      sizer.style.setProperty("float", "left", "important");
++      sizer.appendChild(odfnode);
++      element.appendChild(sizer);
++      annotationsPane = (doc.createElementNS(element.namespaceURI, "div"));
++      annotationsPane.id = "annotationsPane";
++      shadowContent = doc.createElementNS(element.namespaceURI, "div");
++      shadowContent.id = "shadowContent";
++      shadowContent.style.position = "absolute";
++      shadowContent.style.top = 0;
++      shadowContent.style.left = 0;
++      container.getContentElement().appendChild(shadowContent);
++      modifyDrawElements(odfnode.body, css);
++      cloneMasterPages(container, shadowContent, odfnode.body, css);
++      modifyTables(odfnode.body, element.namespaceURI);
++      modifyLineBreakElements(odfnode.body);
++      expandSpaceElements(odfnode.body);
++      expandTabElements(odfnode.body);
++      loadImages(container, odfnode.body, css);
++      loadVideos(container, odfnode.body);
++      loadLists(odfnode.body, css, element.namespaceURI);
++      sizer.insertBefore(shadowContent, sizer.firstChild);
++      zoomHelper.setZoomableElement(sizer)
 +    }
-     formatParagraphAnchors(odfbody)
-   }
-   function cloneMasterPages(odfContainer, shadowContent, odfbody, stylesheet) {
-     var masterPageName, masterPageElement, styleId, clonedPageElement, clonedElement, pageNumber = 0, i, element, elementToClone, document = odfContainer.rootElement.ownerDocument;
-     element = odfbody.firstElementChild;
-     if(!(element && (element.namespaceURI === officens && (element.localName === "presentation" || element.localName === "drawing")))) {
-       return
++    function modifyAnnotations(odffragment) {
++      var annotationNodes = (domUtils.getElementsByTagNameNS(odffragment, officens, "annotation"));
++      annotationNodes.forEach(annotationViewManager.addAnnotation);
++      annotationViewManager.rerenderAnnotations()
 +    }
-     element = element.firstElementChild;
-     while(element) {
-       masterPageName = element.getAttributeNS(drawns, "master-page-name");
-       masterPageElement = getMasterPageElement(odfContainer, masterPageName);
-       if(masterPageElement) {
-         styleId = element.getAttributeNS(webodfhelperns, "styleid");
-         clonedPageElement = document.createElementNS(drawns, "draw:page");
-         elementToClone = masterPageElement.firstElementChild;
-         i = 0;
-         while(elementToClone) {
-           if(elementToClone.getAttributeNS(presentationns, "placeholder") !== "true") {
-             clonedElement = (elementToClone.cloneNode(true));
-             clonedPageElement.appendChild(clonedElement);
-             setDrawElementPosition(styleId + "_" + i, clonedElement, stylesheet)
-           }
-           elementToClone = elementToClone.nextElementSibling;
-           i += 1
++    function handleAnnotations(odfnode) {
++      if(allowAnnotations) {
++        if(!annotationsPane.parentNode) {
++          sizer.appendChild(annotationsPane)
 +        }
-         dropTemplateDrawFrames(clonedPageElement);
-         shadowContent.appendChild(clonedPageElement);
-         pageNumber = String(shadowContent.getElementsByTagNameNS(drawns, "page").length);
-         setContainerValue(clonedPageElement, textns, "page-number", pageNumber);
-         setContainerValue(clonedPageElement, presentationns, "header", getHeaderFooter(odfContainer, (element), "header"));
-         setContainerValue(clonedPageElement, presentationns, "footer", getHeaderFooter(odfContainer, (element), "footer"));
-         setDrawElementPosition(styleId, clonedPageElement, stylesheet);
-         clonedPageElement.setAttributeNS(drawns, "draw:master-page-name", masterPageElement.getAttributeNS(stylens, "name"))
-       }
-       element = element.nextElementSibling
-     }
-   }
-   function setVideo(container, plugin) {
-     var video, source, url, doc = plugin.ownerDocument, part;
-     url = plugin.getAttributeNS(xlinkns, "href");
-     function callback(url, mimetype) {
-       var ns = doc.documentElement.namespaceURI;
-       if(mimetype.substr(0, 6) === "video/") {
-         video = doc.createElementNS(ns, "video");
-         video.setAttribute("controls", "controls");
-         source = doc.createElementNS(ns, "source");
-         if(url) {
-           source.setAttribute("src", url)
++        if(annotationViewManager) {
++          annotationViewManager.forgetAnnotations()
 +        }
-         source.setAttribute("type", mimetype);
-         video.appendChild(source);
-         plugin.parentNode.appendChild(video)
++        annotationViewManager = new gui.AnnotationViewManager(self, odfnode.body, annotationsPane, showAnnotationRemoveButton);
++        modifyAnnotations(odfnode.body);
++        fixContainerSize()
 +      }else {
-         plugin.innerHtml = "Unrecognised Plugin"
-       }
-     }
-     function onchange(p) {
-       callback(p.url, p.mimetype)
-     }
-     if(url) {
-       try {
-         part = container.getPart(url);
-         part.onchange = onchange;
-         part.load()
-       }catch(e) {
-         runtime.log("slight problem: " + String(e))
++        if(annotationsPane.parentNode) {
++          sizer.removeChild(annotationsPane);
++          annotationViewManager.forgetAnnotations();
++          fixContainerSize()
++        }
 +      }
-     }else {
-       runtime.log("using MP4 data fallback");
-       url = getUrlFromBinaryDataElement(plugin);
-       callback(url, "video/mp4")
 +    }
-   }
-   function getNumberRule(node) {
-     var style = node.getAttributeNS(stylens, "num-format"), suffix = node.getAttributeNS(stylens, "num-suffix") || "", prefix = node.getAttributeNS(stylens, "num-prefix") || "", rule = "", stylemap = {1:"decimal", "a":"lower-latin", "A":"upper-latin", "i":"lower-roman", "I":"upper-roman"}, content;
-     content = prefix;
-     if(stylemap.hasOwnProperty(style)) {
-       content += " counter(list, " + stylemap[style] + ")"
-     }else {
-       if(style) {
-         content += "'" + style + "';"
-       }else {
-         content += " ''"
++    function refreshOdf(suppressEvent) {
++      function callback() {
++        clearCSSStyleSheet(fontcss);
++        clearCSSStyleSheet(stylesxmlcss);
++        clearCSSStyleSheet(positioncss);
++        clear(element);
++        element.style.display = "inline-block";
++        var odfnode = odfcontainer.rootElement;
++        element.ownerDocument.importNode(odfnode, true);
++        formatting.setOdfContainer(odfcontainer);
++        handleFonts(odfcontainer, fontcss);
++        handleStyles(odfcontainer, formatting, stylesxmlcss);
++        handleContent(odfcontainer, odfnode);
++        handleAnnotations(odfnode);
++        if(!suppressEvent) {
++          fireEvent("statereadychange", [odfcontainer])
++        }
 +      }
-     }
-     if(suffix) {
-       content += " '" + suffix + "'"
-     }
-     rule = "content: " + content + ";";
-     return rule
-   }
-   function getImageRule() {
-     var rule = "content: none;";
-     return rule
-   }
-   function getBulletRule(node) {
-     var bulletChar = node.getAttributeNS(textns, "bullet-char");
-     return"content: '" + bulletChar + "';"
-   }
-   function getBulletsRule(node) {
-     var itemrule;
-     if(node) {
-       if(node.localName === "list-level-style-number") {
-         itemrule = getNumberRule(node)
++      if(odfcontainer.state === odf.OdfContainer.DONE) {
++        callback()
 +      }else {
-         if(node.localName === "list-level-style-image") {
-           itemrule = getImageRule()
-         }else {
-           if(node.localName === "list-level-style-bullet") {
-             itemrule = getBulletRule(node)
++        runtime.log("WARNING: refreshOdf called but ODF was not DONE.");
++        waitingForDoneTimeoutId = runtime.setTimeout(function later_cb() {
++          if(odfcontainer.state === odf.OdfContainer.DONE) {
++            callback()
++          }else {
++            runtime.log("will be back later...");
++            waitingForDoneTimeoutId = runtime.setTimeout(later_cb, 500)
 +          }
-         }
++        }, 100)
 +      }
 +    }
-     return itemrule
-   }
-   function loadLists(odffragment, stylesheet, documentns) {
-     var i, lists, node, id, continueList, styleName, rule, listMap = {}, parentList, listStyles, listStyleMap = {}, bulletRule;
-     listStyles = window.document.getElementsByTagNameNS(textns, "list-style");
-     for(i = 0;i < listStyles.length;i += 1) {
-       node = (listStyles.item(i));
-       styleName = node.getAttributeNS(stylens, "name");
-       if(styleName) {
-         listStyleMap[styleName] = node
-       }
-     }
-     lists = odffragment.getElementsByTagNameNS(textns, "list");
-     for(i = 0;i < lists.length;i += 1) {
-       node = (lists.item(i));
-       id = node.getAttributeNS(xmlns, "id");
-       if(id) {
-         continueList = node.getAttributeNS(textns, "continue-list");
-         node.setAttributeNS(documentns, "id", id);
-         rule = "text|list#" + id + " > text|list-item > *:first-child:before {";
-         styleName = node.getAttributeNS(textns, "style-name");
-         if(styleName) {
-           node = listStyleMap[styleName];
-           bulletRule = getBulletsRule((odfUtils.getFirstNonWhitespaceChild(node)))
-         }
-         if(continueList) {
-           parentList = listMap[continueList];
-           while(parentList) {
-             parentList = listMap[parentList]
-           }
-           rule += "counter-increment:" + continueList + ";";
-           if(bulletRule) {
-             bulletRule = bulletRule.replace("list", continueList);
-             rule += bulletRule
-           }else {
-             rule += "content:counter(" + continueList + ");"
-           }
-         }else {
-           continueList = "";
-           if(bulletRule) {
-             bulletRule = bulletRule.replace("list", id);
-             rule += bulletRule
-           }else {
-             rule += "content: counter(" + id + ");"
-           }
-           rule += "counter-increment:" + id + ";";
-           stylesheet.insertRule("text|list#" + id + " {counter-reset:" + id + "}", stylesheet.cssRules.length)
-         }
-         rule += "}";
-         listMap[id] = continueList;
-         if(rule) {
-           stylesheet.insertRule(rule, stylesheet.cssRules.length)
-         }
-       }
-     }
-   }
-   function addWebODFStyleSheet(document) {
-     var head = (document.getElementsByTagName("head")[0]), style, href;
-     if(String(typeof webodf_css) !== "undefined") {
-       style = document.createElementNS(head.namespaceURI, "style");
-       style.setAttribute("media", "screen, print, handheld, projection");
-       style.appendChild(document.createTextNode(webodf_css))
-     }else {
-       style = document.createElementNS(head.namespaceURI, "link");
-       href = "webodf.css";
-       if(runtime.currentDirectory) {
-         href = runtime.currentDirectory() + "/../" + href
-       }
-       style.setAttribute("href", href);
-       style.setAttribute("rel", "stylesheet")
-     }
-     style.setAttribute("type", "text/css");
-     head.appendChild(style);
-     return(style)
-   }
-   function addStyleSheet(document) {
-     var head = (document.getElementsByTagName("head")[0]), style = document.createElementNS(head.namespaceURI, "style"), text = "";
-     style.setAttribute("type", "text/css");
-     style.setAttribute("media", "screen, print, handheld, projection");
-     odf.Namespaces.forEachPrefix(function(prefix, ns) {
-       text += "@namespace " + prefix + " url(" + ns + ");\n"
-     });
-     text += "@namespace webodfhelper url(" + webodfhelperns + ");\n";
-     style.appendChild(document.createTextNode(text));
-     head.appendChild(style);
-     return(style)
-   }
-   odf.OdfCanvas = function OdfCanvas(element) {
-     runtime.assert(element !== null && element !== undefined, "odf.OdfCanvas constructor needs DOM element");
-     runtime.assert(element.ownerDocument !== null && element.ownerDocument !== undefined, "odf.OdfCanvas constructor needs DOM");
-     var self = this, doc = (element.ownerDocument), odfcontainer, formatting = new odf.Formatting, pageSwitcher, sizer = null, annotationsPane = null, allowAnnotations = false, annotationViewManager = null, webodfcss, fontcss, stylesxmlcss, positioncss, shadowContent, zoomLevel = 1, eventHandlers = {}, loadingQueue = new LoadingQueue;
-     function loadImages(container, odffragment, stylesheet) {
-       var i, images, node;
-       function loadImage(name, container, node, stylesheet) {
-         loadingQueue.addToQueue(function() {
-           setImage(name, container, node, stylesheet)
-         })
-       }
-       images = odffragment.getElementsByTagNameNS(drawns, "image");
-       for(i = 0;i < images.length;i += 1) {
-         node = (images.item(i));
-         loadImage("image" + String(i), container, node, stylesheet)
-       }
-     }
-     function loadVideos(container, odffragment) {
-       var i, plugins, node;
-       function loadVideo(container, node) {
-         loadingQueue.addToQueue(function() {
-           setVideo(container, node)
-         })
-       }
-       plugins = odffragment.getElementsByTagNameNS(drawns, "plugin");
-       for(i = 0;i < plugins.length;i += 1) {
-         node = (plugins.item(i));
-         loadVideo(container, node)
-       }
-     }
-     function addEventListener(eventType, eventHandler) {
-       var handlers;
-       if(eventHandlers.hasOwnProperty(eventType)) {
-         handlers = eventHandlers[eventType]
-       }else {
-         handlers = eventHandlers[eventType] = []
-       }
-       if(eventHandler && handlers.indexOf(eventHandler) === -1) {
-         handlers.push(eventHandler)
-       }
-     }
-     function fireEvent(eventType, args) {
-       if(!eventHandlers.hasOwnProperty(eventType)) {
-         return
-       }
-       var handlers = eventHandlers[eventType], i;
-       for(i = 0;i < handlers.length;i += 1) {
-         handlers[i].apply(null, args)
-       }
-     }
-     function fixContainerSize() {
-       var odfdoc = sizer.firstChild;
-       if(!odfdoc) {
-         return
-       }
-       if(zoomLevel > 1) {
-         sizer.style.MozTransformOrigin = "center top";
-         sizer.style.WebkitTransformOrigin = "center top";
-         sizer.style.OTransformOrigin = "center top";
-         sizer.style.msTransformOrigin = "center top"
-       }else {
-         sizer.style.MozTransformOrigin = "left top";
-         sizer.style.WebkitTransformOrigin = "left top";
-         sizer.style.OTransformOrigin = "left top";
-         sizer.style.msTransformOrigin = "left top"
-       }
-       sizer.style.WebkitTransform = "scale(" + zoomLevel + ")";
-       sizer.style.MozTransform = "scale(" + zoomLevel + ")";
-       sizer.style.OTransform = "scale(" + zoomLevel + ")";
-       sizer.style.msTransform = "scale(" + zoomLevel + ")";
-       element.style.width = Math.round(zoomLevel * sizer.offsetWidth) + "px";
-       element.style.height = Math.round(zoomLevel * sizer.offsetHeight) + "px"
-     }
-     function handleContent(container, odfnode) {
-       var css = (positioncss.sheet);
-       clear(element);
-       sizer = (doc.createElementNS(element.namespaceURI, "div"));
-       sizer.style.display = "inline-block";
-       sizer.style.background = "white";
-       sizer.appendChild(odfnode);
-       element.appendChild(sizer);
-       annotationsPane = (doc.createElementNS(element.namespaceURI, "div"));
-       annotationsPane.id = "annotationsPane";
-       shadowContent = doc.createElementNS(element.namespaceURI, "div");
-       shadowContent.id = "shadowContent";
-       shadowContent.style.position = "absolute";
-       shadowContent.style.top = 0;
-       shadowContent.style.left = 0;
-       container.getContentElement().appendChild(shadowContent);
-       modifyDrawElements(odfnode.body, css);
-       cloneMasterPages(container, shadowContent, odfnode.body, css);
-       modifyTables(odfnode.body, element.namespaceURI);
-       modifyLinks(odfnode.body);
-       modifyLineBreakElements(odfnode.body);
-       expandSpaceElements(odfnode.body);
-       expandTabElements(odfnode.body);
-       loadImages(container, odfnode.body, css);
-       loadVideos(container, odfnode.body);
-       loadLists(odfnode.body, css, element.namespaceURI);
-       sizer.insertBefore(shadowContent, sizer.firstChild);
-       fixContainerSize()
-     }
-     function modifyAnnotations(odffragment) {
-       var annotationNodes = domUtils.getElementsByTagNameNS(odffragment, officens, "annotation"), annotationEnds = domUtils.getElementsByTagNameNS(odffragment, officens, "annotation-end"), currentAnnotationName, i;
-       function matchAnnotationEnd(element) {
-         return currentAnnotationName === element.getAttributeNS(officens, "name")
-       }
-       for(i = 0;i < annotationNodes.length;i += 1) {
-         currentAnnotationName = annotationNodes[i].getAttributeNS(officens, "name");
-         annotationViewManager.addAnnotation({node:annotationNodes[i], end:annotationEnds.filter(matchAnnotationEnd)[0] || null})
-       }
-       annotationViewManager.rerenderAnnotations()
-     }
-     function handleAnnotations(odfnode) {
-       if(allowAnnotations) {
-         if(!annotationsPane.parentNode) {
-           sizer.appendChild(annotationsPane);
-           fixContainerSize()
-         }
-         if(annotationViewManager) {
-           annotationViewManager.forgetAnnotations()
-         }
-         annotationViewManager = new gui.AnnotationViewManager(self, odfnode.body, annotationsPane);
-         modifyAnnotations(odfnode.body)
-       }else {
-         if(annotationsPane.parentNode) {
-           sizer.removeChild(annotationsPane);
-           annotationViewManager.forgetAnnotations();
-           fixContainerSize()
-         }
-       }
-     }
-     function refreshOdf(suppressEvent) {
-       function callback() {
-         clear(element);
-         element.style.display = "inline-block";
-         var odfnode = odfcontainer.rootElement;
-         element.ownerDocument.importNode(odfnode, true);
-         formatting.setOdfContainer(odfcontainer);
-         handleFonts(odfcontainer, fontcss);
-         handleStyles(odfcontainer, formatting, stylesxmlcss);
-         handleContent(odfcontainer, odfnode);
-         handleAnnotations(odfnode);
-         if(!suppressEvent) {
-           fireEvent("statereadychange", [odfcontainer])
-         }
-       }
-       if(odfcontainer.state === odf.OdfContainer.DONE) {
-         callback()
-       }else {
-         runtime.log("WARNING: refreshOdf called but ODF was not DONE.");
-         runtime.setTimeout(function later_cb() {
-           if(odfcontainer.state === odf.OdfContainer.DONE) {
-             callback()
-           }else {
-             runtime.log("will be back later...");
-             runtime.setTimeout(later_cb, 500)
-           }
-         }, 100)
-       }
-     }
-     this.refreshCSS = function() {
-       handleStyles(odfcontainer, formatting, stylesxmlcss);
-       fixContainerSize()
-     };
-     this.refreshSize = function() {
-       fixContainerSize()
-     };
-     this.odfContainer = function() {
-       return odfcontainer
-     };
-     this.setOdfContainer = function(container, suppressEvent) {
-       odfcontainer = container;
-       refreshOdf(suppressEvent === true)
-     };
-     function load(url) {
-       loadingQueue.clearQueue();
-       element.innerHTML = runtime.tr("Loading") + " " + url + "...";
-       element.removeAttribute("style");
-       odfcontainer = new odf.OdfContainer(url, function(container) {
-         odfcontainer = container;
-         refreshOdf(false)
-       })
++    this.refreshCSS = function() {
++      shouldRefreshCss = true;
++      redrawContainerTask.trigger()
++    };
++    this.refreshSize = function() {
++      redrawContainerTask.trigger()
++    };
++    this.odfContainer = function() {
++      return odfcontainer
++    };
++    this.setOdfContainer = function(container, suppressEvent) {
++      odfcontainer = container;
++      refreshOdf(suppressEvent === true)
++    };
++    function load(url) {
++      loadingQueue.clearQueue();
++      element.innerHTML = runtime.tr("Loading") + " " + url + "...";
++      element.removeAttribute("style");
++      odfcontainer = new odf.OdfContainer(url, function(container) {
++        odfcontainer = container;
++        refreshOdf(false)
++      })
 +    }
 +    this["load"] = load;
 +    this.load = load;
 +    this.save = function(callback) {
 +      odfcontainer.save(callback)
 +    };
 +    this.addListener = function(eventName, handler) {
 +      switch(eventName) {
 +        case "click":
 +          listenEvent(element, eventName, handler);
 +          break;
 +        default:
 +          addEventListener(eventName, handler);
 +          break
 +      }
 +    };
 +    this.getFormatting = function() {
 +      return formatting
 +    };
 +    this.getAnnotationViewManager = function() {
 +      return annotationViewManager
 +    };
 +    this.refreshAnnotations = function() {
 +      handleAnnotations(odfcontainer.rootElement)
 +    };
 +    this.rerenderAnnotations = function() {
 +      if(annotationViewManager) {
-         annotationViewManager.rerenderAnnotations()
++        shouldRerenderAnnotations = true;
++        redrawContainerTask.trigger()
 +      }
 +    };
 +    this.getSizer = function() {
-       return sizer
++      return(sizer)
 +    };
-     this.enableAnnotations = function(allow) {
++    this.enableAnnotations = function(allow, showRemoveButton) {
 +      if(allow !== allowAnnotations) {
 +        allowAnnotations = allow;
++        showAnnotationRemoveButton = showRemoveButton;
 +        if(odfcontainer) {
 +          handleAnnotations(odfcontainer.rootElement)
 +        }
 +      }
 +    };
 +    this.addAnnotation = function(annotation) {
 +      if(annotationViewManager) {
-         annotationViewManager.addAnnotation(annotation)
++        annotationViewManager.addAnnotation(annotation);
++        fixContainerSize()
 +      }
 +    };
 +    this.forgetAnnotations = function() {
 +      if(annotationViewManager) {
-         annotationViewManager.forgetAnnotations()
++        annotationViewManager.forgetAnnotations();
++        fixContainerSize()
 +      }
 +    };
++    this.getZoomHelper = function() {
++      return zoomHelper
++    };
 +    this.setZoomLevel = function(zoom) {
-       zoomLevel = zoom;
-       fixContainerSize()
++      zoomHelper.setZoomLevel(zoom)
 +    };
 +    this.getZoomLevel = function() {
-       return zoomLevel
++      return zoomHelper.getZoomLevel()
 +    };
 +    this.fitToContainingElement = function(width, height) {
-       var realWidth = element.offsetWidth / zoomLevel, realHeight = element.offsetHeight / zoomLevel;
-       zoomLevel = width / realWidth;
-       if(height / realHeight < zoomLevel) {
-         zoomLevel = height / realHeight
++      var zoomLevel = zoomHelper.getZoomLevel(), realWidth = element.offsetWidth / zoomLevel, realHeight = element.offsetHeight / zoomLevel, zoom;
++      zoom = width / realWidth;
++      if(height / realHeight < zoom) {
++        zoom = height / realHeight
 +      }
-       fixContainerSize()
++      zoomHelper.setZoomLevel(zoom)
 +    };
 +    this.fitToWidth = function(width) {
-       var realWidth = element.offsetWidth / zoomLevel;
-       zoomLevel = width / realWidth;
-       fixContainerSize()
++      var realWidth = element.offsetWidth / zoomHelper.getZoomLevel();
++      zoomHelper.setZoomLevel(width / realWidth)
 +    };
 +    this.fitSmart = function(width, height) {
-       var realWidth, realHeight, newScale;
++      var realWidth, realHeight, newScale, zoomLevel = zoomHelper.getZoomLevel();
 +      realWidth = element.offsetWidth / zoomLevel;
 +      realHeight = element.offsetHeight / zoomLevel;
 +      newScale = width / realWidth;
 +      if(height !== undefined) {
 +        if(height / realHeight < newScale) {
 +          newScale = height / realHeight
 +        }
 +      }
-       zoomLevel = Math.min(1, newScale);
-       fixContainerSize()
++      zoomHelper.setZoomLevel(Math.min(1, newScale))
 +    };
 +    this.fitToHeight = function(height) {
-       var realHeight = element.offsetHeight / zoomLevel;
-       zoomLevel = height / realHeight;
-       fixContainerSize()
++      var realHeight = element.offsetHeight / zoomHelper.getZoomLevel();
++      zoomHelper.setZoomLevel(height / realHeight)
 +    };
 +    this.showFirstPage = function() {
 +      pageSwitcher.showFirstPage()
 +    };
 +    this.showNextPage = function() {
 +      pageSwitcher.showNextPage()
 +    };
 +    this.showPreviousPage = function() {
 +      pageSwitcher.showPreviousPage()
 +    };
 +    this.showPage = function(n) {
 +      pageSwitcher.showPage(n);
 +      fixContainerSize()
 +    };
 +    this.getElement = function() {
 +      return element
 +    };
 +    this.addCssForFrameWithImage = function(frame) {
 +      var frameName = frame.getAttributeNS(drawns, "name"), fc = frame.firstElementChild;
 +      setDrawElementPosition(frameName, frame, (positioncss.sheet));
 +      if(fc) {
 +        setImage(frameName + "img", odfcontainer, fc, (positioncss.sheet))
 +      }
 +    };
 +    this.destroy = function(callback) {
-       var head = (doc.getElementsByTagName("head")[0]);
++      var head = (doc.getElementsByTagName("head")[0]), cleanup = [pageSwitcher.destroy, redrawContainerTask.destroy];
++      runtime.clearTimeout(waitingForDoneTimeoutId);
 +      if(annotationsPane && annotationsPane.parentNode) {
 +        annotationsPane.parentNode.removeChild(annotationsPane)
 +      }
-       if(sizer) {
-         element.removeChild(sizer);
-         sizer = null
-       }
-       head.removeChild(webodfcss);
++      zoomHelper.destroy(function() {
++        if(sizer) {
++          element.removeChild(sizer);
++          sizer = null
++        }
++      });
++      removeWebODFStyleSheet(webodfcss);
 +      head.removeChild(fontcss);
 +      head.removeChild(stylesxmlcss);
 +      head.removeChild(positioncss);
-       pageSwitcher.destroy(callback)
++      async.destroyAll(cleanup, callback)
 +    };
 +    function init() {
 +      webodfcss = addWebODFStyleSheet(doc);
 +      pageSwitcher = new PageSwitcher(addStyleSheet(doc));
 +      fontcss = addStyleSheet(doc);
 +      stylesxmlcss = addStyleSheet(doc);
-       positioncss = addStyleSheet(doc)
++      positioncss = addStyleSheet(doc);
++      redrawContainerTask = new core.ScheduledTask(redrawContainer, 0);
++      zoomHelper.subscribe(gui.ZoomHelper.signalZoomChanged, fixContainerSize)
 +    }
 +    init()
 +  }
 +})();
 +/*
 +
-  Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
++ Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
-  The JavaScript code in this page is free software: you can redistribute it
-  and/or modify it under the terms of the GNU Affero General Public License
-  (GNU AGPL) as published by the Free Software Foundation, either version 3 of
-  the License, or (at your option) any later version.  The code is distributed
-  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
++ This file is part of WebODF.
 +
-  You should have received a copy of the GNU Affero General Public License
-  along with this code.  If not, see <http://www.gnu.org/licenses/>.
++ WebODF is free software: you can redistribute it and/or modify it
++ under the terms of the GNU Affero General Public License (GNU AGPL)
++ as published by the Free Software Foundation, either version 3 of
++ the License, or (at your option) any later version.
 +
-  As additional permission under GNU AGPL version 3 section 7, you
-  may distribute non-source (e.g., minimized or compacted) forms of
-  that code without the copy of the GNU GPL normally required by
-  section 4, provided you include this license notice and a URL
-  through which recipients can access the Corresponding Source.
++ WebODF is distributed in the hope that it will be useful, but
++ WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ GNU Affero General Public License for more details.
 +
-  As a special exception to the AGPL, any HTML file which merely makes function
-  calls to this code, and for that purpose includes it by reference shall be
-  deemed a separate work for copyright law purposes. In addition, the copyright
-  holders of this code give you permission to combine this code with free
-  software libraries that are released under the GNU LGPL. You may copy and
-  distribute such a system following the terms of the GNU AGPL for this code
-  and the LGPL for the libraries. If you modify this code, you may extend this
-  exception to your version of the code, but you are not obligated to do so.
-  If you do not wish to do so, delete this exception statement from your
-  version.
- 
-  This license applies to this entire compilation.
++ You should have received a copy of the GNU Affero General Public License
++ along with WebODF.  If not, see <http://www.gnu.org/licenses/>.
 + @licend
++
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("core.DomUtils");
- runtime.loadClass("core.LoopWatchDog");
- runtime.loadClass("odf.Namespaces");
- odf.TextStyleApplicator = function TextStyleApplicator(objectNameGenerator, formatting, automaticStyles) {
-   var domUtils = new core.DomUtils, textns = odf.Namespaces.textns, stylens = odf.Namespaces.stylens, textProperties = "style:text-properties", webodfns = "urn:webodf:names:scope";
-   function StyleLookup(info) {
-     function compare(expected, actual) {
-       if(typeof expected === "object" && typeof actual === "object") {
-         return Object.keys(expected).every(function(key) {
-           return compare(expected[key], actual[key])
-         })
-       }
-       return expected === actual
-     }
-     this.isStyleApplied = function(textNode) {
-       var appliedStyle = formatting.getAppliedStylesForElement(textNode);
-       return compare(info, appliedStyle)
-     }
++ops.MemberProperties = function() {
++  this.fullName;
++  this.color;
++  this.imageUrl
++};
++ops.Member = function Member(memberId, properties) {
++  var props = new ops.MemberProperties;
++  function getMemberId() {
++    return memberId
 +  }
-   function StyleManager(info) {
-     var createdStyles = {};
-     function createDirectFormat(existingStyleName, document) {
-       var derivedStyleInfo, derivedStyleNode;
-       derivedStyleInfo = existingStyleName ? formatting.createDerivedStyleObject(existingStyleName, "text", info) : info;
-       derivedStyleNode = document.createElementNS(stylens, "style:style");
-       formatting.updateStyle(derivedStyleNode, derivedStyleInfo);
-       derivedStyleNode.setAttributeNS(stylens, "style:name", objectNameGenerator.generateStyleName());
-       derivedStyleNode.setAttributeNS(stylens, "style:family", "text");
-       derivedStyleNode.setAttributeNS(webodfns, "scope", "document-content");
-       automaticStyles.appendChild(derivedStyleNode);
-       return derivedStyleNode
-     }
-     function getDirectStyle(existingStyleName, document) {
-       existingStyleName = existingStyleName || "";
-       if(!createdStyles.hasOwnProperty(existingStyleName)) {
-         createdStyles[existingStyleName] = createDirectFormat(existingStyleName, document)
-       }
-       return createdStyles[existingStyleName].getAttributeNS(stylens, "name")
-     }
-     this.applyStyleToContainer = function(container) {
-       var name = getDirectStyle(container.getAttributeNS(textns, "style-name"), container.ownerDocument);
-       container.setAttributeNS(textns, "text:style-name", name)
-     }
++  function getProperties() {
++    return props
 +  }
-   function isTextSpan(node) {
-     return node.localName === "span" && node.namespaceURI === textns
++  function setProperties(newProperties) {
++    Object.keys(newProperties).forEach(function(key) {
++      props[key] = newProperties[key]
++    })
 +  }
-   function moveToNewSpan(startNode, limits) {
-     var document = startNode.ownerDocument, originalContainer = (startNode.parentNode), styledContainer, trailingContainer, moveTrailing, node, nextNode, loopGuard = new core.LoopWatchDog(1E4), styledNodes = [];
-     if(!isTextSpan(originalContainer)) {
-       styledContainer = document.createElementNS(textns, "text:span");
-       originalContainer.insertBefore(styledContainer, startNode);
-       moveTrailing = false
-     }else {
-       if(startNode.previousSibling && !domUtils.rangeContainsNode(limits, (originalContainer.firstChild))) {
-         styledContainer = originalContainer.cloneNode(false);
-         originalContainer.parentNode.insertBefore(styledContainer, originalContainer.nextSibling);
-         moveTrailing = true
-       }else {
-         styledContainer = originalContainer;
-         moveTrailing = true
++  function removeProperties(removedProperties) {
++    Object.keys(removedProperties).forEach(function(key) {
++      if(key !== "fullName" && (key !== "color" && (key !== "imageUrl" && props.hasOwnProperty(key)))) {
++        delete props[key]
 +      }
++    })
++  }
++  this.getMemberId = getMemberId;
++  this.getProperties = getProperties;
++  this.setProperties = setProperties;
++  this.removeProperties = removeProperties;
++  function init() {
++    runtime.assert(Boolean(memberId), "No memberId was supplied!");
++    if(!properties.fullName) {
++      properties.fullName = runtime.tr("Unknown Author")
 +    }
-     styledNodes.push(startNode);
-     node = startNode.nextSibling;
-     while(node && domUtils.rangeContainsNode(limits, node)) {
-       loopGuard.check();
-       styledNodes.push(node);
-       node = node.nextSibling
-     }
-     styledNodes.forEach(function(n) {
-       if(n.parentNode !== styledContainer) {
-         styledContainer.appendChild(n)
-       }
-     });
-     if(node && moveTrailing) {
-       trailingContainer = styledContainer.cloneNode(false);
-       styledContainer.parentNode.insertBefore(trailingContainer, styledContainer.nextSibling);
-       while(node) {
-         loopGuard.check();
-         nextNode = node.nextSibling;
-         trailingContainer.appendChild(node);
-         node = nextNode
-       }
++    if(!properties.color) {
++      properties.color = "black"
 +    }
-     return(styledContainer)
-   }
-   this.applyStyle = function(textNodes, limits, info) {
-     var textPropsOnly = {}, isStyled, container, styleCache, styleLookup;
-     runtime.assert(info && info.hasOwnProperty(textProperties), "applyStyle without any text properties");
-     textPropsOnly[textProperties] = info[textProperties];
-     styleCache = new StyleManager(textPropsOnly);
-     styleLookup = new StyleLookup(textPropsOnly);
-     function apply(n) {
-       isStyled = styleLookup.isStyleApplied(n);
-       if(isStyled === false) {
-         container = moveToNewSpan(n, limits);
-         styleCache.applyStyleToContainer(container)
-       }
++    if(!properties.imageUrl) {
++      properties.imageUrl = "avatar-joe.png"
 +    }
-     textNodes.forEach(apply)
++    props = properties
 +  }
++  init()
 +};
 +/*
 +
 + Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("odf.Namespaces");
- runtime.loadClass("odf.OdfUtils");
- gui.StyleHelper = function StyleHelper(formatting) {
-   var odfUtils = new odf.OdfUtils, textns = odf.Namespaces.textns;
-   function getAppliedStyles(range) {
-     var container, nodes;
-     if(range.collapsed) {
-       container = range.startContainer;
-       if(container.hasChildNodes() && range.startOffset < container.childNodes.length) {
-         container = container.childNodes.item(range.startOffset)
-       }
-       nodes = [container]
-     }else {
-       nodes = odfUtils.getTextNodes(range, true)
-     }
-     return formatting.getAppliedStyles(nodes)
++gui.StepCounter;
++gui.SelectionMover = function SelectionMover(cursor, rootNode) {
++  var odfUtils = new odf.OdfUtils, positionIterator, FILTER_ACCEPT = core.PositionFilter.FilterResult.FILTER_ACCEPT;
++  function getIteratorAtCursor() {
++    positionIterator.setUnfilteredPosition(cursor.getNode(), 0);
++    return positionIterator
 +  }
-   this.getAppliedStyles = getAppliedStyles;
-   function hasTextPropertyValue(appliedStyles, propertyName, propertyValue) {
-     var hasOtherValue = true, properties, i;
-     for(i = 0;i < appliedStyles.length;i += 1) {
-       properties = appliedStyles[i]["style:text-properties"];
-       hasOtherValue = !properties || properties[propertyName] !== propertyValue;
-       if(hasOtherValue) {
-         break
-       }
++  function getMaximumNodePosition(node) {
++    return node.nodeType === Node.TEXT_NODE ? node.textContent.length : node.childNodes.length
++  }
++  function getClientRect(clientRectangles, useRightEdge) {
++    var rectangle, simplifiedRectangle = null;
++    if(clientRectangles && clientRectangles.length > 0) {
++      rectangle = useRightEdge ? clientRectangles.item(clientRectangles.length - 1) : clientRectangles.item(0)
++    }
++    if(rectangle) {
++      simplifiedRectangle = {top:rectangle.top, left:useRightEdge ? rectangle.right : rectangle.left, bottom:rectangle.bottom}
 +    }
-     return!hasOtherValue
++    return simplifiedRectangle
 +  }
-   this.isBold = function(appliedStyles) {
-     return hasTextPropertyValue(appliedStyles, "fo:font-weight", "bold")
-   };
-   this.isItalic = function(appliedStyles) {
-     return hasTextPropertyValue(appliedStyles, "fo:font-style", "italic")
-   };
-   this.hasUnderline = function(appliedStyles) {
-     return hasTextPropertyValue(appliedStyles, "style:text-underline-style", "solid")
-   };
-   this.hasStrikeThrough = function(appliedStyles) {
-     return hasTextPropertyValue(appliedStyles, "style:text-line-through-style", "solid")
-   };
-   function hasParagraphPropertyValue(range, propertyName, propertyValues) {
-     var paragraphStyleName, paragraphStyleElement, paragraphStyleAttributes, properties, nodes = odfUtils.getParagraphElements(range), isStyleChecked = {}, isDefaultParagraphStyleChecked = false;
-     function pickDefaultParagraphStyleElement() {
-       isDefaultParagraphStyleChecked = true;
-       paragraphStyleElement = formatting.getDefaultStyleElement("paragraph");
-       if(!paragraphStyleElement) {
-         paragraphStyleElement = null
-       }
++  function getVisibleRect(container, offset, range, useRightEdge) {
++    var rectangle, nodeType = container.nodeType;
++    range.setStart(container, offset);
++    range.collapse(!useRightEdge);
++    rectangle = getClientRect(range.getClientRects(), useRightEdge === true);
++    if(!rectangle && offset > 0) {
++      range.setStart(container, offset - 1);
++      range.setEnd(container, offset);
++      rectangle = getClientRect(range.getClientRects(), true)
 +    }
-     while(nodes.length > 0) {
-       paragraphStyleName = nodes[0].getAttributeNS(textns, "style-name");
-       if(paragraphStyleName) {
-         if(!isStyleChecked[paragraphStyleName]) {
-           paragraphStyleElement = formatting.getStyleElement(paragraphStyleName, "paragraph");
-           isStyleChecked[paragraphStyleName] = true;
-           if(!paragraphStyleElement && !isDefaultParagraphStyleChecked) {
-             pickDefaultParagraphStyleElement()
-           }
-         }
++    if(!rectangle) {
++      if(nodeType === Node.ELEMENT_NODE && (offset > 0 && (container).childNodes.length >= offset)) {
++        rectangle = getVisibleRect(container, offset - 1, range, true)
 +      }else {
-         if(!isDefaultParagraphStyleChecked) {
-           pickDefaultParagraphStyleElement()
++        if(container.nodeType === Node.TEXT_NODE && offset > 0) {
++          rectangle = getVisibleRect(container, offset - 1, range, true)
 +        }else {
-           paragraphStyleElement = undefined
++          if(container.previousSibling) {
++            rectangle = getVisibleRect(container.previousSibling, getMaximumNodePosition(container.previousSibling), range, true)
++          }else {
++            if(container.parentNode && container.parentNode !== rootNode) {
++              rectangle = getVisibleRect(container.parentNode, 0, range, false)
++            }else {
++              range.selectNode(rootNode);
++              rectangle = getClientRect(range.getClientRects(), false)
++            }
++          }
 +        }
 +      }
-       if(paragraphStyleElement !== undefined) {
-         if(paragraphStyleElement === null) {
-           paragraphStyleAttributes = formatting.getSystemDefaultStyleAttributes("paragraph")
-         }else {
-           paragraphStyleAttributes = formatting.getInheritedStyleAttributes((paragraphStyleElement), true)
-         }
-         properties = paragraphStyleAttributes["style:paragraph-properties"];
-         if(properties && propertyValues.indexOf(properties[propertyName]) === -1) {
-           return false
++    }
++    runtime.assert(Boolean(rectangle), "No visible rectangle found");
++    return(rectangle)
++  }
++  function convertForwardStepsBetweenFilters(stepsFilter1, filter1, filter2) {
++    var iterator = getIteratorAtCursor(), watch = new core.LoopWatchDog(1E4), pendingStepsFilter2 = 0, stepsFilter2 = 0;
++    while(stepsFilter1 > 0 && iterator.nextPosition()) {
++      watch.check();
++      if(filter2.acceptPosition(iterator) === FILTER_ACCEPT) {
++        pendingStepsFilter2 += 1;
++        if(filter1.acceptPosition(iterator) === FILTER_ACCEPT) {
++          stepsFilter2 += pendingStepsFilter2;
++          pendingStepsFilter2 = 0;
++          stepsFilter1 -= 1
 +        }
 +      }
-       nodes.pop()
 +    }
-     return true
-   }
-   this.isAlignedLeft = function(range) {
-     return hasParagraphPropertyValue(range, "fo:text-align", ["left", "start"])
-   };
-   this.isAlignedCenter = function(range) {
-     return hasParagraphPropertyValue(range, "fo:text-align", ["center"])
-   };
-   this.isAlignedRight = function(range) {
-     return hasParagraphPropertyValue(range, "fo:text-align", ["right", "end"])
-   };
-   this.isAlignedJustified = function(range) {
-     return hasParagraphPropertyValue(range, "fo:text-align", ["justify"])
++    return stepsFilter2
 +  }
- };
- core.RawDeflate = function() {
-   var zip_WSIZE = 32768, zip_STORED_BLOCK = 0, zip_STATIC_TREES = 1, zip_DYN_TREES = 2, zip_DEFAULT_LEVEL = 6, zip_FULL_SEARCH = true, zip_INBUFSIZ = 32768, zip_INBUF_EXTRA = 64, zip_OUTBUFSIZ = 1024 * 8, zip_window_size = 2 * zip_WSIZE, zip_MIN_MATCH = 3, zip_MAX_MATCH = 258, zip_BITS = 16, zip_LIT_BUFSIZE = 8192, zip_HASH_BITS = 13, zip_DIST_BUFSIZE = zip_LIT_BUFSIZE, zip_HASH_SIZE = 1 << zip_HASH_BITS, zip_HASH_MASK = zip_HASH_SIZE - 1, zip_WMASK = zip_WSIZE - 1, zip_NIL = 0, zip_TOO [...]
-   zip_MIN_LOOKAHEAD = zip_MAX_MATCH + zip_MIN_MATCH + 1, zip_MAX_DIST = zip_WSIZE - zip_MIN_LOOKAHEAD, zip_SMALLEST = 1, zip_MAX_BITS = 15, zip_MAX_BL_BITS = 7, zip_LENGTH_CODES = 29, zip_LITERALS = 256, zip_END_BLOCK = 256, zip_L_CODES = zip_LITERALS + 1 + zip_LENGTH_CODES, zip_D_CODES = 30, zip_BL_CODES = 19, zip_REP_3_6 = 16, zip_REPZ_3_10 = 17, zip_REPZ_11_138 = 18, zip_HEAP_SIZE = 2 * zip_L_CODES + 1, zip_H_SHIFT = parseInt((zip_HASH_BITS + zip_MIN_MATCH - 1) / zip_MIN_MATCH, 10),  [...]
-   zip_qhead, zip_qtail, zip_initflag, zip_outbuf = null, zip_outcnt, zip_outoff, zip_complete, zip_window, zip_d_buf, zip_l_buf, zip_prev, zip_bi_buf, zip_bi_valid, zip_block_start, zip_ins_h, zip_hash_head, zip_prev_match, zip_match_available, zip_match_length, zip_prev_length, zip_strstart, zip_match_start, zip_eofile, zip_lookahead, zip_max_chain_length, zip_max_lazy_match, zip_compr_level, zip_good_match, zip_nice_match, zip_dyn_ltree, zip_dyn_dtree, zip_static_ltree, zip_static_dtr [...]
-   zip_l_desc, zip_d_desc, zip_bl_desc, zip_bl_count, zip_heap, zip_heap_len, zip_heap_max, zip_depth, zip_length_code, zip_dist_code, zip_base_length, zip_base_dist, zip_flag_buf, zip_last_lit, zip_last_dist, zip_last_flags, zip_flags, zip_flag_bit, zip_opt_len, zip_static_len, zip_deflate_data, zip_deflate_pos, zip_extra_lbits = [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0], zip_extra_dbits = [0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7,  [...]
-   9, 10, 10, 11, 11, 12, 12, 13, 13], zip_extra_blbits = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7], zip_bl_order = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15], zip_configuration_table;
-   if(zip_LIT_BUFSIZE > zip_INBUFSIZ) {
-     runtime.log("error: zip_INBUFSIZ is too small")
-   }
-   if(zip_WSIZE << 1 > 1 << zip_BITS) {
-     runtime.log("error: zip_WSIZE is too large")
-   }
-   if(zip_HASH_BITS > zip_BITS - 1) {
-     runtime.log("error: zip_HASH_BITS is too large")
-   }
-   if(zip_HASH_BITS < 8 || zip_MAX_MATCH !== 258) {
-     runtime.log("error: Code too clever")
-   }
-   function Zip_DeflateCT() {
-     this.fc = 0;
-     this.dl = 0
-   }
-   function Zip_DeflateTreeDesc() {
-     this.dyn_tree = null;
-     this.static_tree = null;
-     this.extra_bits = null;
-     this.extra_base = 0;
-     this.elems = 0;
-     this.max_length = 0;
-     this.max_code = 0
-   }
-   function Zip_DeflateConfiguration(a, b, c, d) {
-     this.good_length = a;
-     this.max_lazy = b;
-     this.nice_length = c;
-     this.max_chain = d
-   }
-   function Zip_DeflateBuffer() {
-     this.next = null;
-     this.len = 0;
-     this.ptr = [];
-     this.ptr.length = zip_OUTBUFSIZ;
-     this.off = 0
-   }
-   zip_configuration_table = [new Zip_DeflateConfiguration(0, 0, 0, 0), new Zip_DeflateConfiguration(4, 4, 8, 4), new Zip_DeflateConfiguration(4, 5, 16, 8), new Zip_DeflateConfiguration(4, 6, 32, 32), new Zip_DeflateConfiguration(4, 4, 16, 16), new Zip_DeflateConfiguration(8, 16, 32, 32), new Zip_DeflateConfiguration(8, 16, 128, 128), new Zip_DeflateConfiguration(8, 32, 128, 256), new Zip_DeflateConfiguration(32, 128, 258, 1024), new Zip_DeflateConfiguration(32, 258, 258, 4096)];
-   function zip_deflate_start(level) {
-     var i;
-     if(!level) {
-       level = zip_DEFAULT_LEVEL
-     }else {
-       if(level < 1) {
-         level = 1
-       }else {
-         if(level > 9) {
-           level = 9
++  function convertBackwardStepsBetweenFilters(stepsFilter1, filter1, filter2) {
++    var iterator = getIteratorAtCursor(), watch = new core.LoopWatchDog(1E4), pendingStepsFilter2 = 0, stepsFilter2 = 0;
++    while(stepsFilter1 > 0 && iterator.previousPosition()) {
++      watch.check();
++      if(filter2.acceptPosition(iterator) === FILTER_ACCEPT) {
++        pendingStepsFilter2 += 1;
++        if(filter1.acceptPosition(iterator) === FILTER_ACCEPT) {
++          stepsFilter2 += pendingStepsFilter2;
++          pendingStepsFilter2 = 0;
++          stepsFilter1 -= 1
 +        }
 +      }
 +    }
-     zip_compr_level = level;
-     zip_initflag = false;
-     zip_eofile = false;
-     if(zip_outbuf !== null) {
-       return
++    return stepsFilter2
++  }
++  function countLineSteps(filter, direction, iterator) {
++    var c = iterator.container(), steps = 0, bestContainer = null, bestOffset, bestXDiff = 10, xDiff, bestCount = 0, top, left, lastTop, rect, range = (rootNode.ownerDocument.createRange()), watch = new core.LoopWatchDog(1E4);
++    rect = getVisibleRect(c, iterator.unfilteredDomOffset(), range);
++    top = rect.top;
++    left = rect.left;
++    lastTop = top;
++    while((direction < 0 ? iterator.previousPosition() : iterator.nextPosition()) === true) {
++      watch.check();
++      if(filter.acceptPosition(iterator) === FILTER_ACCEPT) {
++        steps += 1;
++        c = iterator.container();
++        rect = getVisibleRect(c, iterator.unfilteredDomOffset(), range);
++        if(rect.top !== top) {
++          if(rect.top !== lastTop && lastTop !== top) {
++            break
++          }
++          lastTop = rect.top;
++          xDiff = Math.abs(left - rect.left);
++          if(bestContainer === null || xDiff < bestXDiff) {
++            bestContainer = c;
++            bestOffset = iterator.unfilteredDomOffset();
++            bestXDiff = xDiff;
++            bestCount = steps
++          }
++        }
++      }
 +    }
-     zip_free_queue = zip_qhead = zip_qtail = null;
-     zip_outbuf = [];
-     zip_outbuf.length = zip_OUTBUFSIZ;
-     zip_window = [];
-     zip_window.length = zip_window_size;
-     zip_d_buf = [];
-     zip_d_buf.length = zip_DIST_BUFSIZE;
-     zip_l_buf = [];
-     zip_l_buf.length = zip_INBUFSIZ + zip_INBUF_EXTRA;
-     zip_prev = [];
-     zip_prev.length = 1 << zip_BITS;
-     zip_dyn_ltree = [];
-     zip_dyn_ltree.length = zip_HEAP_SIZE;
-     for(i = 0;i < zip_HEAP_SIZE;i++) {
-       zip_dyn_ltree[i] = new Zip_DeflateCT
-     }
-     zip_dyn_dtree = [];
-     zip_dyn_dtree.length = 2 * zip_D_CODES + 1;
-     for(i = 0;i < 2 * zip_D_CODES + 1;i++) {
-       zip_dyn_dtree[i] = new Zip_DeflateCT
-     }
-     zip_static_ltree = [];
-     zip_static_ltree.length = zip_L_CODES + 2;
-     for(i = 0;i < zip_L_CODES + 2;i++) {
-       zip_static_ltree[i] = new Zip_DeflateCT
-     }
-     zip_static_dtree = [];
-     zip_static_dtree.length = zip_D_CODES;
-     for(i = 0;i < zip_D_CODES;i++) {
-       zip_static_dtree[i] = new Zip_DeflateCT
-     }
-     zip_bl_tree = [];
-     zip_bl_tree.length = 2 * zip_BL_CODES + 1;
-     for(i = 0;i < 2 * zip_BL_CODES + 1;i++) {
-       zip_bl_tree[i] = new Zip_DeflateCT
-     }
-     zip_l_desc = new Zip_DeflateTreeDesc;
-     zip_d_desc = new Zip_DeflateTreeDesc;
-     zip_bl_desc = new Zip_DeflateTreeDesc;
-     zip_bl_count = [];
-     zip_bl_count.length = zip_MAX_BITS + 1;
-     zip_heap = [];
-     zip_heap.length = 2 * zip_L_CODES + 1;
-     zip_depth = [];
-     zip_depth.length = 2 * zip_L_CODES + 1;
-     zip_length_code = [];
-     zip_length_code.length = zip_MAX_MATCH - zip_MIN_MATCH + 1;
-     zip_dist_code = [];
-     zip_dist_code.length = 512;
-     zip_base_length = [];
-     zip_base_length.length = zip_LENGTH_CODES;
-     zip_base_dist = [];
-     zip_base_dist.length = zip_D_CODES;
-     zip_flag_buf = [];
-     zip_flag_buf.length = parseInt(zip_LIT_BUFSIZE / 8, 10)
-   }
-   var zip_reuse_queue = function(p) {
-     p.next = zip_free_queue;
-     zip_free_queue = p
-   };
-   var zip_new_queue = function() {
-     var p;
-     if(zip_free_queue !== null) {
-       p = zip_free_queue;
-       zip_free_queue = zip_free_queue.next
++    if(bestContainer !== null) {
++      iterator.setUnfilteredPosition(bestContainer, (bestOffset));
++      steps = bestCount
 +    }else {
-       p = new Zip_DeflateBuffer
++      steps = 0
 +    }
-     p.next = null;
-     p.len = p.off = 0;
-     return p
-   };
-   var zip_head1 = function(i) {
-     return zip_prev[zip_WSIZE + i]
-   };
-   var zip_head2 = function(i, val) {
-     zip_prev[zip_WSIZE + i] = val;
-     return val
-   };
-   var zip_qoutbuf = function() {
-     var q, i;
-     if(zip_outcnt !== 0) {
-       q = zip_new_queue();
-       if(zip_qhead === null) {
-         zip_qhead = zip_qtail = q
-       }else {
-         zip_qtail = zip_qtail.next = q
-       }
-       q.len = zip_outcnt - zip_outoff;
-       for(i = 0;i < q.len;i++) {
-         q.ptr[i] = zip_outbuf[zip_outoff + i]
++    range.detach();
++    return steps
++  }
++  function countLinesSteps(lines, filter) {
++    var iterator = getIteratorAtCursor(), stepCount = 0, steps = 0, direction = lines < 0 ? -1 : 1;
++    lines = Math.abs(lines);
++    while(lines > 0) {
++      stepCount += countLineSteps(filter, direction, iterator);
++      if(stepCount === 0) {
++        break
 +      }
-       zip_outcnt = zip_outoff = 0
-     }
-   };
-   var zip_put_byte = function(c) {
-     zip_outbuf[zip_outoff + zip_outcnt++] = c;
-     if(zip_outoff + zip_outcnt === zip_OUTBUFSIZ) {
-       zip_qoutbuf()
++      steps += stepCount;
++      lines -= 1
 +    }
-   };
-   var zip_put_short = function(w) {
-     w &= 65535;
-     if(zip_outoff + zip_outcnt < zip_OUTBUFSIZ - 2) {
-       zip_outbuf[zip_outoff + zip_outcnt++] = w & 255;
-       zip_outbuf[zip_outoff + zip_outcnt++] = w >>> 8
-     }else {
-       zip_put_byte(w & 255);
-       zip_put_byte(w >>> 8)
-     }
-   };
-   var zip_INSERT_STRING = function() {
-     zip_ins_h = (zip_ins_h << zip_H_SHIFT ^ zip_window[zip_strstart + zip_MIN_MATCH - 1] & 255) & zip_HASH_MASK;
-     zip_hash_head = zip_head1(zip_ins_h);
-     zip_prev[zip_strstart & zip_WMASK] = zip_hash_head;
-     zip_head2(zip_ins_h, zip_strstart)
-   };
-   var zip_Buf_size = 16;
-   var zip_send_bits = function(value, length) {
-     if(zip_bi_valid > zip_Buf_size - length) {
-       zip_bi_buf |= value << zip_bi_valid;
-       zip_put_short(zip_bi_buf);
-       zip_bi_buf = value >> zip_Buf_size - zip_bi_valid;
-       zip_bi_valid += length - zip_Buf_size
++    return steps * direction
++  }
++  function countStepsToLineBoundary(direction, filter) {
++    var fnNextPos, increment, lastRect, rect, onSameLine, iterator = getIteratorAtCursor(), paragraphNode = odfUtils.getParagraphElement(iterator.getCurrentNode()), steps = 0, range = (rootNode.ownerDocument.createRange());
++    if(direction < 0) {
++      fnNextPos = iterator.previousPosition;
++      increment = -1
 +    }else {
-       zip_bi_buf |= value << zip_bi_valid;
-       zip_bi_valid += length
-     }
-   };
-   var zip_SEND_CODE = function(c, tree) {
-     zip_send_bits(tree[c].fc, tree[c].dl)
-   };
-   var zip_D_CODE = function(dist) {
-     return(dist < 256 ? zip_dist_code[dist] : zip_dist_code[256 + (dist >> 7)]) & 255
-   };
-   var zip_SMALLER = function(tree, n, m) {
-     return tree[n].fc < tree[m].fc || tree[n].fc === tree[m].fc && zip_depth[n] <= zip_depth[m]
-   };
-   var zip_read_buff = function(buff, offset, n) {
-     var i;
-     for(i = 0;i < n && zip_deflate_pos < zip_deflate_data.length;i++) {
-       buff[offset + i] = zip_deflate_data.charCodeAt(zip_deflate_pos++) & 255
++      fnNextPos = iterator.nextPosition;
++      increment = 1
 +    }
-     return i
-   };
-   var zip_fill_window = function() {
-     var n, m;
-     var more = zip_window_size - zip_lookahead - zip_strstart;
-     if(more === -1) {
-       more--
-     }else {
-       if(zip_strstart >= zip_WSIZE + zip_MAX_DIST) {
-         for(n = 0;n < zip_WSIZE;n++) {
-           zip_window[n] = zip_window[n + zip_WSIZE]
-         }
-         zip_match_start -= zip_WSIZE;
-         zip_strstart -= zip_WSIZE;
-         zip_block_start -= zip_WSIZE;
-         for(n = 0;n < zip_HASH_SIZE;n++) {
-           m = zip_head1(n);
-           zip_head2(n, m >= zip_WSIZE ? m - zip_WSIZE : zip_NIL)
++    lastRect = getVisibleRect(iterator.container(), iterator.unfilteredDomOffset(), range);
++    while(fnNextPos.call(iterator)) {
++      if(filter.acceptPosition(iterator) === FILTER_ACCEPT) {
++        if(odfUtils.getParagraphElement(iterator.getCurrentNode()) !== paragraphNode) {
++          break
 +        }
-         for(n = 0;n < zip_WSIZE;n++) {
-           m = zip_prev[n];
-           zip_prev[n] = m >= zip_WSIZE ? m - zip_WSIZE : zip_NIL
++        rect = getVisibleRect(iterator.container(), iterator.unfilteredDomOffset(), range);
++        if(rect.bottom !== lastRect.bottom) {
++          onSameLine = rect.top >= lastRect.top && rect.bottom < lastRect.bottom || rect.top <= lastRect.top && rect.bottom > lastRect.bottom;
++          if(!onSameLine) {
++            break
++          }
 +        }
-         more += zip_WSIZE
++        steps += increment;
++        lastRect = rect
 +      }
 +    }
-     if(!zip_eofile) {
-       n = zip_read_buff(zip_window, zip_strstart + zip_lookahead, more);
-       if(n <= 0) {
-         zip_eofile = true
-       }else {
-         zip_lookahead += n
++    range.detach();
++    return steps
++  }
++  this.getStepCounter = function() {
++    return{convertForwardStepsBetweenFilters:convertForwardStepsBetweenFilters, convertBackwardStepsBetweenFilters:convertBackwardStepsBetweenFilters, countLinesSteps:countLinesSteps, countStepsToLineBoundary:countStepsToLineBoundary}
++  };
++  function init() {
++    positionIterator = gui.SelectionMover.createPositionIterator(rootNode);
++    var range = rootNode.ownerDocument.createRange();
++    range.setStart(positionIterator.container(), positionIterator.unfilteredDomOffset());
++    range.collapse(true);
++    cursor.setSelectedRange(range)
++  }
++  init()
++};
++gui.SelectionMover.createPositionIterator = function(rootNode) {
++  function CursorFilter() {
++    this.acceptNode = function(node) {
++      if(!node || (node.namespaceURI === "urn:webodf:names:cursor" || node.namespaceURI === "urn:webodf:names:editinfo")) {
++        return NodeFilter.FILTER_REJECT
 +      }
++      return NodeFilter.FILTER_ACCEPT
 +    }
++  }
++  var filter = new CursorFilter;
++  return new core.PositionIterator(rootNode, 5, filter, false)
++};
++(function() {
++  return gui.SelectionMover
++})();
++/*
++
++ Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
++
++ @licstart
++ The JavaScript code in this page is free software: you can redistribute it
++ and/or modify it under the terms of the GNU Affero General Public License
++ (GNU AGPL) as published by the Free Software Foundation, either version 3 of
++ the License, or (at your option) any later version.  The code is distributed
++ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
++
++ You should have received a copy of the GNU Affero General Public License
++ along with this code.  If not, see <http://www.gnu.org/licenses/>.
++
++ As additional permission under GNU AGPL version 3 section 7, you
++ may distribute non-source (e.g., minimized or compacted) forms of
++ that code without the copy of the GNU GPL normally required by
++ section 4, provided you include this license notice and a URL
++ through which recipients can access the Corresponding Source.
++
++ As a special exception to the AGPL, any HTML file which merely makes function
++ calls to this code, and for that purpose includes it by reference shall be
++ deemed a separate work for copyright law purposes. In addition, the copyright
++ holders of this code give you permission to combine this code with free
++ software libraries that are released under the GNU LGPL. You may copy and
++ distribute such a system following the terms of the GNU AGPL for this code
++ and the LGPL for the libraries. If you modify this code, you may extend this
++ exception to your version of the code, but you are not obligated to do so.
++ If you do not wish to do so, delete this exception statement from your
++ version.
++
++ This license applies to this entire compilation.
++ @licend
++ @source: http://www.webodf.org/
++ @source: https://github.com/kogmbh/WebODF/
++*/
++ops.Document = function Document() {
++};
++ops.Document.prototype.getMemberIds = function() {
++};
++ops.Document.prototype.removeCursor = function(memberid) {
++};
++ops.Document.prototype.getDocumentElement = function() {
++};
++ops.Document.prototype.getRootNode = function() {
++};
++ops.Document.prototype.getDOMDocument = function() {
++};
++ops.Document.prototype.cloneDocumentElement = function() {
++};
++ops.Document.prototype.setDocumentElement = function(element) {
++};
++ops.Document.prototype.subscribe = function(eventid, cb) {
++};
++ops.Document.prototype.unsubscribe = function(eventid, cb) {
++};
++ops.Document.prototype.getCanvas = function() {
++};
++ops.Document.prototype.createRootFilter = function(inputMemberId) {
++};
++ops.Document.signalCursorAdded = "cursor/added";
++ops.Document.signalCursorRemoved = "cursor/removed";
++ops.Document.signalCursorMoved = "cursor/moved";
++ops.Document.signalMemberAdded = "member/added";
++ops.Document.signalMemberUpdated = "member/updated";
++ops.Document.signalMemberRemoved = "member/removed";
++ops.OdtCursor = function OdtCursor(memberId, document) {
++  var self = this, validSelectionTypes = {}, selectionType, selectionMover, cursor, events = new core.EventNotifier([ops.OdtCursor.signalCursorUpdated]);
++  this.removeFromDocument = function() {
++    cursor.remove()
 +  };
-   var zip_lm_init = function() {
-     var j;
-     for(j = 0;j < zip_HASH_SIZE;j++) {
-       zip_prev[zip_WSIZE + j] = 0
-     }
-     zip_max_lazy_match = zip_configuration_table[zip_compr_level].max_lazy;
-     zip_good_match = zip_configuration_table[zip_compr_level].good_length;
-     if(!zip_FULL_SEARCH) {
-       zip_nice_match = zip_configuration_table[zip_compr_level].nice_length
-     }
-     zip_max_chain_length = zip_configuration_table[zip_compr_level].max_chain;
-     zip_strstart = 0;
-     zip_block_start = 0;
-     zip_lookahead = zip_read_buff(zip_window, 0, 2 * zip_WSIZE);
-     if(zip_lookahead <= 0) {
-       zip_eofile = true;
-       zip_lookahead = 0;
-       return
-     }
-     zip_eofile = false;
-     while(zip_lookahead < zip_MIN_LOOKAHEAD && !zip_eofile) {
-       zip_fill_window()
-     }
-     zip_ins_h = 0;
-     for(j = 0;j < zip_MIN_MATCH - 1;j++) {
-       zip_ins_h = (zip_ins_h << zip_H_SHIFT ^ zip_window[j] & 255) & zip_HASH_MASK
-     }
++  this.subscribe = function(eventid, cb) {
++    events.subscribe(eventid, cb)
 +  };
-   var zip_longest_match = function(cur_match) {
-     var chain_length = zip_max_chain_length;
-     var scanp = zip_strstart;
-     var matchp;
-     var len;
-     var best_len = zip_prev_length;
-     var limit = zip_strstart > zip_MAX_DIST ? zip_strstart - zip_MAX_DIST : zip_NIL;
-     var strendp = zip_strstart + zip_MAX_MATCH;
-     var scan_end1 = zip_window[scanp + best_len - 1];
-     var scan_end = zip_window[scanp + best_len];
-     if(zip_prev_length >= zip_good_match) {
-       chain_length >>= 2
-     }
-     do {
-       matchp = cur_match;
-       if(zip_window[matchp + best_len] !== scan_end || (zip_window[matchp + best_len - 1] !== scan_end1 || (zip_window[matchp] !== zip_window[scanp] || zip_window[++matchp] !== zip_window[scanp + 1]))) {
-         continue
-       }
-       scanp += 2;
-       matchp++;
-       do {
-         ++scanp
-       }while(zip_window[scanp] === zip_window[++matchp] && (zip_window[++scanp] === zip_window[++matchp] && (zip_window[++scanp] === zip_window[++matchp] && (zip_window[++scanp] === zip_window[++matchp] && (zip_window[++scanp] === zip_window[++matchp] && (zip_window[++scanp] === zip_window[++matchp] && (zip_window[++scanp] === zip_window[++matchp] && (zip_window[++scanp] === zip_window[++matchp] && scanp < strendp))))))));
-       len = zip_MAX_MATCH - (strendp - scanp);
-       scanp = strendp - zip_MAX_MATCH;
-       if(len > best_len) {
-         zip_match_start = cur_match;
-         best_len = len;
-         if(zip_FULL_SEARCH) {
-           if(len >= zip_MAX_MATCH) {
-             break
-           }
-         }else {
-           if(len >= zip_nice_match) {
-             break
-           }
-         }
-         scan_end1 = zip_window[scanp + best_len - 1];
-         scan_end = zip_window[scanp + best_len]
-       }
-       cur_match = zip_prev[cur_match & zip_WMASK]
-     }while(cur_match > limit && --chain_length !== 0);
-     return best_len
++  this.unsubscribe = function(eventid, cb) {
++    events.unsubscribe(eventid, cb)
 +  };
-   var zip_ct_tally = function(dist, lc) {
-     zip_l_buf[zip_last_lit++] = lc;
-     if(dist === 0) {
-       zip_dyn_ltree[lc].fc++
-     }else {
-       dist--;
-       zip_dyn_ltree[zip_length_code[lc] + zip_LITERALS + 1].fc++;
-       zip_dyn_dtree[zip_D_CODE(dist)].fc++;
-       zip_d_buf[zip_last_dist++] = dist;
-       zip_flags |= zip_flag_bit
-     }
-     zip_flag_bit <<= 1;
-     if((zip_last_lit & 7) === 0) {
-       zip_flag_buf[zip_last_flags++] = zip_flags;
-       zip_flags = 0;
-       zip_flag_bit = 1
-     }
-     if(zip_compr_level > 2 && (zip_last_lit & 4095) === 0) {
-       var out_length = zip_last_lit * 8;
-       var in_length = zip_strstart - zip_block_start;
-       var dcode;
-       for(dcode = 0;dcode < zip_D_CODES;dcode++) {
-         out_length += zip_dyn_dtree[dcode].fc * (5 + zip_extra_dbits[dcode])
-       }
-       out_length >>= 3;
-       if(zip_last_dist < parseInt(zip_last_lit / 2, 10) && out_length < parseInt(in_length / 2, 10)) {
-         return true
-       }
-     }
-     return zip_last_lit === zip_LIT_BUFSIZE - 1 || zip_last_dist === zip_DIST_BUFSIZE
++  this.getStepCounter = function() {
++    return selectionMover.getStepCounter()
 +  };
-   var zip_pqdownheap = function(tree, k) {
-     var v = zip_heap[k];
-     var j = k << 1;
-     while(j <= zip_heap_len) {
-       if(j < zip_heap_len && zip_SMALLER(tree, zip_heap[j + 1], zip_heap[j])) {
-         j++
-       }
-       if(zip_SMALLER(tree, v, zip_heap[j])) {
-         break
-       }
-       zip_heap[k] = zip_heap[j];
-       k = j;
-       j <<= 1
-     }
-     zip_heap[k] = v
++  this.getMemberId = function() {
++    return memberId
 +  };
-   var zip_gen_bitlen = function(desc) {
-     var tree = desc.dyn_tree;
-     var extra = desc.extra_bits;
-     var base = desc.extra_base;
-     var max_code = desc.max_code;
-     var max_length = desc.max_length;
-     var stree = desc.static_tree;
-     var h;
-     var n, m;
-     var bits;
-     var xbits;
-     var f;
-     var overflow = 0;
-     for(bits = 0;bits <= zip_MAX_BITS;bits++) {
-       zip_bl_count[bits] = 0
-     }
-     tree[zip_heap[zip_heap_max]].dl = 0;
-     for(h = zip_heap_max + 1;h < zip_HEAP_SIZE;h++) {
-       n = zip_heap[h];
-       bits = tree[tree[n].dl].dl + 1;
-       if(bits > max_length) {
-         bits = max_length;
-         overflow++
-       }
-       tree[n].dl = bits;
-       if(n > max_code) {
-         continue
-       }
-       zip_bl_count[bits]++;
-       xbits = 0;
-       if(n >= base) {
-         xbits = extra[n - base]
-       }
-       f = tree[n].fc;
-       zip_opt_len += f * (bits + xbits);
-       if(stree !== null) {
-         zip_static_len += f * (stree[n].dl + xbits)
-       }
-     }
-     if(overflow === 0) {
-       return
-     }
-     do {
-       bits = max_length - 1;
-       while(zip_bl_count[bits] === 0) {
-         bits--
-       }
-       zip_bl_count[bits]--;
-       zip_bl_count[bits + 1] += 2;
-       zip_bl_count[max_length]--;
-       overflow -= 2
-     }while(overflow > 0);
-     for(bits = max_length;bits !== 0;bits--) {
-       n = zip_bl_count[bits];
-       while(n !== 0) {
-         m = zip_heap[--h];
-         if(m > max_code) {
-           continue
-         }
-         if(tree[m].dl !== bits) {
-           zip_opt_len += (bits - tree[m].dl) * tree[m].fc;
-           tree[m].fc = bits
-         }
-         n--
-       }
-     }
++  this.getNode = function() {
++    return cursor.getNode()
 +  };
-   var zip_bi_reverse = function(code, len) {
-     var res = 0;
-     do {
-       res |= code & 1;
-       code >>= 1;
-       res <<= 1
-     }while(--len > 0);
-     return res >> 1
-   };
-   var zip_gen_codes = function(tree, max_code) {
-     var next_code = [];
-     next_code.length = zip_MAX_BITS + 1;
-     var code = 0;
-     var bits;
-     var n;
-     for(bits = 1;bits <= zip_MAX_BITS;bits++) {
-       code = code + zip_bl_count[bits - 1] << 1;
-       next_code[bits] = code
-     }
-     var len;
-     for(n = 0;n <= max_code;n++) {
-       len = tree[n].dl;
-       if(len === 0) {
-         continue
-       }
-       tree[n].fc = zip_bi_reverse(next_code[len]++, len)
-     }
-   };
-   var zip_build_tree = function(desc) {
-     var tree = desc.dyn_tree;
-     var stree = desc.static_tree;
-     var elems = desc.elems;
-     var n, m;
-     var max_code = -1;
-     var node = elems;
-     zip_heap_len = 0;
-     zip_heap_max = zip_HEAP_SIZE;
-     for(n = 0;n < elems;n++) {
-       if(tree[n].fc !== 0) {
-         zip_heap[++zip_heap_len] = max_code = n;
-         zip_depth[n] = 0
-       }else {
-         tree[n].dl = 0
-       }
-     }
-     var xnew;
-     while(zip_heap_len < 2) {
-       xnew = zip_heap[++zip_heap_len] = max_code < 2 ? ++max_code : 0;
-       tree[xnew].fc = 1;
-       zip_depth[xnew] = 0;
-       zip_opt_len--;
-       if(stree !== null) {
-         zip_static_len -= stree[xnew].dl
-       }
-     }
-     desc.max_code = max_code;
-     for(n = zip_heap_len >> 1;n >= 1;n--) {
-       zip_pqdownheap(tree, n)
-     }
-     do {
-       n = zip_heap[zip_SMALLEST];
-       zip_heap[zip_SMALLEST] = zip_heap[zip_heap_len--];
-       zip_pqdownheap(tree, zip_SMALLEST);
-       m = zip_heap[zip_SMALLEST];
-       zip_heap[--zip_heap_max] = n;
-       zip_heap[--zip_heap_max] = m;
-       tree[node].fc = tree[n].fc + tree[m].fc;
-       if(zip_depth[n] > zip_depth[m] + 1) {
-         zip_depth[node] = zip_depth[n]
-       }else {
-         zip_depth[node] = zip_depth[m] + 1
-       }
-       tree[n].dl = tree[m].dl = node;
-       zip_heap[zip_SMALLEST] = node++;
-       zip_pqdownheap(tree, zip_SMALLEST)
-     }while(zip_heap_len >= 2);
-     zip_heap[--zip_heap_max] = zip_heap[zip_SMALLEST];
-     zip_gen_bitlen(desc);
-     zip_gen_codes(tree, max_code)
++  this.getAnchorNode = function() {
++    return cursor.getAnchorNode()
 +  };
-   var zip_scan_tree = function(tree, max_code) {
-     var n;
-     var prevlen = -1;
-     var curlen;
-     var nextlen = tree[0].dl;
-     var count = 0;
-     var max_count = 7;
-     var min_count = 4;
-     if(nextlen === 0) {
-       max_count = 138;
-       min_count = 3
-     }
-     tree[max_code + 1].dl = 65535;
-     for(n = 0;n <= max_code;n++) {
-       curlen = nextlen;
-       nextlen = tree[n + 1].dl;
-       if(++count < max_count && curlen === nextlen) {
-         continue
-       }
-       if(count < min_count) {
-         zip_bl_tree[curlen].fc += count
-       }else {
-         if(curlen !== 0) {
-           if(curlen !== prevlen) {
-             zip_bl_tree[curlen].fc++
-           }
-           zip_bl_tree[zip_REP_3_6].fc++
-         }else {
-           if(count <= 10) {
-             zip_bl_tree[zip_REPZ_3_10].fc++
-           }else {
-             zip_bl_tree[zip_REPZ_11_138].fc++
-           }
-         }
-       }
-       count = 0;
-       prevlen = curlen;
-       if(nextlen === 0) {
-         max_count = 138;
-         min_count = 3
-       }else {
-         if(curlen === nextlen) {
-           max_count = 6;
-           min_count = 3
-         }else {
-           max_count = 7;
-           min_count = 4
-         }
-       }
-     }
++  this.getSelectedRange = function() {
++    return cursor.getSelectedRange()
 +  };
-   var zip_build_bl_tree = function() {
-     var max_blindex;
-     zip_scan_tree(zip_dyn_ltree, zip_l_desc.max_code);
-     zip_scan_tree(zip_dyn_dtree, zip_d_desc.max_code);
-     zip_build_tree(zip_bl_desc);
-     for(max_blindex = zip_BL_CODES - 1;max_blindex >= 3;max_blindex--) {
-       if(zip_bl_tree[zip_bl_order[max_blindex]].dl !== 0) {
-         break
-       }
-     }
-     zip_opt_len += 3 * (max_blindex + 1) + 5 + 5 + 4;
-     return max_blindex
++  this.setSelectedRange = function(range, isForwardSelection) {
++    cursor.setSelectedRange(range, isForwardSelection);
++    events.emit(ops.OdtCursor.signalCursorUpdated, self)
 +  };
-   var zip_bi_windup = function() {
-     if(zip_bi_valid > 8) {
-       zip_put_short(zip_bi_buf)
-     }else {
-       if(zip_bi_valid > 0) {
-         zip_put_byte(zip_bi_buf)
-       }
-     }
-     zip_bi_buf = 0;
-     zip_bi_valid = 0
-   };
-   var zip_compress_block = function(ltree, dtree) {
-     var dist;
-     var lc;
-     var lx = 0;
-     var dx = 0;
-     var fx = 0;
-     var flag = 0;
-     var code;
-     var extra;
-     if(zip_last_lit !== 0) {
-       do {
-         if((lx & 7) === 0) {
-           flag = zip_flag_buf[fx++]
-         }
-         lc = zip_l_buf[lx++] & 255;
-         if((flag & 1) === 0) {
-           zip_SEND_CODE(lc, ltree)
-         }else {
-           code = zip_length_code[lc];
-           zip_SEND_CODE(code + zip_LITERALS + 1, ltree);
-           extra = zip_extra_lbits[code];
-           if(extra !== 0) {
-             lc -= zip_base_length[code];
-             zip_send_bits(lc, extra)
-           }
-           dist = zip_d_buf[dx++];
-           code = zip_D_CODE(dist);
-           zip_SEND_CODE(code, dtree);
-           extra = zip_extra_dbits[code];
-           if(extra !== 0) {
-             dist -= zip_base_dist[code];
-             zip_send_bits(dist, extra)
-           }
-         }
-         flag >>= 1
-       }while(lx < zip_last_lit)
-     }
-     zip_SEND_CODE(zip_END_BLOCK, ltree)
++  this.hasForwardSelection = function() {
++    return cursor.hasForwardSelection()
 +  };
-   var zip_send_tree = function(tree, max_code) {
-     var n;
-     var prevlen = -1;
-     var curlen;
-     var nextlen = tree[0].dl;
-     var count = 0;
-     var max_count = 7;
-     var min_count = 4;
-     if(nextlen === 0) {
-       max_count = 138;
-       min_count = 3
-     }
-     for(n = 0;n <= max_code;n++) {
-       curlen = nextlen;
-       nextlen = tree[n + 1].dl;
-       if(++count < max_count && curlen === nextlen) {
-         continue
-       }
-       if(count < min_count) {
-         do {
-           zip_SEND_CODE(curlen, zip_bl_tree)
-         }while(--count !== 0)
-       }else {
-         if(curlen !== 0) {
-           if(curlen !== prevlen) {
-             zip_SEND_CODE(curlen, zip_bl_tree);
-             count--
-           }
-           zip_SEND_CODE(zip_REP_3_6, zip_bl_tree);
-           zip_send_bits(count - 3, 2)
-         }else {
-           if(count <= 10) {
-             zip_SEND_CODE(zip_REPZ_3_10, zip_bl_tree);
-             zip_send_bits(count - 3, 3)
-           }else {
-             zip_SEND_CODE(zip_REPZ_11_138, zip_bl_tree);
-             zip_send_bits(count - 11, 7)
-           }
-         }
-       }
-       count = 0;
-       prevlen = curlen;
-       if(nextlen === 0) {
-         max_count = 138;
-         min_count = 3
-       }else {
-         if(curlen === nextlen) {
-           max_count = 6;
-           min_count = 3
-         }else {
-           max_count = 7;
-           min_count = 4
-         }
-       }
-     }
++  this.getDocument = function() {
++    return document
 +  };
-   var zip_send_all_trees = function(lcodes, dcodes, blcodes) {
-     var rank;
-     zip_send_bits(lcodes - 257, 5);
-     zip_send_bits(dcodes - 1, 5);
-     zip_send_bits(blcodes - 4, 4);
-     for(rank = 0;rank < blcodes;rank++) {
-       zip_send_bits(zip_bl_tree[zip_bl_order[rank]].dl, 3)
-     }
-     zip_send_tree(zip_dyn_ltree, lcodes - 1);
-     zip_send_tree(zip_dyn_dtree, dcodes - 1)
++  this.getSelectionType = function() {
++    return selectionType
 +  };
-   var zip_init_block = function() {
-     var n;
-     for(n = 0;n < zip_L_CODES;n++) {
-       zip_dyn_ltree[n].fc = 0
-     }
-     for(n = 0;n < zip_D_CODES;n++) {
-       zip_dyn_dtree[n].fc = 0
-     }
-     for(n = 0;n < zip_BL_CODES;n++) {
-       zip_bl_tree[n].fc = 0
-     }
-     zip_dyn_ltree[zip_END_BLOCK].fc = 1;
-     zip_opt_len = zip_static_len = 0;
-     zip_last_lit = zip_last_dist = zip_last_flags = 0;
-     zip_flags = 0;
-     zip_flag_bit = 1
-   };
-   var zip_flush_block = function(eof) {
-     var opt_lenb, static_lenb;
-     var max_blindex;
-     var stored_len;
-     stored_len = zip_strstart - zip_block_start;
-     zip_flag_buf[zip_last_flags] = zip_flags;
-     zip_build_tree(zip_l_desc);
-     zip_build_tree(zip_d_desc);
-     max_blindex = zip_build_bl_tree();
-     opt_lenb = zip_opt_len + 3 + 7 >> 3;
-     static_lenb = zip_static_len + 3 + 7 >> 3;
-     if(static_lenb <= opt_lenb) {
-       opt_lenb = static_lenb
-     }
-     if(stored_len + 4 <= opt_lenb && zip_block_start >= 0) {
-       var i;
-       zip_send_bits((zip_STORED_BLOCK << 1) + eof, 3);
-       zip_bi_windup();
-       zip_put_short(stored_len);
-       zip_put_short(~stored_len);
-       for(i = 0;i < stored_len;i++) {
-         zip_put_byte(zip_window[zip_block_start + i])
-       }
++  this.setSelectionType = function(value) {
++    if(validSelectionTypes.hasOwnProperty(value)) {
++      selectionType = value
 +    }else {
-       if(static_lenb === opt_lenb) {
-         zip_send_bits((zip_STATIC_TREES << 1) + eof, 3);
-         zip_compress_block(zip_static_ltree, zip_static_dtree)
-       }else {
-         zip_send_bits((zip_DYN_TREES << 1) + eof, 3);
-         zip_send_all_trees(zip_l_desc.max_code + 1, zip_d_desc.max_code + 1, max_blindex + 1);
-         zip_compress_block(zip_dyn_ltree, zip_dyn_dtree)
-       }
-     }
-     zip_init_block();
-     if(eof !== 0) {
-       zip_bi_windup()
++      runtime.log("Invalid selection type: " + value)
 +    }
 +  };
-   var zip_deflate_fast = function() {
-     var flush;
-     while(zip_lookahead !== 0 && zip_qhead === null) {
-       zip_INSERT_STRING();
-       if(zip_hash_head !== zip_NIL && zip_strstart - zip_hash_head <= zip_MAX_DIST) {
-         zip_match_length = zip_longest_match(zip_hash_head);
-         if(zip_match_length > zip_lookahead) {
-           zip_match_length = zip_lookahead
-         }
-       }
-       if(zip_match_length >= zip_MIN_MATCH) {
-         flush = zip_ct_tally(zip_strstart - zip_match_start, zip_match_length - zip_MIN_MATCH);
-         zip_lookahead -= zip_match_length;
-         if(zip_match_length <= zip_max_lazy_match) {
-           zip_match_length--;
-           do {
-             zip_strstart++;
-             zip_INSERT_STRING()
-           }while(--zip_match_length !== 0);
-           zip_strstart++
-         }else {
-           zip_strstart += zip_match_length;
-           zip_match_length = 0;
-           zip_ins_h = zip_window[zip_strstart] & 255;
-           zip_ins_h = (zip_ins_h << zip_H_SHIFT ^ zip_window[zip_strstart + 1] & 255) & zip_HASH_MASK
-         }
-       }else {
-         flush = zip_ct_tally(0, zip_window[zip_strstart] & 255);
-         zip_lookahead--;
-         zip_strstart++
-       }
-       if(flush) {
-         zip_flush_block(0);
-         zip_block_start = zip_strstart
-       }
-       while(zip_lookahead < zip_MIN_LOOKAHEAD && !zip_eofile) {
-         zip_fill_window()
-       }
-     }
-   };
-   var zip_deflate_better = function() {
-     var flush;
-     while(zip_lookahead !== 0 && zip_qhead === null) {
-       zip_INSERT_STRING();
-       zip_prev_length = zip_match_length;
-       zip_prev_match = zip_match_start;
-       zip_match_length = zip_MIN_MATCH - 1;
-       if(zip_hash_head !== zip_NIL && (zip_prev_length < zip_max_lazy_match && zip_strstart - zip_hash_head <= zip_MAX_DIST)) {
-         zip_match_length = zip_longest_match(zip_hash_head);
-         if(zip_match_length > zip_lookahead) {
-           zip_match_length = zip_lookahead
-         }
-         if(zip_match_length === zip_MIN_MATCH && zip_strstart - zip_match_start > zip_TOO_FAR) {
-           zip_match_length--
-         }
-       }
-       if(zip_prev_length >= zip_MIN_MATCH && zip_match_length <= zip_prev_length) {
-         flush = zip_ct_tally(zip_strstart - 1 - zip_prev_match, zip_prev_length - zip_MIN_MATCH);
-         zip_lookahead -= zip_prev_length - 1;
-         zip_prev_length -= 2;
-         do {
-           zip_strstart++;
-           zip_INSERT_STRING()
-         }while(--zip_prev_length !== 0);
-         zip_match_available = 0;
-         zip_match_length = zip_MIN_MATCH - 1;
-         zip_strstart++;
-         if(flush) {
-           zip_flush_block(0);
-           zip_block_start = zip_strstart
-         }
-       }else {
-         if(zip_match_available !== 0) {
-           if(zip_ct_tally(0, zip_window[zip_strstart - 1] & 255)) {
-             zip_flush_block(0);
-             zip_block_start = zip_strstart
-           }
-           zip_strstart++;
-           zip_lookahead--
-         }else {
-           zip_match_available = 1;
-           zip_strstart++;
-           zip_lookahead--
-         }
-       }
-       while(zip_lookahead < zip_MIN_LOOKAHEAD && !zip_eofile) {
-         zip_fill_window()
-       }
-     }
-   };
-   var zip_ct_init = function() {
-     var n;
-     var bits;
-     var length;
-     var code;
-     var dist;
-     if(zip_static_dtree[0].dl !== 0) {
-       return
-     }
-     zip_l_desc.dyn_tree = zip_dyn_ltree;
-     zip_l_desc.static_tree = zip_static_ltree;
-     zip_l_desc.extra_bits = zip_extra_lbits;
-     zip_l_desc.extra_base = zip_LITERALS + 1;
-     zip_l_desc.elems = zip_L_CODES;
-     zip_l_desc.max_length = zip_MAX_BITS;
-     zip_l_desc.max_code = 0;
-     zip_d_desc.dyn_tree = zip_dyn_dtree;
-     zip_d_desc.static_tree = zip_static_dtree;
-     zip_d_desc.extra_bits = zip_extra_dbits;
-     zip_d_desc.extra_base = 0;
-     zip_d_desc.elems = zip_D_CODES;
-     zip_d_desc.max_length = zip_MAX_BITS;
-     zip_d_desc.max_code = 0;
-     zip_bl_desc.dyn_tree = zip_bl_tree;
-     zip_bl_desc.static_tree = null;
-     zip_bl_desc.extra_bits = zip_extra_blbits;
-     zip_bl_desc.extra_base = 0;
-     zip_bl_desc.elems = zip_BL_CODES;
-     zip_bl_desc.max_length = zip_MAX_BL_BITS;
-     zip_bl_desc.max_code = 0;
-     length = 0;
-     for(code = 0;code < zip_LENGTH_CODES - 1;code++) {
-       zip_base_length[code] = length;
-       for(n = 0;n < 1 << zip_extra_lbits[code];n++) {
-         zip_length_code[length++] = code
-       }
-     }
-     zip_length_code[length - 1] = code;
-     dist = 0;
-     for(code = 0;code < 16;code++) {
-       zip_base_dist[code] = dist;
-       for(n = 0;n < 1 << zip_extra_dbits[code];n++) {
-         zip_dist_code[dist++] = code
-       }
-     }
-     dist >>= 7;
-     n = code;
-     for(code = n;code < zip_D_CODES;code++) {
-       zip_base_dist[code] = dist << 7;
-       for(n = 0;n < 1 << zip_extra_dbits[code] - 7;n++) {
-         zip_dist_code[256 + dist++] = code
-       }
-     }
-     for(bits = 0;bits <= zip_MAX_BITS;bits++) {
-       zip_bl_count[bits] = 0
-     }
-     n = 0;
-     while(n <= 143) {
-       zip_static_ltree[n++].dl = 8;
-       zip_bl_count[8]++
-     }
-     while(n <= 255) {
-       zip_static_ltree[n++].dl = 9;
-       zip_bl_count[9]++
-     }
-     while(n <= 279) {
-       zip_static_ltree[n++].dl = 7;
-       zip_bl_count[7]++
-     }
-     while(n <= 287) {
-       zip_static_ltree[n++].dl = 8;
-       zip_bl_count[8]++
-     }
-     zip_gen_codes(zip_static_ltree, zip_L_CODES + 1);
-     for(n = 0;n < zip_D_CODES;n++) {
-       zip_static_dtree[n].dl = 5;
-       zip_static_dtree[n].fc = zip_bi_reverse(n, 5)
-     }
-     zip_init_block()
-   };
-   var zip_init_deflate = function() {
-     if(zip_eofile) {
-       return
-     }
-     zip_bi_buf = 0;
-     zip_bi_valid = 0;
-     zip_ct_init();
-     zip_lm_init();
-     zip_qhead = null;
-     zip_outcnt = 0;
-     zip_outoff = 0;
-     if(zip_compr_level <= 3) {
-       zip_prev_length = zip_MIN_MATCH - 1;
-       zip_match_length = 0
-     }else {
-       zip_match_length = zip_MIN_MATCH - 1;
-       zip_match_available = 0
-     }
-     zip_complete = false
-   };
-   var zip_qcopy = function(buff, off, buff_size) {
-     var n, i, j, p;
-     n = 0;
-     while(zip_qhead !== null && n < buff_size) {
-       i = buff_size - n;
-       if(i > zip_qhead.len) {
-         i = zip_qhead.len
-       }
-       for(j = 0;j < i;j++) {
-         buff[off + n + j] = zip_qhead.ptr[zip_qhead.off + j]
-       }
-       zip_qhead.off += i;
-       zip_qhead.len -= i;
-       n += i;
-       if(zip_qhead.len === 0) {
-         p = zip_qhead;
-         zip_qhead = zip_qhead.next;
-         zip_reuse_queue(p)
-       }
-     }
-     if(n === buff_size) {
-       return n
-     }
-     if(zip_outoff < zip_outcnt) {
-       i = buff_size - n;
-       if(i > zip_outcnt - zip_outoff) {
-         i = zip_outcnt - zip_outoff
-       }
-       for(j = 0;j < i;j++) {
-         buff[off + n + j] = zip_outbuf[zip_outoff + j]
-       }
-       zip_outoff += i;
-       n += i;
-       if(zip_outcnt === zip_outoff) {
-         zip_outcnt = zip_outoff = 0
-       }
-     }
-     return n
-   };
-   var zip_deflate_internal = function(buff, off, buff_size) {
-     var n;
-     if(!zip_initflag) {
-       zip_init_deflate();
-       zip_initflag = true;
-       if(zip_lookahead === 0) {
-         zip_complete = true;
-         return 0
-       }
-     }
-     n = zip_qcopy(buff, off, buff_size);
-     if(n === buff_size) {
-       return buff_size
-     }
-     if(zip_complete) {
-       return n
-     }
-     if(zip_compr_level <= 3) {
-       zip_deflate_fast()
-     }else {
-       zip_deflate_better()
-     }
-     if(zip_lookahead === 0) {
-       if(zip_match_available !== 0) {
-         zip_ct_tally(0, zip_window[zip_strstart - 1] & 255)
-       }
-       zip_flush_block(1);
-       zip_complete = true
-     }
-     return n + zip_qcopy(buff, n + off, buff_size - n)
-   };
-   var zip_deflate = function(str, level) {
-     var i, j;
-     zip_deflate_data = str;
-     zip_deflate_pos = 0;
-     if(String(typeof level) === "undefined") {
-       level = zip_DEFAULT_LEVEL
-     }
-     zip_deflate_start(level);
-     var buff = new Array(1024);
-     var aout = [], cbuf = [];
-     i = zip_deflate_internal(buff, 0, buff.length);
-     while(i > 0) {
-       cbuf.length = i;
-       for(j = 0;j < i;j++) {
-         cbuf[j] = String.fromCharCode(buff[j])
-       }
-       aout[aout.length] = cbuf.join("");
-       i = zip_deflate_internal(buff, 0, buff.length)
-     }
-     zip_deflate_data = "";
-     return aout.join("")
-   };
-   this.deflate = zip_deflate
- };
- runtime.loadClass("odf.Namespaces");
- gui.ImageSelector = function ImageSelector(odfCanvas) {
-   var svgns = odf.Namespaces.svgns, imageSelectorId = "imageSelector", selectorBorderWidth = 1, squareClassNames = ["topLeft", "topRight", "bottomRight", "bottomLeft", "topMiddle", "rightMiddle", "bottomMiddle", "leftMiddle"], document = odfCanvas.getElement().ownerDocument, hasSelection = false;
-   function createSelectorElement() {
-     var sizerElement = odfCanvas.getSizer(), selectorElement, squareElement;
-     selectorElement = document.createElement("div");
-     selectorElement.id = "imageSelector";
-     selectorElement.style.borderWidth = selectorBorderWidth + "px";
-     sizerElement.appendChild(selectorElement);
-     squareClassNames.forEach(function(className) {
-       squareElement = document.createElement("div");
-       squareElement.className = className;
-       selectorElement.appendChild(squareElement)
-     });
-     return selectorElement
-   }
-   function getPosition(element, referenceElement) {
-     var rect = element.getBoundingClientRect(), refRect = referenceElement.getBoundingClientRect(), zoomLevel = odfCanvas.getZoomLevel();
-     return{left:(rect.left - refRect.left) / zoomLevel - selectorBorderWidth, top:(rect.top - refRect.top) / zoomLevel - selectorBorderWidth}
-   }
-   this.select = function(frameElement) {
-     var selectorElement = document.getElementById(imageSelectorId), position;
-     if(!selectorElement) {
-       selectorElement = createSelectorElement()
-     }
-     hasSelection = true;
-     position = getPosition(frameElement, (selectorElement.parentNode));
-     selectorElement.style.display = "block";
-     selectorElement.style.left = position.left + "px";
-     selectorElement.style.top = position.top + "px";
-     selectorElement.style.width = frameElement.getAttributeNS(svgns, "width");
-     selectorElement.style.height = frameElement.getAttributeNS(svgns, "height")
-   };
-   this.clearSelection = function() {
-     var selectorElement;
-     if(hasSelection) {
-       selectorElement = document.getElementById(imageSelectorId);
-       if(selectorElement) {
-         selectorElement.style.display = "none"
-       }
-     }
-     hasSelection = false
-   };
-   this.isSelectorElement = function(node) {
-     var selectorElement = document.getElementById(imageSelectorId);
-     if(!selectorElement) {
-       return false
-     }
-     return node === selectorElement || node.parentNode === selectorElement
-   }
- };
- runtime.loadClass("odf.OdfCanvas");
- odf.CommandLineTools = function CommandLineTools() {
-   this.roundTrip = function(inputfilepath, outputfilepath, callback) {
-     function onready(odfcontainer) {
-       if(odfcontainer.state === odf.OdfContainer.INVALID) {
-         return callback("Document " + inputfilepath + " is invalid.")
-       }
-       if(odfcontainer.state === odf.OdfContainer.DONE) {
-         odfcontainer.saveAs(outputfilepath, function(err) {
-           callback(err)
-         })
-       }else {
-         callback("Document was not completely loaded.")
-       }
-     }
-     var odfcontainer = new odf.OdfContainer(inputfilepath, onready);
-     return odfcontainer
++  this.resetSelectionType = function() {
++    self.setSelectionType(ops.OdtCursor.RangeSelection)
 +  };
-   this.render = function(inputfilepath, document, callback) {
-     var body = document.getElementsByTagName("body")[0], odfcanvas;
-     while(body.firstChild) {
-       body.removeChild(body.firstChild)
-     }
-     odfcanvas = new odf.OdfCanvas(body);
-     odfcanvas.addListener("statereadychange", function(err) {
-       callback(err)
-     });
-     odfcanvas.load(inputfilepath)
-   }
- };
- /*
- 
-  Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
- 
-  @licstart
-  This file is part of WebODF.
- 
-  WebODF is free software: you can redistribute it and/or modify it
-  under the terms of the GNU Affero General Public License (GNU AGPL)
-  as published by the Free Software Foundation, either version 3 of
-  the License, or (at your option) any later version.
- 
-  WebODF is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-  GNU Affero General Public License for more details.
- 
-  You should have received a copy of the GNU Affero General Public License
-  along with WebODF.  If not, see <http://www.gnu.org/licenses/>.
-  @licend
- 
-  @source: http://www.webodf.org/
-  @source: https://github.com/kogmbh/WebODF/
- */
- ops.Member = function Member(memberId, properties) {
-   var props = {};
-   function getMemberId() {
-     return memberId
-   }
-   function getProperties() {
-     return props
-   }
-   function setProperties(newProperties) {
-     Object.keys(newProperties).forEach(function(key) {
-       props[key] = newProperties[key]
-     })
-   }
-   function removeProperties(removedProperties) {
-     delete removedProperties.fullName;
-     delete removedProperties.color;
-     delete removedProperties.imageUrl;
-     Object.keys(removedProperties).forEach(function(key) {
-       if(props.hasOwnProperty(key)) {
-         delete props[key]
-       }
-     })
-   }
-   this.getMemberId = getMemberId;
-   this.getProperties = getProperties;
-   this.setProperties = setProperties;
-   this.removeProperties = removeProperties;
 +  function init() {
-     runtime.assert(Boolean(memberId), "No memberId was supplied!");
-     if(!properties.fullName) {
-       properties.fullName = runtime.tr("Unknown Author")
-     }
-     if(!properties.color) {
-       properties.color = "black"
-     }
-     if(!properties.imageUrl) {
-       properties.imageUrl = "avatar-joe.png"
-     }
-     props = properties
++    cursor = new core.Cursor(document.getDOMDocument(), memberId);
++    selectionMover = new gui.SelectionMover(cursor, document.getRootNode());
++    validSelectionTypes[ops.OdtCursor.RangeSelection] = true;
++    validSelectionTypes[ops.OdtCursor.RegionSelection] = true;
++    self.resetSelectionType()
 +  }
 +  init()
 +};
++ops.OdtCursor.RangeSelection = "Range";
++ops.OdtCursor.RegionSelection = "Region";
++ops.OdtCursor.signalCursorUpdated = "cursorUpdated";
++(function() {
++  return ops.OdtCursor
++})();
 +/*
 +
 + Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("core.DomUtils");
- runtime.loadClass("core.PositionFilter");
- runtime.loadClass("odf.OdfUtils");
++ops.Operation = function Operation() {
++};
++ops.Operation.prototype.init = function(data) {
++};
++ops.Operation.prototype.isEdit;
++ops.Operation.prototype.group;
++ops.Operation.prototype.execute = function(document) {
++};
++ops.Operation.prototype.spec = function() {
++};
++/*
++
++ Copyright (C) 2010-2014 KO GmbH <copyright at kogmbh.com>
++
++ @licstart
++ This file is part of WebODF.
++
++ WebODF is free software: you can redistribute it and/or modify it
++ under the terms of the GNU Affero General Public License (GNU AGPL)
++ as published by the Free Software Foundation, either version 3 of
++ the License, or (at your option) any later version.
++
++ WebODF is distributed in the hope that it will be useful, but
++ WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ GNU Affero General Public License for more details.
++
++ You should have received a copy of the GNU Affero General Public License
++ along with WebODF.  If not, see <http://www.gnu.org/licenses/>.
++ @licend
++
++ @source: http://www.webodf.org/
++ @source: https://github.com/kogmbh/WebODF/
++*/
 +(function() {
-   var nextNodeId = 0, PREVIOUS_STEP = 0, NEXT_STEP = 1;
-   function StepsCache(rootNode, filter, bucketSize) {
-     var coordinatens = "urn:webodf:names:steps", stepToDomPoint = {}, nodeToBookmark = {}, odfUtils = new odf.OdfUtils, domUtils = new core.DomUtils, basePoint, FILTER_ACCEPT = core.PositionFilter.FilterResult.FILTER_ACCEPT;
-     function ParagraphBookmark(steps, paragraphNode) {
++  var nextNodeId = 0;
++  ops.StepsCache = function StepsCache(rootElement, filter, bucketSize) {
++    var coordinatens = "urn:webodf:names:steps", stepToDomPoint = {}, nodeToBookmark = {}, odfUtils = new odf.OdfUtils, domUtils = new core.DomUtils, basePoint, lastUndamagedCacheStep, FILTER_ACCEPT = core.PositionFilter.FilterResult.FILTER_ACCEPT, verifyCache;
++    function ParagraphBookmark(nodeId, steps, paragraphNode) {
++      this.nodeId = nodeId;
 +      this.steps = steps;
 +      this.node = paragraphNode;
-       function positionInContainer(node) {
-         var position = 0;
-         while(node && node.previousSibling) {
-           position += 1;
-           node = node.previousSibling
-         }
-         return position
-       }
++      this.nextBookmark = null;
++      this.previousBookmark = null;
 +      this.setIteratorPosition = function(iterator) {
-         iterator.setUnfilteredPosition(paragraphNode.parentNode, positionInContainer(paragraphNode));
++        iterator.setPositionBeforeElement(paragraphNode);
 +        do {
 +          if(filter.acceptPosition(iterator) === FILTER_ACCEPT) {
 +            break
 +          }
 +        }while(iterator.nextPosition())
 +      }
 +    }
-     function RootBookmark(steps, rootNode) {
++    function RootBookmark(nodeId, steps, rootNode) {
++      this.nodeId = nodeId;
 +      this.steps = steps;
 +      this.node = rootNode;
++      this.nextBookmark = null;
++      this.previousBookmark = null;
 +      this.setIteratorPosition = function(iterator) {
 +        iterator.setUnfilteredPosition(rootNode, 0);
 +        do {
 +          if(filter.acceptPosition(iterator) === FILTER_ACCEPT) {
 +            break
 +          }
 +        }while(iterator.nextPosition())
 +      }
 +    }
++    function inspectBookmarks(bookmark1, bookmark2) {
++      var parts = "[" + bookmark1.nodeId;
++      if(bookmark2) {
++        parts += " => " + bookmark2.nodeId
++      }
++      return parts + "]"
++    }
++    function isUndamagedBookmark(bookmark) {
++      return lastUndamagedCacheStep === undefined || bookmark.steps <= lastUndamagedCacheStep
++    }
++    function verifyCacheImpl() {
++      var bookmark = basePoint, previousBookmark, nextBookmark, documentPosition, loopCheck = new core.LoopWatchDog(0, 1E5);
++      while(bookmark) {
++        loopCheck.check();
++        previousBookmark = bookmark.previousBookmark;
++        if(previousBookmark) {
++          runtime.assert(previousBookmark.nextBookmark === bookmark, "Broken bookmark link to previous @" + inspectBookmarks(previousBookmark, bookmark))
++        }else {
++          runtime.assert(bookmark === basePoint, "Broken bookmark link @" + inspectBookmarks(bookmark));
++          runtime.assert(isUndamagedBookmark(basePoint), "Base point is damaged @" + inspectBookmarks(bookmark))
++        }
++        nextBookmark = bookmark.nextBookmark;
++        if(nextBookmark) {
++          runtime.assert(nextBookmark.previousBookmark === bookmark, "Broken bookmark link to next @" + inspectBookmarks(bookmark, nextBookmark))
++        }
++        if(isUndamagedBookmark(bookmark)) {
++          runtime.assert(domUtils.containsNode(rootElement, bookmark.node), "Disconnected node is being reported as undamaged @" + inspectBookmarks(bookmark));
++          if(previousBookmark) {
++            documentPosition = bookmark.node.compareDocumentPosition(previousBookmark.node);
++            runtime.assert(documentPosition === 0 || (documentPosition & Node.DOCUMENT_POSITION_PRECEDING) !== 0, "Bookmark order with previous does not reflect DOM order @" + inspectBookmarks(previousBookmark, bookmark))
++          }
++          if(nextBookmark) {
++            if(domUtils.containsNode(rootElement, nextBookmark.node)) {
++              documentPosition = bookmark.node.compareDocumentPosition(nextBookmark.node);
++              runtime.assert(documentPosition === 0 || (documentPosition & Node.DOCUMENT_POSITION_FOLLOWING) !== 0, "Bookmark order with next does not reflect DOM order @" + inspectBookmarks(bookmark, nextBookmark))
++            }
++          }
++        }
++        bookmark = bookmark.nextBookmark
++      }
++    }
 +    function getBucket(steps) {
 +      return Math.floor(steps / bucketSize) * bucketSize
 +    }
 +    function getDestinationBucket(steps) {
 +      return Math.ceil(steps / bucketSize) * bucketSize
 +    }
 +    function clearNodeId(node) {
 +      node.removeAttributeNS(coordinatens, "nodeId")
 +    }
 +    function getNodeId(node) {
-       return node.nodeType === Node.ELEMENT_NODE && node.getAttributeNS(coordinatens, "nodeId")
++      var id = "";
++      if(node.nodeType === Node.ELEMENT_NODE) {
++        id = (node).getAttributeNS(coordinatens, "nodeId")
++      }
++      return id
 +    }
 +    function setNodeId(node) {
-       var nodeId = nextNodeId;
-       node.setAttributeNS(coordinatens, "nodeId", nodeId.toString());
++      var nodeId = nextNodeId.toString();
++      node.setAttributeNS(coordinatens, "nodeId", nodeId);
 +      nextNodeId += 1;
 +      return nodeId
 +    }
 +    function isValidBookmarkForNode(node, bookmark) {
 +      return bookmark.node === node
 +    }
 +    function getNodeBookmark(node, steps) {
 +      var nodeId = getNodeId(node) || setNodeId(node), existingBookmark;
 +      existingBookmark = nodeToBookmark[nodeId];
 +      if(!existingBookmark) {
-         existingBookmark = nodeToBookmark[nodeId] = new ParagraphBookmark(steps, node)
++        existingBookmark = nodeToBookmark[nodeId] = new ParagraphBookmark(nodeId, steps, node)
 +      }else {
 +        if(!isValidBookmarkForNode(node, existingBookmark)) {
 +          runtime.log("Cloned node detected. Creating new bookmark");
 +          nodeId = setNodeId(node);
-           existingBookmark = nodeToBookmark[nodeId] = new ParagraphBookmark(steps, node)
++          existingBookmark = nodeToBookmark[nodeId] = new ParagraphBookmark(nodeId, steps, node)
 +        }else {
 +          existingBookmark.steps = steps
 +        }
 +      }
 +      return existingBookmark
 +    }
-     function isFirstPositionInParagraph(node, offset) {
-       return offset === 0 && odfUtils.isParagraph(node)
++    function getClosestBookmark(steps) {
++      var cacheBucket, cachePoint, loopGuard = new core.LoopWatchDog(0, 1E4);
++      if(lastUndamagedCacheStep !== undefined && steps > lastUndamagedCacheStep) {
++        steps = lastUndamagedCacheStep
++      }
++      cacheBucket = getBucket(steps);
++      while(!cachePoint && cacheBucket !== 0) {
++        cachePoint = stepToDomPoint[cacheBucket];
++        cacheBucket -= bucketSize
++      }
++      cachePoint = cachePoint || basePoint;
++      while(cachePoint.nextBookmark && cachePoint.nextBookmark.steps <= steps) {
++        loopGuard.check();
++        cachePoint = cachePoint.nextBookmark
++      }
++      return cachePoint
++    }
++    function getUndamagedBookmark(bookmark) {
++      if(lastUndamagedCacheStep !== undefined && bookmark.steps > lastUndamagedCacheStep) {
++        bookmark = getClosestBookmark(lastUndamagedCacheStep)
++      }
++      return bookmark
 +    }
-     this.updateCache = function(steps, node, offset, isWalkable) {
-       var stablePoint, cacheBucket, existingCachePoint, bookmark;
-       if(isFirstPositionInParagraph(node, offset)) {
-         stablePoint = true;
-         if(!isWalkable) {
-           steps += 1
-         }
-       }else {
-         if(node.hasChildNodes() && node.childNodes[offset]) {
-           node = node.childNodes[offset];
-           offset = 0;
-           stablePoint = isFirstPositionInParagraph(node, offset);
-           if(stablePoint) {
-             steps += 1
++    function removeBookmark(currentBookmark) {
++      if(currentBookmark.previousBookmark) {
++        currentBookmark.previousBookmark.nextBookmark = currentBookmark.nextBookmark
++      }
++      if(currentBookmark.nextBookmark) {
++        currentBookmark.nextBookmark.previousBookmark = currentBookmark.previousBookmark
++      }
++    }
++    function insertBookmark(previousBookmark, newBookmark) {
++      var nextBookmark;
++      if(previousBookmark !== newBookmark && previousBookmark.nextBookmark !== newBookmark) {
++        removeBookmark(newBookmark);
++        nextBookmark = previousBookmark.nextBookmark;
++        newBookmark.nextBookmark = previousBookmark.nextBookmark;
++        newBookmark.previousBookmark = previousBookmark;
++        previousBookmark.nextBookmark = newBookmark;
++        if(nextBookmark) {
++          nextBookmark.previousBookmark = newBookmark
++        }
++      }
++    }
++    function repairCacheUpToStep(currentIteratorStep) {
++      var damagedBookmark, undamagedBookmark, nextBookmark, stepsBucket;
++      if(lastUndamagedCacheStep !== undefined && lastUndamagedCacheStep < currentIteratorStep) {
++        undamagedBookmark = getClosestBookmark(lastUndamagedCacheStep);
++        damagedBookmark = undamagedBookmark.nextBookmark;
++        while(damagedBookmark && damagedBookmark.steps <= currentIteratorStep) {
++          nextBookmark = damagedBookmark.nextBookmark;
++          stepsBucket = getDestinationBucket(damagedBookmark.steps);
++          if(stepToDomPoint[stepsBucket] === damagedBookmark) {
++            delete stepToDomPoint[stepsBucket]
++          }
++          if(!domUtils.containsNode(rootElement, damagedBookmark.node)) {
++            removeBookmark(damagedBookmark);
++            delete nodeToBookmark[damagedBookmark.nodeId]
++          }else {
++            damagedBookmark.steps = currentIteratorStep + 1
 +          }
++          damagedBookmark = nextBookmark
 +        }
++        lastUndamagedCacheStep = currentIteratorStep
++      }else {
++        undamagedBookmark = getClosestBookmark(currentIteratorStep)
 +      }
-       if(stablePoint) {
-         bookmark = getNodeBookmark(node, steps);
++      return undamagedBookmark
++    }
++    this.updateCache = function(steps, iterator, isStep) {
++      var cacheBucket, existingCachePoint, bookmark, closestPriorBookmark, node = iterator.getCurrentNode();
++      if(iterator.isBeforeNode() && odfUtils.isParagraph(node)) {
++        if(!isStep) {
++          steps += 1
++        }
++        closestPriorBookmark = repairCacheUpToStep(steps);
++        bookmark = getNodeBookmark((node), steps);
++        insertBookmark(closestPriorBookmark, bookmark);
 +        cacheBucket = getDestinationBucket(bookmark.steps);
 +        existingCachePoint = stepToDomPoint[cacheBucket];
 +        if(!existingCachePoint || bookmark.steps > existingCachePoint.steps) {
 +          stepToDomPoint[cacheBucket] = bookmark
 +        }
++        verifyCache()
 +      }
 +    };
 +    this.setToClosestStep = function(steps, iterator) {
-       var cacheBucket = getBucket(steps), cachePoint;
-       while(!cachePoint && cacheBucket !== 0) {
-         cachePoint = stepToDomPoint[cacheBucket];
-         cacheBucket -= bucketSize
-       }
-       cachePoint = cachePoint || basePoint;
++      var cachePoint;
++      verifyCache();
++      cachePoint = getClosestBookmark(steps);
 +      cachePoint.setIteratorPosition(iterator);
 +      return cachePoint.steps
 +    };
-     function findBookmarkedAncestor(node, offset) {
-       var nodeId, bookmark = null;
-       node = node.childNodes[offset] || node;
-       while(!bookmark && (node && node !== rootNode)) {
-         nodeId = getNodeId(node);
++    function findBookmarkedAncestor(node) {
++      var currentNode = node, nodeId, bookmark = null;
++      while(!bookmark && (currentNode && currentNode !== rootElement)) {
++        nodeId = getNodeId(currentNode);
 +        if(nodeId) {
 +          bookmark = nodeToBookmark[nodeId];
-           if(bookmark && !isValidBookmarkForNode(node, bookmark)) {
++          if(bookmark && !isValidBookmarkForNode(currentNode, bookmark)) {
 +            runtime.log("Cloned node detected. Creating new bookmark");
 +            bookmark = null;
-             clearNodeId(node)
++            clearNodeId((currentNode))
 +          }
 +        }
-         node = node.parentNode
++        currentNode = currentNode.parentNode
 +      }
 +      return bookmark
 +    }
 +    this.setToClosestDomPoint = function(node, offset, iterator) {
-       var bookmark;
-       if(node === rootNode && offset === 0) {
++      var bookmark, b, key;
++      verifyCache();
++      if(node === rootElement && offset === 0) {
 +        bookmark = basePoint
 +      }else {
-         if(node === rootNode && offset === rootNode.childNodes.length) {
-           bookmark = Object.keys(stepToDomPoint).map(function(cacheBucket) {
-             return stepToDomPoint[cacheBucket]
-           }).reduce(function(largestBookmark, bookmark) {
-             return bookmark.steps > largestBookmark.steps ? bookmark : largestBookmark
-           }, basePoint)
++        if(node === rootElement && offset === rootElement.childNodes.length) {
++          bookmark = basePoint;
++          for(key in stepToDomPoint) {
++            if(stepToDomPoint.hasOwnProperty(key)) {
++              b = stepToDomPoint[key];
++              if(b.steps > bookmark.steps) {
++                bookmark = b
++              }
++            }
++          }
 +        }else {
-           bookmark = findBookmarkedAncestor(node, offset);
++          bookmark = findBookmarkedAncestor(node.childNodes.item(offset) || node);
 +          if(!bookmark) {
 +            iterator.setUnfilteredPosition(node, offset);
 +            while(!bookmark && iterator.previousNode()) {
-               bookmark = findBookmarkedAncestor(iterator.container(), iterator.unfilteredDomOffset())
++              bookmark = findBookmarkedAncestor(iterator.getCurrentNode())
 +            }
 +          }
 +        }
 +      }
-       bookmark = bookmark || basePoint;
++      bookmark = getUndamagedBookmark(bookmark || basePoint);
 +      bookmark.setIteratorPosition(iterator);
 +      return bookmark.steps
 +    };
-     this.updateCacheAtPoint = function(inflectionStep, doUpdate) {
-       var affectedBookmarks, updatedBuckets = {};
-       affectedBookmarks = Object.keys(nodeToBookmark).map(function(nodeId) {
-         return nodeToBookmark[nodeId]
-       }).filter(function(bookmark) {
-         return bookmark.steps > inflectionStep
-       });
-       affectedBookmarks.forEach(function(bookmark) {
-         var originalCacheBucket = getDestinationBucket(bookmark.steps), newCacheBucket, existingBookmark;
-         if(domUtils.containsNode(rootNode, bookmark.node)) {
-           doUpdate(bookmark);
-           newCacheBucket = getDestinationBucket(bookmark.steps);
-           existingBookmark = updatedBuckets[newCacheBucket];
-           if(!existingBookmark || bookmark.steps > existingBookmark.steps) {
-             updatedBuckets[newCacheBucket] = bookmark
-           }
-         }else {
-           delete nodeToBookmark[getNodeId(bookmark.node)]
-         }
-         if(stepToDomPoint[originalCacheBucket] === bookmark) {
-           delete stepToDomPoint[originalCacheBucket]
++    this.damageCacheAfterStep = function(inflectionStep) {
++      if(inflectionStep < 0) {
++        inflectionStep = 0
++      }
++      if(lastUndamagedCacheStep === undefined) {
++        lastUndamagedCacheStep = inflectionStep
++      }else {
++        if(inflectionStep < lastUndamagedCacheStep) {
++          lastUndamagedCacheStep = inflectionStep
 +        }
-       });
-       Object.keys(updatedBuckets).forEach(function(cacheBucket) {
-         stepToDomPoint[cacheBucket] = updatedBuckets[cacheBucket]
-       })
++      }
++      verifyCache()
 +    };
 +    function init() {
-       basePoint = new RootBookmark(0, rootNode)
++      var rootElementId = getNodeId(rootElement) || setNodeId(rootElement);
++      basePoint = new RootBookmark(rootElementId, 0, rootElement);
++      verifyCache = ops.StepsCache.ENABLE_CACHE_VERIFICATION ? verifyCacheImpl : function() {
++      }
 +    }
 +    init()
++  };
++  ops.StepsCache.ENABLE_CACHE_VERIFICATION = false;
++  ops.StepsCache.Bookmark = function Bookmark() {
++  };
++  ops.StepsCache.Bookmark.prototype.nodeId;
++  ops.StepsCache.Bookmark.prototype.node;
++  ops.StepsCache.Bookmark.prototype.steps;
++  ops.StepsCache.Bookmark.prototype.previousBookmark;
++  ops.StepsCache.Bookmark.prototype.nextBookmark;
++  ops.StepsCache.Bookmark.prototype.setIteratorPosition = function(iterator) {
 +  }
++})();
++/*
++
++ Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
++
++ @licstart
++ The JavaScript code in this page is free software: you can redistribute it
++ and/or modify it under the terms of the GNU Affero General Public License
++ (GNU AGPL) as published by the Free Software Foundation, either version 3 of
++ the License, or (at your option) any later version.  The code is distributed
++ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
++
++ You should have received a copy of the GNU Affero General Public License
++ along with this code.  If not, see <http://www.gnu.org/licenses/>.
++
++ As additional permission under GNU AGPL version 3 section 7, you
++ may distribute non-source (e.g., minimized or compacted) forms of
++ that code without the copy of the GNU GPL normally required by
++ section 4, provided you include this license notice and a URL
++ through which recipients can access the Corresponding Source.
++
++ As a special exception to the AGPL, any HTML file which merely makes function
++ calls to this code, and for that purpose includes it by reference shall be
++ deemed a separate work for copyright law purposes. In addition, the copyright
++ holders of this code give you permission to combine this code with free
++ software libraries that are released under the GNU LGPL. You may copy and
++ distribute such a system following the terms of the GNU AGPL for this code
++ and the LGPL for the libraries. If you modify this code, you may extend this
++ exception to your version of the code, but you are not obligated to do so.
++ If you do not wish to do so, delete this exception statement from your
++ version.
++
++ This license applies to this entire compilation.
++ @licend
++ @source: http://www.webodf.org/
++ @source: https://github.com/kogmbh/WebODF/
++*/
++(function() {
++  var PREVIOUS_STEP = 0, NEXT_STEP = 1;
 +  ops.StepsTranslator = function StepsTranslator(getRootNode, newIterator, filter, bucketSize) {
-     var rootNode = getRootNode(), stepsCache = new StepsCache(rootNode, filter, bucketSize), domUtils = new core.DomUtils, iterator = newIterator(getRootNode()), FILTER_ACCEPT = core.PositionFilter.FilterResult.FILTER_ACCEPT;
++    var rootNode = getRootNode(), stepsCache = new ops.StepsCache(rootNode, filter, bucketSize), domUtils = new core.DomUtils, iterator = newIterator(getRootNode()), FILTER_ACCEPT = core.PositionFilter.FilterResult.FILTER_ACCEPT;
 +    function verifyRootNode() {
 +      var currentRootNode = getRootNode();
 +      if(currentRootNode !== rootNode) {
 +        runtime.log("Undo detected. Resetting steps cache");
 +        rootNode = currentRootNode;
-         stepsCache = new StepsCache(rootNode, filter, bucketSize);
++        stepsCache = new ops.StepsCache(rootNode, filter, bucketSize);
 +        iterator = newIterator(rootNode)
 +      }
 +    }
 +    this.convertStepsToDomPoint = function(steps) {
-       var stepsFromRoot, isWalkable;
++      var stepsFromRoot, isStep;
++      if(isNaN(steps)) {
++        throw new TypeError("Requested steps is not numeric (" + steps + ")");
++      }
 +      if(steps < 0) {
-         runtime.log("warn", "Requested steps were negative (" + steps + ")");
-         steps = 0
++        throw new RangeError("Requested steps is negative (" + steps + ")");
 +      }
 +      verifyRootNode();
 +      stepsFromRoot = stepsCache.setToClosestStep(steps, iterator);
 +      while(stepsFromRoot < steps && iterator.nextPosition()) {
-         isWalkable = filter.acceptPosition(iterator) === FILTER_ACCEPT;
-         if(isWalkable) {
++        isStep = filter.acceptPosition(iterator) === FILTER_ACCEPT;
++        if(isStep) {
 +          stepsFromRoot += 1
 +        }
-         stepsCache.updateCache(stepsFromRoot, iterator.container(), iterator.unfilteredDomOffset(), isWalkable)
++        stepsCache.updateCache(stepsFromRoot, iterator, isStep)
 +      }
 +      if(stepsFromRoot !== steps) {
-         runtime.log("warn", "Requested " + steps + " steps but only " + stepsFromRoot + " are available")
++        throw new RangeError("Requested steps (" + steps + ") exceeds available steps (" + stepsFromRoot + ")");
 +      }
 +      return{node:iterator.container(), offset:iterator.unfilteredDomOffset()}
 +    };
 +    function roundToPreferredStep(iterator, roundDirection) {
 +      if(!roundDirection || filter.acceptPosition(iterator) === FILTER_ACCEPT) {
 +        return true
 +      }
 +      while(iterator.previousPosition()) {
 +        if(filter.acceptPosition(iterator) === FILTER_ACCEPT) {
 +          if(roundDirection(PREVIOUS_STEP, iterator.container(), iterator.unfilteredDomOffset())) {
 +            return true
 +          }
 +          break
 +        }
 +      }
 +      while(iterator.nextPosition()) {
 +        if(filter.acceptPosition(iterator) === FILTER_ACCEPT) {
 +          if(roundDirection(NEXT_STEP, iterator.container(), iterator.unfilteredDomOffset())) {
 +            return true
 +          }
 +          break
 +        }
 +      }
 +      return false
 +    }
 +    this.convertDomPointToSteps = function(node, offset, roundDirection) {
-       var stepsFromRoot, beforeRoot, destinationNode, destinationOffset, rounding = 0, isWalkable;
++      var stepsFromRoot, beforeRoot, destinationNode, destinationOffset, rounding = 0, isStep;
 +      verifyRootNode();
 +      if(!domUtils.containsNode(rootNode, node)) {
 +        beforeRoot = domUtils.comparePoints(rootNode, 0, node, offset) < 0;
-         node = rootNode;
-         offset = beforeRoot ? 0 : rootNode.childNodes.length
++        node = (rootNode);
++        offset = beforeRoot ? 0 : (rootNode).childNodes.length
 +      }
 +      iterator.setUnfilteredPosition(node, offset);
 +      if(!roundToPreferredStep(iterator, roundDirection)) {
 +        iterator.setUnfilteredPosition(node, offset)
 +      }
 +      destinationNode = iterator.container();
 +      destinationOffset = iterator.unfilteredDomOffset();
 +      stepsFromRoot = stepsCache.setToClosestDomPoint(destinationNode, destinationOffset, iterator);
 +      if(domUtils.comparePoints(iterator.container(), iterator.unfilteredDomOffset(), destinationNode, destinationOffset) < 0) {
 +        return stepsFromRoot > 0 ? stepsFromRoot - 1 : stepsFromRoot
 +      }
 +      while(!(iterator.container() === destinationNode && iterator.unfilteredDomOffset() === destinationOffset) && iterator.nextPosition()) {
-         isWalkable = filter.acceptPosition(iterator) === FILTER_ACCEPT;
-         if(isWalkable) {
++        isStep = filter.acceptPosition(iterator) === FILTER_ACCEPT;
++        if(isStep) {
 +          stepsFromRoot += 1
 +        }
-         stepsCache.updateCache(stepsFromRoot, iterator.container(), iterator.unfilteredDomOffset(), isWalkable)
++        stepsCache.updateCache(stepsFromRoot, iterator, isStep)
 +      }
 +      return stepsFromRoot + rounding
 +    };
 +    this.prime = function() {
-       var stepsFromRoot, isWalkable;
++      var stepsFromRoot, isStep;
 +      verifyRootNode();
 +      stepsFromRoot = stepsCache.setToClosestStep(0, iterator);
 +      while(iterator.nextPosition()) {
-         isWalkable = filter.acceptPosition(iterator) === FILTER_ACCEPT;
-         if(isWalkable) {
++        isStep = filter.acceptPosition(iterator) === FILTER_ACCEPT;
++        if(isStep) {
 +          stepsFromRoot += 1
 +        }
-         stepsCache.updateCache(stepsFromRoot, iterator.container(), iterator.unfilteredDomOffset(), isWalkable)
++        stepsCache.updateCache(stepsFromRoot, iterator, isStep)
 +      }
 +    };
 +    this.handleStepsInserted = function(eventArgs) {
 +      verifyRootNode();
-       stepsCache.updateCacheAtPoint(eventArgs.position, function(bucket) {
-         bucket.steps += eventArgs.length
-       })
++      stepsCache.damageCacheAfterStep(eventArgs.position)
 +    };
 +    this.handleStepsRemoved = function(eventArgs) {
 +      verifyRootNode();
-       stepsCache.updateCacheAtPoint(eventArgs.position, function(bucket) {
-         bucket.steps -= eventArgs.length;
-         if(bucket.steps < 0) {
-           bucket.steps = 0
-         }
-       })
++      stepsCache.damageCacheAfterStep(eventArgs.position - 1)
 +    }
 +  };
 +  ops.StepsTranslator.PREVIOUS_STEP = PREVIOUS_STEP;
 +  ops.StepsTranslator.NEXT_STEP = NEXT_STEP;
 +  return ops.StepsTranslator
 +})();
- xmldom.RNG = {};
- xmldom.RNG.Name;
- xmldom.RNG.Attr;
- xmldom.RNG.Element;
- xmldom.RelaxNGParser = function RelaxNGParser() {
-   var self = this, rngns = "http://relaxng.org/ns/structure/1.0", xmlnsns = "http://www.w3.org/2000/xmlns/", start, nsmap = {"http://www.w3.org/XML/1998/namespace":"xml"}, parse;
-   function RelaxNGParseError(error, context) {
-     this.message = function() {
-       if(context) {
-         error += context.nodeType === 1 ? " Element " : " Node ";
-         error += context.nodeName;
-         if(context.nodeValue) {
-           error += " with value '" + context.nodeValue + "'"
-         }
-         error += "."
-       }
-       return error
-     }
-   }
-   function splitToDuos(e) {
-     if(e.e.length <= 2) {
-       return e
-     }
-     var o = {name:e.name, e:e.e.slice(0, 2)};
-     return splitToDuos({name:e.name, e:[o].concat(e.e.slice(2))})
-   }
-   function splitQName(name) {
-     var r = name.split(":", 2), prefix = "", i;
-     if(r.length === 1) {
-       r = ["", r[0]]
-     }else {
-       prefix = r[0]
-     }
-     for(i in nsmap) {
-       if(nsmap[i] === prefix) {
-         r[0] = i
-       }
-     }
-     return r
-   }
-   function splitQNames(def) {
-     var i, l = def.names ? def.names.length : 0, name, localnames = [], namespaces = [];
-     for(i = 0;i < l;i += 1) {
-       name = splitQName(def.names[i]);
-       namespaces[i] = name[0];
-       localnames[i] = name[1]
-     }
-     def.localnames = localnames;
-     def.namespaces = namespaces
-   }
-   function trim(str) {
-     str = str.replace(/^\s\s*/, "");
-     var ws = /\s/, i = str.length - 1;
-     while(ws.test(str.charAt(i))) {
-       i -= 1
-     }
-     return str.slice(0, i + 1)
-   }
-   function copyAttributes(atts, name, names) {
-     var a = {}, i, att;
-     for(i = 0;atts && i < atts.length;i += 1) {
-       att = (atts.item(i));
-       if(!att.namespaceURI) {
-         if(att.localName === "name" && (name === "element" || name === "attribute")) {
-           names.push(att.value)
-         }
-         if(att.localName === "name" || (att.localName === "combine" || att.localName === "type")) {
-           att.value = trim(att.value)
-         }
-         a[att.localName] = att.value
-       }else {
-         if(att.namespaceURI === xmlnsns) {
-           nsmap[att.value] = att.localName
-         }
-       }
-     }
-     return a
-   }
-   function parseChildren(c, e, elements, names) {
-     var text = "", ce;
-     while(c) {
-       if(c.nodeType === Node.ELEMENT_NODE && c.namespaceURI === rngns) {
-         ce = parse((c), elements, e);
-         if(ce) {
-           if(ce.name === "name") {
-             names.push(nsmap[ce.a.ns] + ":" + ce.text);
-             e.push(ce)
-           }else {
-             if(ce.name === "choice" && (ce.names && ce.names.length)) {
-               names = names.concat(ce.names);
-               delete ce.names;
-               e.push(ce)
-             }else {
-               e.push(ce)
-             }
-           }
-         }
-       }else {
-         if(c.nodeType === Node.TEXT_NODE) {
-           text += c.nodeValue
-         }
-       }
-       c = c.nextSibling
-     }
-     return text
-   }
-   function combineDefines(combine, name, e, siblings) {
-     var i, ce;
-     for(i = 0;siblings && i < siblings.length;i += 1) {
-       ce = siblings[i];
-       if(ce.name === "define" && (ce.a && ce.a.name === name)) {
-         ce.e = [{name:combine, e:ce.e.concat(e)}];
-         return ce
-       }
-     }
-     return null
-   }
-   parse = function parse(element, elements, siblings) {
-     var e = [], a, ce, i, text, name = element.localName, names = [];
-     a = copyAttributes(element.attributes, name, names);
-     a.combine = a.combine || undefined;
-     text = parseChildren(element.firstChild, e, elements, names);
-     if(name !== "value" && name !== "param") {
-       text = /^\s*([\s\S]*\S)?\s*$/.exec(text)[1]
-     }
-     if(name === "value" && a.type === undefined) {
-       a.type = "token";
-       a.datatypeLibrary = ""
-     }
-     if((name === "attribute" || name === "element") && a.name !== undefined) {
-       i = splitQName(a.name);
-       e = [{name:"name", text:i[1], a:{ns:i[0]}}].concat(e);
-       delete a.name
-     }
-     if(name === "name" || (name === "nsName" || name === "value")) {
-       if(a.ns === undefined) {
-         a.ns = ""
-       }
-     }else {
-       delete a.ns
-     }
-     if(name === "name") {
-       i = splitQName(text);
-       a.ns = i[0];
-       text = i[1]
-     }
-     if(e.length > 1 && (name === "define" || (name === "oneOrMore" || (name === "zeroOrMore" || (name === "optional" || (name === "list" || name === "mixed")))))) {
-       e = [{name:"group", e:splitToDuos({name:"group", e:e}).e}]
-     }
-     if(e.length > 2 && name === "element") {
-       e = [e[0]].concat({name:"group", e:splitToDuos({name:"group", e:e.slice(1)}).e})
-     }
-     if(e.length === 1 && name === "attribute") {
-       e.push({name:"text", text:text})
-     }
-     if(e.length === 1 && (name === "choice" || (name === "group" || name === "interleave"))) {
-       name = e[0].name;
-       names = e[0].names;
-       a = e[0].a;
-       text = e[0].text;
-       e = e[0].e
-     }else {
-       if(e.length > 2 && (name === "choice" || (name === "group" || name === "interleave"))) {
-         e = splitToDuos({name:name, e:e}).e
-       }
-     }
-     if(name === "mixed") {
-       name = "interleave";
-       e = [e[0], {name:"text"}]
-     }
-     if(name === "optional") {
-       name = "choice";
-       e = [e[0], {name:"empty"}]
-     }
-     if(name === "zeroOrMore") {
-       name = "choice";
-       e = [{name:"oneOrMore", e:[e[0]]}, {name:"empty"}]
-     }
-     if(name === "define" && a.combine) {
-       ce = combineDefines(a.combine, a.name, e, siblings);
-       if(ce) {
-         return null
-       }
-     }
-     ce = {name:name};
-     if(e && e.length > 0) {
-       ce.e = e
-     }
-     for(i in a) {
-       if(a.hasOwnProperty(i)) {
-         ce.a = a;
-         break
-       }
-     }
-     if(text !== undefined) {
-       ce.text = text
-     }
-     if(names && names.length > 0) {
-       ce.names = names
-     }
-     if(name === "element") {
-       ce.id = elements.length;
-       elements.push(ce);
-       ce = {name:"elementref", id:ce.id}
-     }
-     return ce
-   };
-   function resolveDefines(def, defines) {
-     var i = 0, e, defs, end, name = def.name;
-     while(def.e && i < def.e.length) {
-       e = def.e[i];
-       if(e.name === "ref") {
-         defs = defines[e.a.name];
-         if(!defs) {
-           throw e.a.name + " was not defined.";
-         }
-         end = def.e.slice(i + 1);
-         def.e = def.e.slice(0, i);
-         def.e = def.e.concat(defs.e);
-         def.e = def.e.concat(end)
-       }else {
-         i += 1;
-         resolveDefines(e, defines)
-       }
-     }
-     e = def.e;
-     if(name === "choice") {
-       if(!e || (!e[1] || e[1].name === "empty")) {
-         if(!e || (!e[0] || e[0].name === "empty")) {
-           delete def.e;
-           def.name = "empty"
-         }else {
-           e[1] = e[0];
-           e[0] = {name:"empty"}
-         }
-       }
-     }
-     if(name === "group" || name === "interleave") {
-       if(e[0].name === "empty") {
-         if(e[1].name === "empty") {
-           delete def.e;
-           def.name = "empty"
-         }else {
-           name = def.name = e[1].name;
-           def.names = e[1].names;
-           e = def.e = e[1].e
-         }
-       }else {
-         if(e[1].name === "empty") {
-           name = def.name = e[0].name;
-           def.names = e[0].names;
-           e = def.e = e[0].e
-         }
-       }
-     }
-     if(name === "oneOrMore" && e[0].name === "empty") {
-       delete def.e;
-       def.name = "empty"
-     }
-     if(name === "attribute") {
-       splitQNames(def)
-     }
-     if(name === "interleave") {
-       if(e[0].name === "interleave") {
-         if(e[1].name === "interleave") {
-           e = def.e = e[0].e.concat(e[1].e)
-         }else {
-           e = def.e = [e[1]].concat(e[0].e)
-         }
-       }else {
-         if(e[1].name === "interleave") {
-           e = def.e = [e[0]].concat(e[1].e)
-         }
-       }
-     }
-   }
-   function resolveElements(def, elements) {
-     var i = 0, e;
-     while(def.e && i < def.e.length) {
-       e = def.e[i];
-       if(e.name === "elementref") {
-         e.id = e.id || 0;
-         def.e[i] = elements[e.id]
-       }else {
-         if(e.name !== "element") {
-           resolveElements(e, elements)
-         }
-       }
-       i += 1
-     }
-   }
-   function main(dom, callback) {
-     var elements = [], grammar = parse(dom && dom.documentElement, elements, undefined), i, e, defines = {};
-     for(i = 0;i < grammar.e.length;i += 1) {
-       e = grammar.e[i];
-       if(e.name === "define") {
-         defines[e.a.name] = e
-       }else {
-         if(e.name === "start") {
-           start = e
-         }
-       }
-     }
-     if(!start) {
-       return[new RelaxNGParseError("No Relax NG start element was found.")]
-     }
-     resolveDefines(start, defines);
-     for(i in defines) {
-       if(defines.hasOwnProperty(i)) {
-         resolveDefines(defines[i], defines)
-       }
-     }
-     for(i = 0;i < elements.length;i += 1) {
-       resolveDefines(elements[i], defines)
-     }
-     if(callback) {
-       self.rootPattern = callback(start.e[0], elements)
-     }
-     resolveElements(start, elements);
-     for(i = 0;i < elements.length;i += 1) {
-       resolveElements(elements[i], elements)
-     }
-     self.start = start;
-     self.elements = elements;
-     self.nsmap = nsmap;
-     return null
-   }
-   this.parseRelaxNGDOM = main
- };
- runtime.loadClass("core.Cursor");
- runtime.loadClass("gui.SelectionMover");
- ops.OdtCursor = function OdtCursor(memberId, odtDocument) {
-   var self = this, validSelectionTypes = {}, selectionType, selectionMover, cursor;
-   this.removeFromOdtDocument = function() {
-     cursor.remove()
-   };
-   this.move = function(number, extend) {
-     var moved = 0;
-     if(number > 0) {
-       moved = selectionMover.movePointForward(number, extend)
-     }else {
-       if(number <= 0) {
-         moved = -selectionMover.movePointBackward(-number, extend)
-       }
-     }
-     self.handleUpdate();
-     return moved
-   };
-   this.handleUpdate = function() {
-   };
-   this.getStepCounter = function() {
-     return selectionMover.getStepCounter()
-   };
-   this.getMemberId = function() {
-     return memberId
-   };
-   this.getNode = function() {
-     return cursor.getNode()
-   };
-   this.getAnchorNode = function() {
-     return cursor.getAnchorNode()
-   };
-   this.getSelectedRange = function() {
-     return cursor.getSelectedRange()
-   };
-   this.setSelectedRange = function(range, isForwardSelection) {
-     cursor.setSelectedRange(range, isForwardSelection);
-     self.handleUpdate()
-   };
-   this.hasForwardSelection = function() {
-     return cursor.hasForwardSelection()
-   };
-   this.getOdtDocument = function() {
-     return odtDocument
-   };
-   this.getSelectionType = function() {
-     return selectionType
-   };
-   this.setSelectionType = function(value) {
-     if(validSelectionTypes.hasOwnProperty(value)) {
-       selectionType = value
-     }else {
-       runtime.log("Invalid selection type: " + value)
-     }
-   };
-   this.resetSelectionType = function() {
-     self.setSelectionType(ops.OdtCursor.RangeSelection)
-   };
-   function init() {
-     cursor = new core.Cursor(odtDocument.getDOM(), memberId);
-     selectionMover = new gui.SelectionMover(cursor, odtDocument.getRootNode());
-     validSelectionTypes[ops.OdtCursor.RangeSelection] = true;
-     validSelectionTypes[ops.OdtCursor.RegionSelection] = true;
-     self.resetSelectionType()
-   }
-   init()
- };
- ops.OdtCursor.RangeSelection = "Range";
- ops.OdtCursor.RegionSelection = "Region";
- (function() {
-   return ops.OdtCursor
- })();
 +/*
 +
 + Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("core.EventNotifier");
- runtime.loadClass("core.DomUtils");
- runtime.loadClass("odf.OdfUtils");
- runtime.loadClass("odf.Namespaces");
- runtime.loadClass("gui.SelectionMover");
- runtime.loadClass("core.PositionFilterChain");
- runtime.loadClass("ops.StepsTranslator");
- runtime.loadClass("ops.TextPositionFilter");
- runtime.loadClass("ops.Member");
- ops.OdtDocument = function OdtDocument(odfCanvas) {
-   var self = this, odfUtils, domUtils, cursors = {}, members = {}, eventNotifier = new core.EventNotifier([ops.OdtDocument.signalMemberAdded, ops.OdtDocument.signalMemberUpdated, ops.OdtDocument.signalMemberRemoved, ops.OdtDocument.signalCursorAdded, ops.OdtDocument.signalCursorRemoved, ops.OdtDocument.signalCursorMoved, ops.OdtDocument.signalParagraphChanged, ops.OdtDocument.signalParagraphStyleModified, ops.OdtDocument.signalCommonStyleCreated, ops.OdtDocument.signalCommonStyleDeleted [...]
-   ops.OdtDocument.signalOperationExecuted, ops.OdtDocument.signalUndoStackChanged, ops.OdtDocument.signalStepsInserted, ops.OdtDocument.signalStepsRemoved]), FILTER_ACCEPT = core.PositionFilter.FilterResult.FILTER_ACCEPT, FILTER_REJECT = core.PositionFilter.FilterResult.FILTER_REJECT, filter, stepsTranslator, lastEditingOp, unsupportedMetadataRemoved = false;
-   function getRootNode() {
-     var element = odfCanvas.odfContainer().getContentElement(), localName = element && element.localName;
-     runtime.assert(localName === "text", "Unsupported content element type '" + localName + "' for OdtDocument");
-     return element
-   }
-   function getDOM() {
-     return(getRootNode().ownerDocument)
-   }
-   this.getDOM = getDOM;
-   function isRoot(node) {
-     if(node.namespaceURI === odf.Namespaces.officens && node.localName === "text" || node.namespaceURI === odf.Namespaces.officens && node.localName === "annotation") {
-       return true
-     }
-     return false
-   }
-   function getRoot(node) {
-     while(node && !isRoot(node)) {
-       node = (node.parentNode)
-     }
-     return node
-   }
-   this.getRootElement = getRoot;
-   function RootFilter(anchor) {
-     this.acceptPosition = function(iterator) {
-       var node = iterator.container(), anchorNode;
-       if(typeof anchor === "string") {
++ops.TextPositionFilter = function TextPositionFilter(getRootNode) {
++  var odfUtils = new odf.OdfUtils, ELEMENT_NODE = Node.ELEMENT_NODE, TEXT_NODE = Node.TEXT_NODE, FILTER_ACCEPT = core.PositionFilter.FilterResult.FILTER_ACCEPT, FILTER_REJECT = core.PositionFilter.FilterResult.FILTER_REJECT;
++  function checkLeftRight(container, leftNode, rightNode) {
++    var r, firstPos, rightOfChar;
++    if(leftNode) {
++      if(odfUtils.isInlineRoot(leftNode) && odfUtils.isGroupingElement(rightNode)) {
++        return FILTER_REJECT
++      }
++      r = odfUtils.lookLeftForCharacter(leftNode);
++      if(r === 1) {
++        return FILTER_ACCEPT
++      }
++      if(r === 2 && (odfUtils.scanRightForAnyCharacter(rightNode) || odfUtils.scanRightForAnyCharacter(odfUtils.nextNode(container)))) {
++        return FILTER_ACCEPT
++      }
++    }
++    firstPos = leftNode === null && odfUtils.isParagraph(container);
++    rightOfChar = odfUtils.lookRightForCharacter(rightNode);
++    if(firstPos) {
++      if(rightOfChar) {
++        return FILTER_ACCEPT
++      }
++      return odfUtils.scanRightForAnyCharacter(rightNode) ? FILTER_REJECT : FILTER_ACCEPT
++    }
++    if(!rightOfChar) {
++      return FILTER_REJECT
++    }
++    leftNode = leftNode || odfUtils.previousNode(container);
++    return odfUtils.scanLeftForAnyCharacter(leftNode) ? FILTER_REJECT : FILTER_ACCEPT
++  }
++  this.acceptPosition = function(iterator) {
++    var container = iterator.container(), nodeType = container.nodeType, offset, text, leftChar, rightChar, leftNode, rightNode, r;
++    if(nodeType !== ELEMENT_NODE && nodeType !== TEXT_NODE) {
++      return FILTER_REJECT
++    }
++    if(nodeType === TEXT_NODE) {
++      if(!odfUtils.isGroupingElement(container.parentNode) || odfUtils.isWithinTrackedChanges(container.parentNode, getRootNode())) {
++        return FILTER_REJECT
++      }
++      offset = iterator.unfilteredDomOffset();
++      text = container.data;
++      runtime.assert(offset !== text.length, "Unexpected offset.");
++      if(offset > 0) {
++        leftChar = (text[offset - 1]);
++        if(!odfUtils.isODFWhitespace(leftChar)) {
++          return FILTER_ACCEPT
++        }
++        if(offset > 1) {
++          leftChar = (text[offset - 2]);
++          if(!odfUtils.isODFWhitespace(leftChar)) {
++            r = FILTER_ACCEPT
++          }else {
++            if(!odfUtils.isODFWhitespace(text.substr(0, offset))) {
++              return FILTER_REJECT
++            }
++          }
++        }else {
++          leftNode = odfUtils.previousNode(container);
++          if(odfUtils.scanLeftForNonSpace(leftNode)) {
++            r = FILTER_ACCEPT
++          }
++        }
++        if(r === FILTER_ACCEPT) {
++          return odfUtils.isTrailingWhitespace((container), offset) ? FILTER_REJECT : FILTER_ACCEPT
++        }
++        rightChar = (text[offset]);
++        if(odfUtils.isODFWhitespace(rightChar)) {
++          return FILTER_REJECT
++        }
++        return odfUtils.scanLeftForAnyCharacter(odfUtils.previousNode(container)) ? FILTER_REJECT : FILTER_ACCEPT
++      }
++      leftNode = iterator.leftNode();
++      rightNode = container;
++      container = (container.parentNode);
++      r = checkLeftRight(container, leftNode, rightNode)
++    }else {
++      if(!odfUtils.isGroupingElement(container) || odfUtils.isWithinTrackedChanges(container, getRootNode())) {
++        r = FILTER_REJECT
++      }else {
++        leftNode = iterator.leftNode();
++        rightNode = iterator.rightNode();
++        r = checkLeftRight(container, leftNode, rightNode)
++      }
++    }
++    return r
++  }
++};
++/*
++
++ Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
++
++ @licstart
++ The JavaScript code in this page is free software: you can redistribute it
++ and/or modify it under the terms of the GNU Affero General Public License
++ (GNU AGPL) as published by the Free Software Foundation, either version 3 of
++ the License, or (at your option) any later version.  The code is distributed
++ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
++
++ You should have received a copy of the GNU Affero General Public License
++ along with this code.  If not, see <http://www.gnu.org/licenses/>.
++
++ As additional permission under GNU AGPL version 3 section 7, you
++ may distribute non-source (e.g., minimized or compacted) forms of
++ that code without the copy of the GNU GPL normally required by
++ section 4, provided you include this license notice and a URL
++ through which recipients can access the Corresponding Source.
++
++ As a special exception to the AGPL, any HTML file which merely makes function
++ calls to this code, and for that purpose includes it by reference shall be
++ deemed a separate work for copyright law purposes. In addition, the copyright
++ holders of this code give you permission to combine this code with free
++ software libraries that are released under the GNU LGPL. You may copy and
++ distribute such a system following the terms of the GNU AGPL for this code
++ and the LGPL for the libraries. If you modify this code, you may extend this
++ exception to your version of the code, but you are not obligated to do so.
++ If you do not wish to do so, delete this exception statement from your
++ version.
++
++ This license applies to this entire compilation.
++ @licend
++ @source: http://www.webodf.org/
++ @source: https://github.com/kogmbh/WebODF/
++*/
++ops.OdtDocument = function OdtDocument(odfCanvas) {
++  var self = this, odfUtils, domUtils, cursors = {}, members = {}, eventNotifier = new core.EventNotifier([ops.Document.signalMemberAdded, ops.Document.signalMemberUpdated, ops.Document.signalMemberRemoved, ops.Document.signalCursorAdded, ops.Document.signalCursorRemoved, ops.Document.signalCursorMoved, ops.OdtDocument.signalParagraphChanged, ops.OdtDocument.signalParagraphStyleModified, ops.OdtDocument.signalCommonStyleCreated, ops.OdtDocument.signalCommonStyleDeleted, ops.OdtDocument. [...]
++  ops.OdtDocument.signalOperationStart, ops.OdtDocument.signalOperationEnd, ops.OdtDocument.signalProcessingBatchStart, ops.OdtDocument.signalProcessingBatchEnd, ops.OdtDocument.signalUndoStackChanged, ops.OdtDocument.signalStepsInserted, ops.OdtDocument.signalStepsRemoved]), FILTER_ACCEPT = core.PositionFilter.FilterResult.FILTER_ACCEPT, FILTER_REJECT = core.PositionFilter.FilterResult.FILTER_REJECT, filter, stepsTranslator, lastEditingOp, unsupportedMetadataRemoved = false;
++  function getRootNode() {
++    var element = odfCanvas.odfContainer().getContentElement(), localName = element && element.localName;
++    runtime.assert(localName === "text", "Unsupported content element type '" + localName + "' for OdtDocument");
++    return element
++  }
++  this.getDocumentElement = function() {
++    return odfCanvas.odfContainer().rootElement
++  };
++  this.getDOMDocument = function() {
++    return(this.getDocumentElement().ownerDocument)
++  };
++  this.cloneDocumentElement = function() {
++    var rootElement = self.getDocumentElement(), annotationViewManager = odfCanvas.getAnnotationViewManager(), initialDoc;
++    if(annotationViewManager) {
++      annotationViewManager.forgetAnnotations()
++    }
++    initialDoc = rootElement.cloneNode(true);
++    odfCanvas.refreshAnnotations();
++    return initialDoc
++  };
++  this.setDocumentElement = function(documentElement) {
++    var odfContainer = odfCanvas.odfContainer();
++    odfContainer.setRootElement(documentElement);
++    odfCanvas.setOdfContainer(odfContainer, true);
++    odfCanvas.refreshCSS()
++  };
++  function getDOMDocument() {
++    return(self.getDocumentElement().ownerDocument)
++  }
++  this.getDOMDocument = getDOMDocument;
++  function isRoot(node) {
++    if(node.namespaceURI === odf.Namespaces.officens && node.localName === "text" || node.namespaceURI === odf.Namespaces.officens && node.localName === "annotation") {
++      return true
++    }
++    return false
++  }
++  function getRoot(node) {
++    while(node && !isRoot(node)) {
++      node = (node.parentNode)
++    }
++    return node
++  }
++  this.getRootElement = getRoot;
++  function RootFilter(anchor) {
++    this.acceptPosition = function(iterator) {
++      var node = iterator.container(), anchorNode;
++      if(typeof anchor === "string") {
 +        anchorNode = cursors[anchor].getNode()
 +      }else {
 +        anchorNode = anchor
 +      }
 +      if(getRoot(node) === getRoot(anchorNode)) {
 +        return FILTER_ACCEPT
 +      }
 +      return FILTER_REJECT
 +    }
 +  }
++  function createStepIterator(container, offset, filters, subTree) {
++    var positionIterator = gui.SelectionMover.createPositionIterator(subTree), filterOrChain, stepIterator;
++    if(filters.length === 1) {
++      filterOrChain = filters[0]
++    }else {
++      filterOrChain = new core.PositionFilterChain;
++      filters.forEach(filterOrChain.addFilter)
++    }
++    stepIterator = new core.StepIterator(filterOrChain, positionIterator);
++    stepIterator.setPosition(container, offset);
++    return stepIterator
++  }
++  this.createStepIterator = createStepIterator;
 +  function getIteratorAtPosition(position) {
 +    var iterator = gui.SelectionMover.createPositionIterator(getRootNode()), point = stepsTranslator.convertStepsToDomPoint(position);
 +    iterator.setUnfilteredPosition(point.node, point.offset);
 +    return iterator
 +  }
 +  this.getIteratorAtPosition = getIteratorAtPosition;
 +  this.convertDomPointToCursorStep = function(node, offset, roundDirection) {
 +    return stepsTranslator.convertDomPointToSteps(node, offset, roundDirection)
 +  };
 +  this.convertDomToCursorRange = function(selection, constraint) {
-     var point1, point2, anchorConstraint = constraint(selection.anchorNode, selection.anchorOffset), focusConstraint;
++    var point1, point2, anchorConstraint = constraint && constraint(selection.anchorNode, selection.anchorOffset), focusConstraint;
 +    point1 = stepsTranslator.convertDomPointToSteps(selection.anchorNode, selection.anchorOffset, anchorConstraint);
 +    if(!constraint && (selection.anchorNode === selection.focusNode && selection.anchorOffset === selection.focusOffset)) {
 +      point2 = point1
 +    }else {
-       focusConstraint = constraint(selection.focusNode, selection.focusOffset);
++      focusConstraint = constraint && constraint(selection.focusNode, selection.focusOffset);
 +      point2 = stepsTranslator.convertDomPointToSteps(selection.focusNode, selection.focusOffset, focusConstraint)
 +    }
 +    return{position:point1, length:point2 - point1}
 +  };
 +  this.convertCursorToDomRange = function(position, length) {
-     var range = getDOM().createRange(), point1, point2;
++    var range = getDOMDocument().createRange(), point1, point2;
 +    point1 = stepsTranslator.convertStepsToDomPoint(position);
 +    if(length) {
 +      point2 = stepsTranslator.convertStepsToDomPoint(position + length);
 +      if(length > 0) {
 +        range.setStart(point1.node, point1.offset);
 +        range.setEnd(point2.node, point2.offset)
 +      }else {
 +        range.setStart(point2.node, point2.offset);
 +        range.setEnd(point1.node, point1.offset)
 +      }
 +    }else {
 +      range.setStart(point1.node, point1.offset)
 +    }
 +    return range
 +  };
 +  function getTextNodeAtStep(steps, memberid) {
-     var iterator = getIteratorAtPosition(steps), node = iterator.container(), lastTextNode, nodeOffset = 0, cursorNode = null;
++    var iterator = getIteratorAtPosition(steps), node = iterator.container(), lastTextNode, nodeOffset = 0, cursorNode = null, text;
 +    if(node.nodeType === Node.TEXT_NODE) {
 +      lastTextNode = (node);
 +      nodeOffset = (iterator.unfilteredDomOffset());
 +      if(lastTextNode.length > 0) {
 +        if(nodeOffset > 0) {
 +          lastTextNode = lastTextNode.splitText(nodeOffset)
 +        }
-         lastTextNode.parentNode.insertBefore(getDOM().createTextNode(""), lastTextNode);
++        lastTextNode.parentNode.insertBefore(getDOMDocument().createTextNode(""), lastTextNode);
 +        lastTextNode = (lastTextNode.previousSibling);
 +        nodeOffset = 0
 +      }
 +    }else {
-       lastTextNode = getDOM().createTextNode("");
++      lastTextNode = getDOMDocument().createTextNode("");
 +      nodeOffset = 0;
 +      node.insertBefore(lastTextNode, iterator.rightNode())
 +    }
 +    if(memberid) {
 +      if(cursors[memberid] && self.getCursorPosition(memberid) === steps) {
 +        cursorNode = cursors[memberid].getNode();
 +        while(cursorNode.nextSibling && cursorNode.nextSibling.localName === "cursor") {
 +          cursorNode.parentNode.insertBefore(cursorNode.nextSibling, cursorNode)
 +        }
 +        if(lastTextNode.length > 0 && lastTextNode.nextSibling !== cursorNode) {
-           lastTextNode = getDOM().createTextNode("");
++          lastTextNode = getDOMDocument().createTextNode("");
 +          nodeOffset = 0
 +        }
 +        cursorNode.parentNode.insertBefore(lastTextNode, cursorNode)
 +      }
 +    }else {
 +      while(lastTextNode.nextSibling && lastTextNode.nextSibling.localName === "cursor") {
 +        lastTextNode.parentNode.insertBefore(lastTextNode.nextSibling, lastTextNode)
 +      }
 +    }
 +    while(lastTextNode.previousSibling && lastTextNode.previousSibling.nodeType === Node.TEXT_NODE) {
-       lastTextNode.previousSibling.appendData(lastTextNode.data);
-       nodeOffset = (lastTextNode.previousSibling.length);
-       lastTextNode = (lastTextNode.previousSibling);
++      text = (lastTextNode.previousSibling);
++      text.appendData(lastTextNode.data);
++      nodeOffset = text.length;
++      lastTextNode = text;
 +      lastTextNode.parentNode.removeChild(lastTextNode.nextSibling)
 +    }
 +    while(lastTextNode.nextSibling && lastTextNode.nextSibling.nodeType === Node.TEXT_NODE) {
-       lastTextNode.appendData(lastTextNode.nextSibling.data);
-       lastTextNode.parentNode.removeChild(lastTextNode.nextSibling)
++      text = (lastTextNode.nextSibling);
++      lastTextNode.appendData(text.data);
++      lastTextNode.parentNode.removeChild(text)
 +    }
 +    return{textNode:lastTextNode, offset:nodeOffset}
 +  }
 +  function getParagraphElement(node) {
 +    return odfUtils.getParagraphElement(node)
 +  }
 +  function getStyleElement(styleName, styleFamily) {
 +    return odfCanvas.getFormatting().getStyleElement(styleName, styleFamily)
 +  }
 +  this.getStyleElement = getStyleElement;
 +  function getParagraphStyleElement(styleName) {
 +    return getStyleElement(styleName, "paragraph")
 +  }
 +  function getParagraphStyleAttributes(styleName) {
 +    var node = getParagraphStyleElement(styleName);
 +    if(node) {
-       return odfCanvas.getFormatting().getInheritedStyleAttributes(node)
++      return odfCanvas.getFormatting().getInheritedStyleAttributes(node, false)
 +    }
 +    return null
 +  }
 +  function handleOperationExecuted(op) {
 +    var spec = op.spec(), memberId = spec.memberid, date = (new Date(spec.timestamp)).toISOString(), odfContainer = odfCanvas.odfContainer(), fullName;
 +    if(op.isEdit) {
 +      fullName = self.getMember(memberId).getProperties().fullName;
 +      odfContainer.setMetadata({"dc:creator":fullName, "dc:date":date}, null);
 +      if(!lastEditingOp) {
 +        odfContainer.incrementEditingCycles();
 +        if(!unsupportedMetadataRemoved) {
 +          odfContainer.setMetadata(null, ["meta:editing-duration", "meta:document-statistic"])
 +        }
 +      }
 +      lastEditingOp = op
 +    }
 +  }
 +  function upgradeWhitespaceToElement(textNode, offset) {
 +    runtime.assert(textNode.data[offset] === " ", "upgradeWhitespaceToElement: textNode.data[offset] should be a literal space");
-     var space = textNode.ownerDocument.createElementNS(odf.Namespaces.textns, "text:s");
++    var space = textNode.ownerDocument.createElementNS(odf.Namespaces.textns, "text:s"), container = textNode.parentNode, adjacentNode = textNode;
 +    space.appendChild(textNode.ownerDocument.createTextNode(" "));
-     textNode.deleteData(offset, 1);
-     if(offset > 0) {
-       textNode = (textNode.splitText(offset))
++    if(textNode.length === 1) {
++      container.replaceChild(space, textNode)
++    }else {
++      textNode.deleteData(offset, 1);
++      if(offset > 0) {
++        if(offset < textNode.length) {
++          textNode.splitText(offset)
++        }
++        adjacentNode = textNode.nextSibling
++      }
++      container.insertBefore(space, adjacentNode)
 +    }
-     textNode.parentNode.insertBefore(space, textNode);
 +    return space
 +  }
 +  function upgradeWhitespacesAtPosition(position) {
 +    var iterator = getIteratorAtPosition(position), container, offset, i;
 +    iterator.previousPosition();
 +    iterator.previousPosition();
 +    for(i = -1;i <= 1;i += 1) {
 +      container = iterator.container();
 +      offset = iterator.unfilteredDomOffset();
-       if(container.nodeType === Node.TEXT_NODE && (container.data[offset] === " " && odfUtils.isSignificantWhitespace(container, offset))) {
++      if(container.nodeType === Node.TEXT_NODE && (container.data[offset] === " " && odfUtils.isSignificantWhitespace((container), offset))) {
 +        container = upgradeWhitespaceToElement((container), offset);
 +        iterator.moveToEndOfNode(container)
 +      }
 +      iterator.nextPosition()
 +    }
 +  }
 +  this.upgradeWhitespacesAtPosition = upgradeWhitespacesAtPosition;
 +  this.downgradeWhitespacesAtPosition = function(position) {
 +    var iterator = getIteratorAtPosition(position), container, offset, firstSpaceElementChild, lastSpaceElementChild;
 +    container = iterator.container();
 +    offset = iterator.unfilteredDomOffset();
-     while(!odfUtils.isSpaceElement(container) && container.childNodes[offset]) {
-       container = container.childNodes[offset];
++    while(!odfUtils.isSpaceElement(container) && container.childNodes.item(offset)) {
++      container = (container.childNodes.item(offset));
 +      offset = 0
 +    }
 +    if(container.nodeType === Node.TEXT_NODE) {
-       container = container.parentNode
++      container = (container.parentNode)
 +    }
 +    if(odfUtils.isDowngradableSpaceElement(container)) {
 +      firstSpaceElementChild = container.firstChild;
 +      lastSpaceElementChild = container.lastChild;
 +      domUtils.mergeIntoParent(container);
 +      if(lastSpaceElementChild !== firstSpaceElementChild) {
 +        domUtils.normalizeTextNodes(lastSpaceElementChild)
 +      }
 +      domUtils.normalizeTextNodes(firstSpaceElementChild)
 +    }
 +  };
 +  this.getParagraphStyleElement = getParagraphStyleElement;
 +  this.getParagraphElement = getParagraphElement;
 +  this.getParagraphStyleAttributes = getParagraphStyleAttributes;
 +  this.getTextNodeAtStep = getTextNodeAtStep;
++  function paragraphOrRoot(container, offset, root) {
++    var node = container.childNodes.item(offset) || container, paragraph = getParagraphElement(node);
++    if(paragraph && domUtils.containsNode(root, paragraph)) {
++      return(paragraph)
++    }
++    return root
++  }
 +  this.fixCursorPositions = function() {
-     var rootConstrainedFilter = new core.PositionFilterChain;
-     rootConstrainedFilter.addFilter("BaseFilter", filter);
 +    Object.keys(cursors).forEach(function(memberId) {
-       var cursor = cursors[memberId], stepCounter = cursor.getStepCounter(), stepsSelectionLength, positionsToAdjustFocus, positionsToAdjustAnchor, positionsToAnchor, cursorMoved = false;
-       rootConstrainedFilter.addFilter("RootFilter", self.createRootFilter(memberId));
-       stepsSelectionLength = stepCounter.countStepsToPosition(cursor.getAnchorNode(), 0, rootConstrainedFilter);
-       if(!stepCounter.isPositionWalkable(rootConstrainedFilter)) {
++      var cursor = cursors[memberId], root = getRoot(cursor.getNode()), rootFilter = self.createRootFilter(root), subTree, startPoint, endPoint, selectedRange, cursorMoved = false;
++      selectedRange = cursor.getSelectedRange();
++      subTree = paragraphOrRoot((selectedRange.startContainer), selectedRange.startOffset, root);
++      startPoint = createStepIterator((selectedRange.startContainer), selectedRange.startOffset, [filter, rootFilter], subTree);
++      if(!selectedRange.collapsed) {
++        subTree = paragraphOrRoot((selectedRange.endContainer), selectedRange.endOffset, root);
++        endPoint = createStepIterator((selectedRange.endContainer), selectedRange.endOffset, [filter, rootFilter], subTree)
++      }else {
++        endPoint = startPoint
++      }
++      if(!startPoint.isStep() || !endPoint.isStep()) {
 +        cursorMoved = true;
-         positionsToAdjustFocus = stepCounter.countPositionsToNearestStep(cursor.getNode(), 0, rootConstrainedFilter);
-         positionsToAdjustAnchor = stepCounter.countPositionsToNearestStep(cursor.getAnchorNode(), 0, rootConstrainedFilter);
-         cursor.move(positionsToAdjustFocus);
-         if(stepsSelectionLength !== 0) {
-           if(positionsToAdjustAnchor > 0) {
-             stepsSelectionLength += 1
-           }
-           if(positionsToAdjustFocus > 0) {
-             stepsSelectionLength -= 1
-           }
-           positionsToAnchor = stepCounter.countSteps(stepsSelectionLength, rootConstrainedFilter);
-           cursor.move(positionsToAnchor);
-           cursor.move(-positionsToAnchor, true)
-         }
++        runtime.assert(startPoint.roundToClosestStep(), "No walkable step found for cursor owned by " + memberId);
++        selectedRange.setStart(startPoint.container(), startPoint.offset());
++        runtime.assert(endPoint.roundToClosestStep(), "No walkable step found for cursor owned by " + memberId);
++        selectedRange.setEnd(endPoint.container(), endPoint.offset())
 +      }else {
-         if(stepsSelectionLength === 0) {
-           cursorMoved = true;
-           cursor.move(0)
++        if(startPoint.container() === endPoint.container() && startPoint.offset() === endPoint.offset()) {
++          if(!selectedRange.collapsed || cursor.getAnchorNode() !== cursor.getNode()) {
++            cursorMoved = true;
++            selectedRange.setStart(startPoint.container(), startPoint.offset());
++            selectedRange.collapse(true)
++          }
 +        }
 +      }
 +      if(cursorMoved) {
-         self.emit(ops.OdtDocument.signalCursorMoved, cursor)
++        cursor.setSelectedRange(selectedRange, cursor.hasForwardSelection());
++        self.emit(ops.Document.signalCursorMoved, cursor)
 +      }
-       rootConstrainedFilter.removeFilter("RootFilter")
 +    })
 +  };
-   this.getDistanceFromCursor = function(memberid, node, offset) {
-     var cursor = cursors[memberid], focusPosition, targetPosition;
-     runtime.assert(node !== null && node !== undefined, "OdtDocument.getDistanceFromCursor called without node");
-     if(cursor) {
-       focusPosition = stepsTranslator.convertDomPointToSteps(cursor.getNode(), 0);
-       targetPosition = stepsTranslator.convertDomPointToSteps(node, offset)
-     }
-     return targetPosition - focusPosition
-   };
 +  this.getCursorPosition = function(memberid) {
 +    var cursor = cursors[memberid];
 +    return cursor ? stepsTranslator.convertDomPointToSteps(cursor.getNode(), 0) : 0
 +  };
 +  this.getCursorSelection = function(memberid) {
 +    var cursor = cursors[memberid], focusPosition = 0, anchorPosition = 0;
 +    if(cursor) {
 +      focusPosition = stepsTranslator.convertDomPointToSteps(cursor.getNode(), 0);
 +      anchorPosition = stepsTranslator.convertDomPointToSteps(cursor.getAnchorNode(), 0)
 +    }
 +    return{position:anchorPosition, length:focusPosition - anchorPosition}
 +  };
 +  this.getPositionFilter = function() {
 +    return filter
 +  };
 +  this.getOdfCanvas = function() {
 +    return odfCanvas
 +  };
++  this.getCanvas = function() {
++    return odfCanvas
++  };
 +  this.getRootNode = getRootNode;
 +  this.addMember = function(member) {
 +    runtime.assert(members[member.getMemberId()] === undefined, "This member already exists");
 +    members[member.getMemberId()] = member
 +  };
 +  this.getMember = function(memberId) {
 +    return members.hasOwnProperty(memberId) ? members[memberId] : null
 +  };
 +  this.removeMember = function(memberId) {
 +    delete members[memberId]
 +  };
 +  this.getCursor = function(memberid) {
 +    return cursors[memberid]
 +  };
-   this.getCursors = function() {
++  this.getMemberIds = function() {
 +    var list = [], i;
 +    for(i in cursors) {
 +      if(cursors.hasOwnProperty(i)) {
-         list.push(cursors[i])
++        list.push(cursors[i].getMemberId())
 +      }
 +    }
 +    return list
 +  };
 +  this.addCursor = function(cursor) {
 +    runtime.assert(Boolean(cursor), "OdtDocument::addCursor without cursor");
-     var distanceToFirstTextNode = cursor.getStepCounter().countSteps(1, filter), memberid = cursor.getMemberId();
++    var memberid = cursor.getMemberId(), initialSelection = self.convertCursorToDomRange(0, 0);
 +    runtime.assert(typeof memberid === "string", "OdtDocument::addCursor has cursor without memberid");
 +    runtime.assert(!cursors[memberid], "OdtDocument::addCursor is adding a duplicate cursor with memberid " + memberid);
-     cursor.move(distanceToFirstTextNode);
++    cursor.setSelectedRange(initialSelection, true);
 +    cursors[memberid] = cursor
 +  };
 +  this.removeCursor = function(memberid) {
 +    var cursor = cursors[memberid];
 +    if(cursor) {
-       cursor.removeFromOdtDocument();
++      cursor.removeFromDocument();
 +      delete cursors[memberid];
-       self.emit(ops.OdtDocument.signalCursorRemoved, memberid);
++      self.emit(ops.Document.signalCursorRemoved, memberid);
 +      return true
 +    }
 +    return false
 +  };
 +  this.moveCursor = function(memberid, position, length, selectionType) {
 +    var cursor = cursors[memberid], selectionRange = self.convertCursorToDomRange(position, length);
-     if(cursor && selectionRange) {
++    if(cursor) {
 +      cursor.setSelectedRange(selectionRange, length >= 0);
 +      cursor.setSelectionType(selectionType || ops.OdtCursor.RangeSelection)
 +    }
 +  };
 +  this.getFormatting = function() {
 +    return odfCanvas.getFormatting()
 +  };
 +  this.emit = function(eventid, args) {
 +    eventNotifier.emit(eventid, args)
 +  };
 +  this.subscribe = function(eventid, cb) {
 +    eventNotifier.subscribe(eventid, cb)
 +  };
 +  this.unsubscribe = function(eventid, cb) {
 +    eventNotifier.unsubscribe(eventid, cb)
 +  };
 +  this.createRootFilter = function(inputMemberId) {
 +    return new RootFilter(inputMemberId)
 +  };
 +  this.close = function(callback) {
 +    callback()
 +  };
 +  this.destroy = function(callback) {
 +    callback()
 +  };
 +  function init() {
 +    filter = new ops.TextPositionFilter(getRootNode);
 +    odfUtils = new odf.OdfUtils;
 +    domUtils = new core.DomUtils;
 +    stepsTranslator = new ops.StepsTranslator(getRootNode, gui.SelectionMover.createPositionIterator, filter, 500);
 +    eventNotifier.subscribe(ops.OdtDocument.signalStepsInserted, stepsTranslator.handleStepsInserted);
 +    eventNotifier.subscribe(ops.OdtDocument.signalStepsRemoved, stepsTranslator.handleStepsRemoved);
-     eventNotifier.subscribe(ops.OdtDocument.signalOperationExecuted, handleOperationExecuted)
++    eventNotifier.subscribe(ops.OdtDocument.signalOperationEnd, handleOperationExecuted)
 +  }
 +  init()
 +};
- ops.OdtDocument.signalMemberAdded = "member/added";
- ops.OdtDocument.signalMemberUpdated = "member/updated";
- ops.OdtDocument.signalMemberRemoved = "member/removed";
- ops.OdtDocument.signalCursorAdded = "cursor/added";
- ops.OdtDocument.signalCursorRemoved = "cursor/removed";
- ops.OdtDocument.signalCursorMoved = "cursor/moved";
 +ops.OdtDocument.signalParagraphChanged = "paragraph/changed";
 +ops.OdtDocument.signalTableAdded = "table/added";
 +ops.OdtDocument.signalCommonStyleCreated = "style/created";
 +ops.OdtDocument.signalCommonStyleDeleted = "style/deleted";
 +ops.OdtDocument.signalParagraphStyleModified = "paragraphstyle/modified";
- ops.OdtDocument.signalOperationExecuted = "operation/executed";
++ops.OdtDocument.signalOperationStart = "operation/start";
++ops.OdtDocument.signalOperationEnd = "operation/end";
++ops.OdtDocument.signalProcessingBatchStart = "router/batchstart";
++ops.OdtDocument.signalProcessingBatchEnd = "router/batchend";
 +ops.OdtDocument.signalUndoStackChanged = "undo/changed";
 +ops.OdtDocument.signalStepsInserted = "steps/inserted";
 +ops.OdtDocument.signalStepsRemoved = "steps/removed";
 +(function() {
 +  return ops.OdtDocument
 +})();
 +/*
 +
 + Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- ops.Operation = function Operation() {
- };
- ops.Operation.prototype.init = function(data) {
- };
- ops.Operation.prototype.isEdit;
- ops.Operation.prototype.execute = function(odtDocument) {
- };
- ops.Operation.prototype.spec = function() {
- };
- runtime.loadClass("xmldom.RelaxNGParser");
- xmldom.RelaxNGItem;
- xmldom.RelaxNG = function RelaxNG() {
-   var xmlnsns = "http://www.w3.org/2000/xmlns/", createChoice, createInterleave, createGroup, createAfter, createOneOrMore, createValue, createAttribute, createNameClass, createData, makePattern, applyAfter, childDeriv, rootPattern, notAllowed = {type:"notAllowed", nullable:false, hash:"notAllowed", nc:undefined, p:undefined, p1:undefined, p2:undefined, textDeriv:function() {
-     return notAllowed
-   }, startTagOpenDeriv:function() {
-     return notAllowed
-   }, attDeriv:function() {
-     return notAllowed
-   }, startTagCloseDeriv:function() {
-     return notAllowed
-   }, endTagDeriv:function() {
-     return notAllowed
-   }}, empty = {type:"empty", nullable:true, hash:"empty", nc:undefined, p:undefined, p1:undefined, p2:undefined, textDeriv:function() {
-     return notAllowed
-   }, startTagOpenDeriv:function() {
-     return notAllowed
-   }, attDeriv:function() {
-     return notAllowed
-   }, startTagCloseDeriv:function() {
-     return empty
-   }, endTagDeriv:function() {
-     return notAllowed
-   }}, text = {type:"text", nullable:true, hash:"text", nc:undefined, p:undefined, p1:undefined, p2:undefined, textDeriv:function() {
-     return text
-   }, startTagOpenDeriv:function() {
-     return notAllowed
-   }, attDeriv:function() {
-     return notAllowed
-   }, startTagCloseDeriv:function() {
-     return text
-   }, endTagDeriv:function() {
-     return notAllowed
-   }};
-   function memoize0arg(func) {
-     function f() {
-       var cache;
-       function g() {
-         if(cache === undefined) {
-           cache = func()
-         }
-         return cache
-       }
-       return g
-     }
-     return f()
++ops.OpAddAnnotation = function OpAddAnnotation() {
++  var memberid, timestamp, position, length, name, doc;
++  this.init = function(data) {
++    memberid = data.memberid;
++    timestamp = parseInt(data.timestamp, 10);
++    position = parseInt(data.position, 10);
++    length = parseInt(data.length, 10) || 0;
++    name = data.name
++  };
++  this.isEdit = true;
++  this.group = undefined;
++  function createAnnotationNode(odtDocument, date) {
++    var annotationNode, creatorNode, dateNode, listNode, listItemNode, paragraphNode;
++    annotationNode = (doc.createElementNS(odf.Namespaces.officens, "office:annotation"));
++    annotationNode.setAttributeNS(odf.Namespaces.officens, "office:name", name);
++    creatorNode = doc.createElementNS(odf.Namespaces.dcns, "dc:creator");
++    creatorNode.setAttributeNS("urn:webodf:names:editinfo", "editinfo:memberid", memberid);
++    creatorNode.textContent = odtDocument.getMember(memberid).getProperties().fullName;
++    dateNode = doc.createElementNS(odf.Namespaces.dcns, "dc:date");
++    dateNode.appendChild(doc.createTextNode(date.toISOString()));
++    listNode = doc.createElementNS(odf.Namespaces.textns, "text:list");
++    listItemNode = doc.createElementNS(odf.Namespaces.textns, "text:list-item");
++    paragraphNode = doc.createElementNS(odf.Namespaces.textns, "text:p");
++    listItemNode.appendChild(paragraphNode);
++    listNode.appendChild(listItemNode);
++    annotationNode.appendChild(creatorNode);
++    annotationNode.appendChild(dateNode);
++    annotationNode.appendChild(listNode);
++    return annotationNode
 +  }
-   function memoize1arg(type, func) {
-     function f() {
-       var cache = {}, cachecount = 0;
-       function g(a) {
-         var ahash = a.hash || a.toString(), v;
-         if(cache.hasOwnProperty(ahash)) {
-           return cache[ahash]
-         }
-         cache[ahash] = v = func(a);
-         v.hash = type + cachecount.toString();
-         cachecount += 1;
-         return v
-       }
-       return g
-     }
-     return f()
++  function createAnnotationEnd() {
++    var annotationEnd;
++    annotationEnd = doc.createElementNS(odf.Namespaces.officens, "office:annotation-end");
++    annotationEnd.setAttributeNS(odf.Namespaces.officens, "office:name", name);
++    return annotationEnd
 +  }
-   function memoizeNode(func) {
-     function f() {
-       var cache = {};
-       function g(node) {
-         var v, m;
-         if(!cache.hasOwnProperty(node.localName)) {
-           cache[node.localName] = m = {}
-         }else {
-           m = cache[node.localName];
-           v = m[node.namespaceURI];
-           if(v !== undefined) {
-             return v
-           }
-         }
-         m[node.namespaceURI] = v = func(node);
-         return v
++  function insertNodeAtPosition(odtDocument, node, insertPosition) {
++    var previousNode, parentNode, domPosition = odtDocument.getTextNodeAtStep(insertPosition, memberid);
++    if(domPosition) {
++      previousNode = domPosition.textNode;
++      parentNode = previousNode.parentNode;
++      if(domPosition.offset !== previousNode.length) {
++        previousNode.splitText(domPosition.offset)
 +      }
-       return g
-     }
-     return f()
-   }
-   function memoize2arg(type, fastfunc, func) {
-     function f() {
-       var cache = {}, cachecount = 0;
-       function g(a, b) {
-         var v = fastfunc && fastfunc(a, b), ahash, bhash, m;
-         if(v !== undefined) {
-           return v
-         }
-         ahash = a.hash || a.toString();
-         bhash = b.hash || b.toString();
-         if(!cache.hasOwnProperty(ahash)) {
-           cache[ahash] = m = {}
-         }else {
-           m = cache[ahash];
-           if(m.hasOwnProperty(bhash)) {
-             return m[bhash]
-           }
-         }
-         m[bhash] = v = func(a, b);
-         v.hash = type + cachecount.toString();
-         cachecount += 1;
-         return v
++      parentNode.insertBefore(node, previousNode.nextSibling);
++      if(previousNode.length === 0) {
++        parentNode.removeChild(previousNode)
 +      }
-       return g
 +    }
-     return f()
 +  }
-   function unorderedMemoize2arg(type, fastfunc, func) {
-     function f() {
-       var cache = {}, cachecount = 0;
-       function g(a, b) {
-         var v = fastfunc && fastfunc(a, b), ahash, bhash, hash, m;
-         if(v !== undefined) {
-           return v
-         }
-         ahash = a.hash || a.toString();
-         bhash = b.hash || b.toString();
-         if(ahash < bhash) {
-           hash = ahash;
-           ahash = bhash;
-           bhash = hash;
-           hash = a;
-           a = b;
-           b = hash
-         }
-         if(!cache.hasOwnProperty(ahash)) {
-           cache[ahash] = m = {}
-         }else {
-           m = cache[ahash];
-           if(m.hasOwnProperty(bhash)) {
-             return m[bhash]
-           }
-         }
-         m[bhash] = v = func(a, b);
-         v.hash = type + cachecount.toString();
-         cachecount += 1;
-         return v
-       }
-       return g
++  this.execute = function(document) {
++    var odtDocument = (document), annotation, annotationEnd, cursor = odtDocument.getCursor(memberid), selectedRange, paragraphElement, domUtils = new core.DomUtils;
++    doc = odtDocument.getDOMDocument();
++    annotation = createAnnotationNode(odtDocument, new Date(timestamp));
++    if(length) {
++      annotationEnd = createAnnotationEnd();
++      annotation.annotationEndElement = annotationEnd;
++      insertNodeAtPosition(odtDocument, annotationEnd, position + length)
 +    }
-     return f()
-   }
-   function getUniqueLeaves(leaves, pattern) {
-     if(pattern.p1.type === "choice") {
-       getUniqueLeaves(leaves, pattern.p1)
-     }else {
-       leaves[pattern.p1.hash] = pattern.p1
-     }
-     if(pattern.p2.type === "choice") {
-       getUniqueLeaves(leaves, pattern.p2)
-     }else {
-       leaves[pattern.p2.hash] = pattern.p2
-     }
-   }
-   createChoice = memoize2arg("choice", function(p1, p2) {
-     if(p1 === notAllowed) {
-       return p2
-     }
-     if(p2 === notAllowed) {
-       return p1
-     }
-     if(p1 === p2) {
-       return p1
-     }
-   }, function(p1, p2) {
-     function makeChoice(p1, p2) {
-       return{type:"choice", nullable:p1.nullable || p2.nullable, hash:undefined, nc:undefined, p:undefined, p1:p1, p2:p2, textDeriv:function(context, text) {
-         return createChoice(p1.textDeriv(context, text), p2.textDeriv(context, text))
-       }, startTagOpenDeriv:memoizeNode(function(node) {
-         return createChoice(p1.startTagOpenDeriv(node), p2.startTagOpenDeriv(node))
-       }), attDeriv:function(context, attribute) {
-         return createChoice(p1.attDeriv(context, attribute), p2.attDeriv(context, attribute))
-       }, startTagCloseDeriv:memoize0arg(function() {
-         return createChoice(p1.startTagCloseDeriv(), p2.startTagCloseDeriv())
-       }), endTagDeriv:memoize0arg(function() {
-         return createChoice(p1.endTagDeriv(), p2.endTagDeriv())
-       })}
-     }
-     var leaves = {}, i;
-     getUniqueLeaves(leaves, {p1:p1, p2:p2});
-     p1 = undefined;
-     p2 = undefined;
-     for(i in leaves) {
-       if(leaves.hasOwnProperty(i)) {
-         if(p1 === undefined) {
-           p1 = leaves[i]
-         }else {
-           if(p2 === undefined) {
-             p2 = leaves[i]
-           }else {
-             p2 = createChoice(p2, leaves[i])
-           }
-         }
-       }
-     }
-     return makeChoice(p1, p2)
-   });
-   createInterleave = unorderedMemoize2arg("interleave", function(p1, p2) {
-     if(p1 === notAllowed || p2 === notAllowed) {
-       return notAllowed
-     }
-     if(p1 === empty) {
-       return p2
-     }
-     if(p2 === empty) {
-       return p1
-     }
-   }, function(p1, p2) {
-     return{type:"interleave", nullable:p1.nullable && p2.nullable, hash:undefined, p1:p1, p2:p2, textDeriv:function(context, text) {
-       return createChoice(createInterleave(p1.textDeriv(context, text), p2), createInterleave(p1, p2.textDeriv(context, text)))
-     }, startTagOpenDeriv:memoizeNode(function(node) {
-       return createChoice(applyAfter(function(p) {
-         return createInterleave(p, p2)
-       }, p1.startTagOpenDeriv(node)), applyAfter(function(p) {
-         return createInterleave(p1, p)
-       }, p2.startTagOpenDeriv(node)))
-     }), attDeriv:function(context, attribute) {
-       return createChoice(createInterleave(p1.attDeriv(context, attribute), p2), createInterleave(p1, p2.attDeriv(context, attribute)))
-     }, startTagCloseDeriv:memoize0arg(function() {
-       return createInterleave(p1.startTagCloseDeriv(), p2.startTagCloseDeriv())
-     }), endTagDeriv:undefined}
-   });
-   createGroup = memoize2arg("group", function(p1, p2) {
-     if(p1 === notAllowed || p2 === notAllowed) {
-       return notAllowed
-     }
-     if(p1 === empty) {
-       return p2
-     }
-     if(p2 === empty) {
-       return p1
-     }
-   }, function(p1, p2) {
-     return{type:"group", p1:p1, p2:p2, nullable:p1.nullable && p2.nullable, textDeriv:function(context, text) {
-       var p = createGroup(p1.textDeriv(context, text), p2);
-       if(p1.nullable) {
-         return createChoice(p, p2.textDeriv(context, text))
-       }
-       return p
-     }, startTagOpenDeriv:function(node) {
-       var x = applyAfter(function(p) {
-         return createGroup(p, p2)
-       }, p1.startTagOpenDeriv(node));
-       if(p1.nullable) {
-         return createChoice(x, p2.startTagOpenDeriv(node))
-       }
-       return x
-     }, attDeriv:function(context, attribute) {
-       return createChoice(createGroup(p1.attDeriv(context, attribute), p2), createGroup(p1, p2.attDeriv(context, attribute)))
-     }, startTagCloseDeriv:memoize0arg(function() {
-       return createGroup(p1.startTagCloseDeriv(), p2.startTagCloseDeriv())
-     })}
-   });
-   createAfter = memoize2arg("after", function(p1, p2) {
-     if(p1 === notAllowed || p2 === notAllowed) {
-       return notAllowed
-     }
-   }, function(p1, p2) {
-     return{type:"after", p1:p1, p2:p2, nullable:false, textDeriv:function(context, text) {
-       return createAfter(p1.textDeriv(context, text), p2)
-     }, startTagOpenDeriv:memoizeNode(function(node) {
-       return applyAfter(function(p) {
-         return createAfter(p, p2)
-       }, p1.startTagOpenDeriv(node))
-     }), attDeriv:function(context, attribute) {
-       return createAfter(p1.attDeriv(context, attribute), p2)
-     }, startTagCloseDeriv:memoize0arg(function() {
-       return createAfter(p1.startTagCloseDeriv(), p2)
-     }), endTagDeriv:memoize0arg(function() {
-       return p1.nullable ? p2 : notAllowed
-     })}
-   });
-   createOneOrMore = memoize1arg("oneormore", function(p) {
-     if(p === notAllowed) {
-       return notAllowed
-     }
-     return{type:"oneOrMore", p:p, nullable:p.nullable, textDeriv:function(context, text) {
-       return createGroup(p.textDeriv(context, text), createChoice(this, empty))
-     }, startTagOpenDeriv:function(node) {
-       var oneOrMore = this;
-       return applyAfter(function(pf) {
-         return createGroup(pf, createChoice(oneOrMore, empty))
-       }, p.startTagOpenDeriv(node))
-     }, attDeriv:function(context, attribute) {
-       var oneOrMore = this;
-       return createGroup(p.attDeriv(context, attribute), createChoice(oneOrMore, empty))
-     }, startTagCloseDeriv:memoize0arg(function() {
-       return createOneOrMore(p.startTagCloseDeriv())
-     })}
-   });
-   function createElement(nc, p) {
-     return{type:"element", nc:nc, nullable:false, textDeriv:function() {
-       return notAllowed
-     }, startTagOpenDeriv:function(node) {
-       if(nc.contains(node)) {
-         return createAfter(p, empty)
-       }
-       return notAllowed
-     }, attDeriv:function() {
-       return notAllowed
-     }, startTagCloseDeriv:function() {
-       return this
-     }}
-   }
-   function valueMatch(context, pattern, text) {
-     return pattern.nullable && /^\s+$/.test(text) || pattern.textDeriv(context, text).nullable
-   }
-   createAttribute = memoize2arg("attribute", undefined, function(nc, p) {
-     return{type:"attribute", nullable:false, hash:undefined, nc:nc, p:p, p1:undefined, p2:undefined, textDeriv:undefined, startTagOpenDeriv:undefined, attDeriv:function(context, attribute) {
-       if(nc.contains(attribute) && valueMatch(context, p, attribute.nodeValue)) {
-         return empty
-       }
-       return notAllowed
-     }, startTagCloseDeriv:function() {
-       return notAllowed
-     }, endTagDeriv:undefined}
-   });
-   function createList() {
-     return{type:"list", nullable:false, hash:"list", textDeriv:function() {
-       return empty
-     }}
-   }
-   createValue = memoize1arg("value", function(value) {
-     return{type:"value", nullable:false, value:value, textDeriv:function(context, text) {
-       return text === value ? empty : notAllowed
-     }, attDeriv:function() {
-       return notAllowed
-     }, startTagCloseDeriv:function() {
-       return this
-     }}
-   });
-   createData = memoize1arg("data", function(type) {
-     return{type:"data", nullable:false, dataType:type, textDeriv:function() {
-       return empty
-     }, attDeriv:function() {
-       return notAllowed
-     }, startTagCloseDeriv:function() {
-       return this
-     }}
-   });
-   applyAfter = function applyAfter(f, p) {
-     var result;
-     if(p.type === "after") {
-       result = createAfter(p.p1, f(p.p2))
-     }else {
-       if(p.type === "choice") {
-         result = createChoice(applyAfter(f, p.p1), applyAfter(f, p.p2))
-       }else {
-         result = p
-       }
++    insertNodeAtPosition(odtDocument, annotation, position);
++    odtDocument.emit(ops.OdtDocument.signalStepsInserted, {position:position, length:length});
++    if(cursor) {
++      selectedRange = doc.createRange();
++      paragraphElement = domUtils.getElementsByTagNameNS(annotation, odf.Namespaces.textns, "p")[0];
++      selectedRange.selectNodeContents(paragraphElement);
++      cursor.setSelectedRange(selectedRange, false);
++      odtDocument.emit(ops.Document.signalCursorMoved, cursor)
 +    }
-     return result
++    odtDocument.getOdfCanvas().addAnnotation(annotation);
++    odtDocument.fixCursorPositions();
++    return true
 +  };
-   function attsDeriv(context, pattern, attributes, position) {
-     if(pattern === notAllowed) {
-       return notAllowed
-     }
-     if(position >= attributes.length) {
-       return pattern
-     }
-     if(position === 0) {
-       position = 0
-     }
-     var a = attributes.item(position);
-     while(a.namespaceURI === xmlnsns) {
-       position += 1;
-       if(position >= attributes.length) {
-         return pattern
-       }
-       a = attributes.item(position)
-     }
-     a = attsDeriv(context, pattern.attDeriv(context, attributes.item(position)), attributes, position + 1);
-     return a
-   }
-   function childrenDeriv(context, pattern, walker) {
-     var element = walker.currentNode, childNode = walker.firstChild(), childNodes = [], i, p;
-     while(childNode) {
-       if(childNode.nodeType === Node.ELEMENT_NODE) {
-         childNodes.push(childNode)
-       }else {
-         if(childNode.nodeType === Node.TEXT_NODE && !/^\s*$/.test(childNode.nodeValue)) {
-           childNodes.push(childNode.nodeValue)
-         }
-       }
-       childNode = walker.nextSibling()
-     }
-     if(childNodes.length === 0) {
-       childNodes = [""]
-     }
-     p = pattern;
-     for(i = 0;p !== notAllowed && i < childNodes.length;i += 1) {
-       childNode = childNodes[i];
-       if(typeof childNode === "string") {
-         if(/^\s*$/.test(childNode)) {
-           p = createChoice(p, p.textDeriv(context, childNode))
-         }else {
-           p = p.textDeriv(context, childNode)
-         }
-       }else {
-         walker.currentNode = childNode;
-         p = childDeriv(context, p, walker)
-       }
-     }
-     walker.currentNode = element;
-     return p
-   }
-   childDeriv = function childDeriv(context, pattern, walker) {
-     var childNode = walker.currentNode, p;
-     p = pattern.startTagOpenDeriv(childNode);
-     p = attsDeriv(context, p, childNode.attributes, 0);
-     p = p.startTagCloseDeriv();
-     p = childrenDeriv(context, p, walker);
-     p = p.endTagDeriv();
-     return p
-   };
-   function addNames(name, ns, pattern) {
-     if(pattern.e[0].a) {
-       name.push(pattern.e[0].text);
-       ns.push(pattern.e[0].a.ns)
-     }else {
-       addNames(name, ns, pattern.e[0])
-     }
-     if(pattern.e[1].a) {
-       name.push(pattern.e[1].text);
-       ns.push(pattern.e[1].a.ns)
-     }else {
-       addNames(name, ns, pattern.e[1])
-     }
++  this.spec = function() {
++    return{optype:"AddAnnotation", memberid:memberid, timestamp:timestamp, position:position, length:length, name:name}
 +  }
-   createNameClass = function createNameClass(pattern) {
-     var name, ns, hash, i, result;
-     if(pattern.name === "name") {
-       name = pattern.text;
-       ns = pattern.a.ns;
-       result = {name:name, ns:ns, hash:"{" + ns + "}" + name, contains:function(node) {
-         return node.namespaceURI === ns && node.localName === name
-       }}
-     }else {
-       if(pattern.name === "choice") {
-         name = [];
-         ns = [];
-         addNames(name, ns, pattern);
-         hash = "";
-         for(i = 0;i < name.length;i += 1) {
-           hash += "{" + ns[i] + "}" + name[i] + ","
-         }
-         result = {hash:hash, contains:function(node) {
-           var j;
-           for(j = 0;j < name.length;j += 1) {
-             if(name[j] === node.localName && ns[j] === node.namespaceURI) {
-               return true
-             }
-           }
-           return false
-         }}
-       }else {
-         result = {hash:"anyName", contains:function() {
-           return true
-         }}
-       }
-     }
-     return result
++};
++ops.OpAddAnnotation.Spec;
++ops.OpAddAnnotation.InitSpec;
++/*
++
++ Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
++
++ @licstart
++ The JavaScript code in this page is free software: you can redistribute it
++ and/or modify it under the terms of the GNU Affero General Public License
++ (GNU AGPL) as published by the Free Software Foundation, either version 3 of
++ the License, or (at your option) any later version.  The code is distributed
++ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
++
++ You should have received a copy of the GNU Affero General Public License
++ along with this code.  If not, see <http://www.gnu.org/licenses/>.
++
++ As additional permission under GNU AGPL version 3 section 7, you
++ may distribute non-source (e.g., minimized or compacted) forms of
++ that code without the copy of the GNU GPL normally required by
++ section 4, provided you include this license notice and a URL
++ through which recipients can access the Corresponding Source.
++
++ As a special exception to the AGPL, any HTML file which merely makes function
++ calls to this code, and for that purpose includes it by reference shall be
++ deemed a separate work for copyright law purposes. In addition, the copyright
++ holders of this code give you permission to combine this code with free
++ software libraries that are released under the GNU LGPL. You may copy and
++ distribute such a system following the terms of the GNU AGPL for this code
++ and the LGPL for the libraries. If you modify this code, you may extend this
++ exception to your version of the code, but you are not obligated to do so.
++ If you do not wish to do so, delete this exception statement from your
++ version.
++
++ This license applies to this entire compilation.
++ @licend
++ @source: http://www.webodf.org/
++ @source: https://github.com/kogmbh/WebODF/
++*/
++ops.OpAddCursor = function OpAddCursor() {
++  var memberid, timestamp;
++  this.init = function(data) {
++    memberid = data.memberid;
++    timestamp = data.timestamp
 +  };
-   function resolveElement(pattern, elements) {
-     var element, p, i, hash;
-     hash = "element" + pattern.id.toString();
-     p = elements[pattern.id] = {hash:hash};
-     element = createElement(createNameClass(pattern.e[0]), makePattern(pattern.e[1], elements));
-     for(i in element) {
-       if(element.hasOwnProperty(i)) {
-         p[i] = element[i]
-       }
-     }
-     return p
-   }
-   makePattern = function makePattern(pattern, elements) {
-     var p, i;
-     if(pattern.name === "elementref") {
-       p = pattern.id || 0;
-       pattern = elements[p];
-       if(pattern.name !== undefined) {
-         return resolveElement(pattern, elements)
-       }
-       return pattern
-     }
-     switch(pattern.name) {
-       case "empty":
-         return empty;
-       case "notAllowed":
-         return notAllowed;
-       case "text":
-         return text;
-       case "choice":
-         return createChoice(makePattern(pattern.e[0], elements), makePattern(pattern.e[1], elements));
-       case "interleave":
-         p = makePattern(pattern.e[0], elements);
-         for(i = 1;i < pattern.e.length;i += 1) {
-           p = createInterleave(p, makePattern(pattern.e[i], elements))
-         }
-         return p;
-       case "group":
-         return createGroup(makePattern(pattern.e[0], elements), makePattern(pattern.e[1], elements));
-       case "oneOrMore":
-         return createOneOrMore(makePattern(pattern.e[0], elements));
-       case "attribute":
-         return createAttribute(createNameClass(pattern.e[0]), makePattern(pattern.e[1], elements));
-       case "value":
-         return createValue(pattern.text);
-       case "data":
-         p = pattern.a && pattern.a.type;
-         if(p === undefined) {
-           p = ""
-         }
-         return createData(p);
-       case "list":
-         return createList()
-     }
-     throw"No support for " + pattern.name;
-   };
-   this.makePattern = function(pattern, elements) {
-     var copy = {}, i;
-     for(i in elements) {
-       if(elements.hasOwnProperty(i)) {
-         copy[i] = elements[i]
-       }
-     }
-     i = makePattern(pattern, copy);
-     return i
-   };
-   this.validate = function validate(walker, callback) {
-     var errors;
-     walker.currentNode = walker.root;
-     errors = childDeriv(null, rootPattern, walker);
-     if(!errors.nullable) {
-       runtime.log("Error in Relax NG validation: " + errors);
-       callback(["Error in Relax NG validation: " + errors])
-     }else {
-       callback(null)
++  this.isEdit = false;
++  this.group = undefined;
++  this.execute = function(document) {
++    var odtDocument = (document), cursor = odtDocument.getCursor(memberid);
++    if(cursor) {
++      return false
 +    }
++    cursor = new ops.OdtCursor(memberid, odtDocument);
++    odtDocument.addCursor(cursor);
++    odtDocument.emit(ops.Document.signalCursorAdded, cursor);
++    return true
 +  };
-   this.init = function init(rootPattern1) {
-     rootPattern = rootPattern1
++  this.spec = function() {
++    return{optype:"AddCursor", memberid:memberid, timestamp:timestamp}
 +  }
 +};
- runtime.loadClass("xmldom.RelaxNGParser");
- xmldom.RelaxNG2 = function RelaxNG2() {
-   var start, validateNonEmptyPattern, nsmap;
-   function RelaxNGParseError(error, context) {
-     this.message = function() {
-       if(context) {
-         error += context.nodeType === Node.ELEMENT_NODE ? " Element " : " Node ";
-         error += context.nodeName;
-         if(context.nodeValue) {
-           error += " with value '" + context.nodeValue + "'"
-         }
-         error += "."
-       }
-       return error
-     }
-   }
-   function validateOneOrMore(elementdef, walker, element) {
-     var node, i = 0, err;
-     do {
-       node = walker.currentNode;
-       err = validateNonEmptyPattern(elementdef.e[0], walker, element);
-       i += 1
-     }while(!err && node !== walker.currentNode);
-     if(i > 1) {
-       walker.currentNode = node;
-       return null
-     }
-     return err
-   }
-   function qName(node) {
-     return nsmap[node.namespaceURI] + ":" + node.localName
-   }
-   function isWhitespace(node) {
-     return node && (node.nodeType === Node.TEXT_NODE && /^\s+$/.test(node.nodeValue))
-   }
-   function validatePattern(elementdef, walker, element, data) {
-     if(elementdef.name === "empty") {
-       return null
-     }
-     return validateNonEmptyPattern(elementdef, walker, element, data)
-   }
-   function validateAttribute(elementdef, walker, element) {
-     if(elementdef.e.length !== 2) {
-       throw"Attribute with wrong # of elements: " + elementdef.e.length;
-     }
-     var att, a, l = elementdef.localnames.length, i;
-     for(i = 0;i < l;i += 1) {
-       a = element.getAttributeNS(elementdef.namespaces[i], elementdef.localnames[i]);
-       if(a === "" && !element.hasAttributeNS(elementdef.namespaces[i], elementdef.localnames[i])) {
-         a = undefined
-       }
-       if(att !== undefined && a !== undefined) {
-         return[new RelaxNGParseError("Attribute defined too often.", element)]
-       }
-       att = a
-     }
-     if(att === undefined) {
-       return[new RelaxNGParseError("Attribute not found: " + elementdef.names, element)]
++ops.OpAddCursor.Spec;
++ops.OpAddCursor.InitSpec;
++/*
++
++ Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
++
++ @licstart
++ This file is part of WebODF.
++
++ WebODF is free software: you can redistribute it and/or modify it
++ under the terms of the GNU Affero General Public License (GNU AGPL)
++ as published by the Free Software Foundation, either version 3 of
++ the License, or (at your option) any later version.
++
++ WebODF is distributed in the hope that it will be useful, but
++ WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ GNU Affero General Public License for more details.
++
++ You should have received a copy of the GNU Affero General Public License
++ along with WebODF.  If not, see <http://www.gnu.org/licenses/>.
++ @licend
++
++ @source: http://www.webodf.org/
++ @source: https://github.com/kogmbh/WebODF/
++*/
++ops.OpAddMember = function OpAddMember() {
++  var memberid, timestamp, setProperties;
++  this.init = function(data) {
++    memberid = data.memberid;
++    timestamp = parseInt(data.timestamp, 10);
++    setProperties = data.setProperties
++  };
++  this.isEdit = false;
++  this.group = undefined;
++  this.execute = function(document) {
++    var odtDocument = (document), member;
++    if(odtDocument.getMember(memberid)) {
++      return false
 +    }
-     return validatePattern(elementdef.e[1], walker, element, att)
-   }
-   function validateTop(elementdef, walker, element) {
-     return validatePattern(elementdef, walker, element)
++    member = new ops.Member(memberid, setProperties);
++    odtDocument.addMember(member);
++    odtDocument.emit(ops.Document.signalMemberAdded, member);
++    return true
++  };
++  this.spec = function() {
++    return{optype:"AddMember", memberid:memberid, timestamp:timestamp, setProperties:setProperties}
 +  }
-   function validateElement(elementdef, walker) {
-     if(elementdef.e.length !== 2) {
-       throw"Element with wrong # of elements: " + elementdef.e.length;
-     }
-     var node = walker.currentNode, type = node ? node.nodeType : 0, error = null;
-     while(type > Node.ELEMENT_NODE) {
-       if(type !== Node.COMMENT_NODE && (type !== Node.TEXT_NODE || !/^\s+$/.test(walker.currentNode.nodeValue))) {
-         return[new RelaxNGParseError("Not allowed node of type " + type + ".")]
-       }
-       node = walker.nextSibling();
-       type = node ? node.nodeType : 0
-     }
-     if(!node) {
-       return[new RelaxNGParseError("Missing element " + elementdef.names)]
++};
++ops.OpAddMember.Spec;
++ops.OpAddMember.InitSpec;
++/*
++
++ Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
++
++ @licstart
++ The JavaScript code in this page is free software: you can redistribute it
++ and/or modify it under the terms of the GNU Affero General Public License
++ (GNU AGPL) as published by the Free Software Foundation, either version 3 of
++ the License, or (at your option) any later version.  The code is distributed
++ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
++
++ You should have received a copy of the GNU Affero General Public License
++ along with this code.  If not, see <http://www.gnu.org/licenses/>.
++
++ As additional permission under GNU AGPL version 3 section 7, you
++ may distribute non-source (e.g., minimized or compacted) forms of
++ that code without the copy of the GNU GPL normally required by
++ section 4, provided you include this license notice and a URL
++ through which recipients can access the Corresponding Source.
++
++ As a special exception to the AGPL, any HTML file which merely makes function
++ calls to this code, and for that purpose includes it by reference shall be
++ deemed a separate work for copyright law purposes. In addition, the copyright
++ holders of this code give you permission to combine this code with free
++ software libraries that are released under the GNU LGPL. You may copy and
++ distribute such a system following the terms of the GNU AGPL for this code
++ and the LGPL for the libraries. If you modify this code, you may extend this
++ exception to your version of the code, but you are not obligated to do so.
++ If you do not wish to do so, delete this exception statement from your
++ version.
++
++ This license applies to this entire compilation.
++ @licend
++ @source: http://www.webodf.org/
++ @source: https://github.com/kogmbh/WebODF/
++*/
++ops.OpAddStyle = function OpAddStyle() {
++  var memberid, timestamp, styleName, styleFamily, isAutomaticStyle, setProperties, stylens = odf.Namespaces.stylens;
++  this.init = function(data) {
++    memberid = data.memberid;
++    timestamp = data.timestamp;
++    styleName = data.styleName;
++    styleFamily = data.styleFamily;
++    isAutomaticStyle = data.isAutomaticStyle === "true" || data.isAutomaticStyle === true;
++    setProperties = data.setProperties
++  };
++  this.isEdit = true;
++  this.group = undefined;
++  this.execute = function(document) {
++    var odtDocument = (document), odfContainer = odtDocument.getOdfCanvas().odfContainer(), formatting = odtDocument.getFormatting(), dom = odtDocument.getDOMDocument(), styleNode = dom.createElementNS(stylens, "style:style");
++    if(!styleNode) {
++      return false
 +    }
-     if(elementdef.names && elementdef.names.indexOf(qName(node)) === -1) {
-       return[new RelaxNGParseError("Found " + node.nodeName + " instead of " + elementdef.names + ".", node)]
++    if(setProperties) {
++      formatting.updateStyle(styleNode, setProperties)
 +    }
-     if(walker.firstChild()) {
-       error = validateTop(elementdef.e[1], walker, node);
-       while(walker.nextSibling()) {
-         type = walker.currentNode.nodeType;
-         if(!isWhitespace(walker.currentNode) && type !== Node.COMMENT_NODE) {
-           return[new RelaxNGParseError("Spurious content.", walker.currentNode)]
-         }
-       }
-       if(walker.parentNode() !== node) {
-         return[new RelaxNGParseError("Implementation error.")]
-       }
++    styleNode.setAttributeNS(stylens, "style:family", styleFamily);
++    styleNode.setAttributeNS(stylens, "style:name", styleName);
++    if(isAutomaticStyle) {
++      odfContainer.rootElement.automaticStyles.appendChild(styleNode)
 +    }else {
-       error = validateTop(elementdef.e[1], walker, node)
-     }
-     node = walker.nextSibling();
-     return error
-   }
-   function validateChoice(elementdef, walker, element, data) {
-     if(elementdef.e.length !== 2) {
-       throw"Choice with wrong # of options: " + elementdef.e.length;
-     }
-     var node = walker.currentNode, err;
-     if(elementdef.e[0].name === "empty") {
-       err = validateNonEmptyPattern(elementdef.e[1], walker, element, data);
-       if(err) {
-         walker.currentNode = node
-       }
-       return null
++      odfContainer.rootElement.styles.appendChild(styleNode)
 +    }
-     err = validatePattern(elementdef.e[0], walker, element, data);
-     if(err) {
-       walker.currentNode = node;
-       err = validateNonEmptyPattern(elementdef.e[1], walker, element, data)
++    odtDocument.getOdfCanvas().refreshCSS();
++    if(!isAutomaticStyle) {
++      odtDocument.emit(ops.OdtDocument.signalCommonStyleCreated, {name:styleName, family:styleFamily})
 +    }
-     return err
++    return true
++  };
++  this.spec = function() {
++    return{optype:"AddStyle", memberid:memberid, timestamp:timestamp, styleName:styleName, styleFamily:styleFamily, isAutomaticStyle:isAutomaticStyle, setProperties:setProperties}
 +  }
-   function validateInterleave(elementdef, walker, element) {
-     var l = elementdef.e.length, n = [l], err, i, todo = l, donethisround, node, subnode, e;
-     while(todo > 0) {
-       donethisround = 0;
-       node = walker.currentNode;
-       for(i = 0;i < l;i += 1) {
-         subnode = walker.currentNode;
-         if(n[i] !== true && n[i] !== subnode) {
-           e = elementdef.e[i];
-           err = validateNonEmptyPattern(e, walker, element);
-           if(err) {
-             walker.currentNode = subnode;
-             if(n[i] === undefined) {
-               n[i] = false
-             }
-           }else {
-             if(subnode === walker.currentNode || (e.name === "oneOrMore" || e.name === "choice" && (e.e[0].name === "oneOrMore" || e.e[1].name === "oneOrMore"))) {
-               donethisround += 1;
-               n[i] = subnode
-             }else {
-               donethisround += 1;
-               n[i] = true
-             }
-           }
-         }
-       }
-       if(node === walker.currentNode && donethisround === todo) {
-         return null
-       }
-       if(donethisround === 0) {
-         for(i = 0;i < l;i += 1) {
-           if(n[i] === false) {
-             return[new RelaxNGParseError("Interleave does not match.", element)]
-           }
-         }
-         return null
-       }
-       todo = 0;
-       for(i = 0;i < l;i += 1) {
-         if(n[i] !== true) {
-           todo += 1
-         }
-       }
-     }
-     return null
-   }
-   function validateGroup(elementdef, walker, element) {
-     if(elementdef.e.length !== 2) {
-       throw"Group with wrong # of members: " + elementdef.e.length;
++};
++ops.OpAddStyle.Spec;
++ops.OpAddStyle.InitSpec;
++/*
++
++ Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
++
++ @licstart
++ The JavaScript code in this page is free software: you can redistribute it
++ and/or modify it under the terms of the GNU Affero General Public License
++ (GNU AGPL) as published by the Free Software Foundation, either version 3 of
++ the License, or (at your option) any later version.  The code is distributed
++ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
++
++ You should have received a copy of the GNU Affero General Public License
++ along with this code.  If not, see <http://www.gnu.org/licenses/>.
++
++ As additional permission under GNU AGPL version 3 section 7, you
++ may distribute non-source (e.g., minimized or compacted) forms of
++ that code without the copy of the GNU GPL normally required by
++ section 4, provided you include this license notice and a URL
++ through which recipients can access the Corresponding Source.
++
++ As a special exception to the AGPL, any HTML file which merely makes function
++ calls to this code, and for that purpose includes it by reference shall be
++ deemed a separate work for copyright law purposes. In addition, the copyright
++ holders of this code give you permission to combine this code with free
++ software libraries that are released under the GNU LGPL. You may copy and
++ distribute such a system following the terms of the GNU AGPL for this code
++ and the LGPL for the libraries. If you modify this code, you may extend this
++ exception to your version of the code, but you are not obligated to do so.
++ If you do not wish to do so, delete this exception statement from your
++ version.
++
++ This license applies to this entire compilation.
++ @licend
++ @source: http://www.webodf.org/
++ @source: https://github.com/kogmbh/WebODF/
++*/
++odf.ObjectNameGenerator = function ObjectNameGenerator(odfContainer, memberId) {
++  var stylens = odf.Namespaces.stylens, drawns = odf.Namespaces.drawns, xlinkns = odf.Namespaces.xlinkns, domUtils = new core.DomUtils, utils = new core.Utils, memberIdHash = utils.hashString(memberId), styleNameGenerator = null, frameNameGenerator = null, imageNameGenerator = null, existingFrameNames = {}, existingImageNames = {};
++  function NameGenerator(prefix, findExistingNames) {
++    var reportedNames = {};
++    this.generateName = function() {
++      var existingNames = findExistingNames(), startIndex = 0, name;
++      do {
++        name = prefix + startIndex;
++        startIndex += 1
++      }while(reportedNames[name] || existingNames[name]);
++      reportedNames[name] = true;
++      return name
 +    }
-     return validateNonEmptyPattern(elementdef.e[0], walker, element) || validateNonEmptyPattern(elementdef.e[1], walker, element)
 +  }
-   function validateText(elementdef, walker, element) {
-     var node = walker.currentNode, type = node ? node.nodeType : 0;
-     while(node !== element && type !== 3) {
-       if(type === 1) {
-         return[new RelaxNGParseError("Element not allowed here.", node)]
++  function getAllStyleNames() {
++    var styleElements = [odfContainer.rootElement.automaticStyles, odfContainer.rootElement.styles], styleNames = {};
++    function getStyleNames(styleListElement) {
++      var e = styleListElement.firstElementChild;
++      while(e) {
++        if(e.namespaceURI === stylens && e.localName === "style") {
++          styleNames[e.getAttributeNS(stylens, "name")] = true
++        }
++        e = e.nextElementSibling
 +      }
-       node = walker.nextSibling();
-       type = node ? node.nodeType : 0
 +    }
-     walker.nextSibling();
-     return null
++    styleElements.forEach(getStyleNames);
++    return styleNames
 +  }
-   validateNonEmptyPattern = function validateNonEmptyPattern(elementdef, walker, element, data) {
-     var name = elementdef.name, err = null;
-     if(name === "text") {
-       err = validateText(elementdef, walker, element)
-     }else {
-       if(name === "data") {
-         err = null
-       }else {
-         if(name === "value") {
-           if(data !== elementdef.text) {
-             err = [new RelaxNGParseError("Wrong value, should be '" + elementdef.text + "', not '" + data + "'", element)]
-           }
-         }else {
-           if(name === "list") {
-             err = null
-           }else {
-             if(name === "attribute") {
-               err = validateAttribute(elementdef, walker, element)
-             }else {
-               if(name === "element") {
-                 err = validateElement(elementdef, walker)
-               }else {
-                 if(name === "oneOrMore") {
-                   err = validateOneOrMore(elementdef, walker, element)
-                 }else {
-                   if(name === "choice") {
-                     err = validateChoice(elementdef, walker, element, data)
-                   }else {
-                     if(name === "group") {
-                       err = validateGroup(elementdef, walker, element)
-                     }else {
-                       if(name === "interleave") {
-                         err = validateInterleave(elementdef, walker, element)
-                       }else {
-                         throw name + " not allowed in nonEmptyPattern.";
-                       }
-                     }
-                   }
-                 }
-               }
-             }
-           }
-         }
-       }
++  this.generateStyleName = function() {
++    if(styleNameGenerator === null) {
++      styleNameGenerator = new NameGenerator("auto" + memberIdHash + "_", function() {
++        return getAllStyleNames()
++      })
 +    }
-     return err
++    return styleNameGenerator.generateName()
 +  };
-   this.validate = function validate(walker, callback) {
-     walker.currentNode = walker.root;
-     var errors = validatePattern(start.e[0], walker, (walker.root));
-     callback(errors)
++  this.generateFrameName = function() {
++    if(frameNameGenerator === null) {
++      var nodes = domUtils.getElementsByTagNameNS(odfContainer.rootElement.body, drawns, "frame");
++      nodes.forEach(function(frame) {
++        existingFrameNames[frame.getAttributeNS(drawns, "name")] = true
++      });
++      frameNameGenerator = new NameGenerator("fr" + memberIdHash + "_", function() {
++        return existingFrameNames
++      })
++    }
++    return frameNameGenerator.generateName()
 +  };
-   this.init = function init(start1, nsmap1) {
-     start = start1;
-     nsmap = nsmap1
++  this.generateImageName = function() {
++    if(imageNameGenerator === null) {
++      var nodes = domUtils.getElementsByTagNameNS(odfContainer.rootElement.body, drawns, "image");
++      nodes.forEach(function(image) {
++        var path = image.getAttributeNS(xlinkns, "href");
++        path = path.substring("Pictures/".length, path.lastIndexOf("."));
++        existingImageNames[path] = true
++      });
++      imageNameGenerator = new NameGenerator("img" + memberIdHash + "_", function() {
++        return existingImageNames
++      })
++    }
++    return imageNameGenerator.generateName()
 +  }
 +};
- runtime.loadClass("core.DomUtils");
- runtime.loadClass("gui.Avatar");
- runtime.loadClass("ops.OdtCursor");
- gui.Caret = function Caret(cursor, avatarInitiallyVisible, blinkOnRangeSelect) {
-   var MIN_CARET_HEIGHT_PX = 8, DEFAULT_CARET_TOP = "5%", DEFAULT_CARET_HEIGHT = "1em", span, avatar, cursorNode, isShown = true, shouldBlink = false, blinking = false, blinkTimeout, domUtils = new core.DomUtils;
-   function blink(reset) {
-     if(!shouldBlink || !cursorNode.parentNode) {
-       return
-     }
-     if(!blinking || reset) {
-       if(reset && blinkTimeout !== undefined) {
-         runtime.clearTimeout(blinkTimeout)
++/*
++
++ Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
++
++ @licstart
++ The JavaScript code in this page is free software: you can redistribute it
++ and/or modify it under the terms of the GNU Affero General Public License
++ (GNU AGPL) as published by the Free Software Foundation, either version 3 of
++ the License, or (at your option) any later version.  The code is distributed
++ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
++
++ You should have received a copy of the GNU Affero General Public License
++ along with this code.  If not, see <http://www.gnu.org/licenses/>.
++
++ As additional permission under GNU AGPL version 3 section 7, you
++ may distribute non-source (e.g., minimized or compacted) forms of
++ that code without the copy of the GNU GPL normally required by
++ section 4, provided you include this license notice and a URL
++ through which recipients can access the Corresponding Source.
++
++ As a special exception to the AGPL, any HTML file which merely makes function
++ calls to this code, and for that purpose includes it by reference shall be
++ deemed a separate work for copyright law purposes. In addition, the copyright
++ holders of this code give you permission to combine this code with free
++ software libraries that are released under the GNU LGPL. You may copy and
++ distribute such a system following the terms of the GNU AGPL for this code
++ and the LGPL for the libraries. If you modify this code, you may extend this
++ exception to your version of the code, but you are not obligated to do so.
++ If you do not wish to do so, delete this exception statement from your
++ version.
++
++ This license applies to this entire compilation.
++ @licend
++ @source: http://www.webodf.org/
++ @source: https://github.com/kogmbh/WebODF/
++*/
++odf.TextStyleApplicator = function TextStyleApplicator(objectNameGenerator, formatting, automaticStyles) {
++  var domUtils = new core.DomUtils, textns = odf.Namespaces.textns, stylens = odf.Namespaces.stylens, textProperties = "style:text-properties", webodfns = "urn:webodf:names:scope";
++  function StyleLookup(info) {
++    var cachedAppliedStyles = {};
++    function compare(expected, actual) {
++      if(typeof expected === "object" && typeof actual === "object") {
++        return Object.keys(expected).every(function(key) {
++          return compare(expected[key], actual[key])
++        })
 +      }
-       blinking = true;
-       span.style.opacity = reset || span.style.opacity === "0" ? "1" : "0";
-       blinkTimeout = runtime.setTimeout(function() {
-         blinking = false;
-         blink(false)
-       }, 500)
++      return expected === actual
 +    }
-   }
-   function getCaretClientRectWithMargin(caretElement, margin) {
-     var caretRect = caretElement.getBoundingClientRect();
-     return{left:caretRect.left - margin.left, top:caretRect.top - margin.top, right:caretRect.right + margin.right, bottom:caretRect.bottom + margin.bottom}
-   }
-   function length(node) {
-     return node.nodeType === Node.TEXT_NODE ? node.textContent.length : node.childNodes.length
-   }
-   function verticalOverlap(cursorNode, rangeRect) {
-     var cursorRect = cursorNode.getBoundingClientRect(), intersectTop = 0, intersectBottom = 0;
-     if(cursorRect && rangeRect) {
-       intersectTop = Math.max(cursorRect.top, rangeRect.top);
-       intersectBottom = Math.min(cursorRect.bottom, rangeRect.bottom)
++    this.isStyleApplied = function(textNode) {
++      var appliedStyle = formatting.getAppliedStylesForElement(textNode, cachedAppliedStyles);
++      return compare(info, appliedStyle)
 +    }
-     return intersectBottom - intersectTop
 +  }
-   function getSelectionRect() {
-     var range = cursor.getSelectedRange().cloneRange(), node = cursor.getNode(), nextRectangle, selectionRectangle = null, nodeLength;
-     if(node.previousSibling) {
-       nodeLength = length(node.previousSibling);
-       range.setStart(node.previousSibling, nodeLength > 0 ? nodeLength - 1 : 0);
-       range.setEnd(node.previousSibling, nodeLength);
-       nextRectangle = range.getBoundingClientRect();
-       if(nextRectangle && nextRectangle.height) {
-         selectionRectangle = nextRectangle
-       }
++  function StyleManager(info) {
++    var createdStyles = {};
++    function createDirectFormat(existingStyleName, document) {
++      var derivedStyleInfo, derivedStyleNode;
++      derivedStyleInfo = existingStyleName ? formatting.createDerivedStyleObject(existingStyleName, "text", info) : info;
++      derivedStyleNode = document.createElementNS(stylens, "style:style");
++      formatting.updateStyle(derivedStyleNode, derivedStyleInfo);
++      derivedStyleNode.setAttributeNS(stylens, "style:name", objectNameGenerator.generateStyleName());
++      derivedStyleNode.setAttributeNS(stylens, "style:family", "text");
++      derivedStyleNode.setAttributeNS(webodfns, "scope", "document-content");
++      automaticStyles.appendChild(derivedStyleNode);
++      return derivedStyleNode
 +    }
-     if(node.nextSibling) {
-       range.setStart(node.nextSibling, 0);
-       range.setEnd(node.nextSibling, length(node.nextSibling) > 0 ? 1 : 0);
-       nextRectangle = range.getBoundingClientRect();
-       if(nextRectangle && nextRectangle.height) {
-         if(!selectionRectangle || verticalOverlap(node, nextRectangle) > verticalOverlap(node, selectionRectangle)) {
-           selectionRectangle = nextRectangle
-         }
++    function getDirectStyle(existingStyleName, document) {
++      existingStyleName = existingStyleName || "";
++      if(!createdStyles.hasOwnProperty(existingStyleName)) {
++        createdStyles[existingStyleName] = createDirectFormat(existingStyleName, document)
 +      }
++      return createdStyles[existingStyleName].getAttributeNS(stylens, "name")
 +    }
-     return selectionRectangle
-   }
-   function handleUpdate() {
-     var selectionRect = getSelectionRect(), zoomLevel = cursor.getOdtDocument().getOdfCanvas().getZoomLevel(), caretRect;
-     if(isShown && cursor.getSelectionType() === ops.OdtCursor.RangeSelection) {
-       span.style.visibility = "visible"
-     }else {
-       span.style.visibility = "hidden"
-     }
-     if(selectionRect) {
-       span.style.top = "0";
-       caretRect = domUtils.getBoundingClientRect(span);
-       if(selectionRect.height < MIN_CARET_HEIGHT_PX) {
-         selectionRect = {top:selectionRect.top - (MIN_CARET_HEIGHT_PX - selectionRect.height) / 2, height:MIN_CARET_HEIGHT_PX}
-       }
-       span.style.height = domUtils.adaptRangeDifferenceToZoomLevel(selectionRect.height, zoomLevel) + "px";
-       span.style.top = domUtils.adaptRangeDifferenceToZoomLevel(selectionRect.top - caretRect.top, zoomLevel) + "px"
-     }else {
-       span.style.height = DEFAULT_CARET_HEIGHT;
-       span.style.top = DEFAULT_CARET_TOP
++    this.applyStyleToContainer = function(container) {
++      var name = getDirectStyle(container.getAttributeNS(textns, "style-name"), container.ownerDocument);
++      container.setAttributeNS(textns, "text:style-name", name)
 +    }
 +  }
-   this.handleUpdate = handleUpdate;
-   this.refreshCursorBlinking = function() {
-     if(blinkOnRangeSelect || cursor.getSelectedRange().collapsed) {
-       shouldBlink = true;
-       blink(true)
++  function isTextSpan(node) {
++    return node.localName === "span" && node.namespaceURI === textns
++  }
++  function moveToNewSpan(startNode, limits) {
++    var document = startNode.ownerDocument, originalContainer = (startNode.parentNode), styledContainer, trailingContainer, moveTrailing, node, nextNode, loopGuard = new core.LoopWatchDog(1E4), styledNodes = [];
++    if(!isTextSpan(originalContainer)) {
++      styledContainer = document.createElementNS(textns, "text:span");
++      originalContainer.insertBefore(styledContainer, startNode);
++      moveTrailing = false
 +    }else {
-       shouldBlink = false;
-       span.style.opacity = "0"
++      if(startNode.previousSibling && !domUtils.rangeContainsNode(limits, (originalContainer.firstChild))) {
++        styledContainer = originalContainer.cloneNode(false);
++        originalContainer.parentNode.insertBefore(styledContainer, originalContainer.nextSibling);
++        moveTrailing = true
++      }else {
++        styledContainer = originalContainer;
++        moveTrailing = true
++      }
 +    }
-   };
-   this.setFocus = function() {
-     shouldBlink = true;
-     avatar.markAsFocussed(true);
-     blink(true)
-   };
-   this.removeFocus = function() {
-     shouldBlink = false;
-     avatar.markAsFocussed(false);
-     span.style.opacity = "1"
-   };
-   this.show = function() {
-     isShown = true;
-     handleUpdate();
-     avatar.markAsFocussed(true)
-   };
-   this.hide = function() {
-     isShown = false;
-     handleUpdate();
-     avatar.markAsFocussed(false)
-   };
-   this.setAvatarImageUrl = function(url) {
-     avatar.setImageUrl(url)
-   };
-   this.setColor = function(newColor) {
-     span.style.borderColor = newColor;
-     avatar.setColor(newColor)
-   };
-   this.getCursor = function() {
-     return cursor
-   };
-   this.getFocusElement = function() {
-     return span
-   };
-   this.toggleHandleVisibility = function() {
-     if(avatar.isVisible()) {
-       avatar.hide()
-     }else {
-       avatar.show()
++    styledNodes.push(startNode);
++    node = startNode.nextSibling;
++    while(node && domUtils.rangeContainsNode(limits, node)) {
++      loopGuard.check();
++      styledNodes.push(node);
++      node = node.nextSibling
 +    }
-   };
-   this.showHandle = function() {
-     avatar.show()
-   };
-   this.hideHandle = function() {
-     avatar.hide()
-   };
-   this.ensureVisible = function() {
-     var canvasElement = cursor.getOdtDocument().getOdfCanvas().getElement(), canvasContainerElement = canvasElement.parentNode, caretRect, canvasContainerRect, horizontalMargin = canvasContainerElement.offsetWidth - canvasContainerElement.clientWidth + 5, verticalMargin = canvasContainerElement.offsetHeight - canvasContainerElement.clientHeight + 5;
-     caretRect = getCaretClientRectWithMargin(span, {top:verticalMargin, left:horizontalMargin, bottom:verticalMargin, right:horizontalMargin});
-     canvasContainerRect = canvasContainerElement.getBoundingClientRect();
-     if(caretRect.top < canvasContainerRect.top) {
-       canvasContainerElement.scrollTop -= canvasContainerRect.top - caretRect.top
-     }else {
-       if(caretRect.bottom > canvasContainerRect.bottom) {
-         canvasContainerElement.scrollTop += caretRect.bottom - canvasContainerRect.bottom
++    styledNodes.forEach(function(n) {
++      if(n.parentNode !== styledContainer) {
++        styledContainer.appendChild(n)
++      }
++    });
++    if(node && moveTrailing) {
++      trailingContainer = styledContainer.cloneNode(false);
++      styledContainer.parentNode.insertBefore(trailingContainer, styledContainer.nextSibling);
++      while(node) {
++        loopGuard.check();
++        nextNode = node.nextSibling;
++        trailingContainer.appendChild(node);
++        node = nextNode
 +      }
 +    }
-     if(caretRect.left < canvasContainerRect.left) {
-       canvasContainerElement.scrollLeft -= canvasContainerRect.left - caretRect.left
-     }else {
-       if(caretRect.right > canvasContainerRect.right) {
-         canvasContainerElement.scrollLeft += caretRect.right - canvasContainerRect.right
++    return(styledContainer)
++  }
++  this.applyStyle = function(textNodes, limits, info) {
++    var textPropsOnly = {}, isStyled, container, styleCache, styleLookup;
++    runtime.assert(info && info.hasOwnProperty(textProperties), "applyStyle without any text properties");
++    textPropsOnly[textProperties] = info[textProperties];
++    styleCache = new StyleManager(textPropsOnly);
++    styleLookup = new StyleLookup(textPropsOnly);
++    function apply(n) {
++      isStyled = styleLookup.isStyleApplied(n);
++      if(isStyled === false) {
++        container = moveToNewSpan(n, limits);
++        styleCache.applyStyleToContainer(container)
 +      }
 +    }
-     handleUpdate()
++    textNodes.forEach(apply)
++  }
++};
++/*
++
++ Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
++
++ @licstart
++ The JavaScript code in this page is free software: you can redistribute it
++ and/or modify it under the terms of the GNU Affero General Public License
++ (GNU AGPL) as published by the Free Software Foundation, either version 3 of
++ the License, or (at your option) any later version.  The code is distributed
++ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
++
++ You should have received a copy of the GNU Affero General Public License
++ along with this code.  If not, see <http://www.gnu.org/licenses/>.
++
++ As additional permission under GNU AGPL version 3 section 7, you
++ may distribute non-source (e.g., minimized or compacted) forms of
++ that code without the copy of the GNU GPL normally required by
++ section 4, provided you include this license notice and a URL
++ through which recipients can access the Corresponding Source.
++
++ As a special exception to the AGPL, any HTML file which merely makes function
++ calls to this code, and for that purpose includes it by reference shall be
++ deemed a separate work for copyright law purposes. In addition, the copyright
++ holders of this code give you permission to combine this code with free
++ software libraries that are released under the GNU LGPL. You may copy and
++ distribute such a system following the terms of the GNU AGPL for this code
++ and the LGPL for the libraries. If you modify this code, you may extend this
++ exception to your version of the code, but you are not obligated to do so.
++ If you do not wish to do so, delete this exception statement from your
++ version.
++
++ This license applies to this entire compilation.
++ @licend
++ @source: http://www.webodf.org/
++ @source: https://github.com/kogmbh/WebODF/
++*/
++ops.OpApplyDirectStyling = function OpApplyDirectStyling() {
++  var memberid, timestamp, position, length, setProperties, odfUtils = new odf.OdfUtils, domUtils = new core.DomUtils;
++  this.init = function(data) {
++    memberid = data.memberid;
++    timestamp = data.timestamp;
++    position = parseInt(data.position, 10);
++    length = parseInt(data.length, 10);
++    setProperties = data.setProperties
 +  };
-   this.destroy = function(callback) {
-     avatar.destroy(function(err) {
-       if(err) {
-         callback(err)
-       }else {
-         cursorNode.removeChild(span);
-         callback()
-       }
-     })
++  this.isEdit = true;
++  this.group = undefined;
++  function applyStyle(odtDocument, range, info) {
++    var odfCanvas = odtDocument.getOdfCanvas(), odfContainer = odfCanvas.odfContainer(), nextTextNodes = domUtils.splitBoundaries(range), textNodes = odfUtils.getTextNodes(range, false), limits, textStyles;
++    limits = {startContainer:range.startContainer, startOffset:range.startOffset, endContainer:range.endContainer, endOffset:range.endOffset};
++    textStyles = new odf.TextStyleApplicator(new odf.ObjectNameGenerator((odfContainer), memberid), odtDocument.getFormatting(), odfContainer.rootElement.automaticStyles);
++    textStyles.applyStyle(textNodes, limits, info);
++    nextTextNodes.forEach(domUtils.normalizeTextNodes)
++  }
++  this.execute = function(document) {
++    var odtDocument = (document), range = odtDocument.convertCursorToDomRange(position, length), impactedParagraphs = odfUtils.getParagraphElements(range);
++    applyStyle(odtDocument, range, setProperties);
++    range.detach();
++    odtDocument.getOdfCanvas().refreshCSS();
++    odtDocument.fixCursorPositions();
++    impactedParagraphs.forEach(function(n) {
++      odtDocument.emit(ops.OdtDocument.signalParagraphChanged, {paragraphElement:n, memberId:memberid, timeStamp:timestamp})
++    });
++    odtDocument.getOdfCanvas().rerenderAnnotations();
++    return true
 +  };
-   function init() {
-     var dom = cursor.getOdtDocument().getDOM(), htmlns = dom.documentElement.namespaceURI;
-     span = (dom.createElementNS(htmlns, "span"));
-     span.style.top = DEFAULT_CARET_TOP;
-     cursorNode = cursor.getNode();
-     cursorNode.appendChild(span);
-     avatar = new gui.Avatar(cursorNode, avatarInitiallyVisible);
-     handleUpdate()
++  this.spec = function() {
++    return{optype:"ApplyDirectStyling", memberid:memberid, timestamp:timestamp, position:position, length:length, setProperties:setProperties}
 +  }
-   init()
 +};
- gui.EventManager = function EventManager(odtDocument) {
-   var window = (runtime.getWindow()), bindToDirectHandler = {"beforecut":true, "beforepaste":true}, bindToWindow, eventTrap;
-   function getCanvasElement() {
-     return odtDocument.getOdfCanvas().getElement()
++ops.OpApplyDirectStyling.Spec;
++ops.OpApplyDirectStyling.InitSpec;
++/*
++
++ Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
++
++ @licstart
++ The JavaScript code in this page is free software: you can redistribute it
++ and/or modify it under the terms of the GNU Affero General Public License
++ (GNU AGPL) as published by the Free Software Foundation, either version 3 of
++ the License, or (at your option) any later version.  The code is distributed
++ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
++
++ You should have received a copy of the GNU Affero General Public License
++ along with this code.  If not, see <http://www.gnu.org/licenses/>.
++
++ As additional permission under GNU AGPL version 3 section 7, you
++ may distribute non-source (e.g., minimized or compacted) forms of
++ that code without the copy of the GNU GPL normally required by
++ section 4, provided you include this license notice and a URL
++ through which recipients can access the Corresponding Source.
++
++ As a special exception to the AGPL, any HTML file which merely makes function
++ calls to this code, and for that purpose includes it by reference shall be
++ deemed a separate work for copyright law purposes. In addition, the copyright
++ holders of this code give you permission to combine this code with free
++ software libraries that are released under the GNU LGPL. You may copy and
++ distribute such a system following the terms of the GNU AGPL for this code
++ and the LGPL for the libraries. If you modify this code, you may extend this
++ exception to your version of the code, but you are not obligated to do so.
++ If you do not wish to do so, delete this exception statement from your
++ version.
++
++ This license applies to this entire compilation.
++ @licend
++ @source: http://www.webodf.org/
++ @source: https://github.com/kogmbh/WebODF/
++*/
++ops.OpApplyHyperlink = function OpApplyHyperlink() {
++  var memberid, timestamp, position, length, hyperlink, domUtils = new core.DomUtils, odfUtils = new odf.OdfUtils;
++  this.init = function(data) {
++    memberid = data.memberid;
++    timestamp = data.timestamp;
++    position = data.position;
++    length = data.length;
++    hyperlink = data.hyperlink
++  };
++  this.isEdit = true;
++  this.group = undefined;
++  function createHyperlink(document, hyperlink) {
++    var node = document.createElementNS(odf.Namespaces.textns, "text:a");
++    node.setAttributeNS(odf.Namespaces.xlinkns, "xlink:type", "simple");
++    node.setAttributeNS(odf.Namespaces.xlinkns, "xlink:href", hyperlink);
++    return node
 +  }
-   function EventDelegate() {
-     var self = this, recentEvents = [];
-     this.handlers = [];
-     this.isSubscribed = false;
-     this.handleEvent = function(e) {
-       if(recentEvents.indexOf(e) === -1) {
-         recentEvents.push(e);
-         self.handlers.forEach(function(handler) {
-           handler(e)
-         });
-         runtime.setTimeout(function() {
-           recentEvents.splice(recentEvents.indexOf(e), 1)
-         }, 0)
++  function isPartOfLink(node) {
++    while(node) {
++      if(odfUtils.isHyperlink(node)) {
++        return true
 +      }
++      node = node.parentNode
 +    }
++    return false
 +  }
-   function WindowScrollState(window) {
-     var x = window.scrollX, y = window.scrollY;
-     this.restore = function() {
-       if(window.scrollX !== x || window.scrollY !== y) {
-         window.scrollTo(x, y)
-       }
++  this.execute = function(document) {
++    var odtDocument = (document), ownerDocument = odtDocument.getDOMDocument(), range = odtDocument.convertCursorToDomRange(position, length), boundaryNodes = domUtils.splitBoundaries(range), modifiedParagraphs = [], textNodes = odfUtils.getTextNodes(range, false);
++    if(textNodes.length === 0) {
++      return false
 +    }
-   }
-   function ElementScrollState(element) {
-     var top = element.scrollTop, left = element.scrollLeft;
-     this.restore = function() {
-       if(element.scrollTop !== top || element.scrollLeft !== left) {
-         element.scrollTop = top;
-         element.scrollLeft = left
++    textNodes.forEach(function(node) {
++      var linkNode, paragraph = odfUtils.getParagraphElement(node);
++      runtime.assert(isPartOfLink(node) === false, "The given range should not contain any link.");
++      linkNode = createHyperlink(ownerDocument, hyperlink);
++      node.parentNode.insertBefore(linkNode, node);
++      linkNode.appendChild(node);
++      if(modifiedParagraphs.indexOf(paragraph) === -1) {
++        modifiedParagraphs.push(paragraph)
 +      }
-     }
++    });
++    boundaryNodes.forEach(domUtils.normalizeTextNodes);
++    range.detach();
++    odtDocument.getOdfCanvas().refreshSize();
++    odtDocument.getOdfCanvas().rerenderAnnotations();
++    modifiedParagraphs.forEach(function(paragraph) {
++      odtDocument.emit(ops.OdtDocument.signalParagraphChanged, {paragraphElement:paragraph, memberId:memberid, timeStamp:timestamp})
++    });
++    return true
++  };
++  this.spec = function() {
++    return{optype:"ApplyHyperlink", memberid:memberid, timestamp:timestamp, position:position, length:length, hyperlink:hyperlink}
 +  }
-   function listenEvent(eventTarget, eventType, eventHandler) {
-     var onVariant = "on" + eventType, bound = false;
-     if(eventTarget.attachEvent) {
-       bound = eventTarget.attachEvent(onVariant, eventHandler)
-     }
-     if(!bound && eventTarget.addEventListener) {
-       eventTarget.addEventListener(eventType, eventHandler, false);
-       bound = true
++};
++ops.OpApplyHyperlink.Spec;
++ops.OpApplyHyperlink.InitSpec;
++/*
++
++ Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
++
++ @licstart
++ The JavaScript code in this page is free software: you can redistribute it
++ and/or modify it under the terms of the GNU Affero General Public License
++ (GNU AGPL) as published by the Free Software Foundation, either version 3 of
++ the License, or (at your option) any later version.  The code is distributed
++ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
++
++ You should have received a copy of the GNU Affero General Public License
++ along with this code.  If not, see <http://www.gnu.org/licenses/>.
++
++ As additional permission under GNU AGPL version 3 section 7, you
++ may distribute non-source (e.g., minimized or compacted) forms of
++ that code without the copy of the GNU GPL normally required by
++ section 4, provided you include this license notice and a URL
++ through which recipients can access the Corresponding Source.
++
++ As a special exception to the AGPL, any HTML file which merely makes function
++ calls to this code, and for that purpose includes it by reference shall be
++ deemed a separate work for copyright law purposes. In addition, the copyright
++ holders of this code give you permission to combine this code with free
++ software libraries that are released under the GNU LGPL. You may copy and
++ distribute such a system following the terms of the GNU AGPL for this code
++ and the LGPL for the libraries. If you modify this code, you may extend this
++ exception to your version of the code, but you are not obligated to do so.
++ If you do not wish to do so, delete this exception statement from your
++ version.
++
++ This license applies to this entire compilation.
++ @licend
++ @source: http://www.webodf.org/
++ @source: https://github.com/kogmbh/WebODF/
++*/
++ops.OpInsertImage = function OpInsertImage() {
++  var memberid, timestamp, position, filename, frameWidth, frameHeight, frameStyleName, frameName, drawns = odf.Namespaces.drawns, svgns = odf.Namespaces.svgns, textns = odf.Namespaces.textns, xlinkns = odf.Namespaces.xlinkns;
++  this.init = function(data) {
++    memberid = data.memberid;
++    timestamp = data.timestamp;
++    position = data.position;
++    filename = data.filename;
++    frameWidth = data.frameWidth;
++    frameHeight = data.frameHeight;
++    frameStyleName = data.frameStyleName;
++    frameName = data.frameName
++  };
++  this.isEdit = true;
++  this.group = undefined;
++  function createFrameElement(document) {
++    var imageNode = document.createElementNS(drawns, "draw:image"), frameNode = document.createElementNS(drawns, "draw:frame");
++    imageNode.setAttributeNS(xlinkns, "xlink:href", filename);
++    imageNode.setAttributeNS(xlinkns, "xlink:type", "simple");
++    imageNode.setAttributeNS(xlinkns, "xlink:show", "embed");
++    imageNode.setAttributeNS(xlinkns, "xlink:actuate", "onLoad");
++    frameNode.setAttributeNS(drawns, "draw:style-name", frameStyleName);
++    frameNode.setAttributeNS(drawns, "draw:name", frameName);
++    frameNode.setAttributeNS(textns, "text:anchor-type", "as-char");
++    frameNode.setAttributeNS(svgns, "svg:width", frameWidth);
++    frameNode.setAttributeNS(svgns, "svg:height", frameHeight);
++    frameNode.appendChild(imageNode);
++    return frameNode
++  }
++  this.execute = function(document) {
++    var odtDocument = (document), odfCanvas = odtDocument.getOdfCanvas(), domPosition = odtDocument.getTextNodeAtStep(position, memberid), textNode, refNode, paragraphElement, frameElement;
++    if(!domPosition) {
++      return false
 +    }
-     if((!bound || bindToDirectHandler[eventType]) && eventTarget.hasOwnProperty(onVariant)) {
-       eventTarget[onVariant] = eventHandler
++    textNode = domPosition.textNode;
++    paragraphElement = odtDocument.getParagraphElement(textNode);
++    refNode = domPosition.offset !== textNode.length ? textNode.splitText(domPosition.offset) : textNode.nextSibling;
++    frameElement = createFrameElement(odtDocument.getDOMDocument());
++    textNode.parentNode.insertBefore(frameElement, refNode);
++    odtDocument.emit(ops.OdtDocument.signalStepsInserted, {position:position, length:1});
++    if(textNode.length === 0) {
++      textNode.parentNode.removeChild(textNode)
 +    }
++    odfCanvas.addCssForFrameWithImage(frameElement);
++    odfCanvas.refreshCSS();
++    odtDocument.emit(ops.OdtDocument.signalParagraphChanged, {paragraphElement:paragraphElement, memberId:memberid, timeStamp:timestamp});
++    odfCanvas.rerenderAnnotations();
++    return true
++  };
++  this.spec = function() {
++    return{optype:"InsertImage", memberid:memberid, timestamp:timestamp, filename:filename, position:position, frameWidth:frameWidth, frameHeight:frameHeight, frameStyleName:frameStyleName, frameName:frameName}
 +  }
-   function removeEvent(eventTarget, eventType, eventHandler) {
-     var onVariant = "on" + eventType;
-     if(eventTarget.detachEvent) {
-       eventTarget.detachEvent(onVariant, eventHandler)
++};
++ops.OpInsertImage.Spec;
++ops.OpInsertImage.InitSpec;
++/*
++
++ Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
++
++ @licstart
++ The JavaScript code in this page is free software: you can redistribute it
++ and/or modify it under the terms of the GNU Affero General Public License
++ (GNU AGPL) as published by the Free Software Foundation, either version 3 of
++ the License, or (at your option) any later version.  The code is distributed
++ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
++
++ You should have received a copy of the GNU Affero General Public License
++ along with this code.  If not, see <http://www.gnu.org/licenses/>.
++
++ As additional permission under GNU AGPL version 3 section 7, you
++ may distribute non-source (e.g., minimized or compacted) forms of
++ that code without the copy of the GNU GPL normally required by
++ section 4, provided you include this license notice and a URL
++ through which recipients can access the Corresponding Source.
++
++ As a special exception to the AGPL, any HTML file which merely makes function
++ calls to this code, and for that purpose includes it by reference shall be
++ deemed a separate work for copyright law purposes. In addition, the copyright
++ holders of this code give you permission to combine this code with free
++ software libraries that are released under the GNU LGPL. You may copy and
++ distribute such a system following the terms of the GNU AGPL for this code
++ and the LGPL for the libraries. If you modify this code, you may extend this
++ exception to your version of the code, but you are not obligated to do so.
++ If you do not wish to do so, delete this exception statement from your
++ version.
++
++ This license applies to this entire compilation.
++ @licend
++ @source: http://www.webodf.org/
++ @source: https://github.com/kogmbh/WebODF/
++*/
++ops.OpInsertTable = function OpInsertTable() {
++  var memberid, timestamp, initialRows, initialColumns, position, tableName, tableStyleName, tableColumnStyleName, tableCellStyleMatrix, tablens = "urn:oasis:names:tc:opendocument:xmlns:table:1.0", textns = "urn:oasis:names:tc:opendocument:xmlns:text:1.0";
++  this.init = function(data) {
++    memberid = data.memberid;
++    timestamp = data.timestamp;
++    position = data.position;
++    initialRows = data.initialRows;
++    initialColumns = data.initialColumns;
++    tableName = data.tableName;
++    tableStyleName = data.tableStyleName;
++    tableColumnStyleName = data.tableColumnStyleName;
++    tableCellStyleMatrix = data.tableCellStyleMatrix
++  };
++  this.isEdit = true;
++  this.group = undefined;
++  function getCellStyleName(row, column) {
++    var rowStyles;
++    if(tableCellStyleMatrix.length === 1) {
++      rowStyles = tableCellStyleMatrix[0]
++    }else {
++      if(tableCellStyleMatrix.length === 3) {
++        switch(row) {
++          case 0:
++            rowStyles = tableCellStyleMatrix[0];
++            break;
++          case initialRows - 1:
++            rowStyles = tableCellStyleMatrix[2];
++            break;
++          default:
++            rowStyles = tableCellStyleMatrix[1];
++            break
++        }
++      }else {
++        rowStyles = tableCellStyleMatrix[row]
++      }
 +    }
-     if(eventTarget.removeEventListener) {
-       eventTarget.removeEventListener(eventType, eventHandler, false)
++    if(rowStyles.length === 1) {
++      return rowStyles[0]
 +    }
-     if(eventTarget[onVariant] === eventHandler) {
-       eventTarget[onVariant] = null
++    if(rowStyles.length === 3) {
++      switch(column) {
++        case 0:
++          return rowStyles[0];
++        case initialColumns - 1:
++          return rowStyles[2];
++        default:
++          return rowStyles[1]
++      }
 +    }
++    return rowStyles[column]
 +  }
-   this.subscribe = function(eventName, handler) {
-     var delegate = bindToWindow[eventName], canvasElement = getCanvasElement();
-     if(delegate) {
-       delegate.handlers.push(handler);
-       if(!delegate.isSubscribed) {
-         delegate.isSubscribed = true;
-         listenEvent((window), eventName, delegate.handleEvent);
-         listenEvent(canvasElement, eventName, delegate.handleEvent);
-         listenEvent(eventTrap, eventName, delegate.handleEvent)
++  function createTableNode(document) {
++    var tableNode = document.createElementNS(tablens, "table:table"), columns = document.createElementNS(tablens, "table:table-column"), row, cell, paragraph, rowCounter, columnCounter, cellStyleName;
++    if(tableStyleName) {
++      tableNode.setAttributeNS(tablens, "table:style-name", tableStyleName)
++    }
++    if(tableName) {
++      tableNode.setAttributeNS(tablens, "table:name", tableName)
++    }
++    columns.setAttributeNS(tablens, "table:number-columns-repeated", initialColumns);
++    if(tableColumnStyleName) {
++      columns.setAttributeNS(tablens, "table:style-name", tableColumnStyleName)
++    }
++    tableNode.appendChild(columns);
++    for(rowCounter = 0;rowCounter < initialRows;rowCounter += 1) {
++      row = document.createElementNS(tablens, "table:table-row");
++      for(columnCounter = 0;columnCounter < initialColumns;columnCounter += 1) {
++        cell = document.createElementNS(tablens, "table:table-cell");
++        cellStyleName = getCellStyleName(rowCounter, columnCounter);
++        if(cellStyleName) {
++          cell.setAttributeNS(tablens, "table:style-name", cellStyleName)
++        }
++        paragraph = document.createElementNS(textns, "text:p");
++        cell.appendChild(paragraph);
++        row.appendChild(cell)
 +      }
-     }else {
-       listenEvent(canvasElement, eventName, handler)
++      tableNode.appendChild(row)
++    }
++    return tableNode
++  }
++  this.execute = function(document) {
++    var odtDocument = (document), domPosition = odtDocument.getTextNodeAtStep(position), rootNode = odtDocument.getRootNode(), previousSibling, tableNode;
++    if(domPosition) {
++      tableNode = createTableNode(odtDocument.getDOMDocument());
++      previousSibling = odtDocument.getParagraphElement(domPosition.textNode);
++      rootNode.insertBefore(tableNode, previousSibling.nextSibling);
++      odtDocument.emit(ops.OdtDocument.signalStepsInserted, {position:position, length:initialColumns * initialRows + 1});
++      odtDocument.getOdfCanvas().refreshSize();
++      odtDocument.emit(ops.OdtDocument.signalTableAdded, {tableElement:tableNode, memberId:memberid, timeStamp:timestamp});
++      odtDocument.getOdfCanvas().rerenderAnnotations();
++      return true
++    }
++    return false
++  };
++  this.spec = function() {
++    return{optype:"InsertTable", memberid:memberid, timestamp:timestamp, position:position, initialRows:initialRows, initialColumns:initialColumns, tableName:tableName, tableStyleName:tableStyleName, tableColumnStyleName:tableColumnStyleName, tableCellStyleMatrix:tableCellStyleMatrix}
++  }
++};
++ops.OpInsertTable.Spec;
++ops.OpInsertTable.InitSpec;
++/*
++
++ Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
++
++ @licstart
++ The JavaScript code in this page is free software: you can redistribute it
++ and/or modify it under the terms of the GNU Affero General Public License
++ (GNU AGPL) as published by the Free Software Foundation, either version 3 of
++ the License, or (at your option) any later version.  The code is distributed
++ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
++
++ You should have received a copy of the GNU Affero General Public License
++ along with this code.  If not, see <http://www.gnu.org/licenses/>.
++
++ As additional permission under GNU AGPL version 3 section 7, you
++ may distribute non-source (e.g., minimized or compacted) forms of
++ that code without the copy of the GNU GPL normally required by
++ section 4, provided you include this license notice and a URL
++ through which recipients can access the Corresponding Source.
++
++ As a special exception to the AGPL, any HTML file which merely makes function
++ calls to this code, and for that purpose includes it by reference shall be
++ deemed a separate work for copyright law purposes. In addition, the copyright
++ holders of this code give you permission to combine this code with free
++ software libraries that are released under the GNU LGPL. You may copy and
++ distribute such a system following the terms of the GNU AGPL for this code
++ and the LGPL for the libraries. If you modify this code, you may extend this
++ exception to your version of the code, but you are not obligated to do so.
++ If you do not wish to do so, delete this exception statement from your
++ version.
++
++ This license applies to this entire compilation.
++ @licend
++ @source: http://www.webodf.org/
++ @source: https://github.com/kogmbh/WebODF/
++*/
++ops.OpInsertText = function OpInsertText() {
++  var space = " ", tab = "\t", memberid, timestamp, position, moveCursor, text;
++  this.init = function(data) {
++    memberid = data.memberid;
++    timestamp = data.timestamp;
++    position = data.position;
++    text = data.text;
++    moveCursor = data.moveCursor === "true" || data.moveCursor === true
++  };
++  this.isEdit = true;
++  this.group = undefined;
++  function triggerLayoutInWebkit(textNode) {
++    var parent = textNode.parentNode, next = textNode.nextSibling;
++    parent.removeChild(textNode);
++    parent.insertBefore(textNode, next)
++  }
++  function requiresSpaceElement(text, index) {
++    return text[index] === space && (index === 0 || (index === text.length - 1 || text[index - 1] === space))
++  }
++  this.execute = function(document) {
++    var odtDocument = (document), domPosition, previousNode, parentElement, nextNode = null, ownerDocument = odtDocument.getDOMDocument(), paragraphElement, textns = "urn:oasis:names:tc:opendocument:xmlns:text:1.0", toInsertIndex = 0, spaceTag, spaceElement, cursor = odtDocument.getCursor(memberid), i;
++    function insertTextNode(toInsertText) {
++      parentElement.insertBefore(ownerDocument.createTextNode(toInsertText), nextNode)
++    }
++    odtDocument.upgradeWhitespacesAtPosition(position);
++    domPosition = odtDocument.getTextNodeAtStep(position);
++    if(domPosition) {
++      previousNode = domPosition.textNode;
++      nextNode = previousNode.nextSibling;
++      parentElement = (previousNode.parentNode);
++      paragraphElement = odtDocument.getParagraphElement(previousNode);
++      for(i = 0;i < text.length;i += 1) {
++        if(requiresSpaceElement(text, i) || text[i] === tab) {
++          if(toInsertIndex === 0) {
++            if(domPosition.offset !== previousNode.length) {
++              nextNode = previousNode.splitText(domPosition.offset)
++            }
++            if(0 < i) {
++              previousNode.appendData(text.substring(0, i))
++            }
++          }else {
++            if(toInsertIndex < i) {
++              insertTextNode(text.substring(toInsertIndex, i))
++            }
++          }
++          toInsertIndex = i + 1;
++          spaceTag = text[i] === space ? "text:s" : "text:tab";
++          spaceElement = ownerDocument.createElementNS(textns, spaceTag);
++          spaceElement.appendChild(ownerDocument.createTextNode(text[i]));
++          parentElement.insertBefore(spaceElement, nextNode)
++        }
++      }
++      if(toInsertIndex === 0) {
++        previousNode.insertData(domPosition.offset, text)
++      }else {
++        if(toInsertIndex < text.length) {
++          insertTextNode(text.substring(toInsertIndex))
++        }
++      }
++      triggerLayoutInWebkit(previousNode);
++      if(previousNode.length === 0) {
++        previousNode.parentNode.removeChild(previousNode)
++      }
++      odtDocument.emit(ops.OdtDocument.signalStepsInserted, {position:position, length:text.length});
++      if(cursor && moveCursor) {
++        odtDocument.moveCursor(memberid, position + text.length, 0);
++        odtDocument.emit(ops.Document.signalCursorMoved, cursor)
++      }
++      if(position > 0) {
++        if(position > 1) {
++          odtDocument.downgradeWhitespacesAtPosition(position - 2)
++        }
++        odtDocument.downgradeWhitespacesAtPosition(position - 1)
++      }
++      odtDocument.downgradeWhitespacesAtPosition(position);
++      odtDocument.downgradeWhitespacesAtPosition(position + text.length - 1);
++      odtDocument.downgradeWhitespacesAtPosition(position + text.length);
++      odtDocument.getOdfCanvas().refreshSize();
++      odtDocument.emit(ops.OdtDocument.signalParagraphChanged, {paragraphElement:paragraphElement, memberId:memberid, timeStamp:timestamp});
++      odtDocument.getOdfCanvas().rerenderAnnotations();
++      return true
 +    }
++    return false
++  };
++  this.spec = function() {
++    return{optype:"InsertText", memberid:memberid, timestamp:timestamp, position:position, text:text, moveCursor:moveCursor}
++  }
++};
++ops.OpInsertText.Spec;
++ops.OpInsertText.InitSpec;
++/*
++
++ Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
++
++ @licstart
++ The JavaScript code in this page is free software: you can redistribute it
++ and/or modify it under the terms of the GNU Affero General Public License
++ (GNU AGPL) as published by the Free Software Foundation, either version 3 of
++ the License, or (at your option) any later version.  The code is distributed
++ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
++
++ You should have received a copy of the GNU Affero General Public License
++ along with this code.  If not, see <http://www.gnu.org/licenses/>.
++
++ As additional permission under GNU AGPL version 3 section 7, you
++ may distribute non-source (e.g., minimized or compacted) forms of
++ that code without the copy of the GNU GPL normally required by
++ section 4, provided you include this license notice and a URL
++ through which recipients can access the Corresponding Source.
++
++ As a special exception to the AGPL, any HTML file which merely makes function
++ calls to this code, and for that purpose includes it by reference shall be
++ deemed a separate work for copyright law purposes. In addition, the copyright
++ holders of this code give you permission to combine this code with free
++ software libraries that are released under the GNU LGPL. You may copy and
++ distribute such a system following the terms of the GNU AGPL for this code
++ and the LGPL for the libraries. If you modify this code, you may extend this
++ exception to your version of the code, but you are not obligated to do so.
++ If you do not wish to do so, delete this exception statement from your
++ version.
++
++ This license applies to this entire compilation.
++ @licend
++ @source: http://www.webodf.org/
++ @source: https://github.com/kogmbh/WebODF/
++*/
++ops.OpMoveCursor = function OpMoveCursor() {
++  var memberid, timestamp, position, length, selectionType;
++  this.init = function(data) {
++    memberid = data.memberid;
++    timestamp = data.timestamp;
++    position = data.position;
++    length = data.length || 0;
++    selectionType = data.selectionType || ops.OdtCursor.RangeSelection
 +  };
-   this.unsubscribe = function(eventName, handler) {
-     var delegate = bindToWindow[eventName], handlerIndex = delegate && delegate.handlers.indexOf(handler), canvasElement = getCanvasElement();
-     if(delegate) {
-       if(handlerIndex !== -1) {
-         delegate.handlers.splice(handlerIndex, 1)
-       }
-     }else {
-       removeEvent(canvasElement, eventName, handler)
++  this.isEdit = false;
++  this.group = undefined;
++  this.execute = function(document) {
++    var odtDocument = (document), cursor = odtDocument.getCursor(memberid), selectedRange;
++    if(!cursor) {
++      return false
 +    }
++    selectedRange = odtDocument.convertCursorToDomRange(position, length);
++    cursor.setSelectedRange(selectedRange, length >= 0);
++    cursor.setSelectionType(selectionType);
++    odtDocument.emit(ops.Document.signalCursorMoved, cursor);
++    return true
 +  };
-   function hasFocus() {
-     return odtDocument.getDOM().activeElement === getCanvasElement()
++  this.spec = function() {
++    return{optype:"MoveCursor", memberid:memberid, timestamp:timestamp, position:position, length:length, selectionType:selectionType}
 +  }
-   function findScrollableParent(element) {
-     while(element && (!element.scrollTop && !element.scrollLeft)) {
-       element = (element.parentNode)
++};
++ops.OpMoveCursor.Spec;
++ops.OpMoveCursor.InitSpec;
++/*
++
++ Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
++
++ @licstart
++ The JavaScript code in this page is free software: you can redistribute it
++ and/or modify it under the terms of the GNU Affero General Public License
++ (GNU AGPL) as published by the Free Software Foundation, either version 3 of
++ the License, or (at your option) any later version.  The code is distributed
++ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
++
++ You should have received a copy of the GNU Affero General Public License
++ along with this code.  If not, see <http://www.gnu.org/licenses/>.
++
++ As additional permission under GNU AGPL version 3 section 7, you
++ may distribute non-source (e.g., minimized or compacted) forms of
++ that code without the copy of the GNU GPL normally required by
++ section 4, provided you include this license notice and a URL
++ through which recipients can access the Corresponding Source.
++
++ As a special exception to the AGPL, any HTML file which merely makes function
++ calls to this code, and for that purpose includes it by reference shall be
++ deemed a separate work for copyright law purposes. In addition, the copyright
++ holders of this code give you permission to combine this code with free
++ software libraries that are released under the GNU LGPL. You may copy and
++ distribute such a system following the terms of the GNU AGPL for this code
++ and the LGPL for the libraries. If you modify this code, you may extend this
++ exception to your version of the code, but you are not obligated to do so.
++ If you do not wish to do so, delete this exception statement from your
++ version.
++
++ This license applies to this entire compilation.
++ @licend
++ @source: http://www.webodf.org/
++ @source: https://github.com/kogmbh/WebODF/
++*/
++ops.OpRemoveAnnotation = function OpRemoveAnnotation() {
++  var memberid, timestamp, position, length, domUtils;
++  this.init = function(data) {
++    memberid = data.memberid;
++    timestamp = data.timestamp;
++    position = parseInt(data.position, 10);
++    length = parseInt(data.length, 10);
++    domUtils = new core.DomUtils
++  };
++  this.isEdit = true;
++  this.group = undefined;
++  this.execute = function(document) {
++    var odtDocument = (document), iterator = odtDocument.getIteratorAtPosition(position), container = iterator.container(), annotationNode, annotationEnd;
++    while(!(container.namespaceURI === odf.Namespaces.officens && container.localName === "annotation")) {
++      container = container.parentNode
 +    }
-     if(element) {
-       return new ElementScrollState(element)
++    if(container === null) {
++      return false
 +    }
-     return new WindowScrollState(window)
-   }
-   this.focus = function() {
-     var scrollParent, canvasElement = getCanvasElement(), selection = window.getSelection();
-     if(!hasFocus()) {
-       scrollParent = findScrollableParent(canvasElement);
-       canvasElement.focus();
-       if(scrollParent) {
-         scrollParent.restore()
-       }
++    annotationNode = (container);
++    annotationEnd = annotationNode.annotationEndElement;
++    odtDocument.getOdfCanvas().forgetAnnotations();
++    function insert(node) {
++      (annotationNode).parentNode.insertBefore(node, annotationNode)
 +    }
-     if(selection && selection.extend) {
-       if(eventTrap.parentNode !== canvasElement) {
-         canvasElement.appendChild(eventTrap)
-       }
-       selection.collapse(eventTrap.firstChild, 0);
-       selection.extend(eventTrap, eventTrap.childNodes.length)
++    domUtils.getElementsByTagNameNS(annotationNode, "urn:webodf:names:cursor", "cursor").forEach(insert);
++    domUtils.getElementsByTagNameNS(annotationNode, "urn:webodf:names:cursor", "anchor").forEach(insert);
++    annotationNode.parentNode.removeChild(annotationNode);
++    if(annotationEnd) {
++      annotationEnd.parentNode.removeChild(annotationEnd)
 +    }
++    odtDocument.emit(ops.OdtDocument.signalStepsRemoved, {position:position > 0 ? position - 1 : position, length:length});
++    odtDocument.fixCursorPositions();
++    odtDocument.getOdfCanvas().refreshAnnotations();
++    return true
 +  };
-   function init() {
-     var canvasElement = getCanvasElement(), doc = canvasElement.ownerDocument;
-     runtime.assert(Boolean(window), "EventManager requires a window object to operate correctly");
-     bindToWindow = {"mousedown":new EventDelegate, "mouseup":new EventDelegate, "focus":new EventDelegate};
-     eventTrap = doc.createElement("div");
-     eventTrap.id = "eventTrap";
-     eventTrap.setAttribute("contenteditable", "true");
-     eventTrap.style.position = "absolute";
-     eventTrap.style.left = "-10000px";
-     eventTrap.appendChild(doc.createTextNode("dummy content"));
-     canvasElement.appendChild(eventTrap)
-   }
-   init()
- };
- runtime.loadClass("gui.SelectionMover");
- gui.ShadowCursor = function ShadowCursor(odtDocument) {
-   var selectedRange = (odtDocument.getDOM().createRange()), forwardSelection = true;
-   this.removeFromOdtDocument = function() {
-   };
-   this.getMemberId = function() {
-     return gui.ShadowCursor.ShadowCursorMemberId
-   };
-   this.getSelectedRange = function() {
-     return selectedRange
-   };
-   this.setSelectedRange = function(range, isForwardSelection) {
-     selectedRange = range;
-     forwardSelection = isForwardSelection !== false
-   };
-   this.hasForwardSelection = function() {
-     return forwardSelection
-   };
-   this.getOdtDocument = function() {
-     return odtDocument
-   };
-   this.getSelectionType = function() {
-     return ops.OdtCursor.RangeSelection
-   };
-   function init() {
-     selectedRange.setStart(odtDocument.getRootNode(), 0)
++  this.spec = function() {
++    return{optype:"RemoveAnnotation", memberid:memberid, timestamp:timestamp, position:position, length:length}
 +  }
-   init()
 +};
- gui.ShadowCursor.ShadowCursorMemberId = "";
- (function() {
-   return gui.ShadowCursor
- })();
++ops.OpRemoveAnnotation.Spec;
++ops.OpRemoveAnnotation.InitSpec;
 +/*
 +
-  Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
++ Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- gui.UndoManager = function UndoManager() {
- };
- gui.UndoManager.prototype.subscribe = function(signal, callback) {
- };
- gui.UndoManager.prototype.unsubscribe = function(signal, callback) {
- };
- gui.UndoManager.prototype.setOdtDocument = function(newDocument) {
- };
- gui.UndoManager.prototype.saveInitialState = function() {
- };
- gui.UndoManager.prototype.resetInitialState = function() {
- };
- gui.UndoManager.prototype.setPlaybackFunction = function(playback_func) {
- };
- gui.UndoManager.prototype.hasUndoStates = function() {
- };
- gui.UndoManager.prototype.hasRedoStates = function() {
- };
- gui.UndoManager.prototype.moveForward = function(states) {
- };
- gui.UndoManager.prototype.moveBackward = function(states) {
- };
- gui.UndoManager.prototype.onOperationExecuted = function(op) {
++ops.OpRemoveBlob = function OpRemoveBlob() {
++  var memberid, timestamp, filename;
++  this.init = function(data) {
++    memberid = data.memberid;
++    timestamp = data.timestamp;
++    filename = data.filename
++  };
++  this.isEdit = true;
++  this.group = undefined;
++  this.execute = function(document) {
++    var odtDocument = (document);
++    odtDocument.getOdfCanvas().odfContainer().removeBlob(filename);
++    return true
++  };
++  this.spec = function() {
++    return{optype:"RemoveBlob", memberid:memberid, timestamp:timestamp, filename:filename}
++  }
 +};
- gui.UndoManager.signalUndoStackChanged = "undoStackChanged";
- gui.UndoManager.signalUndoStateCreated = "undoStateCreated";
- gui.UndoManager.signalUndoStateModified = "undoStateModified";
- (function() {
-   return gui.UndoManager
- })();
++ops.OpRemoveBlob.Spec;
++ops.OpRemoveBlob.InitSpec;
 +/*
 +
-  Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
++ Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- gui.UndoStateRules = function UndoStateRules() {
-   function getOpType(op) {
-     return op.spec().optype
-   }
-   this.getOpType = getOpType;
-   function getOpPosition(op) {
-     return op.spec().position
-   }
-   function isEditOperation(op) {
-     return op.isEdit
-   }
-   this.isEditOperation = isEditOperation;
-   function canAggregateOperation(optype) {
-     switch(optype) {
-       case "RemoveText":
-       ;
-       case "InsertText":
-         return true;
-       default:
-         return false
-     }
-   }
-   function isSameDirectionOfTravel(recentEditOps, thisOp) {
-     var existing1 = getOpPosition(recentEditOps[recentEditOps.length - 2]), existing2 = getOpPosition(recentEditOps[recentEditOps.length - 1]), thisPos = getOpPosition(thisOp), direction = existing2 - existing1;
-     return existing2 === thisPos - direction
-   }
-   function isContinuousOperation(recentEditOps, thisOp) {
-     var optype = getOpType(thisOp);
-     if(canAggregateOperation(optype) && optype === getOpType(recentEditOps[0])) {
-       if(recentEditOps.length === 1) {
-         return true
-       }
-       if(isSameDirectionOfTravel(recentEditOps, thisOp)) {
-         return true
-       }
-     }
-     return false
-   }
-   function isPartOfOperationSet(operation, lastOperations) {
-     if(isEditOperation(operation)) {
-       if(lastOperations.length === 0) {
-         return true
-       }
-       return isEditOperation(lastOperations[lastOperations.length - 1]) && isContinuousOperation(lastOperations.filter(isEditOperation), operation)
++ops.OpRemoveCursor = function OpRemoveCursor() {
++  var memberid, timestamp;
++  this.init = function(data) {
++    memberid = data.memberid;
++    timestamp = data.timestamp
++  };
++  this.isEdit = false;
++  this.group = undefined;
++  this.execute = function(document) {
++    var odtDocument = (document);
++    if(!odtDocument.removeCursor(memberid)) {
++      return false
 +    }
 +    return true
++  };
++  this.spec = function() {
++    return{optype:"RemoveCursor", memberid:memberid, timestamp:timestamp}
 +  }
-   this.isPartOfOperationSet = isPartOfOperationSet
 +};
++ops.OpRemoveCursor.Spec;
++ops.OpRemoveCursor.InitSpec;
 +/*
 +
-  Copyright (C) 2012 KO GmbH <aditya.bhatt at kogmbh.com>
++ Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- ops.EditInfo = function EditInfo(container, odtDocument) {
-   var editInfoNode, editHistory = {};
-   function sortEdits() {
-     var arr = [], memberid;
-     for(memberid in editHistory) {
-       if(editHistory.hasOwnProperty(memberid)) {
-         arr.push({"memberid":memberid, "time":editHistory[memberid].time})
-       }
-     }
-     arr.sort(function(a, b) {
-       return a.time - b.time
-     });
-     return arr
-   }
-   this.getNode = function() {
-     return editInfoNode
-   };
-   this.getOdtDocument = function() {
-     return odtDocument
-   };
-   this.getEdits = function() {
-     return editHistory
-   };
-   this.getSortedEdits = function() {
-     return sortEdits()
++ops.OpRemoveHyperlink = function OpRemoveHyperlink() {
++  var memberid, timestamp, position, length, domUtils = new core.DomUtils, odfUtils = new odf.OdfUtils;
++  this.init = function(data) {
++    memberid = data.memberid;
++    timestamp = data.timestamp;
++    position = data.position;
++    length = data.length
 +  };
-   this.addEdit = function(memberid, timestamp) {
-     editHistory[memberid] = {time:timestamp}
++  this.isEdit = true;
++  this.group = undefined;
++  this.execute = function(document) {
++    var odtDocument = (document), range = odtDocument.convertCursorToDomRange(position, length), links = odfUtils.getHyperlinkElements(range), node;
++    runtime.assert(links.length === 1, "The given range should only contain a single link.");
++    node = domUtils.mergeIntoParent((links[0]));
++    range.detach();
++    odtDocument.getOdfCanvas().refreshSize();
++    odtDocument.emit(ops.OdtDocument.signalParagraphChanged, {paragraphElement:odfUtils.getParagraphElement(node), memberId:memberid, timeStamp:timestamp});
++    odtDocument.getOdfCanvas().rerenderAnnotations();
++    return true
 +  };
-   this.clearEdits = function() {
-     editHistory = {}
++  this.spec = function() {
++    return{optype:"RemoveHyperlink", memberid:memberid, timestamp:timestamp, position:position, length:length}
++  }
++};
++ops.OpRemoveHyperlink.Spec;
++ops.OpRemoveHyperlink.InitSpec;
++/*
++
++ Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
++
++ @licstart
++ This file is part of WebODF.
++
++ WebODF is free software: you can redistribute it and/or modify it
++ under the terms of the GNU Affero General Public License (GNU AGPL)
++ as published by the Free Software Foundation, either version 3 of
++ the License, or (at your option) any later version.
++
++ WebODF is distributed in the hope that it will be useful, but
++ WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ GNU Affero General Public License for more details.
++
++ You should have received a copy of the GNU Affero General Public License
++ along with WebODF.  If not, see <http://www.gnu.org/licenses/>.
++ @licend
++
++ @source: http://www.webodf.org/
++ @source: https://github.com/kogmbh/WebODF/
++*/
++ops.OpRemoveMember = function OpRemoveMember() {
++  var memberid, timestamp;
++  this.init = function(data) {
++    memberid = data.memberid;
++    timestamp = parseInt(data.timestamp, 10)
 +  };
-   this.destroy = function(callback) {
-     if(container.parentNode) {
-       container.removeChild(editInfoNode)
++  this.isEdit = false;
++  this.group = undefined;
++  this.execute = function(document) {
++    var odtDocument = (document);
++    if(!odtDocument.getMember(memberid)) {
++      return false
 +    }
-     callback()
++    odtDocument.removeMember(memberid);
++    odtDocument.emit(ops.Document.signalMemberRemoved, memberid);
++    return true
 +  };
-   function init() {
-     var editInfons = "urn:webodf:names:editinfo", dom = odtDocument.getDOM();
-     editInfoNode = dom.createElementNS(editInfons, "editinfo");
-     container.insertBefore(editInfoNode, container.firstChild)
++  this.spec = function() {
++    return{optype:"RemoveMember", memberid:memberid, timestamp:timestamp}
 +  }
-   init()
 +};
++ops.OpRemoveMember.Spec;
++ops.OpRemoveMember.InitSpec;
 +/*
 +
 + Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("core.DomUtils");
- ops.OpAddAnnotation = function OpAddAnnotation() {
-   var memberid, timestamp, position, length, name, doc;
++ops.OpRemoveStyle = function OpRemoveStyle() {
++  var memberid, timestamp, styleName, styleFamily;
 +  this.init = function(data) {
 +    memberid = data.memberid;
-     timestamp = parseInt(data.timestamp, 10);
-     position = parseInt(data.position, 10);
-     length = parseInt(data.length, 10) || 0;
-     name = data.name
++    timestamp = data.timestamp;
++    styleName = data.styleName;
++    styleFamily = data.styleFamily
 +  };
 +  this.isEdit = true;
-   function createAnnotationNode(odtDocument, date) {
-     var annotationNode, creatorNode, dateNode, listNode, listItemNode, paragraphNode;
-     annotationNode = doc.createElementNS(odf.Namespaces.officens, "office:annotation");
-     annotationNode.setAttributeNS(odf.Namespaces.officens, "office:name", name);
-     creatorNode = doc.createElementNS(odf.Namespaces.dcns, "dc:creator");
-     creatorNode.setAttributeNS("urn:webodf:names:editinfo", "editinfo:memberid", memberid);
-     creatorNode.textContent = odtDocument.getMember(memberid).getProperties().fullName;
-     dateNode = doc.createElementNS(odf.Namespaces.dcns, "dc:date");
-     dateNode.appendChild(doc.createTextNode(date.toISOString()));
-     listNode = doc.createElementNS(odf.Namespaces.textns, "text:list");
-     listItemNode = doc.createElementNS(odf.Namespaces.textns, "text:list-item");
-     paragraphNode = doc.createElementNS(odf.Namespaces.textns, "text:p");
-     listItemNode.appendChild(paragraphNode);
-     listNode.appendChild(listItemNode);
-     annotationNode.appendChild(creatorNode);
-     annotationNode.appendChild(dateNode);
-     annotationNode.appendChild(listNode);
-     return annotationNode
-   }
-   function createAnnotationEnd() {
-     var annotationEnd;
-     annotationEnd = doc.createElementNS(odf.Namespaces.officens, "office:annotation-end");
-     annotationEnd.setAttributeNS(odf.Namespaces.officens, "office:name", name);
-     return annotationEnd
-   }
-   function insertNodeAtPosition(odtDocument, node, insertPosition) {
-     var previousNode, parentNode, domPosition = odtDocument.getTextNodeAtStep(insertPosition, memberid);
-     if(domPosition) {
-       previousNode = domPosition.textNode;
-       parentNode = previousNode.parentNode;
-       if(domPosition.offset !== previousNode.length) {
-         previousNode.splitText(domPosition.offset)
-       }
-       parentNode.insertBefore(node, previousNode.nextSibling);
-       if(previousNode.length === 0) {
-         parentNode.removeChild(previousNode)
-       }
-     }
-   }
-   this.execute = function(odtDocument) {
-     var annotation = {}, cursor = odtDocument.getCursor(memberid), selectedRange, paragraphElement, domUtils = new core.DomUtils;
-     doc = odtDocument.getDOM();
-     annotation.node = createAnnotationNode(odtDocument, new Date(timestamp));
-     if(!annotation.node) {
++  this.group = undefined;
++  this.execute = function(document) {
++    var odtDocument = (document), styleNode = odtDocument.getStyleElement(styleName, styleFamily);
++    if(!styleNode) {
 +      return false
 +    }
-     if(length) {
-       annotation.end = createAnnotationEnd();
-       if(!annotation.end) {
-         return false
-       }
-       insertNodeAtPosition(odtDocument, annotation.end, position + length)
-     }
-     insertNodeAtPosition(odtDocument, annotation.node, position);
-     odtDocument.emit(ops.OdtDocument.signalStepsInserted, {position:position, length:length});
-     if(cursor) {
-       selectedRange = doc.createRange();
-       paragraphElement = domUtils.getElementsByTagNameNS(annotation.node, odf.Namespaces.textns, "p")[0];
-       selectedRange.selectNodeContents(paragraphElement);
-       cursor.setSelectedRange(selectedRange);
-       odtDocument.emit(ops.OdtDocument.signalCursorMoved, cursor)
-     }
-     odtDocument.getOdfCanvas().addAnnotation(annotation);
-     odtDocument.fixCursorPositions();
++    styleNode.parentNode.removeChild(styleNode);
++    odtDocument.getOdfCanvas().refreshCSS();
++    odtDocument.emit(ops.OdtDocument.signalCommonStyleDeleted, {name:styleName, family:styleFamily});
 +    return true
 +  };
 +  this.spec = function() {
-     return{optype:"AddAnnotation", memberid:memberid, timestamp:timestamp, position:position, length:length, name:name}
++    return{optype:"RemoveStyle", memberid:memberid, timestamp:timestamp, styleName:styleName, styleFamily:styleFamily}
 +  }
 +};
++ops.OpRemoveStyle.Spec;
++ops.OpRemoveStyle.InitSpec;
 +/*
 +
 + Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- ops.OpAddCursor = function OpAddCursor() {
-   var memberid, timestamp;
++ops.OpRemoveText = function OpRemoveText() {
++  var memberid, timestamp, position, length, odfUtils, domUtils, editinfons = "urn:webodf:names:editinfo", odfNodeNamespaceMap = {};
 +  this.init = function(data) {
++    runtime.assert(data.length >= 0, "OpRemoveText only supports positive lengths");
 +    memberid = data.memberid;
-     timestamp = data.timestamp
++    timestamp = data.timestamp;
++    position = parseInt(data.position, 10);
++    length = parseInt(data.length, 10);
++    odfUtils = new odf.OdfUtils;
++    domUtils = new core.DomUtils;
++    odfNodeNamespaceMap[odf.Namespaces.dbns] = true;
++    odfNodeNamespaceMap[odf.Namespaces.dcns] = true;
++    odfNodeNamespaceMap[odf.Namespaces.dr3dns] = true;
++    odfNodeNamespaceMap[odf.Namespaces.drawns] = true;
++    odfNodeNamespaceMap[odf.Namespaces.chartns] = true;
++    odfNodeNamespaceMap[odf.Namespaces.formns] = true;
++    odfNodeNamespaceMap[odf.Namespaces.numberns] = true;
++    odfNodeNamespaceMap[odf.Namespaces.officens] = true;
++    odfNodeNamespaceMap[odf.Namespaces.presentationns] = true;
++    odfNodeNamespaceMap[odf.Namespaces.stylens] = true;
++    odfNodeNamespaceMap[odf.Namespaces.svgns] = true;
++    odfNodeNamespaceMap[odf.Namespaces.tablens] = true;
++    odfNodeNamespaceMap[odf.Namespaces.textns] = true
 +  };
-   this.isEdit = false;
-   this.execute = function(odtDocument) {
-     var cursor = odtDocument.getCursor(memberid);
-     if(cursor) {
-       return false
++  this.isEdit = true;
++  this.group = undefined;
++  function CollapsingRules(rootNode) {
++    function isOdfNode(node) {
++      return odfNodeNamespaceMap.hasOwnProperty(node.namespaceURI)
 +    }
-     cursor = new ops.OdtCursor(memberid, odtDocument);
-     odtDocument.addCursor(cursor);
-     odtDocument.emit(ops.OdtDocument.signalCursorAdded, cursor);
-     return true
-   };
-   this.spec = function() {
-     return{optype:"AddCursor", memberid:memberid, timestamp:timestamp}
++    function shouldRemove(node) {
++      return isOdfNode(node) || (node.localName === "br" && odfUtils.isLineBreak(node.parentNode) || node.nodeType === Node.TEXT_NODE && isOdfNode((node.parentNode)))
++    }
++    function isEmpty(node) {
++      var childNode;
++      if(odfUtils.isCharacterElement(node)) {
++        return false
++      }
++      if(node.nodeType === Node.TEXT_NODE) {
++        return node.textContent.length === 0
++      }
++      childNode = node.firstChild;
++      while(childNode) {
++        if(isOdfNode(childNode) || !isEmpty(childNode)) {
++          return false
++        }
++        childNode = childNode.nextSibling
++      }
++      return true
++    }
++    this.isEmpty = isEmpty;
++    function isCollapsibleContainer(node) {
++      return!odfUtils.isParagraph(node) && (node !== rootNode && isEmpty(node))
++    }
++    function mergeChildrenIntoParent(targetNode) {
++      var parent;
++      if(targetNode.nodeType === Node.TEXT_NODE) {
++        parent = targetNode.parentNode;
++        parent.removeChild(targetNode)
++      }else {
++        parent = domUtils.removeUnwantedNodes(targetNode, shouldRemove)
++      }
++      if(parent && isCollapsibleContainer(parent)) {
++        return mergeChildrenIntoParent(parent)
++      }
++      return parent
++    }
++    this.mergeChildrenIntoParent = mergeChildrenIntoParent
 +  }
- };
- /*
- 
-  Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
- 
-  @licstart
-  This file is part of WebODF.
- 
-  WebODF is free software: you can redistribute it and/or modify it
-  under the terms of the GNU Affero General Public License (GNU AGPL)
-  as published by the Free Software Foundation, either version 3 of
-  the License, or (at your option) any later version.
- 
-  WebODF is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-  GNU Affero General Public License for more details.
- 
-  You should have received a copy of the GNU Affero General Public License
-  along with WebODF.  If not, see <http://www.gnu.org/licenses/>.
-  @licend
- 
-  @source: http://www.webodf.org/
-  @source: https://github.com/kogmbh/WebODF/
- */
- runtime.loadClass("ops.Member");
- ops.OpAddMember = function OpAddMember() {
-   var memberid, timestamp, setProperties;
-   this.init = function(data) {
-     memberid = data.memberid;
-     timestamp = parseInt(data.timestamp, 10);
-     setProperties = data.setProperties
-   };
-   this.isEdit = false;
-   this.execute = function(odtDocument) {
-     if(odtDocument.getMember(memberid)) {
-       return false
++  function mergeParagraphs(first, second, collapseRules) {
++    var child, destination = first, source = second, secondParent, insertionPoint = null;
++    if(collapseRules.isEmpty(first)) {
++      if(second.parentNode !== first.parentNode) {
++        secondParent = second.parentNode;
++        first.parentNode.insertBefore(second, first.nextSibling)
++      }
++      source = first;
++      destination = second;
++      insertionPoint = destination.getElementsByTagNameNS(editinfons, "editinfo").item(0) || destination.firstChild
 +    }
-     var member = new ops.Member(memberid, setProperties);
-     odtDocument.addMember(member);
-     odtDocument.emit(ops.OdtDocument.signalMemberAdded, member);
++    while(source.firstChild) {
++      child = source.firstChild;
++      source.removeChild(child);
++      if(child.localName !== "editinfo") {
++        destination.insertBefore(child, insertionPoint)
++      }
++    }
++    if(secondParent && collapseRules.isEmpty(secondParent)) {
++      collapseRules.mergeChildrenIntoParent(secondParent)
++    }
++    collapseRules.mergeChildrenIntoParent(source);
++    return destination
++  }
++  this.execute = function(document) {
++    var odtDocument = (document), paragraphElement, destinationParagraph, range, textNodes, paragraphs, cursor = odtDocument.getCursor(memberid), collapseRules = new CollapsingRules(odtDocument.getRootNode());
++    odtDocument.upgradeWhitespacesAtPosition(position);
++    odtDocument.upgradeWhitespacesAtPosition(position + length);
++    range = odtDocument.convertCursorToDomRange(position, length);
++    domUtils.splitBoundaries(range);
++    paragraphElement = odtDocument.getParagraphElement(range.startContainer);
++    textNodes = odfUtils.getTextElements(range, false, true);
++    paragraphs = odfUtils.getParagraphElements(range);
++    range.detach();
++    textNodes.forEach(function(element) {
++      if(element.parentNode) {
++        collapseRules.mergeChildrenIntoParent(element)
++      }else {
++        runtime.log("WARN: text element has already been removed from it's container")
++      }
++    });
++    function merge(destination, paragraph) {
++      return mergeParagraphs(destination, paragraph, collapseRules)
++    }
++    destinationParagraph = paragraphs.reduce(merge);
++    odtDocument.emit(ops.OdtDocument.signalStepsRemoved, {position:position, length:length});
++    odtDocument.downgradeWhitespacesAtPosition(position);
++    odtDocument.fixCursorPositions();
++    odtDocument.getOdfCanvas().refreshSize();
++    odtDocument.emit(ops.OdtDocument.signalParagraphChanged, {paragraphElement:destinationParagraph || paragraphElement, memberId:memberid, timeStamp:timestamp});
++    if(cursor) {
++      cursor.resetSelectionType();
++      odtDocument.emit(ops.Document.signalCursorMoved, cursor)
++    }
++    odtDocument.getOdfCanvas().rerenderAnnotations();
 +    return true
 +  };
 +  this.spec = function() {
-     return{optype:"AddMember", memberid:memberid, timestamp:timestamp, setProperties:setProperties}
++    return{optype:"RemoveText", memberid:memberid, timestamp:timestamp, position:position, length:length}
 +  }
 +};
++ops.OpRemoveText.Spec;
++ops.OpRemoveText.InitSpec;
 +/*
 +
 + Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("odf.Namespaces");
- ops.OpAddStyle = function OpAddStyle() {
-   var memberid, timestamp, styleName, styleFamily, isAutomaticStyle, setProperties, stylens = odf.Namespaces.stylens;
++ops.OpSetBlob = function OpSetBlob() {
++  var memberid, timestamp, filename, mimetype, content;
 +  this.init = function(data) {
 +    memberid = data.memberid;
 +    timestamp = data.timestamp;
-     styleName = data.styleName;
-     styleFamily = data.styleFamily;
-     isAutomaticStyle = data.isAutomaticStyle === "true" || data.isAutomaticStyle === true;
-     setProperties = data.setProperties
++    filename = data.filename;
++    mimetype = data.mimetype;
++    content = data.content
 +  };
 +  this.isEdit = true;
-   this.execute = function(odtDocument) {
-     var odfContainer = odtDocument.getOdfCanvas().odfContainer(), formatting = odtDocument.getFormatting(), dom = odtDocument.getDOM(), styleNode = dom.createElementNS(stylens, "style:style");
-     if(!styleNode) {
-       return false
-     }
-     if(setProperties) {
-       formatting.updateStyle(styleNode, setProperties)
-     }
-     styleNode.setAttributeNS(stylens, "style:family", styleFamily);
-     styleNode.setAttributeNS(stylens, "style:name", styleName);
-     if(isAutomaticStyle) {
-       odfContainer.rootElement.automaticStyles.appendChild(styleNode)
-     }else {
-       odfContainer.rootElement.styles.appendChild(styleNode)
-     }
-     odtDocument.getOdfCanvas().refreshCSS();
-     if(!isAutomaticStyle) {
-       odtDocument.emit(ops.OdtDocument.signalCommonStyleCreated, {name:styleName, family:styleFamily})
-     }
++  this.group = undefined;
++  this.execute = function(document) {
++    var odtDocument = (document);
++    odtDocument.getOdfCanvas().odfContainer().setBlob(filename, mimetype, content);
 +    return true
 +  };
 +  this.spec = function() {
-     return{optype:"AddStyle", memberid:memberid, timestamp:timestamp, styleName:styleName, styleFamily:styleFamily, isAutomaticStyle:isAutomaticStyle, setProperties:setProperties}
++    return{optype:"SetBlob", memberid:memberid, timestamp:timestamp, filename:filename, mimetype:mimetype, content:content}
 +  }
 +};
- ops.OpAddStyle.Spec;
++ops.OpSetBlob.Spec;
++ops.OpSetBlob.InitSpec;
 +/*
 +
 + Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("core.DomUtils");
- runtime.loadClass("odf.OdfUtils");
- runtime.loadClass("odf.TextStyleApplicator");
- ops.OpApplyDirectStyling = function OpApplyDirectStyling() {
-   var memberid, timestamp, position, length, setProperties, odfUtils = new odf.OdfUtils, domUtils = new core.DomUtils;
++ops.OpSetParagraphStyle = function OpSetParagraphStyle() {
++  var memberid, timestamp, position, styleName, textns = "urn:oasis:names:tc:opendocument:xmlns:text:1.0";
 +  this.init = function(data) {
 +    memberid = data.memberid;
 +    timestamp = data.timestamp;
-     position = parseInt(data.position, 10);
-     length = parseInt(data.length, 10);
-     setProperties = data.setProperties
++    position = data.position;
++    styleName = data.styleName
 +  };
 +  this.isEdit = true;
-   function applyStyle(odtDocument, range, info) {
-     var odfCanvas = odtDocument.getOdfCanvas(), odfContainer = odfCanvas.odfContainer(), nextTextNodes = domUtils.splitBoundaries(range), textNodes = odfUtils.getTextNodes(range, false), limits, textStyles;
-     limits = {startContainer:range.startContainer, startOffset:range.startOffset, endContainer:range.endContainer, endOffset:range.endOffset};
-     textStyles = new odf.TextStyleApplicator(new odf.ObjectNameGenerator((odfContainer), memberid), odtDocument.getFormatting(), odfContainer.rootElement.automaticStyles);
-     textStyles.applyStyle(textNodes, limits, info);
-     nextTextNodes.forEach(domUtils.normalizeTextNodes)
-   }
-   this.execute = function(odtDocument) {
-     var range = odtDocument.convertCursorToDomRange(position, length), impactedParagraphs = odfUtils.getImpactedParagraphs(range);
-     applyStyle(odtDocument, range, setProperties);
-     range.detach();
-     odtDocument.getOdfCanvas().refreshCSS();
-     odtDocument.fixCursorPositions();
-     impactedParagraphs.forEach(function(n) {
-       odtDocument.emit(ops.OdtDocument.signalParagraphChanged, {paragraphElement:n, memberId:memberid, timeStamp:timestamp})
-     });
-     odtDocument.getOdfCanvas().rerenderAnnotations();
-     return true
++  this.group = undefined;
++  this.execute = function(document) {
++    var odtDocument = (document), iterator, paragraphNode;
++    iterator = odtDocument.getIteratorAtPosition(position);
++    paragraphNode = odtDocument.getParagraphElement(iterator.container());
++    if(paragraphNode) {
++      if(styleName !== "") {
++        paragraphNode.setAttributeNS(textns, "text:style-name", styleName)
++      }else {
++        paragraphNode.removeAttributeNS(textns, "style-name")
++      }
++      odtDocument.getOdfCanvas().refreshSize();
++      odtDocument.emit(ops.OdtDocument.signalParagraphChanged, {paragraphElement:paragraphNode, timeStamp:timestamp, memberId:memberid});
++      odtDocument.getOdfCanvas().rerenderAnnotations();
++      return true
++    }
++    return false
 +  };
 +  this.spec = function() {
-     return{optype:"ApplyDirectStyling", memberid:memberid, timestamp:timestamp, position:position, length:length, setProperties:setProperties}
++    return{optype:"SetParagraphStyle", memberid:memberid, timestamp:timestamp, position:position, styleName:styleName}
 +  }
 +};
- ops.OpApplyDirectStyling.Spec;
++ops.OpSetParagraphStyle.Spec;
++ops.OpSetParagraphStyle.InitSpec;
 +/*
 +
 + Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- ops.OpInsertImage = function OpInsertImage() {
-   var memberid, timestamp, position, filename, frameWidth, frameHeight, frameStyleName, frameName, drawns = odf.Namespaces.drawns, svgns = odf.Namespaces.svgns, textns = odf.Namespaces.textns, xlinkns = odf.Namespaces.xlinkns;
++ops.OpSplitParagraph = function OpSplitParagraph() {
++  var memberid, timestamp, position, moveCursor, odfUtils;
 +  this.init = function(data) {
 +    memberid = data.memberid;
 +    timestamp = data.timestamp;
 +    position = data.position;
-     filename = data.filename;
-     frameWidth = data.frameWidth;
-     frameHeight = data.frameHeight;
-     frameStyleName = data.frameStyleName;
-     frameName = data.frameName
++    moveCursor = data.moveCursor === "true" || data.moveCursor === true;
++    odfUtils = new odf.OdfUtils
 +  };
 +  this.isEdit = true;
-   function createFrameElement(document) {
-     var imageNode = document.createElementNS(drawns, "draw:image"), frameNode = document.createElementNS(drawns, "draw:frame");
-     imageNode.setAttributeNS(xlinkns, "xlink:href", filename);
-     imageNode.setAttributeNS(xlinkns, "xlink:type", "simple");
-     imageNode.setAttributeNS(xlinkns, "xlink:show", "embed");
-     imageNode.setAttributeNS(xlinkns, "xlink:actuate", "onLoad");
-     frameNode.setAttributeNS(drawns, "draw:style-name", frameStyleName);
-     frameNode.setAttributeNS(drawns, "draw:name", frameName);
-     frameNode.setAttributeNS(textns, "text:anchor-type", "as-char");
-     frameNode.setAttributeNS(svgns, "svg:width", frameWidth);
-     frameNode.setAttributeNS(svgns, "svg:height", frameHeight);
-     frameNode.appendChild(imageNode);
-     return frameNode
-   }
-   this.execute = function(odtDocument) {
-     var odfCanvas = odtDocument.getOdfCanvas(), domPosition = odtDocument.getTextNodeAtStep(position, memberid), textNode, refNode, paragraphElement, frameElement;
++  this.group = undefined;
++  this.execute = function(document) {
++    var odtDocument = (document), domPosition, paragraphNode, targetNode, node, splitNode, splitChildNode, keptChildNode, cursor = odtDocument.getCursor(memberid);
++    odtDocument.upgradeWhitespacesAtPosition(position);
++    domPosition = odtDocument.getTextNodeAtStep(position);
 +    if(!domPosition) {
 +      return false
 +    }
-     textNode = domPosition.textNode;
-     paragraphElement = odtDocument.getParagraphElement(textNode);
-     refNode = domPosition.offset !== textNode.length ? textNode.splitText(domPosition.offset) : textNode.nextSibling;
-     frameElement = createFrameElement(odtDocument.getDOM());
-     textNode.parentNode.insertBefore(frameElement, refNode);
++    paragraphNode = odtDocument.getParagraphElement(domPosition.textNode);
++    if(!paragraphNode) {
++      return false
++    }
++    if(odfUtils.isListItem(paragraphNode.parentNode)) {
++      targetNode = paragraphNode.parentNode
++    }else {
++      targetNode = paragraphNode
++    }
++    if(domPosition.offset === 0) {
++      keptChildNode = domPosition.textNode.previousSibling;
++      splitChildNode = null
++    }else {
++      keptChildNode = domPosition.textNode;
++      if(domPosition.offset >= domPosition.textNode.length) {
++        splitChildNode = null
++      }else {
++        splitChildNode = (domPosition.textNode.splitText(domPosition.offset))
++      }
++    }
++    node = domPosition.textNode;
++    while(node !== targetNode) {
++      node = node.parentNode;
++      splitNode = node.cloneNode(false);
++      if(splitChildNode) {
++        splitNode.appendChild(splitChildNode)
++      }
++      if(keptChildNode) {
++        while(keptChildNode && keptChildNode.nextSibling) {
++          splitNode.appendChild(keptChildNode.nextSibling)
++        }
++      }else {
++        while(node.firstChild) {
++          splitNode.appendChild(node.firstChild)
++        }
++      }
++      node.parentNode.insertBefore(splitNode, node.nextSibling);
++      keptChildNode = node;
++      splitChildNode = splitNode
++    }
++    if(odfUtils.isListItem(splitChildNode)) {
++      splitChildNode = splitChildNode.childNodes.item(0)
++    }
++    if(domPosition.textNode.length === 0) {
++      domPosition.textNode.parentNode.removeChild(domPosition.textNode)
++    }
 +    odtDocument.emit(ops.OdtDocument.signalStepsInserted, {position:position, length:1});
-     if(textNode.length === 0) {
-       textNode.parentNode.removeChild(textNode)
++    if(cursor && moveCursor) {
++      odtDocument.moveCursor(memberid, position + 1, 0);
++      odtDocument.emit(ops.Document.signalCursorMoved, cursor)
 +    }
-     odfCanvas.addCssForFrameWithImage(frameElement);
-     odfCanvas.refreshCSS();
-     odtDocument.emit(ops.OdtDocument.signalParagraphChanged, {paragraphElement:paragraphElement, memberId:memberid, timeStamp:timestamp});
-     odfCanvas.rerenderAnnotations();
++    odtDocument.fixCursorPositions();
++    odtDocument.getOdfCanvas().refreshSize();
++    odtDocument.emit(ops.OdtDocument.signalParagraphChanged, {paragraphElement:paragraphNode, memberId:memberid, timeStamp:timestamp});
++    odtDocument.emit(ops.OdtDocument.signalParagraphChanged, {paragraphElement:splitChildNode, memberId:memberid, timeStamp:timestamp});
++    odtDocument.getOdfCanvas().rerenderAnnotations();
 +    return true
 +  };
 +  this.spec = function() {
-     return{optype:"InsertImage", memberid:memberid, timestamp:timestamp, filename:filename, position:position, frameWidth:frameWidth, frameHeight:frameHeight, frameStyleName:frameStyleName, frameName:frameName}
++    return{optype:"SplitParagraph", memberid:memberid, timestamp:timestamp, position:position, moveCursor:moveCursor}
 +  }
 +};
++ops.OpSplitParagraph.Spec;
++ops.OpSplitParagraph.InitSpec;
 +/*
 +
 + Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
-  The JavaScript code in this page is free software: you can redistribute it
-  and/or modify it under the terms of the GNU Affero General Public License
-  (GNU AGPL) as published by the Free Software Foundation, either version 3 of
-  the License, or (at your option) any later version.  The code is distributed
-  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
- 
-  You should have received a copy of the GNU Affero General Public License
-  along with this code.  If not, see <http://www.gnu.org/licenses/>.
++ This file is part of WebODF.
 +
-  As additional permission under GNU AGPL version 3 section 7, you
-  may distribute non-source (e.g., minimized or compacted) forms of
-  that code without the copy of the GNU GPL normally required by
-  section 4, provided you include this license notice and a URL
-  through which recipients can access the Corresponding Source.
++ WebODF is free software: you can redistribute it and/or modify it
++ under the terms of the GNU Affero General Public License (GNU AGPL)
++ as published by the Free Software Foundation, either version 3 of
++ the License, or (at your option) any later version.
 +
-  As a special exception to the AGPL, any HTML file which merely makes function
-  calls to this code, and for that purpose includes it by reference shall be
-  deemed a separate work for copyright law purposes. In addition, the copyright
-  holders of this code give you permission to combine this code with free
-  software libraries that are released under the GNU LGPL. You may copy and
-  distribute such a system following the terms of the GNU AGPL for this code
-  and the LGPL for the libraries. If you modify this code, you may extend this
-  exception to your version of the code, but you are not obligated to do so.
-  If you do not wish to do so, delete this exception statement from your
-  version.
++ WebODF is distributed in the hope that it will be useful, but
++ WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ GNU Affero General Public License for more details.
 +
-  This license applies to this entire compilation.
++ You should have received a copy of the GNU Affero General Public License
++ along with WebODF.  If not, see <http://www.gnu.org/licenses/>.
 + @licend
++
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- ops.OpInsertTable = function OpInsertTable() {
-   var memberid, timestamp, initialRows, initialColumns, position, tableName, tableStyleName, tableColumnStyleName, tableCellStyleMatrix, tablens = "urn:oasis:names:tc:opendocument:xmlns:table:1.0", textns = "urn:oasis:names:tc:opendocument:xmlns:text:1.0";
++ops.OpUpdateMember = function OpUpdateMember() {
++  var memberid, timestamp, setProperties, removedProperties;
 +  this.init = function(data) {
 +    memberid = data.memberid;
-     timestamp = data.timestamp;
-     position = data.position;
-     initialRows = data.initialRows;
-     initialColumns = data.initialColumns;
-     tableName = data.tableName;
-     tableStyleName = data.tableStyleName;
-     tableColumnStyleName = data.tableColumnStyleName;
-     tableCellStyleMatrix = data.tableCellStyleMatrix
-   };
-   this.isEdit = true;
-   function getCellStyleName(row, column) {
-     var rowStyles;
-     if(tableCellStyleMatrix.length === 1) {
-       rowStyles = tableCellStyleMatrix[0]
-     }else {
-       if(tableCellStyleMatrix.length === 3) {
-         switch(row) {
-           case 0:
-             rowStyles = tableCellStyleMatrix[0];
-             break;
-           case initialRows - 1:
-             rowStyles = tableCellStyleMatrix[2];
-             break;
-           default:
-             rowStyles = tableCellStyleMatrix[1];
-             break
-         }
-       }else {
-         rowStyles = tableCellStyleMatrix[row]
-       }
-     }
-     if(rowStyles.length === 1) {
-       return rowStyles[0]
-     }
-     if(rowStyles.length === 3) {
-       switch(column) {
-         case 0:
-           return rowStyles[0];
-         case initialColumns - 1:
-           return rowStyles[2];
-         default:
-           return rowStyles[1]
++    timestamp = parseInt(data.timestamp, 10);
++    setProperties = data.setProperties;
++    removedProperties = data.removedProperties
++  };
++  this.isEdit = false;
++  this.group = undefined;
++  function updateCreators(doc) {
++    var xpath = xmldom.XPath, xp = "//dc:creator[@editinfo:memberid='" + memberid + "']", creators = xpath.getODFElementsWithXPath(doc.getRootNode(), xp, function(prefix) {
++      if(prefix === "editinfo") {
++        return"urn:webodf:names:editinfo"
 +      }
++      return odf.Namespaces.lookupNamespaceURI(prefix)
++    }), i;
++    for(i = 0;i < creators.length;i += 1) {
++      creators[i].textContent = setProperties.fullName
 +    }
-     return rowStyles[column]
 +  }
-   function createTableNode(document) {
-     var tableNode = document.createElementNS(tablens, "table:table"), columns = document.createElementNS(tablens, "table:table-column"), row, cell, paragraph, rowCounter, columnCounter, cellStyleName;
-     if(tableStyleName) {
-       tableNode.setAttributeNS(tablens, "table:style-name", tableStyleName)
-     }
-     if(tableName) {
-       tableNode.setAttributeNS(tablens, "table:name", tableName)
++  this.execute = function(document) {
++    var odtDocument = (document), member = odtDocument.getMember(memberid);
++    if(!member) {
++      return false
 +    }
-     columns.setAttributeNS(tablens, "table:number-columns-repeated", initialColumns);
-     if(tableColumnStyleName) {
-       columns.setAttributeNS(tablens, "table:style-name", tableColumnStyleName)
++    if(removedProperties) {
++      member.removeProperties(removedProperties)
 +    }
-     tableNode.appendChild(columns);
-     for(rowCounter = 0;rowCounter < initialRows;rowCounter += 1) {
-       row = document.createElementNS(tablens, "table:table-row");
-       for(columnCounter = 0;columnCounter < initialColumns;columnCounter += 1) {
-         cell = document.createElementNS(tablens, "table:table-cell");
-         cellStyleName = getCellStyleName(rowCounter, columnCounter);
-         if(cellStyleName) {
-           cell.setAttributeNS(tablens, "table:style-name", cellStyleName)
-         }
-         paragraph = document.createElementNS(textns, "text:p");
-         cell.appendChild(paragraph);
-         row.appendChild(cell)
++    if(setProperties) {
++      member.setProperties(setProperties);
++      if(setProperties.fullName) {
++        updateCreators(odtDocument)
 +      }
-       tableNode.appendChild(row)
 +    }
-     return tableNode
++    odtDocument.emit(ops.Document.signalMemberUpdated, member);
++    return true
++  };
++  this.spec = function() {
++    return{optype:"UpdateMember", memberid:memberid, timestamp:timestamp, setProperties:setProperties, removedProperties:removedProperties}
 +  }
-   this.execute = function(odtDocument) {
-     var domPosition = odtDocument.getTextNodeAtStep(position), rootNode = odtDocument.getRootNode(), previousSibling, tableNode;
-     if(domPosition) {
-       tableNode = createTableNode(odtDocument.getDOM());
-       previousSibling = odtDocument.getParagraphElement(domPosition.textNode);
-       rootNode.insertBefore(tableNode, previousSibling.nextSibling);
-       odtDocument.emit(ops.OdtDocument.signalStepsInserted, {position:position, length:initialColumns * initialRows + 1});
-       odtDocument.getOdfCanvas().refreshSize();
-       odtDocument.emit(ops.OdtDocument.signalTableAdded, {tableElement:tableNode, memberId:memberid, timeStamp:timestamp});
-       odtDocument.getOdfCanvas().rerenderAnnotations();
-       return true
++};
++ops.OpUpdateMember.Spec;
++ops.OpUpdateMember.InitSpec;
++/*
++
++ Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
++
++ @licstart
++ This file is part of WebODF.
++
++ WebODF is free software: you can redistribute it and/or modify it
++ under the terms of the GNU Affero General Public License (GNU AGPL)
++ as published by the Free Software Foundation, either version 3 of
++ the License, or (at your option) any later version.
++
++ WebODF is distributed in the hope that it will be useful, but
++ WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ GNU Affero General Public License for more details.
++
++ You should have received a copy of the GNU Affero General Public License
++ along with WebODF.  If not, see <http://www.gnu.org/licenses/>.
++ @licend
++
++ @source: http://www.webodf.org/
++ @source: https://github.com/kogmbh/WebODF/
++*/
++ops.OpUpdateMetadata = function OpUpdateMetadata() {
++  var memberid, timestamp, setProperties, removedProperties;
++  this.init = function(data) {
++    memberid = data.memberid;
++    timestamp = parseInt(data.timestamp, 10);
++    setProperties = data.setProperties;
++    removedProperties = data.removedProperties
++  };
++  this.isEdit = true;
++  this.group = undefined;
++  this.execute = function(document) {
++    var odtDocument = (document), odfContainer = odtDocument.getOdfCanvas().odfContainer(), removedPropertiesArray = [];
++    if(removedProperties) {
++      removedPropertiesArray = removedProperties.attributes.split(",")
 +    }
-     return false
++    odfContainer.setMetadata(setProperties, removedPropertiesArray);
++    return true
 +  };
 +  this.spec = function() {
-     return{optype:"InsertTable", memberid:memberid, timestamp:timestamp, position:position, initialRows:initialRows, initialColumns:initialColumns, tableName:tableName, tableStyleName:tableStyleName, tableColumnStyleName:tableColumnStyleName, tableCellStyleMatrix:tableCellStyleMatrix}
++    return{optype:"UpdateMetadata", memberid:memberid, timestamp:timestamp, setProperties:setProperties, removedProperties:removedProperties}
 +  }
 +};
++ops.OpUpdateMetadata.Spec;
++ops.OpUpdateMetadata.InitSpec;
 +/*
 +
 + Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- ops.OpInsertText = function OpInsertText() {
-   var space = " ", tab = "\t", memberid, timestamp, position, text, moveCursor;
++ops.OpUpdateParagraphStyle = function OpUpdateParagraphStyle() {
++  var memberid, timestamp, styleName, setProperties, removedProperties, paragraphPropertiesName = "style:paragraph-properties", textPropertiesName = "style:text-properties", stylens = odf.Namespaces.stylens;
++  function removedAttributesFromStyleNode(node, removedAttributeNames) {
++    var i, attributeNameParts, attributeNameList = removedAttributeNames ? removedAttributeNames.split(",") : [];
++    for(i = 0;i < attributeNameList.length;i += 1) {
++      attributeNameParts = attributeNameList[i].split(":");
++      node.removeAttributeNS((odf.Namespaces.lookupNamespaceURI(attributeNameParts[0])), attributeNameParts[1])
++    }
++  }
 +  this.init = function(data) {
 +    memberid = data.memberid;
 +    timestamp = data.timestamp;
-     position = data.position;
-     text = data.text;
-     moveCursor = data.moveCursor === "true" || data.moveCursor === true
++    styleName = data.styleName;
++    setProperties = data.setProperties;
++    removedProperties = data.removedProperties
 +  };
 +  this.isEdit = true;
-   function triggerLayoutInWebkit(textNode) {
-     var parent = textNode.parentNode, next = textNode.nextSibling;
-     parent.removeChild(textNode);
-     parent.insertBefore(textNode, next)
-   }
-   function requiresSpaceElement(text, index) {
-     return text[index] === space && (index === 0 || (index === text.length - 1 || text[index - 1] === space))
-   }
-   this.execute = function(odtDocument) {
-     var domPosition, previousNode, parentElement, nextNode = null, ownerDocument = odtDocument.getDOM(), paragraphElement, textns = "urn:oasis:names:tc:opendocument:xmlns:text:1.0", toInsertIndex = 0, spaceTag, spaceElement, cursor = odtDocument.getCursor(memberid), i;
-     function insertTextNode(toInsertText) {
-       parentElement.insertBefore(ownerDocument.createTextNode(toInsertText), nextNode)
++  this.group = undefined;
++  this.execute = function(document) {
++    var odtDocument = (document), formatting = odtDocument.getFormatting(), styleNode, object, paragraphPropertiesNode, textPropertiesNode;
++    if(styleName !== "") {
++      styleNode = odtDocument.getParagraphStyleElement(styleName)
++    }else {
++      styleNode = formatting.getDefaultStyleElement("paragraph")
 +    }
-     odtDocument.upgradeWhitespacesAtPosition(position);
-     domPosition = odtDocument.getTextNodeAtStep(position);
-     if(domPosition) {
-       previousNode = domPosition.textNode;
-       nextNode = previousNode.nextSibling;
-       parentElement = previousNode.parentNode;
-       paragraphElement = odtDocument.getParagraphElement(previousNode);
-       for(i = 0;i < text.length;i += 1) {
-         if(requiresSpaceElement(text, i) || text[i] === tab) {
-           if(toInsertIndex === 0) {
-             if(domPosition.offset !== previousNode.length) {
-               nextNode = previousNode.splitText(domPosition.offset)
-             }
-             if(0 < i) {
-               previousNode.appendData(text.substring(0, i))
-             }
-           }else {
-             if(toInsertIndex < i) {
-               insertTextNode(text.substring(toInsertIndex, i))
-             }
-           }
-           toInsertIndex = i + 1;
-           spaceTag = text[i] === space ? "text:s" : "text:tab";
-           spaceElement = ownerDocument.createElementNS(textns, spaceTag);
-           spaceElement.appendChild(ownerDocument.createTextNode(text[i]));
-           parentElement.insertBefore(spaceElement, nextNode)
-         }
++    if(styleNode) {
++      paragraphPropertiesNode = (styleNode.getElementsByTagNameNS(stylens, "paragraph-properties").item(0));
++      textPropertiesNode = (styleNode.getElementsByTagNameNS(stylens, "text-properties").item(0));
++      if(setProperties) {
++        formatting.updateStyle(styleNode, setProperties)
 +      }
-       if(toInsertIndex === 0) {
-         previousNode.insertData(domPosition.offset, text)
-       }else {
-         if(toInsertIndex < text.length) {
-           insertTextNode(text.substring(toInsertIndex))
++      if(removedProperties) {
++        object = (removedProperties[paragraphPropertiesName]);
++        if(paragraphPropertiesNode && object) {
++          removedAttributesFromStyleNode(paragraphPropertiesNode, object.attributes);
++          if(paragraphPropertiesNode.attributes.length === 0) {
++            styleNode.removeChild(paragraphPropertiesNode)
++          }
 +        }
-       }
-       triggerLayoutInWebkit(previousNode);
-       if(previousNode.length === 0) {
-         previousNode.parentNode.removeChild(previousNode)
-       }
-       odtDocument.emit(ops.OdtDocument.signalStepsInserted, {position:position, length:text.length});
-       if(cursor && moveCursor) {
-         odtDocument.moveCursor(memberid, position + text.length, 0);
-         odtDocument.emit(ops.OdtDocument.signalCursorMoved, cursor)
-       }
-       if(position > 0) {
-         if(position > 1) {
-           odtDocument.downgradeWhitespacesAtPosition(position - 2)
++        object = (removedProperties[textPropertiesName]);
++        if(textPropertiesNode && object) {
++          removedAttributesFromStyleNode(textPropertiesNode, object.attributes);
++          if(textPropertiesNode.attributes.length === 0) {
++            styleNode.removeChild(textPropertiesNode)
++          }
 +        }
-         odtDocument.downgradeWhitespacesAtPosition(position - 1)
++        removedAttributesFromStyleNode(styleNode, removedProperties.attributes)
 +      }
-       odtDocument.downgradeWhitespacesAtPosition(position);
-       odtDocument.downgradeWhitespacesAtPosition(position + text.length - 1);
-       odtDocument.downgradeWhitespacesAtPosition(position + text.length);
-       odtDocument.getOdfCanvas().refreshSize();
-       odtDocument.emit(ops.OdtDocument.signalParagraphChanged, {paragraphElement:paragraphElement, memberId:memberid, timeStamp:timestamp});
++      odtDocument.getOdfCanvas().refreshCSS();
++      odtDocument.emit(ops.OdtDocument.signalParagraphStyleModified, styleName);
 +      odtDocument.getOdfCanvas().rerenderAnnotations();
 +      return true
 +    }
 +    return false
 +  };
 +  this.spec = function() {
-     return{optype:"InsertText", memberid:memberid, timestamp:timestamp, position:position, text:text, moveCursor:moveCursor}
++    return{optype:"UpdateParagraphStyle", memberid:memberid, timestamp:timestamp, styleName:styleName, setProperties:setProperties, removedProperties:removedProperties}
 +  }
 +};
- ops.OpInsertText.Spec;
++ops.OpUpdateParagraphStyle.Spec;
++ops.OpUpdateParagraphStyle.InitSpec;
 +/*
 +
 + Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- ops.OpMoveCursor = function OpMoveCursor() {
-   var memberid, timestamp, position, length, selectionType;
-   this.init = function(data) {
-     memberid = data.memberid;
-     timestamp = data.timestamp;
-     position = data.position;
-     length = data.length || 0;
-     selectionType = data.selectionType || ops.OdtCursor.RangeSelection
++ops.OperationFactory = function OperationFactory() {
++  var specs;
++  this.register = function(specName, specConstructor) {
++    specs[specName] = specConstructor
 +  };
-   this.isEdit = false;
-   this.execute = function(odtDocument) {
-     var cursor = odtDocument.getCursor(memberid), selectedRange;
-     if(!cursor) {
-       return false
++  this.create = function(spec) {
++    var op = null, Constructor = specs[spec.optype];
++    if(Constructor) {
++      op = new Constructor;
++      op.init(spec)
 +    }
-     selectedRange = odtDocument.convertCursorToDomRange(position, length);
-     cursor.setSelectedRange(selectedRange, length >= 0);
-     cursor.setSelectionType(selectionType);
-     odtDocument.emit(ops.OdtDocument.signalCursorMoved, cursor);
-     return true
++    return op
 +  };
-   this.spec = function() {
-     return{optype:"MoveCursor", memberid:memberid, timestamp:timestamp, position:position, length:length, selectionType:selectionType}
++  function init() {
++    specs = {AddMember:ops.OpAddMember, UpdateMember:ops.OpUpdateMember, RemoveMember:ops.OpRemoveMember, AddCursor:ops.OpAddCursor, ApplyDirectStyling:ops.OpApplyDirectStyling, SetBlob:ops.OpSetBlob, RemoveBlob:ops.OpRemoveBlob, InsertImage:ops.OpInsertImage, InsertTable:ops.OpInsertTable, InsertText:ops.OpInsertText, RemoveText:ops.OpRemoveText, SplitParagraph:ops.OpSplitParagraph, SetParagraphStyle:ops.OpSetParagraphStyle, UpdateParagraphStyle:ops.OpUpdateParagraphStyle, AddStyle:ops [...]
++    RemoveStyle:ops.OpRemoveStyle, MoveCursor:ops.OpMoveCursor, RemoveCursor:ops.OpRemoveCursor, AddAnnotation:ops.OpAddAnnotation, RemoveAnnotation:ops.OpRemoveAnnotation, UpdateMetadata:ops.OpUpdateMetadata, ApplyHyperlink:ops.OpApplyHyperlink, RemoveHyperlink:ops.OpRemoveHyperlink}
 +  }
++  init()
 +};
- ops.OpMoveCursor.Spec;
 +/*
 +
-  Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
++ Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("odf.Namespaces");
- runtime.loadClass("core.DomUtils");
- ops.OpRemoveAnnotation = function OpRemoveAnnotation() {
-   var memberid, timestamp, position, length, domUtils;
-   this.init = function(data) {
-     memberid = data.memberid;
-     timestamp = data.timestamp;
-     position = parseInt(data.position, 10);
-     length = parseInt(data.length, 10);
-     domUtils = new core.DomUtils
-   };
-   this.isEdit = true;
-   this.execute = function(odtDocument) {
-     var iterator = odtDocument.getIteratorAtPosition(position), container = iterator.container(), annotationName, annotationNode, annotationEnd, cursors;
-     while(!(container.namespaceURI === odf.Namespaces.officens && container.localName === "annotation")) {
-       container = container.parentNode
-     }
-     if(container === null) {
-       return false
-     }
-     annotationNode = container;
-     annotationName = annotationNode.getAttributeNS(odf.Namespaces.officens, "name");
-     if(annotationName) {
-       annotationEnd = domUtils.getElementsByTagNameNS(odtDocument.getRootNode(), odf.Namespaces.officens, "annotation-end").filter(function(element) {
-         return annotationName === element.getAttributeNS(odf.Namespaces.officens, "name")
-       })[0] || null
-     }
-     odtDocument.getOdfCanvas().forgetAnnotations();
-     cursors = domUtils.getElementsByTagNameNS(annotationNode, "urn:webodf:names:cursor", "cursor");
-     while(cursors.length) {
-       annotationNode.parentNode.insertBefore(cursors.pop(), annotationNode)
-     }
-     annotationNode.parentNode.removeChild(annotationNode);
-     if(annotationEnd) {
-       annotationEnd.parentNode.removeChild(annotationEnd)
-     }
-     odtDocument.emit(ops.OdtDocument.signalStepsRemoved, {position:position > 0 ? position - 1 : position, length:length});
-     odtDocument.fixCursorPositions();
-     odtDocument.getOdfCanvas().refreshAnnotations();
-     return true
-   };
-   this.spec = function() {
-     return{optype:"RemoveAnnotation", memberid:memberid, timestamp:timestamp, position:position, length:length}
-   }
++ops.OperationRouter = function OperationRouter() {
++};
++ops.OperationRouter.prototype.setOperationFactory = function(f) {
++};
++ops.OperationRouter.prototype.setPlaybackFunction = function(playback_func) {
++};
++ops.OperationRouter.prototype.push = function(operations) {
++};
++ops.OperationRouter.prototype.close = function(callback) {
++};
++ops.OperationRouter.prototype.subscribe = function(eventId, cb) {
++};
++ops.OperationRouter.prototype.unsubscribe = function(eventId, cb) {
++};
++ops.OperationRouter.prototype.hasLocalUnsyncedOps = function() {
++};
++ops.OperationRouter.prototype.hasSessionHostConnection = function() {
 +};
++ops.OperationRouter.signalProcessingBatchStart = "router/batchstart";
++ops.OperationRouter.signalProcessingBatchEnd = "router/batchend";
 +/*
 +
-  Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
++ Copyright (C) 2012 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- ops.OpRemoveBlob = function OpRemoveBlob() {
-   var memberid, timestamp, filename;
-   this.init = function(data) {
-     memberid = data.memberid;
-     timestamp = data.timestamp;
-     filename = data.filename
++ops.TrivialOperationRouter = function TrivialOperationRouter() {
++  var events = new core.EventNotifier([ops.OperationRouter.signalProcessingBatchStart, ops.OperationRouter.signalProcessingBatchEnd]), operationFactory, playbackFunction, groupIdentifier = 0;
++  this.setOperationFactory = function(f) {
++    operationFactory = f
 +  };
-   this.isEdit = true;
-   this.execute = function(odtDocument) {
-     odtDocument.getOdfCanvas().odfContainer().removeBlob(filename);
-     return true
++  this.setPlaybackFunction = function(playback_func) {
++    playbackFunction = playback_func
 +  };
-   this.spec = function() {
-     return{optype:"RemoveBlob", memberid:memberid, timestamp:timestamp, filename:filename}
++  this.push = function(operations) {
++    groupIdentifier += 1;
++    events.emit(ops.OperationRouter.signalProcessingBatchStart, {});
++    operations.forEach(function(op) {
++      var timedOp, opspec = op.spec();
++      opspec.timestamp = (new Date).getTime();
++      timedOp = operationFactory.create(opspec);
++      timedOp.group = "g" + groupIdentifier;
++      playbackFunction(timedOp)
++    });
++    events.emit(ops.OperationRouter.signalProcessingBatchEnd, {})
++  };
++  this.close = function(cb) {
++    cb()
++  };
++  this.subscribe = function(eventId, cb) {
++    events.subscribe(eventId, cb)
++  };
++  this.unsubscribe = function(eventId, cb) {
++    events.unsubscribe(eventId, cb)
++  };
++  this.hasLocalUnsyncedOps = function() {
++    return false
++  };
++  this.hasSessionHostConnection = function() {
++    return true
 +  }
 +};
 +/*
 +
 + Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- ops.OpRemoveCursor = function OpRemoveCursor() {
-   var memberid, timestamp;
-   this.init = function(data) {
-     memberid = data.memberid;
-     timestamp = data.timestamp
++ops.Session = function Session(odfCanvas) {
++  var self = this, operationFactory = new ops.OperationFactory, odtDocument = new ops.OdtDocument(odfCanvas), operationRouter = null;
++  function forwardBatchStart(args) {
++    odtDocument.emit(ops.OdtDocument.signalProcessingBatchStart, args)
++  }
++  function forwardBatchEnd(args) {
++    odtDocument.emit(ops.OdtDocument.signalProcessingBatchEnd, args)
++  }
++  this.setOperationFactory = function(opFactory) {
++    operationFactory = opFactory;
++    if(operationRouter) {
++      operationRouter.setOperationFactory(operationFactory)
++    }
 +  };
-   this.isEdit = false;
-   this.execute = function(odtDocument) {
-     if(!odtDocument.removeCursor(memberid)) {
-       return false
++  this.setOperationRouter = function(opRouter) {
++    if(operationRouter) {
++      operationRouter.unsubscribe(ops.OperationRouter.signalProcessingBatchStart, forwardBatchStart);
++      operationRouter.unsubscribe(ops.OperationRouter.signalProcessingBatchEnd, forwardBatchEnd)
 +    }
-     return true
++    operationRouter = opRouter;
++    operationRouter.subscribe(ops.OperationRouter.signalProcessingBatchStart, forwardBatchStart);
++    operationRouter.subscribe(ops.OperationRouter.signalProcessingBatchEnd, forwardBatchEnd);
++    opRouter.setPlaybackFunction(function(op) {
++      odtDocument.emit(ops.OdtDocument.signalOperationStart, op);
++      if(op.execute(odtDocument)) {
++        odtDocument.emit(ops.OdtDocument.signalOperationEnd, op);
++        return true
++      }
++      return false
++    });
++    opRouter.setOperationFactory(operationFactory)
 +  };
-   this.spec = function() {
-     return{optype:"RemoveCursor", memberid:memberid, timestamp:timestamp}
++  this.getOperationFactory = function() {
++    return operationFactory
++  };
++  this.getOdtDocument = function() {
++    return odtDocument
++  };
++  this.enqueue = function(ops) {
++    operationRouter.push(ops)
++  };
++  this.close = function(callback) {
++    operationRouter.close(function(err) {
++      if(err) {
++        callback(err)
++      }else {
++        odtDocument.close(callback)
++      }
++    })
++  };
++  this.destroy = function(callback) {
++    odtDocument.destroy(callback)
++  };
++  function init() {
++    self.setOperationRouter(new ops.TrivialOperationRouter)
 +  }
++  init()
 +};
- ops.OpRemoveCursor.Spec;
 +/*
 +
 + Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + This file is part of WebODF.
 +
 + WebODF is free software: you can redistribute it and/or modify it
 + under the terms of the GNU Affero General Public License (GNU AGPL)
 + as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.
 +
 + WebODF is distributed in the hope that it will be useful, but
 + WITHOUT ANY WARRANTY; without even the implied warranty of
 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + GNU Affero General Public License for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with WebODF.  If not, see <http://www.gnu.org/licenses/>.
 + @licend
 +
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("ops.Member");
- ops.OpRemoveMember = function OpRemoveMember() {
-   var memberid, timestamp;
-   this.init = function(data) {
-     memberid = data.memberid;
-     timestamp = parseInt(data.timestamp, 10)
++gui.AnnotationController = function AnnotationController(session, inputMemberId) {
++  var odtDocument = session.getOdtDocument(), isAnnotatable = false, eventNotifier = new core.EventNotifier([gui.AnnotationController.annotatableChanged]), officens = odf.Namespaces.officens;
++  function isWithinAnnotation(node, container) {
++    while(node && node !== container) {
++      if(node.namespaceURI === officens && node.localName === "annotation") {
++        return true
++      }
++      node = node.parentNode
++    }
++    return false
++  }
++  function updatedCachedValues() {
++    var cursor = odtDocument.getCursor(inputMemberId), cursorNode = cursor && cursor.getNode(), newIsAnnotatable = false;
++    if(cursorNode) {
++      newIsAnnotatable = !isWithinAnnotation(cursorNode, odtDocument.getRootNode())
++    }
++    if(newIsAnnotatable !== isAnnotatable) {
++      isAnnotatable = newIsAnnotatable;
++      eventNotifier.emit(gui.AnnotationController.annotatableChanged, isAnnotatable)
++    }
++  }
++  function onCursorAdded(cursor) {
++    if(cursor.getMemberId() === inputMemberId) {
++      updatedCachedValues()
++    }
++  }
++  function onCursorRemoved(memberId) {
++    if(memberId === inputMemberId) {
++      updatedCachedValues()
++    }
++  }
++  function onCursorMoved(cursor) {
++    if(cursor.getMemberId() === inputMemberId) {
++      updatedCachedValues()
++    }
++  }
++  this.isAnnotatable = function() {
++    return isAnnotatable
 +  };
-   this.isEdit = false;
-   this.execute = function(odtDocument) {
-     if(!odtDocument.getMember(memberid)) {
-       return false
++  this.addAnnotation = function() {
++    var op = new ops.OpAddAnnotation, selection = odtDocument.getCursorSelection(inputMemberId), length = selection.length, position = selection.position;
++    if(!isAnnotatable) {
++      return
 +    }
-     odtDocument.removeMember(memberid);
-     odtDocument.emit(ops.OdtDocument.signalMemberRemoved, memberid);
-     return true
++    position = length >= 0 ? position : position + length;
++    length = Math.abs(length);
++    op.init({memberid:inputMemberId, position:position, length:length, name:inputMemberId + Date.now()});
++    session.enqueue([op])
 +  };
-   this.spec = function() {
-     return{optype:"RemoveMember", memberid:memberid, timestamp:timestamp}
++  this.removeAnnotation = function(annotationNode) {
++    var startStep, endStep, op, moveCursor;
++    startStep = odtDocument.convertDomPointToCursorStep(annotationNode, 0) + 1;
++    endStep = odtDocument.convertDomPointToCursorStep(annotationNode, annotationNode.childNodes.length);
++    op = new ops.OpRemoveAnnotation;
++    op.init({memberid:inputMemberId, position:startStep, length:endStep - startStep});
++    moveCursor = new ops.OpMoveCursor;
++    moveCursor.init({memberid:inputMemberId, position:startStep > 0 ? startStep - 1 : startStep, length:0});
++    session.enqueue([op, moveCursor])
++  };
++  this.subscribe = function(eventid, cb) {
++    eventNotifier.subscribe(eventid, cb)
++  };
++  this.unsubscribe = function(eventid, cb) {
++    eventNotifier.unsubscribe(eventid, cb)
++  };
++  this.destroy = function(callback) {
++    odtDocument.unsubscribe(ops.Document.signalCursorAdded, onCursorAdded);
++    odtDocument.unsubscribe(ops.Document.signalCursorRemoved, onCursorRemoved);
++    odtDocument.unsubscribe(ops.Document.signalCursorMoved, onCursorMoved);
++    callback()
++  };
++  function init() {
++    odtDocument.subscribe(ops.Document.signalCursorAdded, onCursorAdded);
++    odtDocument.subscribe(ops.Document.signalCursorRemoved, onCursorRemoved);
++    odtDocument.subscribe(ops.Document.signalCursorMoved, onCursorMoved);
++    updatedCachedValues()
 +  }
++  init()
 +};
- /*
- 
-  Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
- 
-  @licstart
-  The JavaScript code in this page is free software: you can redistribute it
-  and/or modify it under the terms of the GNU Affero General Public License
-  (GNU AGPL) as published by the Free Software Foundation, either version 3 of
-  the License, or (at your option) any later version.  The code is distributed
-  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
- 
-  You should have received a copy of the GNU Affero General Public License
-  along with this code.  If not, see <http://www.gnu.org/licenses/>.
- 
-  As additional permission under GNU AGPL version 3 section 7, you
-  may distribute non-source (e.g., minimized or compacted) forms of
-  that code without the copy of the GNU GPL normally required by
-  section 4, provided you include this license notice and a URL
-  through which recipients can access the Corresponding Source.
- 
-  As a special exception to the AGPL, any HTML file which merely makes function
-  calls to this code, and for that purpose includes it by reference shall be
-  deemed a separate work for copyright law purposes. In addition, the copyright
-  holders of this code give you permission to combine this code with free
-  software libraries that are released under the GNU LGPL. You may copy and
-  distribute such a system following the terms of the GNU AGPL for this code
-  and the LGPL for the libraries. If you modify this code, you may extend this
-  exception to your version of the code, but you are not obligated to do so.
-  If you do not wish to do so, delete this exception statement from your
-  version.
- 
-  This license applies to this entire compilation.
-  @licend
-  @source: http://www.webodf.org/
-  @source: https://github.com/kogmbh/WebODF/
- */
- ops.OpRemoveStyle = function OpRemoveStyle() {
-   var memberid, timestamp, styleName, styleFamily;
-   this.init = function(data) {
-     memberid = data.memberid;
-     timestamp = data.timestamp;
-     styleName = data.styleName;
-     styleFamily = data.styleFamily
++gui.AnnotationController.annotatableChanged = "annotatable/changed";
++(function() {
++  return gui.AnnotationController
++})();
++gui.Avatar = function Avatar(parentElement, avatarInitiallyVisible) {
++  var self = this, handle, image, pendingImageUrl, displayShown = "block", displayHidden = "none";
++  this.setColor = function(color) {
++    image.style.borderColor = color
++  };
++  this.setImageUrl = function(url) {
++    if(self.isVisible()) {
++      image.src = url
++    }else {
++      pendingImageUrl = url
++    }
++  };
++  this.isVisible = function() {
++    return handle.style.display === displayShown
++  };
++  this.show = function() {
++    if(pendingImageUrl) {
++      image.src = pendingImageUrl;
++      pendingImageUrl = undefined
++    }
++    handle.style.display = displayShown
++  };
++  this.hide = function() {
++    handle.style.display = displayHidden
 +  };
-   this.isEdit = true;
-   this.execute = function(odtDocument) {
-     var styleNode = odtDocument.getStyleElement(styleName, styleFamily);
-     if(!styleNode) {
-       return false
++  this.markAsFocussed = function(isFocussed) {
++    if(isFocussed) {
++      handle.classList.add("active")
++    }else {
++      handle.classList.remove("active")
 +    }
-     styleNode.parentNode.removeChild(styleNode);
-     odtDocument.getOdfCanvas().refreshCSS();
-     odtDocument.emit(ops.OdtDocument.signalCommonStyleDeleted, {name:styleName, family:styleFamily});
-     return true
 +  };
-   this.spec = function() {
-     return{optype:"RemoveStyle", memberid:memberid, timestamp:timestamp, styleName:styleName, styleFamily:styleFamily}
++  this.destroy = function(callback) {
++    parentElement.removeChild(handle);
++    callback()
++  };
++  function init() {
++    var document = (parentElement.ownerDocument), htmlns = document.documentElement.namespaceURI;
++    handle = (document.createElementNS(htmlns, "div"));
++    image = (document.createElementNS(htmlns, "img"));
++    image.width = 64;
++    image.height = 64;
++    handle.appendChild(image);
++    handle.style.width = "64px";
++    handle.style.height = "70px";
++    handle.style.position = "absolute";
++    handle.style.top = "-80px";
++    handle.style.left = "-34px";
++    handle.style.display = avatarInitiallyVisible ? displayShown : displayHidden;
++    handle.className = "handle";
++    parentElement.appendChild(handle)
 +  }
++  init()
 +};
- ops.OpRemoveStyle.Spec;
- /*
- 
-  Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
- 
-  @licstart
-  The JavaScript code in this page is free software: you can redistribute it
-  and/or modify it under the terms of the GNU Affero General Public License
-  (GNU AGPL) as published by the Free Software Foundation, either version 3 of
-  the License, or (at your option) any later version.  The code is distributed
-  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
- 
-  You should have received a copy of the GNU Affero General Public License
-  along with this code.  If not, see <http://www.gnu.org/licenses/>.
- 
-  As additional permission under GNU AGPL version 3 section 7, you
-  may distribute non-source (e.g., minimized or compacted) forms of
-  that code without the copy of the GNU GPL normally required by
-  section 4, provided you include this license notice and a URL
-  through which recipients can access the Corresponding Source.
- 
-  As a special exception to the AGPL, any HTML file which merely makes function
-  calls to this code, and for that purpose includes it by reference shall be
-  deemed a separate work for copyright law purposes. In addition, the copyright
-  holders of this code give you permission to combine this code with free
-  software libraries that are released under the GNU LGPL. You may copy and
-  distribute such a system following the terms of the GNU AGPL for this code
-  and the LGPL for the libraries. If you modify this code, you may extend this
-  exception to your version of the code, but you are not obligated to do so.
-  If you do not wish to do so, delete this exception statement from your
-  version.
- 
-  This license applies to this entire compilation.
-  @licend
-  @source: http://www.webodf.org/
-  @source: https://github.com/kogmbh/WebODF/
- */
- runtime.loadClass("odf.Namespaces");
- runtime.loadClass("odf.OdfUtils");
- runtime.loadClass("core.DomUtils");
- ops.OpRemoveText = function OpRemoveText() {
-   var memberid, timestamp, position, length, odfUtils, domUtils, editinfons = "urn:webodf:names:editinfo", odfNodeNamespaceMap = {};
-   this.init = function(data) {
-     runtime.assert(data.length >= 0, "OpRemoveText only supports positive lengths");
-     memberid = data.memberid;
-     timestamp = data.timestamp;
-     position = parseInt(data.position, 10);
-     length = parseInt(data.length, 10);
-     odfUtils = new odf.OdfUtils;
-     domUtils = new core.DomUtils;
-     odfNodeNamespaceMap[odf.Namespaces.dbns] = true;
-     odfNodeNamespaceMap[odf.Namespaces.dcns] = true;
-     odfNodeNamespaceMap[odf.Namespaces.dr3dns] = true;
-     odfNodeNamespaceMap[odf.Namespaces.drawns] = true;
-     odfNodeNamespaceMap[odf.Namespaces.chartns] = true;
-     odfNodeNamespaceMap[odf.Namespaces.formns] = true;
-     odfNodeNamespaceMap[odf.Namespaces.numberns] = true;
-     odfNodeNamespaceMap[odf.Namespaces.officens] = true;
-     odfNodeNamespaceMap[odf.Namespaces.presentationns] = true;
-     odfNodeNamespaceMap[odf.Namespaces.stylens] = true;
-     odfNodeNamespaceMap[odf.Namespaces.svgns] = true;
-     odfNodeNamespaceMap[odf.Namespaces.tablens] = true;
-     odfNodeNamespaceMap[odf.Namespaces.textns] = true
-   };
-   this.isEdit = true;
-   function CollapsingRules(rootNode) {
-     function isOdfNode(node) {
-       return odfNodeNamespaceMap.hasOwnProperty(node.namespaceURI)
-     }
-     function shouldRemove(node) {
-       return isOdfNode(node) || (node.localName === "br" && odfUtils.isLineBreak(node.parentNode) || node.nodeType === Node.TEXT_NODE && isOdfNode((node.parentNode)))
++gui.Caret = function Caret(cursor, avatarInitiallyVisible, blinkOnRangeSelect) {
++  var MIN_CARET_HEIGHT_PX = 8, DEFAULT_CARET_TOP = "5%", DEFAULT_CARET_HEIGHT = "1em", BLINK_PERIOD_MS = 500, span, avatar, cursorNode, overlayElement, domUtils = new core.DomUtils, async = new core.Async, redrawTask, blinkTask, shouldResetBlink = false, shouldCheckCaretVisibility = false, shouldUpdateCaretSize = false, state = {isFocused:false, isShown:true, visibility:"hidden"}, lastState = {isFocused:!state.isFocused, isShown:!state.isShown, visibility:"hidden"};
++  function blinkCaret() {
++    span.style.opacity = span.style.opacity === "0" ? "1" : "0";
++    blinkTask.trigger()
++  }
++  function getCaretClientRectWithMargin(caretElement, margin) {
++    var caretRect = caretElement.getBoundingClientRect();
++    return{left:caretRect.left - margin.left, top:caretRect.top - margin.top, right:caretRect.right + margin.right, bottom:caretRect.bottom + margin.bottom}
++  }
++  function length(node) {
++    return node.nodeType === Node.TEXT_NODE ? node.textContent.length : node.childNodes.length
++  }
++  function verticalOverlap(cursorNode, rangeRect) {
++    var cursorRect = cursorNode.getBoundingClientRect(), intersectTop = 0, intersectBottom = 0;
++    if(cursorRect && rangeRect) {
++      intersectTop = Math.max(cursorRect.top, rangeRect.top);
++      intersectBottom = Math.min(cursorRect.bottom, rangeRect.bottom)
 +    }
-     function isEmpty(node) {
-       var childNode;
-       if(odfUtils.isCharacterElement(node)) {
-         return false
-       }
-       if(node.nodeType === Node.TEXT_NODE) {
-         return node.textContent.length === 0
++    return intersectBottom - intersectTop
++  }
++  function getSelectionRect() {
++    var range = cursor.getSelectedRange().cloneRange(), node = cursor.getNode(), nextRectangle, selectionRectangle = null, nodeLength;
++    if(node.previousSibling) {
++      nodeLength = length(node.previousSibling);
++      range.setStart(node.previousSibling, nodeLength > 0 ? nodeLength - 1 : 0);
++      range.setEnd(node.previousSibling, nodeLength);
++      nextRectangle = range.getBoundingClientRect();
++      if(nextRectangle && nextRectangle.height) {
++        selectionRectangle = nextRectangle
 +      }
-       childNode = node.firstChild;
-       while(childNode) {
-         if(isOdfNode(childNode) || !isEmpty(childNode)) {
-           return false
++    }
++    if(node.nextSibling) {
++      range.setStart(node.nextSibling, 0);
++      range.setEnd(node.nextSibling, length(node.nextSibling) > 0 ? 1 : 0);
++      nextRectangle = range.getBoundingClientRect();
++      if(nextRectangle && nextRectangle.height) {
++        if(!selectionRectangle || verticalOverlap(node, nextRectangle) > verticalOverlap(node, selectionRectangle)) {
++          selectionRectangle = nextRectangle
 +        }
-         childNode = childNode.nextSibling
 +      }
-       return true
 +    }
-     this.isEmpty = isEmpty;
-     function isCollapsibleContainer(node) {
-       return!odfUtils.isParagraph(node) && (node !== rootNode && isEmpty(node))
++    return selectionRectangle
++  }
++  function updateCaretHeightAndPosition() {
++    var selectionRect = getSelectionRect(), canvas = (cursor.getDocument().getCanvas()), zoomLevel = canvas.getZoomLevel(), rootRect = domUtils.getBoundingClientRect(canvas.getSizer()), caretRect, caretStyle;
++    if(selectionRect) {
++      span.style.top = "0";
++      caretRect = domUtils.getBoundingClientRect(span);
++      if(selectionRect.height < MIN_CARET_HEIGHT_PX) {
++        selectionRect = {top:selectionRect.top - (MIN_CARET_HEIGHT_PX - selectionRect.height) / 2, height:MIN_CARET_HEIGHT_PX}
++      }
++      span.style.height = domUtils.adaptRangeDifferenceToZoomLevel(selectionRect.height, zoomLevel) + "px";
++      span.style.top = domUtils.adaptRangeDifferenceToZoomLevel(selectionRect.top - caretRect.top, zoomLevel) + "px"
++    }else {
++      span.style.height = DEFAULT_CARET_HEIGHT;
++      span.style.top = DEFAULT_CARET_TOP
 +    }
-     function mergeChildrenIntoParent(targetNode) {
-       var parent;
-       if(targetNode.nodeType === Node.TEXT_NODE) {
-         parent = targetNode.parentNode;
-         parent.removeChild(targetNode)
++    if(overlayElement) {
++      caretStyle = runtime.getWindow().getComputedStyle(span, null);
++      caretRect = domUtils.getBoundingClientRect(span);
++      overlayElement.style.bottom = domUtils.adaptRangeDifferenceToZoomLevel(rootRect.bottom - caretRect.bottom, zoomLevel) + "px";
++      overlayElement.style.left = domUtils.adaptRangeDifferenceToZoomLevel(caretRect.right - rootRect.left, zoomLevel) + "px";
++      if(caretStyle.font) {
++        overlayElement.style.font = caretStyle.font
 +      }else {
-         parent = domUtils.removeUnwantedNodes(targetNode, shouldRemove)
++        overlayElement.style.fontStyle = caretStyle.fontStyle;
++        overlayElement.style.fontVariant = caretStyle.fontVariant;
++        overlayElement.style.fontWeight = caretStyle.fontWeight;
++        overlayElement.style.fontSize = caretStyle.fontSize;
++        overlayElement.style.lineHeight = caretStyle.lineHeight;
++        overlayElement.style.fontFamily = caretStyle.fontFamily
 +      }
-       if(isCollapsibleContainer(parent)) {
-         return mergeChildrenIntoParent(parent)
-       }
-       return parent
 +    }
-     this.mergeChildrenIntoParent = mergeChildrenIntoParent
 +  }
-   function mergeParagraphs(first, second, collapseRules) {
-     var child, mergeForward = false, destination = first, source = second, secondParent, insertionPoint = null;
-     if(collapseRules.isEmpty(first)) {
-       mergeForward = true;
-       if(second.parentNode !== first.parentNode) {
-         secondParent = second.parentNode;
-         first.parentNode.insertBefore(second, first.nextSibling)
++  function ensureVisible() {
++    var canvasElement = cursor.getDocument().getCanvas().getElement(), canvasContainerElement = (canvasElement.parentNode), caretRect, canvasContainerRect, horizontalMargin = canvasContainerElement.offsetWidth - canvasContainerElement.clientWidth + 5, verticalMargin = canvasContainerElement.offsetHeight - canvasContainerElement.clientHeight + 5;
++    caretRect = getCaretClientRectWithMargin(span, {top:verticalMargin, left:horizontalMargin, bottom:verticalMargin, right:horizontalMargin});
++    canvasContainerRect = canvasContainerElement.getBoundingClientRect();
++    if(caretRect.top < canvasContainerRect.top) {
++      canvasContainerElement.scrollTop -= canvasContainerRect.top - caretRect.top
++    }else {
++      if(caretRect.bottom > canvasContainerRect.bottom) {
++        canvasContainerElement.scrollTop += caretRect.bottom - canvasContainerRect.bottom
 +      }
-       source = first;
-       destination = second;
-       insertionPoint = destination.getElementsByTagNameNS(editinfons, "editinfo")[0] || destination.firstChild
 +    }
-     while(source.hasChildNodes()) {
-       child = mergeForward ? source.lastChild : source.firstChild;
-       source.removeChild(child);
-       if(child.localName !== "editinfo") {
-         destination.insertBefore(child, insertionPoint)
++    if(caretRect.left < canvasContainerRect.left) {
++      canvasContainerElement.scrollLeft -= canvasContainerRect.left - caretRect.left
++    }else {
++      if(caretRect.right > canvasContainerRect.right) {
++        canvasContainerElement.scrollLeft += caretRect.right - canvasContainerRect.right
 +      }
 +    }
-     if(secondParent && collapseRules.isEmpty(secondParent)) {
-       collapseRules.mergeChildrenIntoParent(secondParent)
++  }
++  function hasStateChanged(property) {
++    return lastState[property] !== state[property]
++  }
++  function saveState() {
++    Object.keys(state).forEach(function(key) {
++      lastState[key] = state[key]
++    })
++  }
++  function updateCaret() {
++    if(state.isShown === false || (cursor.getSelectionType() !== ops.OdtCursor.RangeSelection || !blinkOnRangeSelect && !cursor.getSelectedRange().collapsed)) {
++      state.visibility = "hidden";
++      span.style.visibility = "hidden";
++      blinkTask.cancel()
++    }else {
++      state.visibility = "visible";
++      span.style.visibility = "visible";
++      if(state.isFocused === false) {
++        span.style.opacity = "1";
++        blinkTask.cancel()
++      }else {
++        if(shouldResetBlink || hasStateChanged("visibility")) {
++          span.style.opacity = "1";
++          blinkTask.cancel()
++        }
++        blinkTask.trigger()
++      }
++      if(shouldUpdateCaretSize || (shouldCheckCaretVisibility || hasStateChanged("visibility"))) {
++        updateCaretHeightAndPosition()
++      }
++      if(shouldCheckCaretVisibility) {
++        ensureVisible()
++      }
 +    }
-     collapseRules.mergeChildrenIntoParent(source);
-     return destination
++    if(hasStateChanged("isFocused")) {
++      avatar.markAsFocussed(state.isFocused)
++    }
++    saveState();
++    shouldResetBlink = false;
++    shouldCheckCaretVisibility = false;
++    shouldUpdateCaretSize = false
 +  }
-   this.execute = function(odtDocument) {
-     var paragraphElement, destinationParagraph, range, textNodes, paragraphs, cursor = odtDocument.getCursor(memberid), collapseRules = new CollapsingRules(odtDocument.getRootNode());
-     odtDocument.upgradeWhitespacesAtPosition(position);
-     odtDocument.upgradeWhitespacesAtPosition(position + length);
-     range = odtDocument.convertCursorToDomRange(position, length);
-     domUtils.splitBoundaries(range);
-     paragraphElement = odtDocument.getParagraphElement(range.startContainer);
-     textNodes = odfUtils.getTextElements(range, false, true);
-     paragraphs = odfUtils.getParagraphElements(range);
-     range.detach();
-     textNodes.forEach(function(element) {
-       collapseRules.mergeChildrenIntoParent(element)
-     });
-     destinationParagraph = paragraphs.reduce(function(destination, paragraph) {
-       return mergeParagraphs(destination, paragraph, collapseRules)
-     });
-     odtDocument.emit(ops.OdtDocument.signalStepsRemoved, {position:position, length:length});
-     odtDocument.downgradeWhitespacesAtPosition(position);
-     odtDocument.fixCursorPositions();
-     odtDocument.getOdfCanvas().refreshSize();
-     odtDocument.emit(ops.OdtDocument.signalParagraphChanged, {paragraphElement:destinationParagraph || paragraphElement, memberId:memberid, timeStamp:timestamp});
-     if(cursor) {
-       cursor.resetSelectionType();
-       odtDocument.emit(ops.OdtDocument.signalCursorMoved, cursor)
++  this.handleUpdate = function() {
++    shouldUpdateCaretSize = true;
++    if(state.visibility !== "hidden") {
++      state.visibility = "hidden";
++      span.style.visibility = "hidden"
++    }
++    redrawTask.trigger()
++  };
++  this.refreshCursorBlinking = function() {
++    shouldResetBlink = true;
++    redrawTask.trigger()
++  };
++  this.setFocus = function() {
++    state.isFocused = true;
++    redrawTask.trigger()
++  };
++  this.removeFocus = function() {
++    state.isFocused = false;
++    redrawTask.trigger()
++  };
++  this.show = function() {
++    state.isShown = true;
++    redrawTask.trigger()
++  };
++  this.hide = function() {
++    state.isShown = false;
++    redrawTask.trigger()
++  };
++  this.setAvatarImageUrl = function(url) {
++    avatar.setImageUrl(url)
++  };
++  this.setColor = function(newColor) {
++    span.style.borderColor = newColor;
++    avatar.setColor(newColor)
++  };
++  this.getCursor = function() {
++    return cursor
++  };
++  this.getFocusElement = function() {
++    return span
++  };
++  this.toggleHandleVisibility = function() {
++    if(avatar.isVisible()) {
++      avatar.hide()
++    }else {
++      avatar.show()
 +    }
-     odtDocument.getOdfCanvas().rerenderAnnotations();
-     return true
 +  };
-   this.spec = function() {
-     return{optype:"RemoveText", memberid:memberid, timestamp:timestamp, position:position, length:length}
-   }
- };
- ops.OpRemoveText.Spec;
- /*
- 
-  Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
- 
-  @licstart
-  The JavaScript code in this page is free software: you can redistribute it
-  and/or modify it under the terms of the GNU Affero General Public License
-  (GNU AGPL) as published by the Free Software Foundation, either version 3 of
-  the License, or (at your option) any later version.  The code is distributed
-  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
- 
-  You should have received a copy of the GNU Affero General Public License
-  along with this code.  If not, see <http://www.gnu.org/licenses/>.
- 
-  As additional permission under GNU AGPL version 3 section 7, you
-  may distribute non-source (e.g., minimized or compacted) forms of
-  that code without the copy of the GNU GPL normally required by
-  section 4, provided you include this license notice and a URL
-  through which recipients can access the Corresponding Source.
- 
-  As a special exception to the AGPL, any HTML file which merely makes function
-  calls to this code, and for that purpose includes it by reference shall be
-  deemed a separate work for copyright law purposes. In addition, the copyright
-  holders of this code give you permission to combine this code with free
-  software libraries that are released under the GNU LGPL. You may copy and
-  distribute such a system following the terms of the GNU AGPL for this code
-  and the LGPL for the libraries. If you modify this code, you may extend this
-  exception to your version of the code, but you are not obligated to do so.
-  If you do not wish to do so, delete this exception statement from your
-  version.
- 
-  This license applies to this entire compilation.
-  @licend
-  @source: http://www.webodf.org/
-  @source: https://github.com/kogmbh/WebODF/
- */
- ops.OpSetBlob = function OpSetBlob() {
-   var memberid, timestamp, filename, mimetype, content;
-   this.init = function(data) {
-     memberid = data.memberid;
-     timestamp = data.timestamp;
-     filename = data.filename;
-     mimetype = data.mimetype;
-     content = data.content
++  this.showHandle = function() {
++    avatar.show()
 +  };
-   this.isEdit = true;
-   this.execute = function(odtDocument) {
-     odtDocument.getOdfCanvas().odfContainer().setBlob(filename, mimetype, content);
-     return true
++  this.hideHandle = function() {
++    avatar.hide()
 +  };
-   this.spec = function() {
-     return{optype:"SetBlob", memberid:memberid, timestamp:timestamp, filename:filename, mimetype:mimetype, content:content}
-   }
- };
- /*
- 
-  Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
- 
-  @licstart
-  The JavaScript code in this page is free software: you can redistribute it
-  and/or modify it under the terms of the GNU Affero General Public License
-  (GNU AGPL) as published by the Free Software Foundation, either version 3 of
-  the License, or (at your option) any later version.  The code is distributed
-  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
- 
-  You should have received a copy of the GNU Affero General Public License
-  along with this code.  If not, see <http://www.gnu.org/licenses/>.
- 
-  As additional permission under GNU AGPL version 3 section 7, you
-  may distribute non-source (e.g., minimized or compacted) forms of
-  that code without the copy of the GNU GPL normally required by
-  section 4, provided you include this license notice and a URL
-  through which recipients can access the Corresponding Source.
- 
-  As a special exception to the AGPL, any HTML file which merely makes function
-  calls to this code, and for that purpose includes it by reference shall be
-  deemed a separate work for copyright law purposes. In addition, the copyright
-  holders of this code give you permission to combine this code with free
-  software libraries that are released under the GNU LGPL. You may copy and
-  distribute such a system following the terms of the GNU AGPL for this code
-  and the LGPL for the libraries. If you modify this code, you may extend this
-  exception to your version of the code, but you are not obligated to do so.
-  If you do not wish to do so, delete this exception statement from your
-  version.
- 
-  This license applies to this entire compilation.
-  @licend
-  @source: http://www.webodf.org/
-  @source: https://github.com/kogmbh/WebODF/
- */
- ops.OpSetParagraphStyle = function OpSetParagraphStyle() {
-   var memberid, timestamp, position, styleName, textns = "urn:oasis:names:tc:opendocument:xmlns:text:1.0";
-   this.init = function(data) {
-     memberid = data.memberid;
-     timestamp = data.timestamp;
-     position = data.position;
-     styleName = data.styleName
++  this.setOverlayElement = function(element) {
++    overlayElement = element;
++    shouldUpdateCaretSize = true;
++    redrawTask.trigger()
 +  };
-   this.isEdit = true;
-   this.execute = function(odtDocument) {
-     var iterator, paragraphNode;
-     iterator = odtDocument.getIteratorAtPosition(position);
-     paragraphNode = odtDocument.getParagraphElement(iterator.container());
-     if(paragraphNode) {
-       if(styleName !== "") {
-         paragraphNode.setAttributeNS(textns, "text:style-name", styleName)
-       }else {
-         paragraphNode.removeAttributeNS(textns, "style-name")
-       }
-       odtDocument.getOdfCanvas().refreshSize();
-       odtDocument.emit(ops.OdtDocument.signalParagraphChanged, {paragraphElement:paragraphNode, timeStamp:timestamp, memberId:memberid});
-       odtDocument.getOdfCanvas().rerenderAnnotations();
-       return true
-     }
-     return false
++  this.ensureVisible = function() {
++    shouldCheckCaretVisibility = true;
++    redrawTask.trigger()
 +  };
-   this.spec = function() {
-     return{optype:"SetParagraphStyle", memberid:memberid, timestamp:timestamp, position:position, styleName:styleName}
++  function destroy(callback) {
++    cursorNode.removeChild(span);
++    callback()
++  }
++  this.destroy = function(callback) {
++    var cleanup = [redrawTask.destroy, blinkTask.destroy, avatar.destroy, destroy];
++    async.destroyAll(cleanup, callback)
++  };
++  function init() {
++    var dom = cursor.getDocument().getDOMDocument(), htmlns = dom.documentElement.namespaceURI;
++    span = (dom.createElementNS(htmlns, "span"));
++    span.className = "caret";
++    span.style.top = DEFAULT_CARET_TOP;
++    cursorNode = cursor.getNode();
++    cursorNode.appendChild(span);
++    avatar = new gui.Avatar(cursorNode, avatarInitiallyVisible);
++    redrawTask = new core.ScheduledTask(updateCaret, 0);
++    blinkTask = new core.ScheduledTask(blinkCaret, BLINK_PERIOD_MS);
++    redrawTask.triggerImmediate()
 +  }
++  init()
 +};
- ops.OpSetParagraphStyle.Spec;
 +/*
 +
-  Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
++ Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- ops.OpSplitParagraph = function OpSplitParagraph() {
-   var memberid, timestamp, position, moveCursor, odfUtils;
-   this.init = function(data) {
-     memberid = data.memberid;
-     timestamp = data.timestamp;
-     position = data.position;
-     moveCursor = data.moveCursor === "true" || data.moveCursor === true;
-     odfUtils = new odf.OdfUtils
-   };
-   this.isEdit = true;
-   this.execute = function(odtDocument) {
-     var domPosition, paragraphNode, targetNode, node, splitNode, splitChildNode, keptChildNode, cursor = odtDocument.getCursor(memberid);
-     odtDocument.upgradeWhitespacesAtPosition(position);
-     domPosition = odtDocument.getTextNodeAtStep(position);
-     if(!domPosition) {
-       return false
-     }
-     paragraphNode = odtDocument.getParagraphElement(domPosition.textNode);
-     if(!paragraphNode) {
-       return false
-     }
-     if(odfUtils.isListItem(paragraphNode.parentNode)) {
-       targetNode = paragraphNode.parentNode
-     }else {
-       targetNode = paragraphNode
-     }
-     if(domPosition.offset === 0) {
-       keptChildNode = domPosition.textNode.previousSibling;
-       splitChildNode = null
-     }else {
-       keptChildNode = domPosition.textNode;
-       if(domPosition.offset >= domPosition.textNode.length) {
-         splitChildNode = null
-       }else {
-         splitChildNode = (domPosition.textNode.splitText(domPosition.offset))
-       }
-     }
-     node = domPosition.textNode;
-     while(node !== targetNode) {
-       node = node.parentNode;
-       splitNode = node.cloneNode(false);
-       if(splitChildNode) {
-         splitNode.appendChild(splitChildNode)
-       }
-       if(keptChildNode) {
-         while(keptChildNode && keptChildNode.nextSibling) {
-           splitNode.appendChild(keptChildNode.nextSibling)
-         }
-       }else {
-         while(node.firstChild) {
-           splitNode.appendChild(node.firstChild)
-         }
-       }
-       node.parentNode.insertBefore(splitNode, node.nextSibling);
-       keptChildNode = node;
-       splitChildNode = splitNode
-     }
-     if(odfUtils.isListItem(splitChildNode)) {
-       splitChildNode = splitChildNode.childNodes[0]
-     }
-     if(domPosition.textNode.length === 0) {
-       domPosition.textNode.parentNode.removeChild(domPosition.textNode)
-     }
-     odtDocument.emit(ops.OdtDocument.signalStepsInserted, {position:position, length:1});
-     if(cursor && moveCursor) {
-       odtDocument.moveCursor(memberid, position + 1, 0);
-       odtDocument.emit(ops.OdtDocument.signalCursorMoved, cursor)
-     }
-     odtDocument.fixCursorPositions();
-     odtDocument.getOdfCanvas().refreshSize();
-     odtDocument.emit(ops.OdtDocument.signalParagraphChanged, {paragraphElement:paragraphNode, memberId:memberid, timeStamp:timestamp});
-     odtDocument.emit(ops.OdtDocument.signalParagraphChanged, {paragraphElement:splitChildNode, memberId:memberid, timeStamp:timestamp});
-     odtDocument.getOdfCanvas().rerenderAnnotations();
-     return true
-   };
-   this.spec = function() {
-     return{optype:"SplitParagraph", memberid:memberid, timestamp:timestamp, position:position, moveCursor:moveCursor}
-   }
- };
- ops.OpSplitParagraph.Spec;
- /*
- 
-  Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
- 
-  @licstart
-  This file is part of WebODF.
- 
-  WebODF is free software: you can redistribute it and/or modify it
-  under the terms of the GNU Affero General Public License (GNU AGPL)
-  as published by the Free Software Foundation, either version 3 of
-  the License, or (at your option) any later version.
- 
-  WebODF is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-  GNU Affero General Public License for more details.
- 
-  You should have received a copy of the GNU Affero General Public License
-  along with WebODF.  If not, see <http://www.gnu.org/licenses/>.
-  @licend
- 
-  @source: http://www.webodf.org/
-  @source: https://github.com/kogmbh/WebODF/
- */
- runtime.loadClass("ops.Member");
- runtime.loadClass("xmldom.XPath");
- ops.OpUpdateMember = function OpUpdateMember() {
-   var memberid, timestamp, setProperties, removedProperties, doc;
-   this.init = function(data) {
-     memberid = data.memberid;
-     timestamp = parseInt(data.timestamp, 10);
-     setProperties = data.setProperties;
-     removedProperties = data.removedProperties
-   };
-   this.isEdit = false;
-   function updateCreators() {
-     var xpath = xmldom.XPath, xp = "//dc:creator[@editinfo:memberid='" + memberid + "']", creators = xpath.getODFElementsWithXPath(doc.getRootNode(), xp, function(prefix) {
-       if(prefix === "editinfo") {
-         return"urn:webodf:names:editinfo"
++odf.TextSerializer = function TextSerializer() {
++  var self = this, odfUtils = new odf.OdfUtils;
++  function serializeNode(node) {
++    var s = "", accept = self.filter ? self.filter.acceptNode(node) : NodeFilter.FILTER_ACCEPT, nodeType = node.nodeType, child;
++    if((accept === NodeFilter.FILTER_ACCEPT || accept === NodeFilter.FILTER_SKIP) && odfUtils.isTextContentContainingNode(node)) {
++      child = node.firstChild;
++      while(child) {
++        s += serializeNode(child);
++        child = child.nextSibling
 +      }
-       return odf.Namespaces.lookupNamespaceURI(prefix)
-     }), i;
-     for(i = 0;i < creators.length;i += 1) {
-       creators[i].textContent = setProperties.fullName
 +    }
-   }
-   this.execute = function(odtDocument) {
-     doc = odtDocument;
-     var member = odtDocument.getMember(memberid);
-     if(!member) {
-       return false
++    if(accept === NodeFilter.FILTER_ACCEPT) {
++      if(nodeType === Node.ELEMENT_NODE && odfUtils.isParagraph(node)) {
++        s += "\n"
++      }else {
++        if(nodeType === Node.TEXT_NODE && node.textContent) {
++          s += node.textContent
++        }
++      }
 +    }
-     if(removedProperties) {
-       member.removeProperties(removedProperties)
++    return s
++  }
++  this.filter = null;
++  this.writeToString = function(node) {
++    var plainText;
++    if(!node) {
++      return""
 +    }
-     if(setProperties) {
-       member.setProperties(setProperties);
-       if(setProperties.fullName) {
-         updateCreators()
-       }
++    plainText = serializeNode(node);
++    if(plainText[plainText.length - 1] === "\n") {
++      plainText = plainText.substr(0, plainText.length - 1)
 +    }
-     odtDocument.emit(ops.OdtDocument.signalMemberUpdated, member);
-     return true
-   };
-   this.spec = function() {
-     return{optype:"UpdateMember", memberid:memberid, timestamp:timestamp, setProperties:setProperties, removedProperties:removedProperties}
++    return plainText
 +  }
 +};
 +/*
 +
 + Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + This file is part of WebODF.
 +
 + WebODF is free software: you can redistribute it and/or modify it
 + under the terms of the GNU Affero General Public License (GNU AGPL)
 + as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.
 +
 + WebODF is distributed in the hope that it will be useful, but
 + WITHOUT ANY WARRANTY; without even the implied warranty of
 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + GNU Affero General Public License for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with WebODF.  If not, see <http://www.gnu.org/licenses/>.
 + @licend
 +
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- ops.OpUpdateMetadata = function OpUpdateMetadata() {
-   var memberid, timestamp, setProperties, removedProperties;
-   this.init = function(data) {
-     memberid = data.memberid;
-     timestamp = parseInt(data.timestamp, 10);
-     setProperties = data.setProperties;
-     removedProperties = data.removedProperties
-   };
-   this.isEdit = true;
-   this.execute = function(odtDocument) {
-     var odfContainer = odtDocument.getOdfCanvas().odfContainer(), removedPropertiesArray = [], blockedProperties = ["dc:date", "dc:creator", "meta:editing-cycles"];
-     if(setProperties) {
-       blockedProperties.forEach(function(el) {
-         if(setProperties[el]) {
-           return false
-         }
-       })
-     }
-     if(removedProperties) {
-       blockedProperties.forEach(function(el) {
-         if(removedPropertiesArray.indexOf(el) !== -1) {
-           return false
-         }
-       });
-       removedPropertiesArray = removedProperties.attributes.split(",")
++gui.MimeDataExporter = function MimeDataExporter() {
++  var textSerializer, filter;
++  this.exportRangeToDataTransfer = function(dataTransfer, range) {
++    var document = range.startContainer.ownerDocument, serializedFragment, fragmentContainer;
++    fragmentContainer = document.createElement("span");
++    fragmentContainer.appendChild(range.cloneContents());
++    serializedFragment = textSerializer.writeToString(fragmentContainer);
++    try {
++      dataTransfer.setData("text/plain", serializedFragment)
++    }catch(e) {
++      dataTransfer.setData("Text", serializedFragment)
 +    }
-     odfContainer.setMetadata(setProperties, removedPropertiesArray);
-     return true
 +  };
-   this.spec = function() {
-     return{optype:"UpdateMetadata", memberid:memberid, timestamp:timestamp, setProperties:setProperties, removedProperties:removedProperties}
++  function init() {
++    textSerializer = new odf.TextSerializer;
++    filter = new odf.OdfNodeFilter;
++    textSerializer.filter = filter
 +  }
++  init()
 +};
 +/*
 +
-  Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
++ Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("odf.Namespaces");
- ops.OpUpdateParagraphStyle = function OpUpdateParagraphStyle() {
-   var memberid, timestamp, styleName, setProperties, removedProperties, paragraphPropertiesName = "style:paragraph-properties", textPropertiesName = "style:text-properties", stylens = odf.Namespaces.stylens;
-   function removedAttributesFromStyleNode(node, removedAttributeNames) {
-     var i, attributeNameParts, attributeNameList = removedAttributeNames ? removedAttributeNames.split(",") : [];
-     for(i = 0;i < attributeNameList.length;i += 1) {
-       attributeNameParts = attributeNameList[i].split(":");
-       node.removeAttributeNS(odf.Namespaces.lookupNamespaceURI(attributeNameParts[0]), attributeNameParts[1])
++gui.Clipboard = function Clipboard(mimeDataExporter) {
++  this.setDataFromRange = function(e, range) {
++    var result, clipboard = e.clipboardData, window = runtime.getWindow();
++    if(!clipboard && window) {
++      clipboard = window.clipboardData
 +    }
-   }
-   this.init = function(data) {
-     memberid = data.memberid;
-     timestamp = data.timestamp;
-     styleName = data.styleName;
-     setProperties = data.setProperties;
-     removedProperties = data.removedProperties
-   };
-   this.isEdit = true;
-   this.execute = function(odtDocument) {
-     var formatting = odtDocument.getFormatting(), styleNode, paragraphPropertiesNode, textPropertiesNode;
-     if(styleName !== "") {
-       styleNode = odtDocument.getParagraphStyleElement(styleName)
++    if(clipboard) {
++      result = true;
++      mimeDataExporter.exportRangeToDataTransfer((clipboard), range);
++      e.preventDefault()
 +    }else {
-       styleNode = formatting.getDefaultStyleElement("paragraph")
-     }
-     if(styleNode) {
-       paragraphPropertiesNode = styleNode.getElementsByTagNameNS(stylens, "paragraph-properties")[0];
-       textPropertiesNode = styleNode.getElementsByTagNameNS(stylens, "text-properties")[0];
-       if(setProperties) {
-         formatting.updateStyle(styleNode, setProperties)
-       }
-       if(removedProperties) {
-         if(removedProperties[paragraphPropertiesName]) {
-           removedAttributesFromStyleNode(paragraphPropertiesNode, removedProperties[paragraphPropertiesName].attributes);
-           if(paragraphPropertiesNode.attributes.length === 0) {
-             styleNode.removeChild(paragraphPropertiesNode)
-           }
-         }
-         if(removedProperties[textPropertiesName]) {
-           removedAttributesFromStyleNode(textPropertiesNode, removedProperties[textPropertiesName].attributes);
-           if(textPropertiesNode.attributes.length === 0) {
-             styleNode.removeChild(textPropertiesNode)
-           }
-         }
-         removedAttributesFromStyleNode(styleNode, removedProperties.attributes)
-       }
-       odtDocument.getOdfCanvas().refreshCSS();
-       odtDocument.emit(ops.OdtDocument.signalParagraphStyleModified, styleName);
-       odtDocument.getOdfCanvas().rerenderAnnotations();
-       return true
++      result = false
 +    }
-     return false
-   };
-   this.spec = function() {
-     return{optype:"UpdateParagraphStyle", memberid:memberid, timestamp:timestamp, styleName:styleName, setProperties:setProperties, removedProperties:removedProperties}
++    return result
 +  }
 +};
- ops.OpUpdateParagraphStyle.Spec;
 +/*
 +
-  Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
++ Copyright (C) 2012-2014 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("ops.OpAddMember");
- runtime.loadClass("ops.OpUpdateMember");
- runtime.loadClass("ops.OpRemoveMember");
- runtime.loadClass("ops.OpAddCursor");
- runtime.loadClass("ops.OpApplyDirectStyling");
- runtime.loadClass("ops.OpRemoveCursor");
- runtime.loadClass("ops.OpMoveCursor");
- runtime.loadClass("ops.OpSetBlob");
- runtime.loadClass("ops.OpRemoveBlob");
- runtime.loadClass("ops.OpInsertImage");
- runtime.loadClass("ops.OpInsertTable");
- runtime.loadClass("ops.OpInsertText");
- runtime.loadClass("ops.OpRemoveText");
- runtime.loadClass("ops.OpSplitParagraph");
- runtime.loadClass("ops.OpSetParagraphStyle");
- runtime.loadClass("ops.OpUpdateParagraphStyle");
- runtime.loadClass("ops.OpAddStyle");
- runtime.loadClass("ops.OpRemoveStyle");
- runtime.loadClass("ops.OpAddAnnotation");
- runtime.loadClass("ops.OpRemoveAnnotation");
- runtime.loadClass("ops.OpUpdateMetadata");
- ops.OperationFactory = function OperationFactory() {
-   var specs;
-   this.register = function(specName, specConstructor) {
-     specs[specName] = specConstructor
-   };
-   this.create = function(spec) {
-     var op = null, specConstructor = specs[spec.optype];
-     if(specConstructor) {
-       op = specConstructor(spec);
-       op.init(spec)
++gui.StyleSummary = function StyleSummary(styles) {
++  var propertyValues = {};
++  function getPropertyValues(section, propertyName) {
++    var cacheKey = section + "|" + propertyName, values;
++    if(!propertyValues.hasOwnProperty(cacheKey)) {
++      values = [];
++      styles.forEach(function(style) {
++        var styleSection = style[section], value = styleSection && styleSection[propertyName];
++        if(values.indexOf(value) === -1) {
++          values.push(value)
++        }
++      });
++      propertyValues[cacheKey] = values
 +    }
-     return op
-   };
-   function constructor(OperationType) {
++    return propertyValues[cacheKey]
++  }
++  this.getPropertyValues = getPropertyValues;
++  function lazilyLoaded(section, propertyName, acceptedPropertyValues) {
 +    return function() {
-       return new OperationType
++      var existingPropertyValues = getPropertyValues(section, propertyName);
++      return acceptedPropertyValues.length >= existingPropertyValues.length && existingPropertyValues.every(function(v) {
++        return acceptedPropertyValues.indexOf(v) !== -1
++      })
 +    }
 +  }
-   function init() {
-     specs = {AddMember:constructor(ops.OpAddMember), UpdateMember:constructor(ops.OpUpdateMember), RemoveMember:constructor(ops.OpRemoveMember), AddCursor:constructor(ops.OpAddCursor), ApplyDirectStyling:constructor(ops.OpApplyDirectStyling), SetBlob:constructor(ops.OpSetBlob), RemoveBlob:constructor(ops.OpRemoveBlob), InsertImage:constructor(ops.OpInsertImage), InsertTable:constructor(ops.OpInsertTable), InsertText:constructor(ops.OpInsertText), RemoveText:constructor(ops.OpRemoveText) [...]
-     SetParagraphStyle:constructor(ops.OpSetParagraphStyle), UpdateParagraphStyle:constructor(ops.OpUpdateParagraphStyle), AddStyle:constructor(ops.OpAddStyle), RemoveStyle:constructor(ops.OpRemoveStyle), MoveCursor:constructor(ops.OpMoveCursor), RemoveCursor:constructor(ops.OpRemoveCursor), AddAnnotation:constructor(ops.OpAddAnnotation), RemoveAnnotation:constructor(ops.OpRemoveAnnotation), UpdateMetadata:constructor(ops.OpUpdateMetadata)}
++  function getCommonValue(section, propertyName) {
++    var values = getPropertyValues(section, propertyName);
++    return values.length === 1 ? values[0] : undefined
 +  }
-   init()
++  this.getCommonValue = getCommonValue;
++  this.isBold = lazilyLoaded("style:text-properties", "fo:font-weight", ["bold"]);
++  this.isItalic = lazilyLoaded("style:text-properties", "fo:font-style", ["italic"]);
++  this.hasUnderline = lazilyLoaded("style:text-properties", "style:text-underline-style", ["solid"]);
++  this.hasStrikeThrough = lazilyLoaded("style:text-properties", "style:text-line-through-style", ["solid"]);
++  this.fontSize = function() {
++    var stringFontSize = getCommonValue("style:text-properties", "fo:font-size");
++    return(stringFontSize && parseFloat(stringFontSize))
++  };
++  this.fontName = function() {
++    return getCommonValue("style:text-properties", "style:font-name")
++  };
++  this.isAlignedLeft = lazilyLoaded("style:paragraph-properties", "fo:text-align", ["left", "start"]);
++  this.isAlignedCenter = lazilyLoaded("style:paragraph-properties", "fo:text-align", ["center"]);
++  this.isAlignedRight = lazilyLoaded("style:paragraph-properties", "fo:text-align", ["right", "end"]);
++  this.isAlignedJustified = lazilyLoaded("style:paragraph-properties", "fo:text-align", ["justify"]);
++  this.text = {isBold:this.isBold, isItalic:this.isItalic, hasUnderline:this.hasUnderline, hasStrikeThrough:this.hasStrikeThrough, fontSize:this.fontSize, fontName:this.fontName};
++  this.paragraph = {isAlignedLeft:this.isAlignedLeft, isAlignedCenter:this.isAlignedCenter, isAlignedRight:this.isAlignedRight, isAlignedJustified:this.isAlignedJustified}
 +};
 +/*
 +
 + Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- ops.OperationRouter = function OperationRouter() {
- };
- ops.OperationRouter.prototype.setOperationFactory = function(f) {
- };
- ops.OperationRouter.prototype.setPlaybackFunction = function(playback_func) {
- };
- ops.OperationRouter.prototype.push = function(operations) {
- };
- ops.OperationRouter.prototype.close = function(callback) {
- };
- ops.OperationRouter.prototype.subscribe = function(eventId, cb) {
- };
- ops.OperationRouter.prototype.unsubscribe = function(eventId, cb) {
- };
- ops.OperationRouter.prototype.hasLocalUnsyncedOps = function() {
- };
- ops.OperationRouter.prototype.hasSessionHostConnection = function() {
- };
- /*
- 
-  Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
- 
-  @licstart
-  This file is part of WebODF.
- 
-  WebODF is free software: you can redistribute it and/or modify it
-  under the terms of the GNU Affero General Public License (GNU AGPL)
-  as published by the Free Software Foundation, either version 3 of
-  the License, or (at your option) any later version.
- 
-  WebODF is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-  GNU Affero General Public License for more details.
- 
-  You should have received a copy of the GNU Affero General Public License
-  along with WebODF.  If not, see <http://www.gnu.org/licenses/>.
-  @licend
- 
-  @source: http://www.webodf.org/
-  @source: https://github.com/kogmbh/WebODF/
- */
- ops.OperationTransformMatrix = function OperationTransformMatrix() {
-   function invertMoveCursorSpecRange(moveCursorSpec) {
-     moveCursorSpec.position = moveCursorSpec.position + moveCursorSpec.length;
-     moveCursorSpec.length *= -1
-   }
-   function invertMoveCursorSpecRangeOnNegativeLength(moveCursorSpec) {
-     var isBackwards = moveCursorSpec.length < 0;
-     if(isBackwards) {
-       invertMoveCursorSpecRange(moveCursorSpec)
-     }
-     return isBackwards
-   }
-   function getStyleReferencingAttributes(setProperties, styleName) {
-     var attributes = [];
-     if(setProperties) {
-       ["style:parent-style-name", "style:next-style-name"].forEach(function(attributeName) {
-         if(setProperties[attributeName] === styleName) {
-           attributes.push(attributeName)
-         }
-       })
-     }
-     return attributes
-   }
-   function dropStyleReferencingAttributes(setProperties, deletedStyleName) {
-     if(setProperties) {
-       ["style:parent-style-name", "style:next-style-name"].forEach(function(attributeName) {
-         if(setProperties[attributeName] === deletedStyleName) {
-           delete setProperties[attributeName]
-         }
-       })
-     }
-   }
-   function cloneOpspec(opspec) {
-     var result = {};
-     Object.keys(opspec).forEach(function(key) {
-       if(typeof opspec[key] === "object") {
-         result[key] = cloneOpspec(opspec[key])
-       }else {
-         result[key] = opspec[key]
-       }
-     });
-     return result
-   }
-   function dropOverruledAndUnneededAttributes(minorSetProperties, minorRemovedProperties, majorSetProperties, majorRemovedProperties) {
-     var value, i, name, majorChanged = false, minorChanged = false, overrulingPropertyValue, removedPropertyNames, majorRemovedPropertyNames = majorRemovedProperties && majorRemovedProperties.attributes ? majorRemovedProperties.attributes.split(",") : [];
-     if(minorSetProperties && (majorSetProperties || majorRemovedPropertyNames.length > 0)) {
-       Object.keys(minorSetProperties).forEach(function(key) {
-         value = minorSetProperties[key];
-         if(typeof value !== "object") {
-           overrulingPropertyValue = majorSetProperties && majorSetProperties[key];
-           if(overrulingPropertyValue !== undefined) {
-             delete minorSetProperties[key];
-             minorChanged = true;
-             if(overrulingPropertyValue === value) {
-               delete majorSetProperties[key];
-               majorChanged = true
-             }
-           }else {
-             if(majorRemovedPropertyNames && majorRemovedPropertyNames.indexOf(key) !== -1) {
-               delete minorSetProperties[key];
-               minorChanged = true
-             }
-           }
-         }
-       })
-     }
-     if(minorRemovedProperties && (minorRemovedProperties.attributes && (majorSetProperties || majorRemovedPropertyNames.length > 0))) {
-       removedPropertyNames = minorRemovedProperties.attributes.split(",");
-       for(i = 0;i < removedPropertyNames.length;i += 1) {
-         name = removedPropertyNames[i];
-         if(majorSetProperties && majorSetProperties[name] !== undefined || majorRemovedPropertyNames && majorRemovedPropertyNames.indexOf(name) !== -1) {
-           removedPropertyNames.splice(i, 1);
-           i -= 1;
-           minorChanged = true
-         }
-       }
-       if(removedPropertyNames.length > 0) {
-         minorRemovedProperties.attributes = removedPropertyNames.join(",")
-       }else {
-         delete minorRemovedProperties.attributes
++gui.DirectFormattingController = function DirectFormattingController(session, inputMemberId, objectNameGenerator, directParagraphStylingEnabled) {
++  var self = this, odtDocument = session.getOdtDocument(), utils = new core.Utils, odfUtils = new odf.OdfUtils, eventNotifier = new core.EventNotifier([gui.DirectFormattingController.textStylingChanged, gui.DirectFormattingController.paragraphStylingChanged]), textns = odf.Namespaces.textns, FILTER_ACCEPT = core.PositionFilter.FilterResult.FILTER_ACCEPT, directCursorStyleProperties, selectionAppliedStyles = [], selectionStylesSummary = new gui.StyleSummary(selectionAppliedStyles);
++  function getNodes(range) {
++    var container, nodes;
++    if(range.collapsed) {
++      container = range.startContainer;
++      if(container.hasChildNodes() && range.startOffset < container.childNodes.length) {
++        container = container.childNodes.item(range.startOffset)
 +      }
++      nodes = [container]
++    }else {
++      nodes = odfUtils.getTextNodes(range, true)
 +    }
-     return{majorChanged:majorChanged, minorChanged:minorChanged}
++    return nodes
 +  }
-   function hasProperties(properties) {
-     var key;
-     for(key in properties) {
-       if(properties.hasOwnProperty(key)) {
-         return true
-       }
++  function getSelectionAppliedStyles() {
++    var cursor = odtDocument.getCursor(inputMemberId), range = cursor && cursor.getSelectedRange(), nodes = range ? getNodes(range) : [], selectionStyles = odtDocument.getFormatting().getAppliedStyles(nodes);
++    if(selectionStyles[0] && directCursorStyleProperties) {
++      selectionStyles[0] = utils.mergeObjects(selectionStyles[0], (directCursorStyleProperties))
 +    }
-     return false
++    return selectionStyles
 +  }
-   function hasRemovedProperties(properties) {
-     var key;
-     for(key in properties) {
-       if(properties.hasOwnProperty(key)) {
-         if(key !== "attributes" || properties.attributes.length > 0) {
-           return true
-         }
++  function createDiff(oldSummary, newSummary) {
++    var diffMap = {};
++    Object.keys(oldSummary).forEach(function(funcName) {
++      var oldValue = oldSummary[funcName](), newValue = newSummary[funcName]();
++      if(oldValue !== newValue) {
++        diffMap[funcName] = newValue
 +      }
-     }
-     return false
++    });
++    return diffMap
 +  }
-   function dropOverruledAndUnneededProperties(minorOpspec, majorOpspec, propertiesName) {
-     var minorSP = minorOpspec.setProperties ? minorOpspec.setProperties[propertiesName] : null, minorRP = minorOpspec.removedProperties ? minorOpspec.removedProperties[propertiesName] : null, majorSP = majorOpspec.setProperties ? majorOpspec.setProperties[propertiesName] : null, majorRP = majorOpspec.removedProperties ? majorOpspec.removedProperties[propertiesName] : null, result;
-     result = dropOverruledAndUnneededAttributes(minorSP, minorRP, majorSP, majorRP);
-     if(minorSP && !hasProperties(minorSP)) {
-       delete minorOpspec.setProperties[propertiesName]
++  function updateSelectionStylesInfo() {
++    var textStyleDiff, paragraphStyleDiff, newSelectionStylesSummary;
++    selectionAppliedStyles = getSelectionAppliedStyles();
++    newSelectionStylesSummary = new gui.StyleSummary(selectionAppliedStyles);
++    textStyleDiff = createDiff(selectionStylesSummary.text, newSelectionStylesSummary.text);
++    paragraphStyleDiff = createDiff(selectionStylesSummary.paragraph, newSelectionStylesSummary.paragraph);
++    selectionStylesSummary = newSelectionStylesSummary;
++    if(Object.keys(textStyleDiff).length > 0) {
++      eventNotifier.emit(gui.DirectFormattingController.textStylingChanged, textStyleDiff)
 +    }
-     if(minorRP && !hasRemovedProperties(minorRP)) {
-       delete minorOpspec.removedProperties[propertiesName]
++    if(Object.keys(paragraphStyleDiff).length > 0) {
++      eventNotifier.emit(gui.DirectFormattingController.paragraphStylingChanged, paragraphStyleDiff)
 +    }
-     if(majorSP && !hasProperties(majorSP)) {
-       delete majorOpspec.setProperties[propertiesName]
++  }
++  function onCursorEvent(cursorOrId) {
++    var cursorMemberId = typeof cursorOrId === "string" ? cursorOrId : cursorOrId.getMemberId();
++    if(cursorMemberId === inputMemberId) {
++      updateSelectionStylesInfo()
 +    }
-     if(majorRP && !hasRemovedProperties(majorRP)) {
-       delete majorOpspec.removedProperties[propertiesName]
++  }
++  function onParagraphStyleModified() {
++    updateSelectionStylesInfo()
++  }
++  function onParagraphChanged(args) {
++    var cursor = odtDocument.getCursor(inputMemberId), p = args.paragraphElement;
++    if(cursor && odtDocument.getParagraphElement(cursor.getNode()) === p) {
++      updateSelectionStylesInfo()
 +    }
-     return result
 +  }
-   function transformAddStyleRemoveStyle(addStyleSpec, removeStyleSpec) {
-     var setAttributes, helperOpspec, addStyleSpecResult = [addStyleSpec], removeStyleSpecResult = [removeStyleSpec];
-     if(addStyleSpec.styleFamily === removeStyleSpec.styleFamily) {
-       setAttributes = getStyleReferencingAttributes(addStyleSpec.setProperties, removeStyleSpec.styleName);
-       if(setAttributes.length > 0) {
-         helperOpspec = {optype:"UpdateParagraphStyle", memberid:removeStyleSpec.memberid, timestamp:removeStyleSpec.timestamp, styleName:addStyleSpec.styleName, removedProperties:{attributes:setAttributes.join(",")}};
-         removeStyleSpecResult.unshift(helperOpspec)
++  function toggle(predicate, toggleMethod) {
++    toggleMethod(!predicate());
++    return true
++  }
++  function formatTextSelection(textProperties) {
++    var selection = odtDocument.getCursorSelection(inputMemberId), op, properties = {"style:text-properties":textProperties};
++    if(selection.length !== 0) {
++      op = new ops.OpApplyDirectStyling;
++      op.init({memberid:inputMemberId, position:selection.position, length:selection.length, setProperties:properties});
++      session.enqueue([op])
++    }else {
++      directCursorStyleProperties = utils.mergeObjects(directCursorStyleProperties || {}, properties);
++      updateSelectionStylesInfo()
++    }
++  }
++  this.formatTextSelection = formatTextSelection;
++  function applyTextPropertyToSelection(propertyName, propertyValue) {
++    var textProperties = {};
++    textProperties[propertyName] = propertyValue;
++    formatTextSelection(textProperties)
++  }
++  this.createCursorStyleOp = function(position, length, useCachedStyle) {
++    var styleOp = null, properties = useCachedStyle ? selectionAppliedStyles[0] : directCursorStyleProperties;
++    if(properties && properties["style:text-properties"]) {
++      styleOp = new ops.OpApplyDirectStyling;
++      styleOp.init({memberid:inputMemberId, position:position, length:length, setProperties:{"style:text-properties":properties["style:text-properties"]}});
++      directCursorStyleProperties = null;
++      updateSelectionStylesInfo()
++    }
++    return styleOp
++  };
++  function clearCursorStyle(op) {
++    var spec = op.spec();
++    if(directCursorStyleProperties && spec.memberid === inputMemberId) {
++      if(spec.optype !== "SplitParagraph") {
++        directCursorStyleProperties = null;
++        updateSelectionStylesInfo()
 +      }
-       dropStyleReferencingAttributes(addStyleSpec.setProperties, removeStyleSpec.styleName)
 +    }
-     return{opSpecsA:addStyleSpecResult, opSpecsB:removeStyleSpecResult}
 +  }
-   function transformApplyDirectStylingApplyDirectStyling(applyDirectStylingSpecA, applyDirectStylingSpecB, hasAPriority) {
-     var majorSpec, minorSpec, majorSpecResult, minorSpecResult, majorSpecEnd, minorSpecEnd, dropResult, originalMajorSpec, originalMinorSpec, helperOpspecBefore, helperOpspecAfter, applyDirectStylingSpecAResult = [applyDirectStylingSpecA], applyDirectStylingSpecBResult = [applyDirectStylingSpecB];
-     if(!(applyDirectStylingSpecA.position + applyDirectStylingSpecA.length <= applyDirectStylingSpecB.position || applyDirectStylingSpecA.position >= applyDirectStylingSpecB.position + applyDirectStylingSpecB.length)) {
-       majorSpec = hasAPriority ? applyDirectStylingSpecA : applyDirectStylingSpecB;
-       minorSpec = hasAPriority ? applyDirectStylingSpecB : applyDirectStylingSpecA;
-       if(applyDirectStylingSpecA.position !== applyDirectStylingSpecB.position || applyDirectStylingSpecA.length !== applyDirectStylingSpecB.length) {
-         originalMajorSpec = cloneOpspec(majorSpec);
-         originalMinorSpec = cloneOpspec(minorSpec)
++  function setBold(checked) {
++    var value = checked ? "bold" : "normal";
++    applyTextPropertyToSelection("fo:font-weight", value)
++  }
++  this.setBold = setBold;
++  function setItalic(checked) {
++    var value = checked ? "italic" : "normal";
++    applyTextPropertyToSelection("fo:font-style", value)
++  }
++  this.setItalic = setItalic;
++  function setHasUnderline(checked) {
++    var value = checked ? "solid" : "none";
++    applyTextPropertyToSelection("style:text-underline-style", value)
++  }
++  this.setHasUnderline = setHasUnderline;
++  function setHasStrikethrough(checked) {
++    var value = checked ? "solid" : "none";
++    applyTextPropertyToSelection("style:text-line-through-style", value)
++  }
++  this.setHasStrikethrough = setHasStrikethrough;
++  function setFontSize(value) {
++    applyTextPropertyToSelection("fo:font-size", value + "pt")
++  }
++  this.setFontSize = setFontSize;
++  function setFontName(value) {
++    applyTextPropertyToSelection("style:font-name", value)
++  }
++  this.setFontName = setFontName;
++  this.getAppliedStyles = function() {
++    return selectionAppliedStyles
++  };
++  this.toggleBold = toggle.bind(self, function() {
++    return selectionStylesSummary.isBold()
++  }, setBold);
++  this.toggleItalic = toggle.bind(self, function() {
++    return selectionStylesSummary.isItalic()
++  }, setItalic);
++  this.toggleUnderline = toggle.bind(self, function() {
++    return selectionStylesSummary.hasUnderline()
++  }, setHasUnderline);
++  this.toggleStrikethrough = toggle.bind(self, function() {
++    return selectionStylesSummary.hasStrikeThrough()
++  }, setHasStrikethrough);
++  this.isBold = function() {
++    return selectionStylesSummary.isBold()
++  };
++  this.isItalic = function() {
++    return selectionStylesSummary.isItalic()
++  };
++  this.hasUnderline = function() {
++    return selectionStylesSummary.hasUnderline()
++  };
++  this.hasStrikeThrough = function() {
++    return selectionStylesSummary.hasStrikeThrough()
++  };
++  this.fontSize = function() {
++    return selectionStylesSummary.fontSize()
++  };
++  this.fontName = function() {
++    return selectionStylesSummary.fontName()
++  };
++  this.isAlignedLeft = function() {
++    return selectionStylesSummary.isAlignedLeft()
++  };
++  this.isAlignedCenter = function() {
++    return selectionStylesSummary.isAlignedCenter()
++  };
++  this.isAlignedRight = function() {
++    return selectionStylesSummary.isAlignedRight()
++  };
++  this.isAlignedJustified = function() {
++    return selectionStylesSummary.isAlignedJustified()
++  };
++  function roundUp(step) {
++    return step === ops.StepsTranslator.NEXT_STEP
++  }
++  function getOwnProperty(obj, key) {
++    return obj.hasOwnProperty(key) ? obj[key] : undefined
++  }
++  function applyParagraphDirectStyling(applyDirectStyling) {
++    var range = odtDocument.getCursor(inputMemberId).getSelectedRange(), paragraphs = odfUtils.getParagraphElements(range), formatting = odtDocument.getFormatting(), operations = [], derivedStyleNames = {}, defaultStyleName;
++    paragraphs.forEach(function(paragraph) {
++      var paragraphStartPoint = odtDocument.convertDomPointToCursorStep(paragraph, 0, roundUp), paragraphStyleName = paragraph.getAttributeNS(odf.Namespaces.textns, "style-name"), newParagraphStyleName, opAddStyle, opSetParagraphStyle, paragraphProperties;
++      if(paragraphStyleName) {
++        newParagraphStyleName = getOwnProperty(derivedStyleNames, paragraphStyleName)
++      }else {
++        newParagraphStyleName = defaultStyleName
 +      }
-       dropResult = dropOverruledAndUnneededProperties(minorSpec, majorSpec, "style:text-properties");
-       if(dropResult.majorChanged || dropResult.minorChanged) {
-         majorSpecResult = [];
-         minorSpecResult = [];
-         majorSpecEnd = majorSpec.position + majorSpec.length;
-         minorSpecEnd = minorSpec.position + minorSpec.length;
-         if(minorSpec.position < majorSpec.position) {
-           if(dropResult.minorChanged) {
-             helperOpspecBefore = cloneOpspec((originalMinorSpec));
-             helperOpspecBefore.length = majorSpec.position - minorSpec.position;
-             minorSpecResult.push(helperOpspecBefore);
-             minorSpec.position = majorSpec.position;
-             minorSpec.length = minorSpecEnd - minorSpec.position
-           }
-         }else {
-           if(majorSpec.position < minorSpec.position) {
-             if(dropResult.majorChanged) {
-               helperOpspecBefore = cloneOpspec((originalMajorSpec));
-               helperOpspecBefore.length = minorSpec.position - majorSpec.position;
-               majorSpecResult.push(helperOpspecBefore);
-               majorSpec.position = minorSpec.position;
-               majorSpec.length = majorSpecEnd - majorSpec.position
-             }
-           }
-         }
-         if(minorSpecEnd > majorSpecEnd) {
-           if(dropResult.minorChanged) {
-             helperOpspecAfter = originalMinorSpec;
-             helperOpspecAfter.position = majorSpecEnd;
-             helperOpspecAfter.length = minorSpecEnd - majorSpecEnd;
-             minorSpecResult.push(helperOpspecAfter);
-             minorSpec.length = majorSpecEnd - minorSpec.position
-           }
-         }else {
-           if(majorSpecEnd > minorSpecEnd) {
-             if(dropResult.majorChanged) {
-               helperOpspecAfter = originalMajorSpec;
-               helperOpspecAfter.position = minorSpecEnd;
-               helperOpspecAfter.length = majorSpecEnd - minorSpecEnd;
-               majorSpecResult.push(helperOpspecAfter);
-               majorSpec.length = minorSpecEnd - majorSpec.position
-             }
-           }
-         }
-         if(majorSpec.setProperties && hasProperties(majorSpec.setProperties)) {
-           majorSpecResult.push(majorSpec)
-         }
-         if(minorSpec.setProperties && hasProperties(minorSpec.setProperties)) {
-           minorSpecResult.push(minorSpec)
-         }
-         if(hasAPriority) {
-           applyDirectStylingSpecAResult = majorSpecResult;
-           applyDirectStylingSpecBResult = minorSpecResult
++      if(!newParagraphStyleName) {
++        newParagraphStyleName = objectNameGenerator.generateStyleName();
++        if(paragraphStyleName) {
++          derivedStyleNames[paragraphStyleName] = newParagraphStyleName;
++          paragraphProperties = formatting.createDerivedStyleObject(paragraphStyleName, "paragraph", {})
 +        }else {
-           applyDirectStylingSpecAResult = minorSpecResult;
-           applyDirectStylingSpecBResult = majorSpecResult
++          defaultStyleName = newParagraphStyleName;
++          paragraphProperties = {}
 +        }
++        paragraphProperties = applyDirectStyling(paragraphProperties);
++        opAddStyle = new ops.OpAddStyle;
++        opAddStyle.init({memberid:inputMemberId, styleName:newParagraphStyleName.toString(), styleFamily:"paragraph", isAutomaticStyle:true, setProperties:paragraphProperties});
++        operations.push(opAddStyle)
++      }
++      opSetParagraphStyle = new ops.OpSetParagraphStyle;
++      opSetParagraphStyle.init({memberid:inputMemberId, styleName:newParagraphStyleName.toString(), position:paragraphStartPoint});
++      operations.push(opSetParagraphStyle)
++    });
++    session.enqueue(operations)
++  }
++  function applySimpleParagraphDirectStyling(styleOverrides) {
++    applyParagraphDirectStyling(function(paragraphStyle) {
++      return utils.mergeObjects(paragraphStyle, styleOverrides)
++    })
++  }
++  function alignParagraph(alignment) {
++    applySimpleParagraphDirectStyling({"style:paragraph-properties":{"fo:text-align":alignment}})
++  }
++  this.alignParagraphLeft = function() {
++    alignParagraph("left");
++    return true
++  };
++  this.alignParagraphCenter = function() {
++    alignParagraph("center");
++    return true
++  };
++  this.alignParagraphRight = function() {
++    alignParagraph("right");
++    return true
++  };
++  this.alignParagraphJustified = function() {
++    alignParagraph("justify");
++    return true
++  };
++  function modifyParagraphIndent(direction, paragraphStyle) {
++    var tabStopDistance = odtDocument.getFormatting().getDefaultTabStopDistance(), paragraphProperties = paragraphStyle["style:paragraph-properties"], indentValue, indent, newIndent;
++    if(paragraphProperties) {
++      indentValue = paragraphProperties["fo:margin-left"];
++      if(indentValue) {
++        indent = odfUtils.parseLength(indentValue)
++      }
++    }
++    if(indent && indent.unit === tabStopDistance.unit) {
++      newIndent = indent.value + direction * tabStopDistance.value + indent.unit
++    }else {
++      newIndent = direction * tabStopDistance.value + tabStopDistance.unit
++    }
++    return utils.mergeObjects(paragraphStyle, {"style:paragraph-properties":{"fo:margin-left":newIndent}})
++  }
++  this.indent = function() {
++    applyParagraphDirectStyling(modifyParagraphIndent.bind(null, 1));
++    return true
++  };
++  this.outdent = function() {
++    applyParagraphDirectStyling(modifyParagraphIndent.bind(null, -1));
++    return true
++  };
++  function isSelectionAtTheEndOfLastParagraph(range, paragraphNode) {
++    var iterator = gui.SelectionMover.createPositionIterator(paragraphNode), rootConstrainedFilter = new core.PositionFilterChain;
++    rootConstrainedFilter.addFilter(odtDocument.getPositionFilter());
++    rootConstrainedFilter.addFilter(odtDocument.createRootFilter(inputMemberId));
++    iterator.setUnfilteredPosition((range.endContainer), range.endOffset);
++    while(iterator.nextPosition()) {
++      if(rootConstrainedFilter.acceptPosition(iterator) === FILTER_ACCEPT) {
++        return odtDocument.getParagraphElement(iterator.getCurrentNode()) !== paragraphNode
 +      }
 +    }
-     return{opSpecsA:applyDirectStylingSpecAResult, opSpecsB:applyDirectStylingSpecBResult}
++    return true
++  }
++  function isTextStyleDifferentFromFirstParagraph(range, paragraphNode) {
++    var textNodes = getNodes(range), textStyle = odtDocument.getFormatting().getAppliedStyles(textNodes)[0], paragraphStyle = odtDocument.getFormatting().getAppliedStylesForElement(paragraphNode);
++    if(!textStyle || (textStyle["style:family"] !== "text" || !textStyle["style:text-properties"])) {
++      return false
++    }
++    if(!paragraphStyle || !paragraphStyle["style:text-properties"]) {
++      return true
++    }
++    textStyle = (textStyle["style:text-properties"]);
++    paragraphStyle = (paragraphStyle["style:text-properties"]);
++    return!Object.keys(textStyle).every(function(key) {
++      return textStyle[key] === paragraphStyle[key]
++    })
++  }
++  this.createParagraphStyleOps = function(position) {
++    var cursor = odtDocument.getCursor(inputMemberId), range = cursor.getSelectedRange(), operations = [], op, startNode, endNode, paragraphNode, properties, parentStyleName, styleName;
++    if(cursor.hasForwardSelection()) {
++      startNode = cursor.getAnchorNode();
++      endNode = cursor.getNode()
++    }else {
++      startNode = cursor.getNode();
++      endNode = cursor.getAnchorNode()
++    }
++    paragraphNode = (odtDocument.getParagraphElement(endNode));
++    runtime.assert(Boolean(paragraphNode), "DirectFormattingController: Cursor outside paragraph");
++    if(!isSelectionAtTheEndOfLastParagraph(range, paragraphNode)) {
++      return operations
++    }
++    if(endNode !== startNode) {
++      paragraphNode = (odtDocument.getParagraphElement(startNode))
++    }
++    if(!directCursorStyleProperties && !isTextStyleDifferentFromFirstParagraph(range, paragraphNode)) {
++      return operations
++    }
++    properties = selectionAppliedStyles[0];
++    if(!properties) {
++      return operations
++    }
++    parentStyleName = paragraphNode.getAttributeNS(textns, "style-name");
++    if(parentStyleName) {
++      properties = {"style:text-properties":properties["style:text-properties"]};
++      properties = odtDocument.getFormatting().createDerivedStyleObject(parentStyleName, "paragraph", properties)
++    }
++    styleName = objectNameGenerator.generateStyleName();
++    op = new ops.OpAddStyle;
++    op.init({memberid:inputMemberId, styleName:styleName, styleFamily:"paragraph", isAutomaticStyle:true, setProperties:properties});
++    operations.push(op);
++    op = new ops.OpSetParagraphStyle;
++    op.init({memberid:inputMemberId, styleName:styleName, position:position});
++    operations.push(op);
++    return operations
++  };
++  this.subscribe = function(eventid, cb) {
++    eventNotifier.subscribe(eventid, cb)
++  };
++  this.unsubscribe = function(eventid, cb) {
++    eventNotifier.unsubscribe(eventid, cb)
++  };
++  this.destroy = function(callback) {
++    odtDocument.unsubscribe(ops.Document.signalCursorAdded, onCursorEvent);
++    odtDocument.unsubscribe(ops.Document.signalCursorRemoved, onCursorEvent);
++    odtDocument.unsubscribe(ops.Document.signalCursorMoved, onCursorEvent);
++    odtDocument.unsubscribe(ops.OdtDocument.signalParagraphStyleModified, onParagraphStyleModified);
++    odtDocument.unsubscribe(ops.OdtDocument.signalParagraphChanged, onParagraphChanged);
++    odtDocument.unsubscribe(ops.OdtDocument.signalOperationEnd, clearCursorStyle);
++    callback()
++  };
++  function emptyFunction() {
 +  }
-   function transformApplyDirectStylingInsertText(applyDirectStylingSpec, insertTextSpec) {
-     if(insertTextSpec.position <= applyDirectStylingSpec.position) {
-       applyDirectStylingSpec.position += insertTextSpec.text.length
-     }else {
-       if(insertTextSpec.position <= applyDirectStylingSpec.position + applyDirectStylingSpec.length) {
-         applyDirectStylingSpec.length += insertTextSpec.text.length
-       }
++  function init() {
++    odtDocument.subscribe(ops.Document.signalCursorAdded, onCursorEvent);
++    odtDocument.subscribe(ops.Document.signalCursorRemoved, onCursorEvent);
++    odtDocument.subscribe(ops.Document.signalCursorMoved, onCursorEvent);
++    odtDocument.subscribe(ops.OdtDocument.signalParagraphStyleModified, onParagraphStyleModified);
++    odtDocument.subscribe(ops.OdtDocument.signalParagraphChanged, onParagraphChanged);
++    odtDocument.subscribe(ops.OdtDocument.signalOperationEnd, clearCursorStyle);
++    updateSelectionStylesInfo();
++    if(!directParagraphStylingEnabled) {
++      self.alignParagraphCenter = emptyFunction;
++      self.alignParagraphJustified = emptyFunction;
++      self.alignParagraphLeft = emptyFunction;
++      self.alignParagraphRight = emptyFunction;
++      self.createParagraphStyleOps = function() {
++        return[]
++      };
++      self.indent = emptyFunction;
++      self.outdent = emptyFunction
 +    }
-     return{opSpecsA:[applyDirectStylingSpec], opSpecsB:[insertTextSpec]}
 +  }
-   function transformApplyDirectStylingRemoveText(applyDirectStylingSpec, removeTextSpec) {
-     var applyDirectStylingSpecEnd = applyDirectStylingSpec.position + applyDirectStylingSpec.length, removeTextSpecEnd = removeTextSpec.position + removeTextSpec.length, applyDirectStylingSpecResult = [applyDirectStylingSpec], removeTextSpecResult = [removeTextSpec];
-     if(removeTextSpecEnd <= applyDirectStylingSpec.position) {
-       applyDirectStylingSpec.position -= removeTextSpec.length
-     }else {
-       if(removeTextSpec.position < applyDirectStylingSpecEnd) {
-         if(applyDirectStylingSpec.position < removeTextSpec.position) {
-           if(removeTextSpecEnd < applyDirectStylingSpecEnd) {
-             applyDirectStylingSpec.length -= removeTextSpec.length
-           }else {
-             applyDirectStylingSpec.length = removeTextSpec.position - applyDirectStylingSpec.position
-           }
-         }else {
-           applyDirectStylingSpec.position = removeTextSpec.position;
-           if(removeTextSpecEnd < applyDirectStylingSpecEnd) {
-             applyDirectStylingSpec.length = applyDirectStylingSpecEnd - removeTextSpecEnd
-           }else {
-             applyDirectStylingSpecResult = []
-           }
-         }
++  init()
++};
++gui.DirectFormattingController.textStylingChanged = "textStyling/changed";
++gui.DirectFormattingController.paragraphStylingChanged = "paragraphStyling/changed";
++(function() {
++  return gui.DirectFormattingController
++})();
++gui.HyperlinkClickHandler = function HyperlinkClickHandler(getRootNode) {
++  var webodfns = "urn:webodf:names:helper", links = "links", inactive = "inactive", None = gui.HyperlinkClickHandler.Modifier.None, Ctrl = gui.HyperlinkClickHandler.Modifier.Ctrl, Meta = gui.HyperlinkClickHandler.Modifier.Meta, odfUtils = new odf.OdfUtils, xpath = xmldom.XPath, modifier = None;
++  function getHyperlinkElement(node) {
++    while(node !== null) {
++      if(odfUtils.isHyperlink(node)) {
++        return(node)
++      }
++      if(odfUtils.isParagraph(node)) {
++        break
 +      }
++      node = node.parentNode
 +    }
-     return{opSpecsA:applyDirectStylingSpecResult, opSpecsB:removeTextSpecResult}
++    return null
 +  }
-   function transformApplyDirectStylingSplitParagraph(applyDirectStylingSpec, splitParagraphSpec) {
-     if(splitParagraphSpec.position < applyDirectStylingSpec.position) {
-       applyDirectStylingSpec.position += 1
++  this.handleClick = function(e) {
++    var target = e.target || e.srcElement, modifierPressed, linkElement, url, rootNode, bookmarks;
++    if(e.ctrlKey) {
++      modifierPressed = Ctrl
 +    }else {
-       if(splitParagraphSpec.position < applyDirectStylingSpec.position + applyDirectStylingSpec.length) {
-         applyDirectStylingSpec.length += 1
++      if(e.metaKey) {
++        modifierPressed = Meta
 +      }
 +    }
-     return{opSpecsA:[applyDirectStylingSpec], opSpecsB:[splitParagraphSpec]}
++    if(modifier !== None && modifier !== modifierPressed) {
++      return
++    }
++    linkElement = getHyperlinkElement((target));
++    if(!linkElement) {
++      return
++    }
++    url = odfUtils.getHyperlinkTarget(linkElement);
++    if(url === "") {
++      return
++    }
++    if(url[0] === "#") {
++      url = url.substring(1);
++      rootNode = (getRootNode());
++      bookmarks = xpath.getODFElementsWithXPath(rootNode, "//text:bookmark-start[@text:name='" + url + "']", odf.Namespaces.lookupNamespaceURI);
++      if(bookmarks.length === 0) {
++        bookmarks = xpath.getODFElementsWithXPath(rootNode, "//text:bookmark[@text:name='" + url + "']", odf.Namespaces.lookupNamespaceURI)
++      }
++      if(bookmarks.length > 0) {
++        bookmarks[0].scrollIntoView(true)
++      }
++    }else {
++      runtime.getWindow().open(url)
++    }
++    if(e.preventDefault) {
++      e.preventDefault()
++    }else {
++      e.returnValue = false
++    }
++  };
++  function showPointerCursor() {
++    getRootNode().removeAttributeNS(webodfns, links)
 +  }
-   function transformInsertTextInsertText(insertTextSpecA, insertTextSpecB, hasAPriority) {
-     if(insertTextSpecA.position < insertTextSpecB.position) {
-       insertTextSpecB.position += insertTextSpecA.text.length
++  this.showPointerCursor = showPointerCursor;
++  function showTextCursor() {
++    getRootNode().setAttributeNS(webodfns, links, inactive)
++  }
++  this.showTextCursor = showTextCursor;
++  this.setModifier = function(value) {
++    modifier = value;
++    if(modifier !== None) {
++      showTextCursor()
 +    }else {
-       if(insertTextSpecA.position > insertTextSpecB.position) {
-         insertTextSpecA.position += insertTextSpecB.text.length
-       }else {
-         if(hasAPriority) {
-           insertTextSpecB.position += insertTextSpecA.text.length
-         }else {
-           insertTextSpecA.position += insertTextSpecB.text.length
++      showPointerCursor()
++    }
++  }
++};
++gui.HyperlinkClickHandler.Modifier = {None:0, Ctrl:1, Meta:2};
++gui.HyperlinkController = function HyperlinkController(session, inputMemberId) {
++  var odfUtils = new odf.OdfUtils, odtDocument = session.getOdtDocument();
++  function addHyperlink(hyperlink, insertionText) {
++    var selection = odtDocument.getCursorSelection(inputMemberId), op = new ops.OpApplyHyperlink, operations = [];
++    if(selection.length === 0 || insertionText) {
++      insertionText = insertionText || hyperlink;
++      op = new ops.OpInsertText;
++      op.init({memberid:inputMemberId, position:selection.position, text:insertionText});
++      selection.length = insertionText.length;
++      operations.push(op)
++    }
++    op = new ops.OpApplyHyperlink;
++    op.init({memberid:inputMemberId, position:selection.position, length:selection.length, hyperlink:hyperlink});
++    operations.push(op);
++    session.enqueue(operations)
++  }
++  this.addHyperlink = addHyperlink;
++  function removeHyperlinks() {
++    var iterator = gui.SelectionMover.createPositionIterator(odtDocument.getRootNode()), selectedRange = odtDocument.getCursor(inputMemberId).getSelectedRange(), links = odfUtils.getHyperlinkElements(selectedRange), removeEntireLink = selectedRange.collapsed && links.length === 1, domRange = odtDocument.getDOMDocument().createRange(), operations = [], cursorRange, firstLink, lastLink, offset, op;
++    if(links.length === 0) {
++      return
++    }
++    links.forEach(function(link) {
++      domRange.selectNodeContents(link);
++      cursorRange = odtDocument.convertDomToCursorRange({anchorNode:(domRange.startContainer), anchorOffset:domRange.startOffset, focusNode:(domRange.endContainer), focusOffset:domRange.endOffset});
++      op = new ops.OpRemoveHyperlink;
++      op.init({memberid:inputMemberId, position:cursorRange.position, length:cursorRange.length});
++      operations.push(op)
++    });
++    if(!removeEntireLink) {
++      firstLink = (links[0]);
++      if(selectedRange.comparePoint(firstLink, 0) === -1) {
++        domRange.setStart(firstLink, 0);
++        domRange.setEnd(selectedRange.startContainer, selectedRange.startOffset);
++        cursorRange = odtDocument.convertDomToCursorRange({anchorNode:(domRange.startContainer), anchorOffset:domRange.startOffset, focusNode:(domRange.endContainer), focusOffset:domRange.endOffset});
++        if(cursorRange.length > 0) {
++          op = new ops.OpApplyHyperlink;
++          (op).init({memberid:inputMemberId, position:cursorRange.position, length:cursorRange.length, hyperlink:odfUtils.getHyperlinkTarget(firstLink)});
++          operations.push(op)
++        }
++      }
++      lastLink = (links[links.length - 1]);
++      iterator.moveToEndOfNode(lastLink);
++      offset = iterator.unfilteredDomOffset();
++      if(selectedRange.comparePoint(lastLink, offset) === 1) {
++        domRange.setStart(selectedRange.endContainer, selectedRange.endOffset);
++        domRange.setEnd(lastLink, offset);
++        cursorRange = odtDocument.convertDomToCursorRange({anchorNode:(domRange.startContainer), anchorOffset:domRange.startOffset, focusNode:(domRange.endContainer), focusOffset:domRange.endOffset});
++        if(cursorRange.length > 0) {
++          op = new ops.OpApplyHyperlink;
++          (op).init({memberid:inputMemberId, position:cursorRange.position, length:cursorRange.length, hyperlink:odfUtils.getHyperlinkTarget(lastLink)});
++          operations.push(op)
 +        }
 +      }
 +    }
-     return{opSpecsA:[insertTextSpecA], opSpecsB:[insertTextSpecB]}
++    session.enqueue(operations);
++    domRange.detach()
 +  }
-   function transformInsertTextMoveCursor(insertTextSpec, moveCursorSpec) {
-     var isMoveCursorSpecRangeInverted = invertMoveCursorSpecRangeOnNegativeLength(moveCursorSpec);
-     if(insertTextSpec.position < moveCursorSpec.position) {
-       moveCursorSpec.position += insertTextSpec.text.length
-     }else {
-       if(insertTextSpec.position < moveCursorSpec.position + moveCursorSpec.length) {
-         moveCursorSpec.length += insertTextSpec.text.length
++  this.removeHyperlinks = removeHyperlinks
++};
++gui.EventManager = function EventManager(odtDocument) {
++  var window = (runtime.getWindow()), bindToDirectHandler = {"beforecut":true, "beforepaste":true, "longpress":true, "drag":true, "dragstop":true}, bindToWindow = {"mousedown":true, "mouseup":true, "focus":true}, compoundEvents = {}, eventDelegates = {}, eventTrap, canvasElement = (odtDocument.getCanvas().getElement()), eventManager = this, longPressTimers = {}, LONGPRESS_DURATION = 400;
++  function EventDelegate() {
++    var self = this, recentEvents = [];
++    this.filters = [];
++    this.handlers = [];
++    this.handleEvent = function(e) {
++      if(recentEvents.indexOf(e) === -1) {
++        recentEvents.push(e);
++        if(self.filters.every(function(filter) {
++          return filter(e)
++        })) {
++          self.handlers.forEach(function(handler) {
++            handler(e)
++          })
++        }
++        runtime.setTimeout(function() {
++          recentEvents.splice(recentEvents.indexOf(e), 1)
++        }, 0)
 +      }
 +    }
-     if(isMoveCursorSpecRangeInverted) {
-       invertMoveCursorSpecRange(moveCursorSpec)
++  }
++  function CompoundEvent(eventName, dependencies, eventProxy) {
++    var cachedState = {}, events = new core.EventNotifier(["eventTriggered"]);
++    function subscribedProxy(event) {
++      eventProxy(event, cachedState, function(compoundEventInstance) {
++        compoundEventInstance.type = eventName;
++        events.emit("eventTriggered", compoundEventInstance)
++      })
 +    }
-     return{opSpecsA:[insertTextSpec], opSpecsB:[moveCursorSpec]}
++    this.subscribe = function(cb) {
++      events.subscribe("eventTriggered", cb)
++    };
++    this.unsubscribe = function(cb) {
++      events.unsubscribe("eventTriggered", cb)
++    };
++    this.destroy = function() {
++      dependencies.forEach(function(eventName) {
++        eventManager.unsubscribe(eventName, subscribedProxy)
++      })
++    };
++    function init() {
++      dependencies.forEach(function(eventName) {
++        eventManager.subscribe(eventName, subscribedProxy)
++      })
++    }
++    init()
 +  }
-   function transformInsertTextRemoveText(insertTextSpec, removeTextSpec) {
-     var helperOpspec, removeTextSpecEnd = removeTextSpec.position + removeTextSpec.length, insertTextSpecResult = [insertTextSpec], removeTextSpecResult = [removeTextSpec];
-     if(removeTextSpecEnd <= insertTextSpec.position) {
-       insertTextSpec.position -= removeTextSpec.length
++  function clearTimeout(timer) {
++    runtime.clearTimeout(timer);
++    delete longPressTimers[timer]
++  }
++  function setTimeout(fn, duration) {
++    var timer = runtime.setTimeout(function() {
++      fn();
++      clearTimeout(timer)
++    }, duration);
++    longPressTimers[timer] = true;
++    return timer
++  }
++  function getTarget(e) {
++    return(e.target) || (e.srcElement || null)
++  }
++  function emitLongPressEvent(event, cachedState, callback) {
++    var touchEvent = (event), fingers = (touchEvent.touches.length), touch = (touchEvent.touches[0]), timer = (cachedState).timer;
++    if(event.type === "touchmove" || event.type === "touchend") {
++      if(timer) {
++        clearTimeout(timer)
++      }
 +    }else {
-       if(insertTextSpec.position <= removeTextSpec.position) {
-         removeTextSpec.position += insertTextSpec.text.length
-       }else {
-         removeTextSpec.length = insertTextSpec.position - removeTextSpec.position;
-         helperOpspec = {optype:"RemoveText", memberid:removeTextSpec.memberid, timestamp:removeTextSpec.timestamp, position:insertTextSpec.position + insertTextSpec.text.length, length:removeTextSpecEnd - insertTextSpec.position};
-         removeTextSpecResult.unshift(helperOpspec);
-         insertTextSpec.position = removeTextSpec.position
++      if(event.type === "touchstart") {
++        if(fingers !== 1) {
++          runtime.clearTimeout(timer)
++        }else {
++          timer = setTimeout(function() {
++            callback({clientX:touch.clientX, clientY:touch.clientY, pageX:touch.pageX, pageY:touch.pageY, target:getTarget(event), detail:1})
++          }, LONGPRESS_DURATION)
++        }
 +      }
 +    }
-     return{opSpecsA:insertTextSpecResult, opSpecsB:removeTextSpecResult}
++    cachedState.timer = timer
 +  }
-   function transformInsertTextSplitParagraph(insertTextSpec, splitParagraphSpec, hasAPriority) {
-     if(insertTextSpec.position < splitParagraphSpec.position) {
-       splitParagraphSpec.position += insertTextSpec.text.length
++  function emitDragEvent(event, cachedState, callback) {
++    var touchEvent = (event), fingers = (touchEvent.touches.length), touch = (touchEvent.touches[0]), target = (getTarget(event)), cachedTarget = (cachedState).target;
++    if(fingers !== 1 || event.type === "touchend") {
++      cachedTarget = null
 +    }else {
-       if(insertTextSpec.position > splitParagraphSpec.position) {
-         insertTextSpec.position += 1
++      if(event.type === "touchstart" && target.getAttribute("class") === "draggable") {
++        cachedTarget = target
 +      }else {
-         if(hasAPriority) {
-           splitParagraphSpec.position += insertTextSpec.text.length
-         }else {
-           insertTextSpec.position += 1
++        if(event.type === "touchmove" && cachedTarget) {
++          event.preventDefault();
++          event.stopPropagation();
++          callback({clientX:touch.clientX, clientY:touch.clientY, pageX:touch.pageX, pageY:touch.pageY, target:cachedTarget, detail:1})
 +        }
-         return null
 +      }
 +    }
-     return{opSpecsA:[insertTextSpec], opSpecsB:[splitParagraphSpec]}
++    cachedState.target = cachedTarget
 +  }
-   function transformUpdateParagraphStyleUpdateParagraphStyle(updateParagraphStyleSpecA, updateParagraphStyleSpecB, hasAPriority) {
-     var majorSpec, minorSpec, updateParagraphStyleSpecAResult = [updateParagraphStyleSpecA], updateParagraphStyleSpecBResult = [updateParagraphStyleSpecB];
-     if(updateParagraphStyleSpecA.styleName === updateParagraphStyleSpecB.styleName) {
-       majorSpec = hasAPriority ? updateParagraphStyleSpecA : updateParagraphStyleSpecB;
-       minorSpec = hasAPriority ? updateParagraphStyleSpecB : updateParagraphStyleSpecA;
-       dropOverruledAndUnneededProperties(minorSpec, majorSpec, "style:paragraph-properties");
-       dropOverruledAndUnneededProperties(minorSpec, majorSpec, "style:text-properties");
-       dropOverruledAndUnneededAttributes(minorSpec.setProperties || null, minorSpec.removedProperties || null, majorSpec.setProperties || null, majorSpec.removedProperties || null);
-       if(!(majorSpec.setProperties && hasProperties(majorSpec.setProperties)) && !(majorSpec.removedProperties && hasRemovedProperties(majorSpec.removedProperties))) {
-         if(hasAPriority) {
-           updateParagraphStyleSpecAResult = []
-         }else {
-           updateParagraphStyleSpecBResult = []
-         }
-       }
-       if(!(minorSpec.setProperties && hasProperties(minorSpec.setProperties)) && !(minorSpec.removedProperties && hasRemovedProperties(minorSpec.removedProperties))) {
-         if(hasAPriority) {
-           updateParagraphStyleSpecBResult = []
-         }else {
-           updateParagraphStyleSpecAResult = []
-         }
++  function emitDragStopEvent(event, cachedState, callback) {
++    var touchEvent = (event), target = (getTarget(event)), touch, dragging = (cachedState).dragging;
++    if(event.type === "drag") {
++      dragging = true
++    }else {
++      if(event.type === "touchend" && dragging) {
++        dragging = false;
++        touch = (touchEvent.changedTouches[0]);
++        callback({clientX:touch.clientX, clientY:touch.clientY, pageX:touch.pageX, pageY:touch.pageY, target:target, detail:1})
 +      }
 +    }
-     return{opSpecsA:updateParagraphStyleSpecAResult, opSpecsB:updateParagraphStyleSpecBResult}
++    cachedState.dragging = dragging
 +  }
-   function transformUpdateMetadataUpdateMetadata(updateMetadataSpecA, updateMetadataSpecB, hasAPriority) {
-     var majorSpec, minorSpec, updateMetadataSpecAResult = [updateMetadataSpecA], updateMetadataSpecBResult = [updateMetadataSpecB];
-     majorSpec = hasAPriority ? updateMetadataSpecA : updateMetadataSpecB;
-     minorSpec = hasAPriority ? updateMetadataSpecB : updateMetadataSpecA;
-     dropOverruledAndUnneededAttributes(minorSpec.setProperties || null, minorSpec.removedProperties || null, majorSpec.setProperties || null, majorSpec.removedProperties || null);
-     if(!(majorSpec.setProperties && hasProperties(majorSpec.setProperties)) && !(majorSpec.removedProperties && hasRemovedProperties(majorSpec.removedProperties))) {
-       if(hasAPriority) {
-         updateMetadataSpecAResult = []
-       }else {
-         updateMetadataSpecBResult = []
++  function declareTouchEnabled() {
++    canvasElement.classList.add("webodf-touchEnabled");
++    eventManager.unsubscribe("touchstart", declareTouchEnabled)
++  }
++  function WindowScrollState(window) {
++    var x = window.scrollX, y = window.scrollY;
++    this.restore = function() {
++      if(window.scrollX !== x || window.scrollY !== y) {
++        window.scrollTo(x, y)
 +      }
 +    }
-     if(!(minorSpec.setProperties && hasProperties(minorSpec.setProperties)) && !(minorSpec.removedProperties && hasRemovedProperties(minorSpec.removedProperties))) {
-       if(hasAPriority) {
-         updateMetadataSpecBResult = []
-       }else {
-         updateMetadataSpecAResult = []
++  }
++  function ElementScrollState(element) {
++    var top = element.scrollTop, left = element.scrollLeft;
++    this.restore = function() {
++      if(element.scrollTop !== top || element.scrollLeft !== left) {
++        element.scrollTop = top;
++        element.scrollLeft = left
 +      }
 +    }
-     return{opSpecsA:updateMetadataSpecAResult, opSpecsB:updateMetadataSpecBResult}
 +  }
-   function transformSplitParagraphSplitParagraph(splitParagraphSpecA, splitParagraphSpecB, hasAPriority) {
-     if(splitParagraphSpecA.position < splitParagraphSpecB.position) {
-       splitParagraphSpecB.position += 1
-     }else {
-       if(splitParagraphSpecA.position > splitParagraphSpecB.position) {
-         splitParagraphSpecA.position += 1
-       }else {
-         if(splitParagraphSpecA.position === splitParagraphSpecB.position) {
-           if(hasAPriority) {
-             splitParagraphSpecB.position += 1
-           }else {
-             splitParagraphSpecA.position += 1
-           }
-         }
++  function listenEvent(eventTarget, eventType, eventHandler) {
++    var onVariant, bound = false;
++    if(compoundEvents.hasOwnProperty(eventType)) {
++      compoundEvents[eventType].subscribe(eventHandler);
++      return
++    }
++    onVariant = "on" + eventType;
++    if(eventTarget.attachEvent) {
++      eventTarget.attachEvent(onVariant, eventHandler);
++      bound = true
++    }
++    if(!bound && eventTarget.addEventListener) {
++      eventTarget.addEventListener(eventType, eventHandler, false);
++      bound = true
++    }
++    if((!bound || bindToDirectHandler[eventType]) && eventTarget.hasOwnProperty(onVariant)) {
++      eventTarget[onVariant] = eventHandler
++    }
++  }
++  function getDelegateForEvent(eventName, shouldCreate) {
++    var delegate = eventDelegates[eventName] || null;
++    if(!delegate && shouldCreate) {
++      delegate = eventDelegates[eventName] = new EventDelegate;
++      if(bindToWindow[eventName]) {
++        listenEvent(window, eventName, delegate.handleEvent)
 +      }
++      listenEvent(eventTrap, eventName, delegate.handleEvent);
++      listenEvent(canvasElement, eventName, delegate.handleEvent)
++    }
++    return delegate
++  }
++  this.addFilter = function(eventName, filter) {
++    var delegate = getDelegateForEvent(eventName, true);
++    delegate.filters.push(filter)
++  };
++  this.removeFilter = function(eventName, filter) {
++    var delegate = getDelegateForEvent(eventName, true), index = delegate.filters.indexOf(filter);
++    if(index !== -1) {
++      delegate.filters.splice(index, 1)
++    }
++  };
++  this.subscribe = function(eventName, handler) {
++    var delegate = getDelegateForEvent(eventName, true);
++    delegate.handlers.push(handler)
++  };
++  this.unsubscribe = function(eventName, handler) {
++    var delegate = getDelegateForEvent(eventName, false), handlerIndex = delegate && delegate.handlers.indexOf(handler);
++    if(delegate && handlerIndex !== -1) {
++      delegate.handlers.splice(handlerIndex, 1)
 +    }
-     return{opSpecsA:[splitParagraphSpecA], opSpecsB:[splitParagraphSpecB]}
-   }
-   function transformMoveCursorRemoveCursor(moveCursorSpec, removeCursorSpec) {
-     var isSameCursorRemoved = moveCursorSpec.memberid === removeCursorSpec.memberid;
-     return{opSpecsA:isSameCursorRemoved ? [] : [moveCursorSpec], opSpecsB:[removeCursorSpec]}
++  };
++  function hasFocus() {
++    return odtDocument.getDOMDocument().activeElement === eventTrap
 +  }
-   function transformMoveCursorRemoveText(moveCursorSpec, removeTextSpec) {
-     var isMoveCursorSpecRangeInverted = invertMoveCursorSpecRangeOnNegativeLength(moveCursorSpec), moveCursorSpecEnd = moveCursorSpec.position + moveCursorSpec.length, removeTextSpecEnd = removeTextSpec.position + removeTextSpec.length;
-     if(removeTextSpecEnd <= moveCursorSpec.position) {
-       moveCursorSpec.position -= removeTextSpec.length
-     }else {
-       if(removeTextSpec.position < moveCursorSpecEnd) {
-         if(moveCursorSpec.position < removeTextSpec.position) {
-           if(removeTextSpecEnd < moveCursorSpecEnd) {
-             moveCursorSpec.length -= removeTextSpec.length
-           }else {
-             moveCursorSpec.length = removeTextSpec.position - moveCursorSpec.position
-           }
-         }else {
-           moveCursorSpec.position = removeTextSpec.position;
-           if(removeTextSpecEnd < moveCursorSpecEnd) {
-             moveCursorSpec.length = moveCursorSpecEnd - removeTextSpecEnd
-           }else {
-             moveCursorSpec.length = 0
-           }
-         }
++  this.hasFocus = hasFocus;
++  function findScrollableParents(element) {
++    var scrollParents = [];
++    while(element) {
++      if(element.scrollWidth > element.clientWidth || element.scrollHeight > element.clientHeight) {
++        scrollParents.push(new ElementScrollState(element))
 +      }
++      element = (element.parentNode)
 +    }
-     if(isMoveCursorSpecRangeInverted) {
-       invertMoveCursorSpecRange(moveCursorSpec)
++    scrollParents.push(new WindowScrollState(window));
++    return scrollParents
++  }
++  this.focus = function() {
++    var scrollParents;
++    if(!hasFocus()) {
++      scrollParents = findScrollableParents(eventTrap);
++      eventTrap.focus();
++      scrollParents.forEach(function(scrollParent) {
++        scrollParent.restore()
++      })
 +    }
-     return{opSpecsA:[moveCursorSpec], opSpecsB:[removeTextSpec]}
++  };
++  this.getEventTrap = function() {
++    return eventTrap
++  };
++  this.blur = function() {
++    if(hasFocus()) {
++      eventTrap.blur()
++    }
++  };
++  this.destroy = function(callback) {
++    Object.keys(longPressTimers).forEach(function(timer) {
++      clearTimeout(parseInt(timer, 10))
++    });
++    longPressTimers.length = 0;
++    Object.keys(compoundEvents).forEach(function(compoundEventName) {
++      compoundEvents[compoundEventName].destroy()
++    });
++    compoundEvents = {};
++    eventManager.unsubscribe("touchstart", declareTouchEnabled);
++    eventTrap.parentNode.removeChild(eventTrap);
++    callback()
++  };
++  function init() {
++    var sizerElement = odtDocument.getOdfCanvas().getSizer(), doc = sizerElement.ownerDocument;
++    runtime.assert(Boolean(window), "EventManager requires a window object to operate correctly");
++    eventTrap = (doc.createElement("input"));
++    eventTrap.id = "eventTrap";
++    eventTrap.setAttribute("tabindex", -1);
++    sizerElement.appendChild(eventTrap);
++    compoundEvents.longpress = new CompoundEvent("longpress", ["touchstart", "touchmove", "touchend"], emitLongPressEvent);
++    compoundEvents.drag = new CompoundEvent("drag", ["touchstart", "touchmove", "touchend"], emitDragEvent);
++    compoundEvents.dragstop = new CompoundEvent("dragstop", ["drag", "touchend"], emitDragStopEvent);
++    eventManager.subscribe("touchstart", declareTouchEnabled)
 +  }
-   function transformMoveCursorSplitParagraph(moveCursorSpec, splitParagraphSpec) {
-     var isMoveCursorSpecRangeInverted = invertMoveCursorSpecRangeOnNegativeLength(moveCursorSpec);
-     if(splitParagraphSpec.position < moveCursorSpec.position) {
-       moveCursorSpec.position += 1
-     }else {
-       if(splitParagraphSpec.position < moveCursorSpec.position + moveCursorSpec.length) {
-         moveCursorSpec.length += 1
-       }
++  init()
++};
++/*
++
++ Copyright (C) 2014 KO GmbH <copyright at kogmbh.com>
++
++ @licstart
++ This file is part of WebODF.
++
++ WebODF is free software: you can redistribute it and/or modify it
++ under the terms of the GNU Affero General Public License (GNU AGPL)
++ as published by the Free Software Foundation, either version 3 of
++ the License, or (at your option) any later version.
++
++ WebODF is distributed in the hope that it will be useful, but
++ WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ GNU Affero General Public License for more details.
++
++ You should have received a copy of the GNU Affero General Public License
++ along with WebODF.  If not, see <http://www.gnu.org/licenses/>.
++ @licend
++
++ @source: http://www.webodf.org/
++ @source: https://github.com/kogmbh/WebODF/
++*/
++gui.IOSSafariSupport = function(eventManager) {
++  var window = runtime.getWindow(), eventTrap = eventManager.getEventTrap();
++  function suppressFocusScrollIfKeyboardOpen() {
++    if(window.innerHeight !== window.outerHeight) {
++      eventTrap.style.display = "none";
++      runtime.requestAnimationFrame(function() {
++        eventTrap.style.display = "block"
++      })
 +    }
-     if(isMoveCursorSpecRangeInverted) {
-       invertMoveCursorSpecRange(moveCursorSpec)
++  }
++  this.destroy = function(callback) {
++    eventManager.unsubscribe("focus", suppressFocusScrollIfKeyboardOpen);
++    eventTrap.removeAttribute("autocapitalize");
++    eventTrap.style.WebkitTransform = "";
++    callback()
++  };
++  function init() {
++    eventManager.subscribe("focus", suppressFocusScrollIfKeyboardOpen);
++    eventTrap.setAttribute("autocapitalize", "off");
++    eventTrap.style.WebkitTransform = "translateX(-10000px)"
++  }
++  init()
++};
++gui.ImageController = function ImageController(session, inputMemberId, objectNameGenerator) {
++  var cmPerPixel = 0.0264583333333334, fileExtensionByMimetype = {"image/gif":".gif", "image/jpeg":".jpg", "image/png":".png"}, textns = odf.Namespaces.textns, odtDocument = session.getOdtDocument(), formatting = odtDocument.getFormatting(), paragraphStyleToPageContentSizeMap = {};
++  function createAddGraphicsStyleOp(name) {
++    var op = new ops.OpAddStyle;
++    op.init({memberid:inputMemberId, styleName:name, styleFamily:"graphic", isAutomaticStyle:false, setProperties:{"style:graphic-properties":{"text:anchor-type":"paragraph", "svg:x":"0cm", "svg:y":"0cm", "style:wrap":"dynamic", "style:number-wrapped-paragraphs":"no-limit", "style:wrap-contour":"false", "style:vertical-pos":"top", "style:vertical-rel":"paragraph", "style:horizontal-pos":"center", "style:horizontal-rel":"paragraph"}}});
++    return op
++  }
++  function createAddFrameStyleOp(styleName, parentStyleName) {
++    var op = new ops.OpAddStyle;
++    op.init({memberid:inputMemberId, styleName:styleName, styleFamily:"graphic", isAutomaticStyle:true, setProperties:{"style:parent-style-name":parentStyleName, "style:graphic-properties":{"style:vertical-pos":"top", "style:vertical-rel":"baseline", "style:horizontal-pos":"center", "style:horizontal-rel":"paragraph", "fo:background-color":"transparent", "style:background-transparency":"100%", "style:shadow":"none", "style:mirror":"none", "fo:clip":"rect(0cm, 0cm, 0cm, 0cm)", "draw:lumi [...]
++    "draw:contrast":"0%", "draw:red":"0%", "draw:green":"0%", "draw:blue":"0%", "draw:gamma":"100%", "draw:color-inversion":"false", "draw:image-opacity":"100%", "draw:color-mode":"standard"}}});
++    return op
++  }
++  function getFileExtension(mimetype) {
++    mimetype = mimetype.toLowerCase();
++    return fileExtensionByMimetype.hasOwnProperty(mimetype) ? fileExtensionByMimetype[mimetype] : null
++  }
++  function insertImageInternal(mimetype, content, widthInCm, heightInCm) {
++    var graphicsStyleName = "Graphics", stylesElement = odtDocument.getOdfCanvas().odfContainer().rootElement.styles, fileExtension = getFileExtension(mimetype), fileName, graphicsStyleElement, frameStyleName, op, operations = [];
++    runtime.assert(fileExtension !== null, "Image type is not supported: " + mimetype);
++    fileName = "Pictures/" + objectNameGenerator.generateImageName() + fileExtension;
++    op = new ops.OpSetBlob;
++    op.init({memberid:inputMemberId, filename:fileName, mimetype:mimetype, content:content});
++    operations.push(op);
++    graphicsStyleElement = formatting.getStyleElement(graphicsStyleName, "graphic", [stylesElement]);
++    if(!graphicsStyleElement) {
++      op = createAddGraphicsStyleOp(graphicsStyleName);
++      operations.push(op)
 +    }
-     return{opSpecsA:[moveCursorSpec], opSpecsB:[splitParagraphSpec]}
++    frameStyleName = objectNameGenerator.generateStyleName();
++    op = createAddFrameStyleOp(frameStyleName, graphicsStyleName);
++    operations.push(op);
++    op = new ops.OpInsertImage;
++    op.init({memberid:inputMemberId, position:odtDocument.getCursorPosition(inputMemberId), filename:fileName, frameWidth:widthInCm + "cm", frameHeight:heightInCm + "cm", frameStyleName:frameStyleName, frameName:objectNameGenerator.generateFrameName()});
++    operations.push(op);
++    session.enqueue(operations)
 +  }
-   function transformRemoveCursorRemoveCursor(removeCursorSpecA, removeCursorSpecB) {
-     var isSameMemberid = removeCursorSpecA.memberid === removeCursorSpecB.memberid;
-     return{opSpecsA:isSameMemberid ? [] : [removeCursorSpecA], opSpecsB:isSameMemberid ? [] : [removeCursorSpecB]}
++  function trimmedSize(originalSize, pageContentSize) {
++    var widthRatio = 1, heightRatio = 1, ratio;
++    if(originalSize.width > pageContentSize.width) {
++      widthRatio = pageContentSize.width / originalSize.width
++    }
++    if(originalSize.height > pageContentSize.height) {
++      heightRatio = pageContentSize.height / originalSize.height
++    }
++    ratio = Math.min(widthRatio, heightRatio);
++    return{width:originalSize.width * ratio, height:originalSize.height * ratio}
 +  }
-   function transformRemoveStyleRemoveStyle(removeStyleSpecA, removeStyleSpecB) {
-     var isSameStyle = removeStyleSpecA.styleName === removeStyleSpecB.styleName && removeStyleSpecA.styleFamily === removeStyleSpecB.styleFamily;
-     return{opSpecsA:isSameStyle ? [] : [removeStyleSpecA], opSpecsB:isSameStyle ? [] : [removeStyleSpecB]}
++  this.insertImage = function(mimetype, content, widthInPx, heightInPx) {
++    var paragraphElement, styleName, pageContentSize, originalSize, newSize;
++    runtime.assert(widthInPx > 0 && heightInPx > 0, "Both width and height of the image should be greater than 0px.");
++    paragraphElement = odtDocument.getParagraphElement(odtDocument.getCursor(inputMemberId).getNode());
++    styleName = paragraphElement.getAttributeNS(textns, "style-name");
++    if(!paragraphStyleToPageContentSizeMap.hasOwnProperty(styleName)) {
++      paragraphStyleToPageContentSizeMap[styleName] = formatting.getContentSize(styleName, "paragraph")
++    }
++    pageContentSize = paragraphStyleToPageContentSizeMap[styleName];
++    originalSize = {width:widthInPx * cmPerPixel, height:heightInPx * cmPerPixel};
++    newSize = trimmedSize(originalSize, pageContentSize);
++    insertImageInternal(mimetype, content, newSize.width, newSize.height)
 +  }
-   function transformRemoveStyleSetParagraphStyle(removeStyleSpec, setParagraphStyleSpec) {
-     var helperOpspec, removeStyleSpecResult = [removeStyleSpec], setParagraphStyleSpecResult = [setParagraphStyleSpec];
-     if(removeStyleSpec.styleFamily === "paragraph" && removeStyleSpec.styleName === setParagraphStyleSpec.styleName) {
-       helperOpspec = {optype:"SetParagraphStyle", memberid:removeStyleSpec.memberid, timestamp:removeStyleSpec.timestamp, position:setParagraphStyleSpec.position, styleName:""};
-       removeStyleSpecResult.unshift(helperOpspec);
-       setParagraphStyleSpec.styleName = ""
++};
++gui.ImageSelector = function ImageSelector(odfCanvas) {
++  var svgns = odf.Namespaces.svgns, imageSelectorId = "imageSelector", selectorBorderWidth = 1, squareClassNames = ["topLeft", "topRight", "bottomRight", "bottomLeft", "topMiddle", "rightMiddle", "bottomMiddle", "leftMiddle"], document = odfCanvas.getElement().ownerDocument, hasSelection = false;
++  function createSelectorElement() {
++    var sizerElement = odfCanvas.getSizer(), selectorElement = (document.createElement("div"));
++    selectorElement.id = "imageSelector";
++    selectorElement.style.borderWidth = selectorBorderWidth + "px";
++    sizerElement.appendChild(selectorElement);
++    function createDiv(className) {
++      var squareElement = document.createElement("div");
++      squareElement.className = className;
++      selectorElement.appendChild(squareElement)
 +    }
-     return{opSpecsA:removeStyleSpecResult, opSpecsB:setParagraphStyleSpecResult}
++    squareClassNames.forEach(createDiv);
++    return selectorElement
 +  }
-   function transformRemoveStyleUpdateParagraphStyle(removeStyleSpec, updateParagraphStyleSpec) {
-     var setAttributes, helperOpspec, removeStyleSpecResult = [removeStyleSpec], updateParagraphStyleSpecResult = [updateParagraphStyleSpec];
-     if(removeStyleSpec.styleFamily === "paragraph") {
-       setAttributes = getStyleReferencingAttributes(updateParagraphStyleSpec.setProperties, removeStyleSpec.styleName);
-       if(setAttributes.length > 0) {
-         helperOpspec = {optype:"UpdateParagraphStyle", memberid:removeStyleSpec.memberid, timestamp:removeStyleSpec.timestamp, styleName:updateParagraphStyleSpec.styleName, removedProperties:{attributes:setAttributes.join(",")}};
-         removeStyleSpecResult.unshift(helperOpspec)
-       }
-       if(removeStyleSpec.styleName === updateParagraphStyleSpec.styleName) {
-         updateParagraphStyleSpecResult = []
-       }else {
-         dropStyleReferencingAttributes(updateParagraphStyleSpec.setProperties, removeStyleSpec.styleName)
++  function getPosition(element, referenceElement) {
++    var rect = element.getBoundingClientRect(), refRect = referenceElement.getBoundingClientRect(), zoomLevel = odfCanvas.getZoomLevel();
++    return{left:(rect.left - refRect.left) / zoomLevel - selectorBorderWidth, top:(rect.top - refRect.top) / zoomLevel - selectorBorderWidth}
++  }
++  this.select = function(frameElement) {
++    var selectorElement = document.getElementById(imageSelectorId), position;
++    if(!selectorElement) {
++      selectorElement = createSelectorElement()
++    }
++    hasSelection = true;
++    position = getPosition(frameElement, (selectorElement.parentNode));
++    selectorElement.style.display = "block";
++    selectorElement.style.left = position.left + "px";
++    selectorElement.style.top = position.top + "px";
++    selectorElement.style.width = frameElement.getAttributeNS(svgns, "width");
++    selectorElement.style.height = frameElement.getAttributeNS(svgns, "height")
++  };
++  this.clearSelection = function() {
++    var selectorElement;
++    if(hasSelection) {
++      selectorElement = document.getElementById(imageSelectorId);
++      if(selectorElement) {
++        selectorElement.style.display = "none"
 +      }
 +    }
-     return{opSpecsA:removeStyleSpecResult, opSpecsB:updateParagraphStyleSpecResult}
++    hasSelection = false
++  };
++  this.isSelectorElement = function(node) {
++    var selectorElement = document.getElementById(imageSelectorId);
++    if(!selectorElement) {
++      return false
++    }
++    return node === selectorElement || node.parentNode === selectorElement
 +  }
-   function transformRemoveTextRemoveText(removeTextSpecA, removeTextSpecB) {
-     var removeTextSpecAEnd = removeTextSpecA.position + removeTextSpecA.length, removeTextSpecBEnd = removeTextSpecB.position + removeTextSpecB.length, removeTextSpecAResult = [removeTextSpecA], removeTextSpecBResult = [removeTextSpecB];
-     if(removeTextSpecBEnd <= removeTextSpecA.position) {
-       removeTextSpecA.position -= removeTextSpecB.length
-     }else {
-       if(removeTextSpecAEnd <= removeTextSpecB.position) {
-         removeTextSpecB.position -= removeTextSpecA.length
-       }else {
-         if(removeTextSpecB.position < removeTextSpecAEnd) {
-           if(removeTextSpecA.position < removeTextSpecB.position) {
-             if(removeTextSpecBEnd < removeTextSpecAEnd) {
-               removeTextSpecA.length = removeTextSpecA.length - removeTextSpecB.length
-             }else {
-               removeTextSpecA.length = removeTextSpecB.position - removeTextSpecA.position
-             }
-             if(removeTextSpecAEnd < removeTextSpecBEnd) {
-               removeTextSpecB.position = removeTextSpecA.position;
-               removeTextSpecB.length = removeTextSpecBEnd - removeTextSpecAEnd
-             }else {
-               removeTextSpecBResult = []
-             }
-           }else {
-             if(removeTextSpecAEnd < removeTextSpecBEnd) {
-               removeTextSpecB.length = removeTextSpecB.length - removeTextSpecA.length
-             }else {
-               if(removeTextSpecB.position < removeTextSpecA.position) {
-                 removeTextSpecB.length = removeTextSpecA.position - removeTextSpecB.position
-               }else {
-                 removeTextSpecBResult = []
-               }
-             }
-             if(removeTextSpecBEnd < removeTextSpecAEnd) {
-               removeTextSpecA.position = removeTextSpecB.position;
-               removeTextSpecA.length = removeTextSpecAEnd - removeTextSpecBEnd
-             }else {
-               removeTextSpecAResult = []
-             }
-           }
++};
++(function() {
++  function DetectSafariCompositionError(eventManager) {
++    var lastCompositionValue, suppressedKeyPress = false;
++    function suppressIncorrectKeyPress(e) {
++      suppressedKeyPress = e.which && String.fromCharCode(e.which) === lastCompositionValue;
++      lastCompositionValue = undefined;
++      return suppressedKeyPress === false
++    }
++    function clearSuppression() {
++      suppressedKeyPress = false
++    }
++    function trapComposedValue(e) {
++      lastCompositionValue = e.data;
++      suppressedKeyPress = false
++    }
++    function init() {
++      eventManager.subscribe("textInput", clearSuppression);
++      eventManager.subscribe("compositionend", trapComposedValue);
++      eventManager.addFilter("keypress", suppressIncorrectKeyPress)
++    }
++    this.destroy = function(callback) {
++      eventManager.unsubscribe("textInput", clearSuppression);
++      eventManager.unsubscribe("compositionend", trapComposedValue);
++      eventManager.removeFilter("keypress", suppressIncorrectKeyPress);
++      callback()
++    };
++    init()
++  }
++  gui.InputMethodEditor = function InputMethodEditor(inputMemberId, eventManager) {
++    var cursorns = "urn:webodf:names:cursor", localCursor = null, eventTrap = eventManager.getEventTrap(), doc = (eventTrap.ownerDocument), compositionElement, async = new core.Async, FAKE_CONTENT = "b", processUpdates, pendingEvent = false, pendingData = "", events = new core.EventNotifier([gui.InputMethodEditor.signalCompositionStart, gui.InputMethodEditor.signalCompositionEnd]), lastCompositionData, filters = [], cleanup, isEditable = false;
++    this.subscribe = events.subscribe;
++    this.unsubscribe = events.unsubscribe;
++    function setCursorComposing(state) {
++      if(localCursor) {
++        if(state) {
++          localCursor.getNode().setAttributeNS(cursorns, "composing", "true")
++        }else {
++          localCursor.getNode().removeAttributeNS(cursorns, "composing");
++          compositionElement.textContent = ""
 +        }
 +      }
 +    }
-     return{opSpecsA:removeTextSpecAResult, opSpecsB:removeTextSpecBResult}
-   }
-   function transformRemoveTextSplitParagraph(removeTextSpec, splitParagraphSpec) {
-     var removeTextSpecEnd = removeTextSpec.position + removeTextSpec.length, helperOpspec, removeTextSpecResult = [removeTextSpec], splitParagraphSpecResult = [splitParagraphSpec];
-     if(splitParagraphSpec.position <= removeTextSpec.position) {
-       removeTextSpec.position += 1
-     }else {
-       if(splitParagraphSpec.position < removeTextSpecEnd) {
-         removeTextSpec.length = splitParagraphSpec.position - removeTextSpec.position;
-         helperOpspec = {optype:"RemoveText", memberid:removeTextSpec.memberid, timestamp:removeTextSpec.timestamp, position:splitParagraphSpec.position + 1, length:removeTextSpecEnd - splitParagraphSpec.position};
-         removeTextSpecResult.unshift(helperOpspec)
++    function flushEvent() {
++      if(pendingEvent) {
++        pendingEvent = false;
++        setCursorComposing(false);
++        events.emit(gui.InputMethodEditor.signalCompositionEnd, {data:pendingData});
++        pendingData = ""
 +      }
 +    }
-     if(removeTextSpec.position + removeTextSpec.length <= splitParagraphSpec.position) {
-       splitParagraphSpec.position -= removeTextSpec.length
-     }else {
-       if(removeTextSpec.position < splitParagraphSpec.position) {
-         splitParagraphSpec.position = removeTextSpec.position
++    function addCompositionData(data) {
++      pendingEvent = true;
++      pendingData += data;
++      processUpdates.trigger()
++    }
++    function resetWindowSelection() {
++      flushEvent();
++      if(localCursor && localCursor.getSelectedRange().collapsed) {
++        eventTrap.value = ""
++      }else {
++        eventTrap.value = FAKE_CONTENT
 +      }
++      eventTrap.setSelectionRange(0, eventTrap.value.length)
 +    }
-     return{opSpecsA:removeTextSpecResult, opSpecsB:splitParagraphSpecResult}
-   }
-   function passUnchanged(opSpecA, opSpecB) {
-     return{opSpecsA:[opSpecA], opSpecsB:[opSpecB]}
-   }
-   var transformations = {"AddCursor":{"AddCursor":passUnchanged, "AddMember":passUnchanged, "AddStyle":passUnchanged, "ApplyDirectStyling":passUnchanged, "InsertText":passUnchanged, "MoveCursor":passUnchanged, "RemoveCursor":passUnchanged, "RemoveMember":passUnchanged, "RemoveStyle":passUnchanged, "RemoveText":passUnchanged, "SetParagraphStyle":passUnchanged, "SplitParagraph":passUnchanged, "UpdateMember":passUnchanged, "UpdateMetadata":passUnchanged, "UpdateParagraphStyle":passUnchange [...]
-   "InsertText":passUnchanged, "MoveCursor":passUnchanged, "RemoveCursor":passUnchanged, "RemoveStyle":passUnchanged, "RemoveText":passUnchanged, "SetParagraphStyle":passUnchanged, "SplitParagraph":passUnchanged, "UpdateMetadata":passUnchanged, "UpdateParagraphStyle":passUnchanged}, "AddStyle":{"AddStyle":passUnchanged, "ApplyDirectStyling":passUnchanged, "InsertText":passUnchanged, "MoveCursor":passUnchanged, "RemoveCursor":passUnchanged, "RemoveMember":passUnchanged, "RemoveStyle":tran [...]
-   "RemoveText":passUnchanged, "SetParagraphStyle":passUnchanged, "SplitParagraph":passUnchanged, "UpdateMember":passUnchanged, "UpdateMetadata":passUnchanged, "UpdateParagraphStyle":passUnchanged}, "ApplyDirectStyling":{"ApplyDirectStyling":transformApplyDirectStylingApplyDirectStyling, "InsertText":transformApplyDirectStylingInsertText, "MoveCursor":passUnchanged, "RemoveCursor":passUnchanged, "RemoveStyle":passUnchanged, "RemoveText":transformApplyDirectStylingRemoveText, "SetParagrap [...]
-   "SplitParagraph":transformApplyDirectStylingSplitParagraph, "UpdateMetadata":passUnchanged, "UpdateParagraphStyle":passUnchanged}, "InsertText":{"InsertText":transformInsertTextInsertText, "MoveCursor":transformInsertTextMoveCursor, "RemoveCursor":passUnchanged, "RemoveMember":passUnchanged, "RemoveStyle":passUnchanged, "RemoveText":transformInsertTextRemoveText, "SplitParagraph":transformInsertTextSplitParagraph, "UpdateMember":passUnchanged, "UpdateMetadata":passUnchanged, "UpdatePa [...]
-   "MoveCursor":{"MoveCursor":passUnchanged, "RemoveCursor":transformMoveCursorRemoveCursor, "RemoveMember":passUnchanged, "RemoveStyle":passUnchanged, "RemoveText":transformMoveCursorRemoveText, "SetParagraphStyle":passUnchanged, "SplitParagraph":transformMoveCursorSplitParagraph, "UpdateMember":passUnchanged, "UpdateMetadata":passUnchanged, "UpdateParagraphStyle":passUnchanged}, "RemoveCursor":{"RemoveCursor":transformRemoveCursorRemoveCursor, "RemoveMember":passUnchanged, "RemoveStyle [...]
-   "RemoveText":passUnchanged, "SetParagraphStyle":passUnchanged, "SplitParagraph":passUnchanged, "UpdateMember":passUnchanged, "UpdateMetadata":passUnchanged, "UpdateParagraphStyle":passUnchanged}, "RemoveMember":{"RemoveStyle":passUnchanged, "RemoveText":passUnchanged, "SetParagraphStyle":passUnchanged, "SplitParagraph":passUnchanged, "UpdateMetadata":passUnchanged, "UpdateParagraphStyle":passUnchanged}, "RemoveStyle":{"RemoveStyle":transformRemoveStyleRemoveStyle, "RemoveText":passUnc [...]
-   "SplitParagraph":passUnchanged, "UpdateMember":passUnchanged, "UpdateMetadata":passUnchanged, "UpdateParagraphStyle":transformRemoveStyleUpdateParagraphStyle}, "RemoveText":{"RemoveText":transformRemoveTextRemoveText, "SplitParagraph":transformRemoveTextSplitParagraph, "UpdateMember":passUnchanged, "UpdateMetadata":passUnchanged, "UpdateParagraphStyle":passUnchanged}, "SetParagraphStyle":{"UpdateMember":passUnchanged, "UpdateMetadata":passUnchanged, "UpdateParagraphStyle":passUnchange [...]
-   "UpdateMember":passUnchanged, "UpdateMetadata":passUnchanged, "UpdateParagraphStyle":passUnchanged}, "UpdateMember":{"UpdateMetadata":passUnchanged, "UpdateParagraphStyle":passUnchanged}, "UpdateMetadata":{"UpdateMetadata":transformUpdateMetadataUpdateMetadata, "UpdateParagraphStyle":passUnchanged}, "UpdateParagraphStyle":{"UpdateParagraphStyle":transformUpdateParagraphStyleUpdateParagraphStyle}};
-   this.passUnchanged = passUnchanged;
-   this.extendTransformations = function(moreTransformations) {
-     Object.keys(moreTransformations).forEach(function(optypeA) {
-       var moreTransformationsOptypeAMap = moreTransformations[optypeA], optypeAMap, isExtendingOptypeAMap = transformations.hasOwnProperty(optypeA);
-       runtime.log((isExtendingOptypeAMap ? "Extending" : "Adding") + " map for optypeA: " + optypeA);
-       if(!isExtendingOptypeAMap) {
-         transformations[optypeA] = {}
++    function compositionStart() {
++      lastCompositionData = undefined;
++      processUpdates.cancel();
++      setCursorComposing(true);
++      if(!pendingEvent) {
++        events.emit(gui.InputMethodEditor.signalCompositionStart, {data:""})
 +      }
-       optypeAMap = transformations[optypeA];
-       Object.keys(moreTransformationsOptypeAMap).forEach(function(optypeB) {
-         var isOverwritingOptypeBEntry = optypeAMap.hasOwnProperty(optypeB);
-         runtime.assert(optypeA <= optypeB, "Wrong order:" + optypeA + ", " + optypeB);
-         runtime.log("  " + (isOverwritingOptypeBEntry ? "Overwriting" : "Adding") + " entry for optypeB: " + optypeB);
-         optypeAMap[optypeB] = moreTransformationsOptypeAMap[optypeB]
-       })
-     })
-   };
-   this.transformOpspecVsOpspec = function(opSpecA, opSpecB) {
-     var isOptypeAAlphaNumericSmaller = opSpecA.optype <= opSpecB.optype, helper, transformationFunctionMap, transformationFunction, result;
-     runtime.log("Crosstransforming:");
-     runtime.log(runtime.toJson(opSpecA));
-     runtime.log(runtime.toJson(opSpecB));
-     if(!isOptypeAAlphaNumericSmaller) {
-       helper = opSpecA;
-       opSpecA = opSpecB;
-       opSpecB = helper
 +    }
-     transformationFunctionMap = transformations[opSpecA.optype];
-     transformationFunction = transformationFunctionMap && transformationFunctionMap[opSpecB.optype];
-     if(transformationFunction) {
-       result = transformationFunction(opSpecA, opSpecB, !isOptypeAAlphaNumericSmaller);
-       if(!isOptypeAAlphaNumericSmaller && result !== null) {
-         result = {opSpecsA:result.opSpecsB, opSpecsB:result.opSpecsA}
++    function compositionEnd(e) {
++      lastCompositionData = e.data;
++      addCompositionData(e.data)
++    }
++    function textInput(e) {
++      if(e.data !== lastCompositionData) {
++        addCompositionData(e.data)
 +      }
-     }else {
-       result = null
++      lastCompositionData = undefined
 +    }
-     runtime.log("result:");
-     if(result) {
-       runtime.log(runtime.toJson(result.opSpecsA));
-       runtime.log(runtime.toJson(result.opSpecsB))
-     }else {
-       runtime.log("null")
++    function synchronizeCompositionText() {
++      compositionElement.textContent = eventTrap.value
 +    }
-     return result
-   }
- };
++    this.registerCursor = function(cursor) {
++      if(cursor.getMemberId() === inputMemberId) {
++        localCursor = cursor;
++        localCursor.getNode().appendChild(compositionElement);
++        eventManager.subscribe("input", synchronizeCompositionText);
++        eventManager.subscribe("compositionupdate", synchronizeCompositionText)
++      }
++    };
++    this.removeCursor = function(memberid) {
++      if(localCursor && memberid === inputMemberId) {
++        localCursor.getNode().removeChild(compositionElement);
++        eventManager.unsubscribe("input", synchronizeCompositionText);
++        eventManager.unsubscribe("compositionupdate", synchronizeCompositionText);
++        localCursor = null
++      }
++    };
++    function suppressFocus() {
++      eventManager.blur();
++      eventTrap.setAttribute("disabled", true)
++    }
++    function synchronizeEventStatus() {
++      var hasFocus = eventManager.hasFocus();
++      if(hasFocus) {
++        eventManager.blur()
++      }
++      if(isEditable) {
++        eventTrap.removeAttribute("disabled")
++      }else {
++        eventTrap.setAttribute("disabled", true)
++      }
++      if(hasFocus) {
++        eventManager.focus()
++      }
++    }
++    this.setEditing = function(editable) {
++      isEditable = editable;
++      synchronizeEventStatus()
++    };
++    this.destroy = function(callback) {
++      eventManager.unsubscribe("compositionstart", compositionStart);
++      eventManager.unsubscribe("compositionend", compositionEnd);
++      eventManager.unsubscribe("textInput", textInput);
++      eventManager.unsubscribe("keypress", flushEvent);
++      eventManager.unsubscribe("mousedown", suppressFocus);
++      eventManager.unsubscribe("mouseup", synchronizeEventStatus);
++      eventManager.unsubscribe("focus", resetWindowSelection);
++      async.destroyAll(cleanup, callback)
++    };
++    function init() {
++      eventManager.subscribe("compositionstart", compositionStart);
++      eventManager.subscribe("compositionend", compositionEnd);
++      eventManager.subscribe("textInput", textInput);
++      eventManager.subscribe("keypress", flushEvent);
++      eventManager.subscribe("mousedown", suppressFocus);
++      eventManager.subscribe("mouseup", synchronizeEventStatus);
++      eventManager.subscribe("focus", resetWindowSelection);
++      filters.push(new DetectSafariCompositionError(eventManager));
++      function getDestroy(filter) {
++        return filter.destroy
++      }
++      cleanup = filters.map(getDestroy);
++      compositionElement = doc.createElement("span");
++      compositionElement.setAttribute("id", "composer");
++      processUpdates = new core.ScheduledTask(resetWindowSelection, 1);
++      cleanup.push(processUpdates.destroy)
++    }
++    init()
++  };
++  gui.InputMethodEditor.signalCompositionStart = "input/compositionstart";
++  gui.InputMethodEditor.signalCompositionEnd = "input/compositionend";
++  return gui.InputMethodEditor
++})();
 +/*
 +
-  Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
++ Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
-  This file is part of WebODF.
++ The JavaScript code in this page is free software: you can redistribute it
++ and/or modify it under the terms of the GNU Affero General Public License
++ (GNU AGPL) as published by the Free Software Foundation, either version 3 of
++ the License, or (at your option) any later version.  The code is distributed
++ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
-  WebODF is free software: you can redistribute it and/or modify it
-  under the terms of the GNU Affero General Public License (GNU AGPL)
-  as published by the Free Software Foundation, either version 3 of
-  the License, or (at your option) any later version.
++ You should have received a copy of the GNU Affero General Public License
++ along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
-  WebODF is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-  GNU Affero General Public License for more details.
++ As additional permission under GNU AGPL version 3 section 7, you
++ may distribute non-source (e.g., minimized or compacted) forms of
++ that code without the copy of the GNU GPL normally required by
++ section 4, provided you include this license notice and a URL
++ through which recipients can access the Corresponding Source.
 +
-  You should have received a copy of the GNU Affero General Public License
-  along with WebODF.  If not, see <http://www.gnu.org/licenses/>.
-  @licend
++ As a special exception to the AGPL, any HTML file which merely makes function
++ calls to this code, and for that purpose includes it by reference shall be
++ deemed a separate work for copyright law purposes. In addition, the copyright
++ holders of this code give you permission to combine this code with free
++ software libraries that are released under the GNU LGPL. You may copy and
++ distribute such a system following the terms of the GNU AGPL for this code
++ and the LGPL for the libraries. If you modify this code, you may extend this
++ exception to your version of the code, but you are not obligated to do so.
++ If you do not wish to do so, delete this exception statement from your
++ version.
 +
++ This license applies to this entire compilation.
++ @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("ops.OperationFactory");
- runtime.loadClass("ops.OperationTransformMatrix");
- ops.OperationTransformer = function OperationTransformer() {
-   var operationFactory, operationTransformMatrix = new ops.OperationTransformMatrix;
-   function operations(opspecs) {
-     var ops = [];
-     opspecs.forEach(function(opspec) {
-       ops.push(operationFactory.create(opspec))
-     });
-     return ops
++gui.KeyboardHandler = function KeyboardHandler() {
++  var modifier = gui.KeyboardHandler.Modifier, defaultBinding = null, bindings = {};
++  function getModifiers(e) {
++    var modifiers = modifier.None;
++    if(e.metaKey) {
++      modifiers |= modifier.Meta
++    }
++    if(e.ctrlKey) {
++      modifiers |= modifier.Ctrl
++    }
++    if(e.altKey) {
++      modifiers |= modifier.Alt
++    }
++    if(e.shiftKey) {
++      modifiers |= modifier.Shift
++    }
++    return modifiers
 +  }
-   function transformOpVsOp(opSpecA, opSpecB) {
-     return operationTransformMatrix.transformOpspecVsOpspec(opSpecA, opSpecB)
++  function getKeyCombo(keyCode, modifiers) {
++    if(!modifiers) {
++      modifiers = modifier.None
++    }
++    return keyCode + ":" + modifiers
 +  }
-   function transformOpListVsOp(opSpecsA, opSpecB) {
-     var transformResult, transformListResult, transformedOpspecsA = [], transformedOpspecsB = [];
-     while(opSpecsA.length > 0 && opSpecB) {
-       transformResult = transformOpVsOp(opSpecsA.shift(), (opSpecB));
-       if(!transformResult) {
-         return null
-       }
-       transformedOpspecsA = transformedOpspecsA.concat(transformResult.opSpecsA);
-       if(transformResult.opSpecsB.length === 0) {
-         transformedOpspecsA = transformedOpspecsA.concat(opSpecsA);
-         opSpecB = null;
-         break
-       }
-       while(transformResult.opSpecsB.length > 1) {
-         transformListResult = transformOpListVsOp(opSpecsA, transformResult.opSpecsB.shift());
-         if(!transformListResult) {
-           return null
-         }
-         transformedOpspecsB = transformedOpspecsB.concat(transformListResult.opSpecsB);
-         opSpecsA = transformListResult.opSpecsA
++  this.setDefault = function(callback) {
++    defaultBinding = callback
++  };
++  this.bind = function(keyCode, modifiers, callback, overwrite) {
++    var keyCombo = getKeyCombo(keyCode, modifiers);
++    runtime.assert(overwrite || bindings.hasOwnProperty(keyCombo) === false, "tried to overwrite the callback handler of key combo: " + keyCombo);
++    bindings[keyCombo] = callback
++  };
++  this.unbind = function(keyCode, modifiers) {
++    var keyCombo = getKeyCombo(keyCode, modifiers);
++    delete bindings[keyCombo]
++  };
++  this.reset = function() {
++    defaultBinding = null;
++    bindings = {}
++  };
++  this.handleEvent = function(e) {
++    var keyCombo = getKeyCombo(e.keyCode, getModifiers(e)), callback = bindings[keyCombo], handled = false;
++    if(callback) {
++      handled = callback()
++    }else {
++      if(defaultBinding !== null) {
++        handled = defaultBinding(e)
 +      }
-       opSpecB = transformResult.opSpecsB.pop()
 +    }
-     if(opSpecB) {
-       transformedOpspecsB.push(opSpecB)
++    if(handled) {
++      if(e.preventDefault) {
++        e.preventDefault()
++      }else {
++        e.returnValue = false
++      }
 +    }
-     return{opSpecsA:transformedOpspecsA, opSpecsB:transformedOpspecsB}
 +  }
-   this.setOperationFactory = function(f) {
-     operationFactory = f
-   };
-   this.getOperationTransformMatrix = function() {
-     return operationTransformMatrix
-   };
-   this.transform = function(opSpecsA, opSpecsB) {
-     var transformResult, transformedOpspecsB = [];
-     while(opSpecsB.length > 0) {
-       transformResult = transformOpListVsOp(opSpecsA, opSpecsB.shift());
-       if(!transformResult) {
-         return null
-       }
-       opSpecsA = transformResult.opSpecsA;
-       transformedOpspecsB = transformedOpspecsB.concat(transformResult.opSpecsB)
-     }
-     return{opsA:operations(opSpecsA), opsB:operations(transformedOpspecsB)}
++};
++gui.KeyboardHandler.Modifier = {None:0, Meta:1, Ctrl:2, Alt:4, CtrlAlt:6, Shift:8, MetaShift:9, CtrlShift:10, AltShift:12};
++gui.KeyboardHandler.KeyCode = {Backspace:8, Tab:9, Clear:12, Enter:13, Ctrl:17, End:35, Home:36, Left:37, Up:38, Right:39, Down:40, Delete:46, A:65, B:66, C:67, D:68, E:69, F:70, G:71, H:72, I:73, J:74, K:75, L:76, M:77, N:78, O:79, P:80, Q:81, R:82, S:83, T:84, U:85, V:86, W:87, X:88, Y:89, Z:90, LeftMeta:91, MetaInMozilla:224};
++(function() {
++  return gui.KeyboardHandler
++})();
++/*
++
++ Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
++
++ @licstart
++ The JavaScript code in this page is free software: you can redistribute it
++ and/or modify it under the terms of the GNU Affero General Public License
++ (GNU AGPL) as published by the Free Software Foundation, either version 3 of
++ the License, or (at your option) any later version.  The code is distributed
++ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
++
++ You should have received a copy of the GNU Affero General Public License
++ along with this code.  If not, see <http://www.gnu.org/licenses/>.
++
++ As additional permission under GNU AGPL version 3 section 7, you
++ may distribute non-source (e.g., minimized or compacted) forms of
++ that code without the copy of the GNU GPL normally required by
++ section 4, provided you include this license notice and a URL
++ through which recipients can access the Corresponding Source.
++
++ As a special exception to the AGPL, any HTML file which merely makes function
++ calls to this code, and for that purpose includes it by reference shall be
++ deemed a separate work for copyright law purposes. In addition, the copyright
++ holders of this code give you permission to combine this code with free
++ software libraries that are released under the GNU LGPL. You may copy and
++ distribute such a system following the terms of the GNU AGPL for this code
++ and the LGPL for the libraries. If you modify this code, you may extend this
++ exception to your version of the code, but you are not obligated to do so.
++ If you do not wish to do so, delete this exception statement from your
++ version.
++
++ This license applies to this entire compilation.
++ @licend
++ @source: http://www.webodf.org/
++ @source: https://github.com/kogmbh/WebODF/
++*/
++gui.PlainTextPasteboard = function PlainTextPasteboard(odtDocument, inputMemberId) {
++  function createOp(op, data) {
++    op.init(data);
++    return op
++  }
++  this.createPasteOps = function(data) {
++    var originalCursorPosition = odtDocument.getCursorPosition(inputMemberId), cursorPosition = originalCursorPosition, operations = [], paragraphs;
++    paragraphs = data.replace(/\r/g, "").split("\n");
++    paragraphs.forEach(function(text) {
++      operations.push(createOp(new ops.OpSplitParagraph, {memberid:inputMemberId, position:cursorPosition, moveCursor:true}));
++      cursorPosition += 1;
++      operations.push(createOp(new ops.OpInsertText, {memberid:inputMemberId, position:cursorPosition, text:text, moveCursor:true}));
++      cursorPosition += text.length
++    });
++    operations.push(createOp(new ops.OpRemoveText, {memberid:inputMemberId, position:originalCursorPosition, length:1}));
++    return operations
 +  }
 +};
 +/*
 +
-  Copyright (C) 2012 KO GmbH <copyright at kogmbh.com>
++ Copyright (C) 2014 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- ops.TrivialOperationRouter = function TrivialOperationRouter() {
-   var operationFactory, playbackFunction;
-   this.setOperationFactory = function(f) {
-     operationFactory = f
-   };
-   this.setPlaybackFunction = function(playback_func) {
-     playbackFunction = playback_func
-   };
-   this.push = function(operations) {
-     operations.forEach(function(op) {
-       var timedOp, opspec = op.spec();
-       opspec.timestamp = (new Date).getTime();
-       timedOp = operationFactory.create(opspec);
-       playbackFunction(timedOp)
-     })
-   };
-   this.close = function(cb) {
-     cb()
-   };
-   this.subscribe = function(eventId, cb) {
-   };
-   this.unsubscribe = function(eventId, cb) {
-   };
-   this.hasLocalUnsyncedOps = function() {
-     return false
-   };
-   this.hasSessionHostConnection = function() {
++odf.WordBoundaryFilter = function WordBoundaryFilter(odtDocument, includeWhitespace) {
++  var TEXT_NODE = Node.TEXT_NODE, ELEMENT_NODE = Node.ELEMENT_NODE, odfUtils = new odf.OdfUtils, punctuation = /[!-#%-*,-\/:-;?-@\[-\]_{}\u00a1\u00ab\u00b7\u00bb\u00bf;\u00b7\u055a-\u055f\u0589-\u058a\u05be\u05c0\u05c3\u05c6\u05f3-\u05f4\u0609-\u060a\u060c-\u060d\u061b\u061e-\u061f\u066a-\u066d\u06d4\u0700-\u070d\u07f7-\u07f9\u0964-\u0965\u0970\u0df4\u0e4f\u0e5a-\u0e5b\u0f04-\u0f12\u0f3a-\u0f3d\u0f85\u0fd0-\u0fd4\u104a-\u104f\u10fb\u1361-\u1368\u166d-\u166e\u169b-\u169c\u16eb-\u16ed\u17 [...]
++  spacing = /\s/, FILTER_ACCEPT = core.PositionFilter.FilterResult.FILTER_ACCEPT, FILTER_REJECT = core.PositionFilter.FilterResult.FILTER_REJECT, TRAILING = odf.WordBoundaryFilter.IncludeWhitespace.TRAILING, LEADING = odf.WordBoundaryFilter.IncludeWhitespace.LEADING, NeighborType = {NO_NEIGHBOUR:0, SPACE_CHAR:1, PUNCTUATION_CHAR:2, WORD_CHAR:3, OTHER:4};
++  function findHigherNeighborNode(node, direction, nodeFilter) {
++    var neighboringNode = null, rootNode = odtDocument.getRootNode(), unfilteredCandidate;
++    while(node !== rootNode && (node !== null && neighboringNode === null)) {
++      unfilteredCandidate = direction < 0 ? node.previousSibling : node.nextSibling;
++      if(nodeFilter(unfilteredCandidate) === NodeFilter.FILTER_ACCEPT) {
++        neighboringNode = unfilteredCandidate
++      }
++      node = node.parentNode
++    }
++    return neighboringNode
++  }
++  function typeOfNeighbor(node, getOffset) {
++    var neighboringChar;
++    if(node === null) {
++      return NeighborType.NO_NEIGHBOUR
++    }
++    if(odfUtils.isCharacterElement(node)) {
++      return NeighborType.SPACE_CHAR
++    }
++    if(node.nodeType === TEXT_NODE || (odfUtils.isTextSpan(node) || odfUtils.isHyperlink(node))) {
++      neighboringChar = node.textContent.charAt(getOffset());
++      if(spacing.test(neighboringChar)) {
++        return NeighborType.SPACE_CHAR
++      }
++      if(punctuation.test(neighboringChar)) {
++        return NeighborType.PUNCTUATION_CHAR
++      }
++      return NeighborType.WORD_CHAR
++    }
++    return NeighborType.OTHER
++  }
++  this.acceptPosition = function(iterator) {
++    var container = iterator.container(), leftNode = iterator.leftNode(), rightNode = iterator.rightNode(), getRightCharOffset = iterator.unfilteredDomOffset, getLeftCharOffset = function() {
++      return iterator.unfilteredDomOffset() - 1
++    }, leftNeighborType, rightNeighborType;
++    if(container.nodeType === ELEMENT_NODE) {
++      if(rightNode === null) {
++        rightNode = findHigherNeighborNode(container, 1, iterator.getNodeFilter())
++      }
++      if(leftNode === null) {
++        leftNode = findHigherNeighborNode(container, -1, iterator.getNodeFilter())
++      }
++    }
++    if(container !== rightNode) {
++      getRightCharOffset = function() {
++        return 0
++      }
++    }
++    if(container !== leftNode && leftNode !== null) {
++      getLeftCharOffset = function() {
++        return leftNode.textContent.length - 1
++      }
++    }
++    leftNeighborType = typeOfNeighbor(leftNode, getLeftCharOffset);
++    rightNeighborType = typeOfNeighbor(rightNode, getRightCharOffset);
++    if(leftNeighborType === NeighborType.WORD_CHAR && rightNeighborType === NeighborType.WORD_CHAR || (leftNeighborType === NeighborType.PUNCTUATION_CHAR && rightNeighborType === NeighborType.PUNCTUATION_CHAR || (includeWhitespace === TRAILING && (leftNeighborType !== NeighborType.NO_NEIGHBOUR && rightNeighborType === NeighborType.SPACE_CHAR) || includeWhitespace === LEADING && (leftNeighborType === NeighborType.SPACE_CHAR && rightNeighborType !== NeighborType.NO_NEIGHBOUR)))) {
++      return FILTER_REJECT
++    }
++    return FILTER_ACCEPT
++  }
++};
++odf.WordBoundaryFilter.IncludeWhitespace = {None:0, TRAILING:1, LEADING:2};
++(function() {
++  return odf.WordBoundaryFilter
++})();
++gui.SelectionController = function SelectionController(session, inputMemberId) {
++  var odtDocument = session.getOdtDocument(), domUtils = new core.DomUtils, odfUtils = new odf.OdfUtils, baseFilter = odtDocument.getPositionFilter(), keyboardMovementsFilter = new core.PositionFilterChain, rootFilter = odtDocument.createRootFilter(inputMemberId), TRAILING_SPACE = odf.WordBoundaryFilter.IncludeWhitespace.TRAILING, LEADING_SPACE = odf.WordBoundaryFilter.IncludeWhitespace.LEADING;
++  function createKeyboardStepIterator() {
++    var cursor = odtDocument.getCursor(inputMemberId), node = cursor.getNode();
++    return odtDocument.createStepIterator(node, 0, [baseFilter, rootFilter], odtDocument.getRootElement(node))
++  }
++  function createWordBoundaryStepIterator(node, offset, includeWhitespace) {
++    var wordBoundaryFilter = new odf.WordBoundaryFilter(odtDocument, includeWhitespace);
++    return odtDocument.createStepIterator(node, offset, [baseFilter, rootFilter, wordBoundaryFilter], odtDocument.getRootElement(node))
++  }
++  function constrain(lookup) {
++    return function(originalNode) {
++      var originalContainer = lookup(originalNode);
++      return function(step, node) {
++        return lookup(node) === originalContainer
++      }
++    }
++  }
++  function selectionToRange(selection) {
++    var hasForwardSelection = domUtils.comparePoints((selection.anchorNode), selection.anchorOffset, (selection.focusNode), selection.focusOffset) >= 0, range = selection.focusNode.ownerDocument.createRange();
++    if(hasForwardSelection) {
++      range.setStart(selection.anchorNode, selection.anchorOffset);
++      range.setEnd(selection.focusNode, selection.focusOffset)
++    }else {
++      range.setStart(selection.focusNode, selection.focusOffset);
++      range.setEnd(selection.anchorNode, selection.anchorOffset)
++    }
++    return{range:range, hasForwardSelection:hasForwardSelection}
++  }
++  this.selectionToRange = selectionToRange;
++  function rangeToSelection(range, hasForwardSelection) {
++    if(hasForwardSelection) {
++      return{anchorNode:(range.startContainer), anchorOffset:range.startOffset, focusNode:(range.endContainer), focusOffset:range.endOffset}
++    }
++    return{anchorNode:(range.endContainer), anchorOffset:range.endOffset, focusNode:(range.startContainer), focusOffset:range.startOffset}
++  }
++  this.rangeToSelection = rangeToSelection;
++  function createOpMoveCursor(position, length, selectionType) {
++    var op = new ops.OpMoveCursor;
++    op.init({memberid:inputMemberId, position:position, length:length || 0, selectionType:selectionType});
++    return op
++  }
++  function selectImage(frameNode) {
++    var frameRoot = odtDocument.getRootElement(frameNode), frameRootFilter = odtDocument.createRootFilter(frameRoot), stepIterator = odtDocument.createStepIterator(frameNode, 0, [frameRootFilter, odtDocument.getPositionFilter()], frameRoot), anchorNode, anchorOffset, newSelection, op;
++    if(!stepIterator.roundToPreviousStep()) {
++      runtime.assert(false, "No walkable position before frame")
++    }
++    anchorNode = stepIterator.container();
++    anchorOffset = stepIterator.offset();
++    stepIterator.setPosition(frameNode, frameNode.childNodes.length);
++    if(!stepIterator.roundToNextStep()) {
++      runtime.assert(false, "No walkable position after frame")
++    }
++    newSelection = odtDocument.convertDomToCursorRange({anchorNode:anchorNode, anchorOffset:anchorOffset, focusNode:stepIterator.container(), focusOffset:stepIterator.offset()});
++    op = createOpMoveCursor(newSelection.position, newSelection.length, ops.OdtCursor.RegionSelection);
++    session.enqueue([op])
++  }
++  this.selectImage = selectImage;
++  function expandToWordBoundaries(range) {
++    var stepIterator;
++    stepIterator = createWordBoundaryStepIterator((range.startContainer), range.startOffset, TRAILING_SPACE);
++    if(stepIterator.roundToPreviousStep()) {
++      range.setStart(stepIterator.container(), stepIterator.offset())
++    }
++    stepIterator = createWordBoundaryStepIterator((range.endContainer), range.endOffset, LEADING_SPACE);
++    if(stepIterator.roundToNextStep()) {
++      range.setEnd(stepIterator.container(), stepIterator.offset())
++    }
++  }
++  this.expandToWordBoundaries = expandToWordBoundaries;
++  function expandToParagraphBoundaries(range) {
++    var paragraphs = odfUtils.getParagraphElements(range), startParagraph = paragraphs[0], endParagraph = paragraphs[paragraphs.length - 1];
++    if(startParagraph) {
++      range.setStart(startParagraph, 0)
++    }
++    if(endParagraph) {
++      if(odfUtils.isParagraph(range.endContainer) && range.endOffset === 0) {
++        range.setEndBefore(endParagraph)
++      }else {
++        range.setEnd(endParagraph, endParagraph.childNodes.length)
++      }
++    }
++  }
++  this.expandToParagraphBoundaries = expandToParagraphBoundaries;
++  function selectRange(range, hasForwardSelection, clickCount) {
++    var canvasElement = odtDocument.getOdfCanvas().getElement(), validSelection, startInsideCanvas, endInsideCanvas, existingSelection, newSelection, op;
++    startInsideCanvas = domUtils.containsNode(canvasElement, range.startContainer);
++    endInsideCanvas = domUtils.containsNode(canvasElement, range.endContainer);
++    if(!startInsideCanvas && !endInsideCanvas) {
++      return
++    }
++    if(startInsideCanvas && endInsideCanvas) {
++      if(clickCount === 2) {
++        expandToWordBoundaries(range)
++      }else {
++        if(clickCount >= 3) {
++          expandToParagraphBoundaries(range)
++        }
++      }
++    }
++    validSelection = rangeToSelection(range, hasForwardSelection);
++    newSelection = odtDocument.convertDomToCursorRange(validSelection, constrain(odfUtils.getParagraphElement));
++    existingSelection = odtDocument.getCursorSelection(inputMemberId);
++    if(newSelection.position !== existingSelection.position || newSelection.length !== existingSelection.length) {
++      op = createOpMoveCursor(newSelection.position, newSelection.length, ops.OdtCursor.RangeSelection);
++      session.enqueue([op])
++    }
++  }
++  this.selectRange = selectRange;
++  function extendCursorByAdjustment(lengthAdjust) {
++    var selection = odtDocument.getCursorSelection(inputMemberId), stepCounter = odtDocument.getCursor(inputMemberId).getStepCounter(), newLength;
++    if(lengthAdjust !== 0) {
++      if(lengthAdjust > 0) {
++        lengthAdjust = stepCounter.convertForwardStepsBetweenFilters(lengthAdjust, keyboardMovementsFilter, baseFilter)
++      }else {
++        lengthAdjust = -stepCounter.convertBackwardStepsBetweenFilters(-lengthAdjust, keyboardMovementsFilter, baseFilter)
++      }
++      newLength = selection.length + lengthAdjust;
++      session.enqueue([createOpMoveCursor(selection.position, newLength)])
++    }
++  }
++  function extendSelection(advanceIterator) {
++    var stepIterator = createKeyboardStepIterator(), anchorNode = odtDocument.getCursor(inputMemberId).getAnchorNode(), newSelection;
++    if(advanceIterator(stepIterator)) {
++      newSelection = odtDocument.convertDomToCursorRange({anchorNode:anchorNode, anchorOffset:0, focusNode:stepIterator.container(), focusOffset:stepIterator.offset()});
++      session.enqueue([createOpMoveCursor(newSelection.position, newSelection.length)])
++    }
++  }
++  function moveCursorByAdjustment(positionAdjust) {
++    var position = odtDocument.getCursorPosition(inputMemberId), stepCounter = odtDocument.getCursor(inputMemberId).getStepCounter();
++    if(positionAdjust !== 0) {
++      positionAdjust = positionAdjust > 0 ? stepCounter.convertForwardStepsBetweenFilters(positionAdjust, keyboardMovementsFilter, baseFilter) : -stepCounter.convertBackwardStepsBetweenFilters(-positionAdjust, keyboardMovementsFilter, baseFilter);
++      position = position + positionAdjust;
++      session.enqueue([createOpMoveCursor(position, 0)])
++    }
++  }
++  function moveCursor(advanceIterator) {
++    var stepIterator = createKeyboardStepIterator(), position;
++    if(advanceIterator(stepIterator)) {
++      position = odtDocument.convertDomPointToCursorStep(stepIterator.container(), stepIterator.offset());
++      session.enqueue([createOpMoveCursor(position, 0)])
++    }
++  }
++  function moveCursorToLeft() {
++    moveCursor(function(iterator) {
++      return iterator.previousStep()
++    });
++    return true
++  }
++  this.moveCursorToLeft = moveCursorToLeft;
++  function moveCursorToRight() {
++    moveCursor(function(iterator) {
++      return iterator.nextStep()
++    });
++    return true
++  }
++  this.moveCursorToRight = moveCursorToRight;
++  function extendSelectionToLeft() {
++    extendSelection(function(iterator) {
++      return iterator.previousStep()
++    });
++    return true
++  }
++  this.extendSelectionToLeft = extendSelectionToLeft;
++  function extendSelectionToRight() {
++    extendSelection(function(iterator) {
++      return iterator.nextStep()
++    });
++    return true
++  }
++  this.extendSelectionToRight = extendSelectionToRight;
++  function moveCursorByLine(direction, extend) {
++    var paragraphNode = odtDocument.getParagraphElement(odtDocument.getCursor(inputMemberId).getNode()), steps;
++    runtime.assert(Boolean(paragraphNode), "SelectionController: Cursor outside paragraph");
++    steps = odtDocument.getCursor(inputMemberId).getStepCounter().countLinesSteps(direction, keyboardMovementsFilter);
++    if(extend) {
++      extendCursorByAdjustment(steps)
++    }else {
++      moveCursorByAdjustment(steps)
++    }
++  }
++  function moveCursorUp() {
++    moveCursorByLine(-1, false);
++    return true
++  }
++  this.moveCursorUp = moveCursorUp;
++  function moveCursorDown() {
++    moveCursorByLine(1, false);
++    return true
++  }
++  this.moveCursorDown = moveCursorDown;
++  function extendSelectionUp() {
++    moveCursorByLine(-1, true);
++    return true
++  }
++  this.extendSelectionUp = extendSelectionUp;
++  function extendSelectionDown() {
++    moveCursorByLine(1, true);
++    return true
++  }
++  this.extendSelectionDown = extendSelectionDown;
++  function moveCursorToLineBoundary(direction, extend) {
++    var steps = odtDocument.getCursor(inputMemberId).getStepCounter().countStepsToLineBoundary(direction, keyboardMovementsFilter);
++    if(extend) {
++      extendCursorByAdjustment(steps)
++    }else {
++      moveCursorByAdjustment(steps)
++    }
++  }
++  function moveCursorByWord(direction, extend) {
++    var cursor = odtDocument.getCursor(inputMemberId), newSelection = rangeToSelection(cursor.getSelectedRange(), cursor.hasForwardSelection()), newCursorSelection, selectionUpdated, stepIterator = createWordBoundaryStepIterator(newSelection.focusNode, newSelection.focusOffset, TRAILING_SPACE);
++    if(direction >= 0) {
++      selectionUpdated = stepIterator.nextStep()
++    }else {
++      selectionUpdated = stepIterator.previousStep()
++    }
++    if(selectionUpdated) {
++      newSelection.focusNode = stepIterator.container();
++      newSelection.focusOffset = stepIterator.offset();
++      if(!extend) {
++        newSelection.anchorNode = newSelection.focusNode;
++        newSelection.anchorOffset = newSelection.focusOffset
++      }
++      newCursorSelection = odtDocument.convertDomToCursorRange(newSelection);
++      session.enqueue([createOpMoveCursor(newCursorSelection.position, newCursorSelection.length)])
++    }
++  }
++  function moveCursorBeforeWord() {
++    moveCursorByWord(-1, false);
++    return true
++  }
++  this.moveCursorBeforeWord = moveCursorBeforeWord;
++  function moveCursorPastWord() {
++    moveCursorByWord(1, false);
++    return true
++  }
++  this.moveCursorPastWord = moveCursorPastWord;
++  function extendSelectionBeforeWord() {
++    moveCursorByWord(-1, true);
++    return true
++  }
++  this.extendSelectionBeforeWord = extendSelectionBeforeWord;
++  function extendSelectionPastWord() {
++    moveCursorByWord(1, true);
++    return true
++  }
++  this.extendSelectionPastWord = extendSelectionPastWord;
++  function moveCursorToLineStart() {
++    moveCursorToLineBoundary(-1, false);
++    return true
++  }
++  this.moveCursorToLineStart = moveCursorToLineStart;
++  function moveCursorToLineEnd() {
++    moveCursorToLineBoundary(1, false);
++    return true
++  }
++  this.moveCursorToLineEnd = moveCursorToLineEnd;
++  function extendSelectionToLineStart() {
++    moveCursorToLineBoundary(-1, true);
++    return true
++  }
++  this.extendSelectionToLineStart = extendSelectionToLineStart;
++  function extendSelectionToLineEnd() {
++    moveCursorToLineBoundary(1, true);
++    return true
++  }
++  this.extendSelectionToLineEnd = extendSelectionToLineEnd;
++  function extendCursorToNodeBoundary(direction, getContainmentNode) {
++    var cursor = odtDocument.getCursor(inputMemberId), node = getContainmentNode(cursor.getNode()), selection = rangeToSelection(cursor.getSelectedRange(), cursor.hasForwardSelection()), newCursorSelection;
++    runtime.assert(Boolean(node), "SelectionController: Cursor outside root");
++    if(direction < 0) {
++      selection.focusNode = (node);
++      selection.focusOffset = 0
++    }else {
++      selection.focusNode = (node);
++      selection.focusOffset = node.childNodes.length
++    }
++    newCursorSelection = odtDocument.convertDomToCursorRange(selection, constrain(getContainmentNode));
++    session.enqueue([createOpMoveCursor(newCursorSelection.position, newCursorSelection.length)])
++  }
++  function extendSelectionToParagraphStart() {
++    extendCursorToNodeBoundary(-1, odtDocument.getParagraphElement);
++    return true
++  }
++  this.extendSelectionToParagraphStart = extendSelectionToParagraphStart;
++  function extendSelectionToParagraphEnd() {
++    extendCursorToNodeBoundary(1, odtDocument.getParagraphElement);
++    return true
++  }
++  this.extendSelectionToParagraphEnd = extendSelectionToParagraphEnd;
++  function moveCursorToRootBoundary(direction) {
++    var cursor = odtDocument.getCursor(inputMemberId), root = odtDocument.getRootElement(cursor.getNode()), newPosition;
++    runtime.assert(Boolean(root), "SelectionController: Cursor outside root");
++    if(direction < 0) {
++      newPosition = odtDocument.convertDomPointToCursorStep(root, 0, function(step) {
++        return step === ops.StepsTranslator.NEXT_STEP
++      })
++    }else {
++      newPosition = odtDocument.convertDomPointToCursorStep(root, root.childNodes.length)
++    }
++    session.enqueue([createOpMoveCursor(newPosition, 0)]);
++    return true
++  }
++  function moveCursorToDocumentStart() {
++    moveCursorToRootBoundary(-1);
++    return true
++  }
++  this.moveCursorToDocumentStart = moveCursorToDocumentStart;
++  function moveCursorToDocumentEnd() {
++    moveCursorToRootBoundary(1);
++    return true
++  }
++  this.moveCursorToDocumentEnd = moveCursorToDocumentEnd;
++  function extendSelectionToDocumentStart() {
++    extendCursorToNodeBoundary(-1, odtDocument.getRootElement);
 +    return true
 +  }
++  this.extendSelectionToDocumentStart = extendSelectionToDocumentStart;
++  function extendSelectionToDocumentEnd() {
++    extendCursorToNodeBoundary(1, odtDocument.getRootElement);
++    return true
++  }
++  this.extendSelectionToDocumentEnd = extendSelectionToDocumentEnd;
++  function extendSelectionToEntireDocument() {
++    var cursor = odtDocument.getCursor(inputMemberId), root = odtDocument.getRootElement(cursor.getNode()), newSelection, newCursorSelection;
++    runtime.assert(Boolean(root), "SelectionController: Cursor outside root");
++    newSelection = {anchorNode:root, anchorOffset:0, focusNode:root, focusOffset:root.childNodes.length};
++    newCursorSelection = odtDocument.convertDomToCursorRange(newSelection, constrain(odtDocument.getRootElement));
++    session.enqueue([createOpMoveCursor(newCursorSelection.position, newCursorSelection.length)]);
++    return true
++  }
++  this.extendSelectionToEntireDocument = extendSelectionToEntireDocument;
++  function init() {
++    keyboardMovementsFilter.addFilter(baseFilter);
++    keyboardMovementsFilter.addFilter(odtDocument.createRootFilter(inputMemberId))
++  }
++  init()
 +};
 +/*
 +
-  Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
++ Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("ops.EditInfo");
- runtime.loadClass("gui.EditInfoHandle");
- gui.EditInfoMarker = function EditInfoMarker(editInfo, initialVisibility) {
-   var self = this, editInfoNode, handle, marker, editinfons = "urn:webodf:names:editinfo", decay1, decay2, decayTimeStep = 1E4;
-   function applyDecay(opacity, delay) {
-     return runtime.setTimeout(function() {
-       marker.style.opacity = opacity
-     }, delay)
-   }
-   function deleteDecay(timer) {
-     runtime.clearTimeout(timer)
++gui.TextController = function TextController(session, inputMemberId, directStyleOp, paragraphStyleOps) {
++  var odtDocument = session.getOdtDocument(), FILTER_ACCEPT = core.PositionFilter.FilterResult.FILTER_ACCEPT;
++  function createOpRemoveSelection(selection) {
++    var op = new ops.OpRemoveText;
++    op.init({memberid:inputMemberId, position:selection.position, length:selection.length});
++    return op
 +  }
-   function setLastAuthor(memberid) {
-     marker.setAttributeNS(editinfons, "editinfo:memberid", memberid)
++  function toForwardSelection(selection) {
++    if(selection.length < 0) {
++      selection.position += selection.length;
++      selection.length = -selection.length
++    }
++    return selection
 +  }
-   this.addEdit = function(memberid, timestamp) {
-     var age = Date.now() - timestamp;
-     editInfo.addEdit(memberid, timestamp);
-     handle.setEdits(editInfo.getSortedEdits());
-     setLastAuthor(memberid);
-     if(decay1) {
-       deleteDecay(decay1)
++  this.enqueueParagraphSplittingOps = function() {
++    var selection = toForwardSelection(odtDocument.getCursorSelection(inputMemberId)), op, operations = [], styleOps;
++    if(selection.length > 0) {
++      op = createOpRemoveSelection(selection);
++      operations.push(op)
++    }
++    op = new ops.OpSplitParagraph;
++    op.init({memberid:inputMemberId, position:selection.position, moveCursor:true});
++    operations.push(op);
++    if(paragraphStyleOps) {
++      styleOps = paragraphStyleOps(selection.position + 1);
++      operations = operations.concat(styleOps)
 +    }
-     if(decay2) {
-       deleteDecay(decay2)
++    session.enqueue(operations);
++    return true
++  };
++  function hasPositionInDirection(cursorNode, forward) {
++    var rootConstrainedFilter = new core.PositionFilterChain, iterator = gui.SelectionMover.createPositionIterator(odtDocument.getRootElement(cursorNode)), nextPosition = (forward ? iterator.nextPosition : iterator.previousPosition);
++    rootConstrainedFilter.addFilter(odtDocument.getPositionFilter());
++    rootConstrainedFilter.addFilter(odtDocument.createRootFilter(inputMemberId));
++    iterator.setUnfilteredPosition(cursorNode, 0);
++    while(nextPosition()) {
++      if(rootConstrainedFilter.acceptPosition(iterator) === FILTER_ACCEPT) {
++        return true
++      }
 +    }
-     if(age < decayTimeStep) {
-       applyDecay(1, 0);
-       decay1 = applyDecay(0.5, decayTimeStep - age);
-       decay2 = applyDecay(0.2, decayTimeStep * 2 - age)
-     }else {
-       if(age >= decayTimeStep && age < decayTimeStep * 2) {
-         applyDecay(0.5, 0);
-         decay2 = applyDecay(0.2, decayTimeStep * 2 - age)
-       }else {
-         applyDecay(0.2, 0)
++    return false
++  }
++  this.removeTextByBackspaceKey = function() {
++    var cursor = odtDocument.getCursor(inputMemberId), selection = toForwardSelection(odtDocument.getCursorSelection(inputMemberId)), op = null;
++    if(selection.length === 0) {
++      if(hasPositionInDirection(cursor.getNode(), false)) {
++        op = new ops.OpRemoveText;
++        op.init({memberid:inputMemberId, position:selection.position - 1, length:1});
++        session.enqueue([op])
 +      }
++    }else {
++      op = createOpRemoveSelection(selection);
++      session.enqueue([op])
 +    }
++    return op !== null
 +  };
-   this.getEdits = function() {
-     return editInfo.getEdits()
-   };
-   this.clearEdits = function() {
-     editInfo.clearEdits();
-     handle.setEdits([]);
-     if(marker.hasAttributeNS(editinfons, "editinfo:memberid")) {
-       marker.removeAttributeNS(editinfons, "editinfo:memberid")
++  this.removeTextByDeleteKey = function() {
++    var cursor = odtDocument.getCursor(inputMemberId), selection = toForwardSelection(odtDocument.getCursorSelection(inputMemberId)), op = null;
++    if(selection.length === 0) {
++      if(hasPositionInDirection(cursor.getNode(), true)) {
++        op = new ops.OpRemoveText;
++        op.init({memberid:inputMemberId, position:selection.position, length:1});
++        session.enqueue([op])
++      }
++    }else {
++      op = createOpRemoveSelection(selection);
++      session.enqueue([op])
 +    }
++    return op !== null
 +  };
-   this.getEditInfo = function() {
-     return editInfo
-   };
-   this.show = function() {
-     marker.style.display = "block"
-   };
-   this.hide = function() {
-     self.hideHandle();
-     marker.style.display = "none"
-   };
-   this.showHandle = function() {
-     handle.show()
-   };
-   this.hideHandle = function() {
-     handle.hide()
++  this.removeCurrentSelection = function() {
++    var selection = toForwardSelection(odtDocument.getCursorSelection(inputMemberId)), op;
++    if(selection.length !== 0) {
++      op = createOpRemoveSelection(selection);
++      session.enqueue([op])
++    }
++    return true
 +  };
-   this.destroy = function(callback) {
-     editInfoNode.removeChild(marker);
-     handle.destroy(function(err) {
-       if(err) {
-         callback(err)
-       }else {
-         editInfo.destroy(callback)
++  function insertText(text) {
++    var selection = toForwardSelection(odtDocument.getCursorSelection(inputMemberId)), op, stylingOp, operations = [], useCachedStyle = false;
++    if(selection.length > 0) {
++      op = createOpRemoveSelection(selection);
++      operations.push(op);
++      useCachedStyle = true
++    }
++    op = new ops.OpInsertText;
++    op.init({memberid:inputMemberId, position:selection.position, text:text, moveCursor:true});
++    operations.push(op);
++    if(directStyleOp) {
++      stylingOp = directStyleOp(selection.position, text.length, useCachedStyle);
++      if(stylingOp) {
++        operations.push(stylingOp)
 +      }
-     })
-   };
-   function init() {
-     var dom = editInfo.getOdtDocument().getDOM(), htmlns = dom.documentElement.namespaceURI;
-     marker = dom.createElementNS(htmlns, "div");
-     marker.setAttribute("class", "editInfoMarker");
-     marker.onmouseover = function() {
-       self.showHandle()
-     };
-     marker.onmouseout = function() {
-       self.hideHandle()
-     };
-     editInfoNode = editInfo.getNode();
-     editInfoNode.appendChild(marker);
-     handle = new gui.EditInfoHandle(editInfoNode);
-     if(!initialVisibility) {
-       self.hide()
 +    }
++    session.enqueue(operations)
 +  }
-   init()
++  this.insertText = insertText
 +};
++(function() {
++  return gui.TextController
++})();
 +/*
 +
 + Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- gui.PlainTextPasteboard = function PlainTextPasteboard(odtDocument, inputMemberId) {
-   function createOp(op, data) {
-     op.init(data);
-     return op
-   }
-   this.createPasteOps = function(data) {
-     var originalCursorPosition = odtDocument.getCursorPosition(inputMemberId), cursorPosition = originalCursorPosition, operations = [], paragraphs;
-     paragraphs = data.replace(/\r/g, "").split("\n");
-     paragraphs.forEach(function(text) {
-       operations.push(createOp(new ops.OpSplitParagraph, {memberid:inputMemberId, position:cursorPosition, moveCursor:true}));
-       cursorPosition += 1;
-       operations.push(createOp(new ops.OpInsertText, {memberid:inputMemberId, position:cursorPosition, text:text, moveCursor:true}));
-       cursorPosition += text.length
-     });
-     operations.push(createOp(new ops.OpRemoveText, {memberid:inputMemberId, position:originalCursorPosition, length:1}));
-     return operations
-   }
++gui.UndoManager = function UndoManager() {
 +};
- runtime.loadClass("core.DomUtils");
- runtime.loadClass("odf.OdfUtils");
- runtime.loadClass("odf.OdfNodeFilter");
- runtime.loadClass("gui.SelectionMover");
- gui.SelectionView = function SelectionView(cursor) {
-   var odtDocument = cursor.getOdtDocument(), documentRoot, root, doc = odtDocument.getDOM(), overlayTop = doc.createElement("div"), overlayMiddle = doc.createElement("div"), overlayBottom = doc.createElement("div"), odfUtils = new odf.OdfUtils, domUtils = new core.DomUtils, isVisible = true, positionIterator = gui.SelectionMover.createPositionIterator(odtDocument.getRootNode()), FILTER_ACCEPT = NodeFilter.FILTER_ACCEPT, FILTER_REJECT = NodeFilter.FILTER_REJECT;
-   function addOverlays() {
-     var newDocumentRoot = odtDocument.getRootNode();
-     if(documentRoot !== newDocumentRoot) {
-       documentRoot = newDocumentRoot;
-       root = (documentRoot.parentNode.parentNode.parentNode);
-       root.appendChild(overlayTop);
-       root.appendChild(overlayMiddle);
-       root.appendChild(overlayBottom)
++gui.UndoManager.prototype.subscribe = function(signal, callback) {
++};
++gui.UndoManager.prototype.unsubscribe = function(signal, callback) {
++};
++gui.UndoManager.prototype.setDocument = function(newDocument) {
++};
++gui.UndoManager.prototype.setInitialState = function() {
++};
++gui.UndoManager.prototype.initialize = function() {
++};
++gui.UndoManager.prototype.purgeInitialState = function() {
++};
++gui.UndoManager.prototype.setPlaybackFunction = function(playback_func) {
++};
++gui.UndoManager.prototype.hasUndoStates = function() {
++};
++gui.UndoManager.prototype.hasRedoStates = function() {
++};
++gui.UndoManager.prototype.moveForward = function(states) {
++};
++gui.UndoManager.prototype.moveBackward = function(states) {
++};
++gui.UndoManager.prototype.onOperationExecuted = function(op) {
++};
++gui.UndoManager.signalUndoStackChanged = "undoStackChanged";
++gui.UndoManager.signalUndoStateCreated = "undoStateCreated";
++gui.UndoManager.signalUndoStateModified = "undoStateModified";
++(function() {
++  return gui.UndoManager
++})();
++(function() {
++  var FILTER_ACCEPT = core.PositionFilter.FilterResult.FILTER_ACCEPT;
++  gui.SessionController = function SessionController(session, inputMemberId, shadowCursor, args) {
++    var window = (runtime.getWindow()), odtDocument = session.getOdtDocument(), async = new core.Async, domUtils = new core.DomUtils, odfUtils = new odf.OdfUtils, mimeDataExporter = new gui.MimeDataExporter, clipboard = new gui.Clipboard(mimeDataExporter), keyDownHandler = new gui.KeyboardHandler, keyPressHandler = new gui.KeyboardHandler, keyUpHandler = new gui.KeyboardHandler, clickStartedWithinCanvas = false, objectNameGenerator = new odf.ObjectNameGenerator(odtDocument.getOdfCanvas( [...]
++    inputMemberId), isMouseMoved = false, mouseDownRootFilter = null, handleMouseClickTimeoutId, undoManager = null, eventManager = new gui.EventManager(odtDocument), annotationController = new gui.AnnotationController(session, inputMemberId), directFormattingController = new gui.DirectFormattingController(session, inputMemberId, objectNameGenerator, args.directParagraphStylingEnabled), createCursorStyleOp = (directFormattingController.createCursorStyleOp), createParagraphStyleOps = (di [...]
++    textController = new gui.TextController(session, inputMemberId, createCursorStyleOp, createParagraphStyleOps), imageController = new gui.ImageController(session, inputMemberId, objectNameGenerator), imageSelector = new gui.ImageSelector(odtDocument.getOdfCanvas()), shadowCursorIterator = gui.SelectionMover.createPositionIterator(odtDocument.getRootNode()), drawShadowCursorTask, redrawRegionSelectionTask, pasteHandler = new gui.PlainTextPasteboard(odtDocument, inputMemberId), inputMe [...]
++    new gui.InputMethodEditor(inputMemberId, eventManager), clickCount = 0, hyperlinkClickHandler = new gui.HyperlinkClickHandler(odtDocument.getRootNode), hyperlinkController = new gui.HyperlinkController(session, inputMemberId), selectionController = new gui.SelectionController(session, inputMemberId), modifier = gui.KeyboardHandler.Modifier, keyCode = gui.KeyboardHandler.KeyCode, isMacOS = window.navigator.appVersion.toLowerCase().indexOf("mac") !== -1, isIOS = ["iPad", "iPod", "iPho [...]
++    -1, iOSSafariSupport;
++    runtime.assert(window !== null, "Expected to be run in an environment which has a global window, like a browser.");
++    function getTarget(e) {
++      return(e.target) || (e.srcElement || null)
++    }
++    function cancelEvent(event) {
++      if(event.preventDefault) {
++        event.preventDefault()
++      }else {
++        event.returnValue = false
++      }
++    }
++    function caretPositionFromPoint(x, y) {
++      var doc = odtDocument.getDOMDocument(), c, result = null;
++      if(doc.caretRangeFromPoint) {
++        c = doc.caretRangeFromPoint(x, y);
++        result = {container:(c.startContainer), offset:c.startOffset}
++      }else {
++        if(doc.caretPositionFromPoint) {
++          c = doc.caretPositionFromPoint(x, y);
++          if(c && c.offsetNode) {
++            result = {container:c.offsetNode, offset:c.offset}
++          }
++        }
++      }
++      return result
++    }
++    function redrawRegionSelection() {
++      var cursor = odtDocument.getCursor(inputMemberId), imageElement;
++      if(cursor && cursor.getSelectionType() === ops.OdtCursor.RegionSelection) {
++        imageElement = odfUtils.getImageElements(cursor.getSelectedRange())[0];
++        if(imageElement) {
++          imageSelector.select((imageElement.parentNode));
++          return
++        }
++      }
++      imageSelector.clearSelection()
++    }
++    function stringFromKeyPress(event) {
++      if(event.which === null || event.which === undefined) {
++        return String.fromCharCode(event.keyCode)
++      }
++      if(event.which !== 0 && event.charCode !== 0) {
++        return String.fromCharCode(event.which)
++      }
++      return null
++    }
++    function handleCut(e) {
++      var cursor = odtDocument.getCursor(inputMemberId), selectedRange = cursor.getSelectedRange();
++      if(selectedRange.collapsed) {
++        e.preventDefault();
++        return
++      }
++      if(clipboard.setDataFromRange(e, selectedRange)) {
++        textController.removeCurrentSelection()
++      }else {
++        runtime.log("Cut operation failed")
++      }
++    }
++    function handleBeforeCut() {
++      var cursor = odtDocument.getCursor(inputMemberId), selectedRange = cursor.getSelectedRange();
++      return selectedRange.collapsed !== false
++    }
++    function handleCopy(e) {
++      var cursor = odtDocument.getCursor(inputMemberId), selectedRange = cursor.getSelectedRange();
++      if(selectedRange.collapsed) {
++        e.preventDefault();
++        return
++      }
++      if(!clipboard.setDataFromRange(e, selectedRange)) {
++        runtime.log("Copy operation failed")
++      }
++    }
++    function handlePaste(e) {
++      var plainText;
++      if(window.clipboardData && window.clipboardData.getData) {
++        plainText = window.clipboardData.getData("Text")
++      }else {
++        if(e.clipboardData && e.clipboardData.getData) {
++          plainText = e.clipboardData.getData("text/plain")
++        }
++      }
++      if(plainText) {
++        textController.removeCurrentSelection();
++        session.enqueue(pasteHandler.createPasteOps(plainText))
++      }
++      cancelEvent(e)
++    }
++    function handleBeforePaste() {
++      return false
++    }
++    function updateUndoStack(op) {
++      if(undoManager) {
++        undoManager.onOperationExecuted(op)
++      }
++    }
++    function forwardUndoStackChange(e) {
++      odtDocument.emit(ops.OdtDocument.signalUndoStackChanged, e)
++    }
++    function undo() {
++      var eventTrap = eventManager.getEventTrap(), sizer, hadFocusBefore;
++      if(undoManager) {
++        hadFocusBefore = eventManager.hasFocus();
++        undoManager.moveBackward(1);
++        sizer = odtDocument.getOdfCanvas().getSizer();
++        if(!domUtils.containsNode(sizer, eventTrap)) {
++          sizer.appendChild(eventTrap);
++          if(hadFocusBefore) {
++            eventManager.focus()
++          }
++        }
++        return true
++      }
++      return false
++    }
++    this.undo = undo;
++    function redo() {
++      var hadFocusBefore;
++      if(undoManager) {
++        hadFocusBefore = eventManager.hasFocus();
++        undoManager.moveForward(1);
++        if(hadFocusBefore) {
++          eventManager.focus()
++        }
++        return true
++      }
++      return false
 +    }
-   }
-   function setRect(div, rect) {
-     div.style.left = rect.left + "px";
-     div.style.top = rect.top + "px";
-     div.style.width = rect.width + "px";
-     div.style.height = rect.height + "px"
-   }
-   function showOverlays(choice) {
-     var display;
-     isVisible = choice;
-     display = choice === true ? "block" : "none";
-     overlayTop.style.display = overlayMiddle.style.display = overlayBottom.style.display = display
-   }
-   function translateRect(rect) {
-     var rootRect = domUtils.getBoundingClientRect(root), zoomLevel = odtDocument.getOdfCanvas().getZoomLevel(), resultRect = {};
-     resultRect.top = domUtils.adaptRangeDifferenceToZoomLevel(rect.top - rootRect.top, zoomLevel);
-     resultRect.left = domUtils.adaptRangeDifferenceToZoomLevel(rect.left - rootRect.left, zoomLevel);
-     resultRect.bottom = domUtils.adaptRangeDifferenceToZoomLevel(rect.bottom - rootRect.top, zoomLevel);
-     resultRect.right = domUtils.adaptRangeDifferenceToZoomLevel(rect.right - rootRect.left, zoomLevel);
-     resultRect.width = domUtils.adaptRangeDifferenceToZoomLevel(rect.width, zoomLevel);
-     resultRect.height = domUtils.adaptRangeDifferenceToZoomLevel(rect.height, zoomLevel);
-     return resultRect
-   }
-   function isRangeVisible(range) {
-     var bcr = range.getBoundingClientRect();
-     return Boolean(bcr && bcr.height !== 0)
-   }
-   function lastVisibleRect(range, nodes) {
-     var nextNodeIndex = nodes.length - 1, node = nodes[nextNodeIndex], startOffset = range.endContainer === node ? range.endOffset : node.length || node.childNodes.length, endOffset = startOffset;
-     range.setStart(node, startOffset);
-     range.setEnd(node, endOffset);
-     while(!isRangeVisible(range)) {
-       if(node.nodeType === Node.ELEMENT_NODE && startOffset > 0) {
-         startOffset = 0
-       }else {
-         if(node.nodeType === Node.TEXT_NODE && startOffset > 0) {
-           startOffset -= 1
-         }else {
-           if(nodes[nextNodeIndex]) {
-             node = nodes[nextNodeIndex];
-             nextNodeIndex -= 1;
-             startOffset = endOffset = node.length || node.childNodes.length
++    this.redo = redo;
++    function extendSelectionByDrag(event) {
++      var position, cursor = odtDocument.getCursor(inputMemberId), selectedRange = cursor.getSelectedRange(), newSelectionRange, handleEnd = (getTarget(event)).getAttribute("end");
++      if(selectedRange && handleEnd) {
++        position = caretPositionFromPoint(event.clientX, event.clientY);
++        if(position) {
++          shadowCursorIterator.setUnfilteredPosition(position.container, position.offset);
++          if(mouseDownRootFilter.acceptPosition(shadowCursorIterator) === FILTER_ACCEPT) {
++            newSelectionRange = (selectedRange.cloneRange());
++            if(handleEnd === "left") {
++              newSelectionRange.setStart(shadowCursorIterator.container(), shadowCursorIterator.unfilteredDomOffset())
++            }else {
++              newSelectionRange.setEnd(shadowCursorIterator.container(), shadowCursorIterator.unfilteredDomOffset())
++            }
++            shadowCursor.setSelectedRange(newSelectionRange, handleEnd === "right");
++            odtDocument.emit(ops.Document.signalCursorMoved, shadowCursor)
++          }
++        }
++      }
++    }
++    function updateCursorSelection() {
++      selectionController.selectRange(shadowCursor.getSelectedRange(), shadowCursor.hasForwardSelection(), 1)
++    }
++    function updateShadowCursor() {
++      var selection = window.getSelection(), selectionRange = selection.rangeCount > 0 && selectionController.selectionToRange(selection);
++      if(clickStartedWithinCanvas && selectionRange) {
++        isMouseMoved = true;
++        imageSelector.clearSelection();
++        shadowCursorIterator.setUnfilteredPosition((selection.focusNode), selection.focusOffset);
++        if(mouseDownRootFilter.acceptPosition(shadowCursorIterator) === FILTER_ACCEPT) {
++          if(clickCount === 2) {
++            selectionController.expandToWordBoundaries(selectionRange.range)
 +          }else {
-             return false
++            if(clickCount >= 3) {
++              selectionController.expandToParagraphBoundaries(selectionRange.range)
++            }
 +          }
++          shadowCursor.setSelectedRange(selectionRange.range, selectionRange.hasForwardSelection);
++          odtDocument.emit(ops.Document.signalCursorMoved, shadowCursor)
 +        }
 +      }
-       range.setStart(node, startOffset);
-       range.setEnd(node, endOffset)
 +    }
-     return true
-   }
-   function firstVisibleRect(range, nodes) {
-     var nextNodeIndex = 0, node = nodes[nextNodeIndex], startOffset = range.startContainer === node ? range.startOffset : 0, endOffset = startOffset;
-     range.setStart(node, startOffset);
-     range.setEnd(node, endOffset);
-     while(!isRangeVisible(range)) {
-       if(node.nodeType === Node.ELEMENT_NODE && endOffset < node.childNodes.length) {
-         endOffset = node.childNodes.length
++    function synchronizeWindowSelection(cursor) {
++      var selection = window.getSelection(), range = cursor.getSelectedRange();
++      if(selection.extend) {
++        if(cursor.hasForwardSelection()) {
++          selection.collapse(range.startContainer, range.startOffset);
++          selection.extend(range.endContainer, range.endOffset)
++        }else {
++          selection.collapse(range.endContainer, range.endOffset);
++          selection.extend(range.startContainer, range.startOffset)
++        }
 +      }else {
-         if(node.nodeType === Node.TEXT_NODE && endOffset < node.length) {
-           endOffset += 1
++        selection.removeAllRanges();
++        selection.addRange(range.cloneRange())
++      }
++    }
++    function handleMouseDown(e) {
++      var target = getTarget(e), cursor = odtDocument.getCursor(inputMemberId);
++      clickStartedWithinCanvas = target !== null && domUtils.containsNode(odtDocument.getOdfCanvas().getElement(), target);
++      if(clickStartedWithinCanvas) {
++        isMouseMoved = false;
++        mouseDownRootFilter = odtDocument.createRootFilter((target));
++        clickCount = e.detail;
++        if(cursor && e.shiftKey) {
++          window.getSelection().collapse(cursor.getAnchorNode(), 0)
 +        }else {
-           if(nodes[nextNodeIndex]) {
-             node = nodes[nextNodeIndex];
-             nextNodeIndex += 1;
-             startOffset = endOffset = 0
-           }else {
-             return false
-           }
++          synchronizeWindowSelection(cursor)
++        }
++        if(clickCount > 1) {
++          updateShadowCursor()
 +        }
 +      }
-       range.setStart(node, startOffset);
-       range.setEnd(node, endOffset)
 +    }
-     return true
-   }
-   function getExtremeRanges(range) {
-     var nodes = odfUtils.getTextElements(range, true, false), firstRange = (range.cloneRange()), lastRange = (range.cloneRange()), fillerRange = range.cloneRange();
-     if(!nodes.length) {
++    function mutableSelection(selection) {
++      if(selection) {
++        return{anchorNode:selection.anchorNode, anchorOffset:selection.anchorOffset, focusNode:selection.focusNode, focusOffset:selection.focusOffset}
++      }
 +      return null
 +    }
-     if(!firstVisibleRect(firstRange, nodes)) {
-       return null
++    function getNextWalkablePosition(node) {
++      var root = odtDocument.getRootElement(node), rootFilter = odtDocument.createRootFilter(root), stepIterator = odtDocument.createStepIterator(node, 0, [rootFilter, odtDocument.getPositionFilter()], root);
++      stepIterator.setPosition(node, node.childNodes.length);
++      if(!stepIterator.roundToNextStep()) {
++        return null
++      }
++      return{container:stepIterator.container(), offset:stepIterator.offset()}
++    }
++    function moveByMouseClickEvent(event) {
++      var selection = mutableSelection(window.getSelection()), position, selectionRange, rect, frameNode;
++      if(!selection.anchorNode && !selection.focusNode) {
++        position = caretPositionFromPoint(event.clientX, event.clientY);
++        if(position) {
++          selection.anchorNode = (position.container);
++          selection.anchorOffset = position.offset;
++          selection.focusNode = selection.anchorNode;
++          selection.focusOffset = selection.anchorOffset
++        }
++      }
++      if(odfUtils.isImage(selection.focusNode) && (selection.focusOffset === 0 && odfUtils.isCharacterFrame(selection.focusNode.parentNode))) {
++        frameNode = (selection.focusNode.parentNode);
++        rect = frameNode.getBoundingClientRect();
++        if(event.clientX > rect.right) {
++          position = getNextWalkablePosition(frameNode);
++          if(position) {
++            selection.anchorNode = selection.focusNode = position.container;
++            selection.anchorOffset = selection.focusOffset = position.offset
++          }
++        }
++      }else {
++        if(odfUtils.isImage(selection.focusNode.firstChild) && (selection.focusOffset === 1 && odfUtils.isCharacterFrame(selection.focusNode))) {
++          position = getNextWalkablePosition(selection.focusNode);
++          if(position) {
++            selection.anchorNode = selection.focusNode = position.container;
++            selection.anchorOffset = selection.focusOffset = position.offset
++          }
++        }
++      }
++      if(selection.anchorNode && selection.focusNode) {
++        selectionRange = selectionController.selectionToRange(selection);
++        selectionController.selectRange(selectionRange.range, selectionRange.hasForwardSelection, event.detail)
++      }
++      eventManager.focus()
 +    }
-     if(!lastVisibleRect(lastRange, nodes)) {
-       return null
++    function selectWordByLongPress(event) {
++      var selection, position, selectionRange, container, offset;
++      position = caretPositionFromPoint(event.clientX, event.clientY);
++      if(position) {
++        container = (position.container);
++        offset = position.offset;
++        selection = {anchorNode:container, anchorOffset:offset, focusNode:container, focusOffset:offset};
++        selectionRange = selectionController.selectionToRange(selection);
++        selectionController.selectRange(selectionRange.range, selectionRange.hasForwardSelection, 2);
++        eventManager.focus()
++      }
 +    }
-     fillerRange.setStart(firstRange.startContainer, firstRange.startOffset);
-     fillerRange.setEnd(lastRange.endContainer, lastRange.endOffset);
-     return{firstRange:firstRange, lastRange:lastRange, fillerRange:fillerRange}
-   }
-   function getBoundingRect(rect1, rect2) {
-     var resultRect = {};
-     resultRect.top = Math.min(rect1.top, rect2.top);
-     resultRect.left = Math.min(rect1.left, rect2.left);
-     resultRect.right = Math.max(rect1.right, rect2.right);
-     resultRect.bottom = Math.max(rect1.bottom, rect2.bottom);
-     resultRect.width = resultRect.right - resultRect.left;
-     resultRect.height = resultRect.bottom - resultRect.top;
-     return resultRect
-   }
-   function checkAndGrowOrCreateRect(originalRect, newRect) {
-     if(newRect && (newRect.width > 0 && newRect.height > 0)) {
-       if(!originalRect) {
-         originalRect = newRect
++    function handleMouseClickEvent(event) {
++      var target = getTarget(event), range, wasCollapsed, frameNode, pos;
++      drawShadowCursorTask.processRequests();
++      if(odfUtils.isImage(target) && (odfUtils.isCharacterFrame(target.parentNode) && window.getSelection().isCollapsed)) {
++        selectionController.selectImage((target.parentNode));
++        eventManager.focus()
 +      }else {
-         originalRect = getBoundingRect(originalRect, newRect)
++        if(imageSelector.isSelectorElement(target)) {
++          eventManager.focus()
++        }else {
++          if(clickStartedWithinCanvas) {
++            if(isMouseMoved) {
++              range = shadowCursor.getSelectedRange();
++              wasCollapsed = range.collapsed;
++              if(odfUtils.isImage(range.endContainer) && (range.endOffset === 0 && odfUtils.isCharacterFrame(range.endContainer.parentNode))) {
++                frameNode = (range.endContainer.parentNode);
++                pos = getNextWalkablePosition(frameNode);
++                if(pos) {
++                  range.setEnd(pos.container, pos.offset);
++                  if(wasCollapsed) {
++                    range.collapse(false)
++                  }
++                }
++              }
++              selectionController.selectRange(range, shadowCursor.hasForwardSelection(), event.detail);
++              eventManager.focus()
++            }else {
++              if(isIOS) {
++                moveByMouseClickEvent(event)
++              }else {
++                handleMouseClickTimeoutId = runtime.setTimeout(function() {
++                  moveByMouseClickEvent(event)
++                }, 0)
++              }
++            }
++          }
++        }
 +      }
++      clickCount = 0;
++      clickStartedWithinCanvas = false;
++      isMouseMoved = false
 +    }
-     return originalRect
-   }
-   function getFillerRect(fillerRange) {
-     var containerNode = fillerRange.commonAncestorContainer, firstNode = (fillerRange.startContainer), lastNode = (fillerRange.endContainer), firstOffset = fillerRange.startOffset, lastOffset = fillerRange.endOffset, currentNode, lastMeasuredNode, firstSibling, lastSibling, grownRect = null, currentRect, range = doc.createRange(), rootFilter, odfNodeFilter = new odf.OdfNodeFilter, treeWalker;
-     function acceptNode(node) {
-       positionIterator.setUnfilteredPosition(node, 0);
-       if(odfNodeFilter.acceptNode(node) === FILTER_ACCEPT && rootFilter.acceptPosition(positionIterator) === FILTER_ACCEPT) {
-         return FILTER_ACCEPT
++    function handleDragStart(e) {
++      var cursor = odtDocument.getCursor(inputMemberId), selectedRange = cursor.getSelectedRange();
++      if(selectedRange.collapsed) {
++        return
 +      }
-       return FILTER_REJECT
++      mimeDataExporter.exportRangeToDataTransfer((e.dataTransfer), selectedRange)
 +    }
-     function getRectFromNodeAfterFiltering(node) {
-       var rect = null;
-       if(acceptNode(node) === FILTER_ACCEPT) {
-         rect = domUtils.getBoundingClientRect(node)
++    function handleDragEnd() {
++      if(clickStartedWithinCanvas) {
++        eventManager.focus()
 +      }
-       return rect
++      clickCount = 0;
++      clickStartedWithinCanvas = false;
++      isMouseMoved = false
 +    }
-     if(firstNode === containerNode || lastNode === containerNode) {
-       range = fillerRange.cloneRange();
-       grownRect = range.getBoundingClientRect();
-       range.detach();
-       return grownRect
++    function handleContextMenu(e) {
++      handleMouseClickEvent(e)
 +    }
-     firstSibling = firstNode;
-     while(firstSibling.parentNode !== containerNode) {
-       firstSibling = firstSibling.parentNode
++    function handleMouseUp(event) {
++      var target = (getTarget(event)), annotationNode = null;
++      if(target.className === "annotationRemoveButton") {
++        annotationNode = domUtils.getElementsByTagNameNS((target.parentNode), odf.Namespaces.officens, "annotation")[0];
++        annotationController.removeAnnotation(annotationNode);
++        eventManager.focus()
++      }else {
++        if(target.getAttribute("class") !== "draggable") {
++          handleMouseClickEvent(event)
++        }
++      }
 +    }
-     lastSibling = lastNode;
-     while(lastSibling.parentNode !== containerNode) {
-       lastSibling = lastSibling.parentNode
++    function insertNonEmptyData(e) {
++      var input = e.data;
++      if(input) {
++        textController.insertText(input)
++      }
 +    }
-     rootFilter = odtDocument.createRootFilter(firstNode);
-     currentNode = firstSibling.nextSibling;
-     while(currentNode && currentNode !== lastSibling) {
-       currentRect = getRectFromNodeAfterFiltering(currentNode);
-       grownRect = checkAndGrowOrCreateRect(grownRect, currentRect);
-       currentNode = currentNode.nextSibling
++    function returnTrue(fn) {
++      return function() {
++        fn();
++        return true
++      }
 +    }
-     if(odfUtils.isParagraph(firstSibling)) {
-       grownRect = checkAndGrowOrCreateRect(grownRect, domUtils.getBoundingClientRect(firstSibling))
-     }else {
-       if(firstSibling.nodeType === Node.TEXT_NODE) {
-         currentNode = firstSibling;
-         range.setStart(currentNode, firstOffset);
-         range.setEnd(currentNode, currentNode === lastSibling ? lastOffset : currentNode.length);
-         currentRect = range.getBoundingClientRect();
-         grownRect = checkAndGrowOrCreateRect(grownRect, currentRect)
++    function rangeSelectionOnly(fn) {
++      return function(e) {
++        var selectionType = odtDocument.getCursor(inputMemberId).getSelectionType();
++        if(selectionType === ops.OdtCursor.RangeSelection) {
++          return fn(e)
++        }
++        return true
++      }
++    }
++    function insertLocalCursor() {
++      runtime.assert(session.getOdtDocument().getCursor(inputMemberId) === undefined, "Inserting local cursor a second time.");
++      var op = new ops.OpAddCursor;
++      op.init({memberid:inputMemberId});
++      session.enqueue([op]);
++      eventManager.focus()
++    }
++    this.insertLocalCursor = insertLocalCursor;
++    function removeLocalCursor() {
++      runtime.assert(session.getOdtDocument().getCursor(inputMemberId) !== undefined, "Removing local cursor without inserting before.");
++      var op = new ops.OpRemoveCursor;
++      op.init({memberid:inputMemberId});
++      session.enqueue([op])
++    }
++    this.removeLocalCursor = removeLocalCursor;
++    this.startEditing = function() {
++      inputMethodEditor.subscribe(gui.InputMethodEditor.signalCompositionStart, textController.removeCurrentSelection);
++      inputMethodEditor.subscribe(gui.InputMethodEditor.signalCompositionEnd, insertNonEmptyData);
++      eventManager.subscribe("beforecut", handleBeforeCut);
++      eventManager.subscribe("cut", handleCut);
++      eventManager.subscribe("beforepaste", handleBeforePaste);
++      eventManager.subscribe("paste", handlePaste);
++      window.addEventListener("focus", hyperlinkClickHandler.showTextCursor, false);
++      if(undoManager) {
++        undoManager.initialize()
++      }
++      inputMethodEditor.setEditing(true);
++      hyperlinkClickHandler.setModifier(isMacOS ? gui.HyperlinkClickHandler.Modifier.Meta : gui.HyperlinkClickHandler.Modifier.Ctrl);
++      keyDownHandler.bind(keyCode.Backspace, modifier.None, returnTrue(textController.removeTextByBackspaceKey), true);
++      keyDownHandler.bind(keyCode.Delete, modifier.None, textController.removeTextByDeleteKey);
++      keyDownHandler.bind(keyCode.Tab, modifier.None, rangeSelectionOnly(function() {
++        textController.insertText("\t");
++        return true
++      }));
++      if(isMacOS) {
++        keyDownHandler.bind(keyCode.Clear, modifier.None, textController.removeCurrentSelection);
++        keyDownHandler.bind(keyCode.B, modifier.Meta, rangeSelectionOnly(directFormattingController.toggleBold));
++        keyDownHandler.bind(keyCode.I, modifier.Meta, rangeSelectionOnly(directFormattingController.toggleItalic));
++        keyDownHandler.bind(keyCode.U, modifier.Meta, rangeSelectionOnly(directFormattingController.toggleUnderline));
++        keyDownHandler.bind(keyCode.L, modifier.MetaShift, rangeSelectionOnly(directFormattingController.alignParagraphLeft));
++        keyDownHandler.bind(keyCode.E, modifier.MetaShift, rangeSelectionOnly(directFormattingController.alignParagraphCenter));
++        keyDownHandler.bind(keyCode.R, modifier.MetaShift, rangeSelectionOnly(directFormattingController.alignParagraphRight));
++        keyDownHandler.bind(keyCode.J, modifier.MetaShift, rangeSelectionOnly(directFormattingController.alignParagraphJustified));
++        keyDownHandler.bind(keyCode.C, modifier.MetaShift, annotationController.addAnnotation);
++        keyDownHandler.bind(keyCode.Z, modifier.Meta, undo);
++        keyDownHandler.bind(keyCode.Z, modifier.MetaShift, redo);
++        keyDownHandler.bind(keyCode.LeftMeta, modifier.Meta, hyperlinkClickHandler.showPointerCursor);
++        keyDownHandler.bind(keyCode.MetaInMozilla, modifier.Meta, hyperlinkClickHandler.showPointerCursor);
++        keyUpHandler.bind(keyCode.LeftMeta, modifier.None, hyperlinkClickHandler.showTextCursor);
++        keyUpHandler.bind(keyCode.MetaInMozilla, modifier.None, hyperlinkClickHandler.showTextCursor)
 +      }else {
-         treeWalker = doc.createTreeWalker(firstSibling, NodeFilter.SHOW_TEXT, acceptNode, false);
-         currentNode = treeWalker.currentNode = firstNode;
-         while(currentNode && currentNode !== lastNode) {
-           range.setStart(currentNode, firstOffset);
-           range.setEnd(currentNode, currentNode.length);
-           currentRect = range.getBoundingClientRect();
-           grownRect = checkAndGrowOrCreateRect(grownRect, currentRect);
-           lastMeasuredNode = currentNode;
-           firstOffset = 0;
-           currentNode = treeWalker.nextNode()
++        keyDownHandler.bind(keyCode.B, modifier.Ctrl, rangeSelectionOnly(directFormattingController.toggleBold));
++        keyDownHandler.bind(keyCode.I, modifier.Ctrl, rangeSelectionOnly(directFormattingController.toggleItalic));
++        keyDownHandler.bind(keyCode.U, modifier.Ctrl, rangeSelectionOnly(directFormattingController.toggleUnderline));
++        keyDownHandler.bind(keyCode.L, modifier.CtrlShift, rangeSelectionOnly(directFormattingController.alignParagraphLeft));
++        keyDownHandler.bind(keyCode.E, modifier.CtrlShift, rangeSelectionOnly(directFormattingController.alignParagraphCenter));
++        keyDownHandler.bind(keyCode.R, modifier.CtrlShift, rangeSelectionOnly(directFormattingController.alignParagraphRight));
++        keyDownHandler.bind(keyCode.J, modifier.CtrlShift, rangeSelectionOnly(directFormattingController.alignParagraphJustified));
++        keyDownHandler.bind(keyCode.C, modifier.CtrlAlt, annotationController.addAnnotation);
++        keyDownHandler.bind(keyCode.Z, modifier.Ctrl, undo);
++        keyDownHandler.bind(keyCode.Z, modifier.CtrlShift, redo);
++        keyDownHandler.bind(keyCode.Ctrl, modifier.Ctrl, hyperlinkClickHandler.showPointerCursor);
++        keyUpHandler.bind(keyCode.Ctrl, modifier.None, hyperlinkClickHandler.showTextCursor)
++      }
++      function handler(e) {
++        var text = stringFromKeyPress(e);
++        if(text && !(e.altKey || (e.ctrlKey || e.metaKey))) {
++          textController.insertText(text);
++          return true
 +        }
++        return false
 +      }
-     }
-     if(!lastMeasuredNode) {
-       lastMeasuredNode = firstNode
-     }
-     if(odfUtils.isParagraph(lastSibling)) {
-       grownRect = checkAndGrowOrCreateRect(grownRect, domUtils.getBoundingClientRect(lastSibling))
-     }else {
-       if(lastSibling.nodeType === Node.TEXT_NODE) {
-         currentNode = lastSibling;
-         range.setStart(currentNode, currentNode === firstSibling ? firstOffset : 0);
-         range.setEnd(currentNode, lastOffset);
-         currentRect = range.getBoundingClientRect();
-         grownRect = checkAndGrowOrCreateRect(grownRect, currentRect)
++      keyPressHandler.setDefault(rangeSelectionOnly(handler));
++      keyPressHandler.bind(keyCode.Enter, modifier.None, rangeSelectionOnly(textController.enqueueParagraphSplittingOps))
++    };
++    this.endEditing = function() {
++      inputMethodEditor.unsubscribe(gui.InputMethodEditor.signalCompositionStart, textController.removeCurrentSelection);
++      inputMethodEditor.unsubscribe(gui.InputMethodEditor.signalCompositionEnd, insertNonEmptyData);
++      eventManager.unsubscribe("cut", handleCut);
++      eventManager.unsubscribe("beforecut", handleBeforeCut);
++      eventManager.unsubscribe("paste", handlePaste);
++      eventManager.unsubscribe("beforepaste", handleBeforePaste);
++      window.removeEventListener("focus", hyperlinkClickHandler.showTextCursor, false);
++      inputMethodEditor.setEditing(false);
++      hyperlinkClickHandler.setModifier(gui.HyperlinkClickHandler.Modifier.None);
++      keyDownHandler.bind(keyCode.Backspace, modifier.None, function() {
++        return true
++      }, true);
++      keyDownHandler.unbind(keyCode.Delete, modifier.None);
++      keyDownHandler.unbind(keyCode.Tab, modifier.None);
++      if(isMacOS) {
++        keyDownHandler.unbind(keyCode.Clear, modifier.None);
++        keyDownHandler.unbind(keyCode.B, modifier.Meta);
++        keyDownHandler.unbind(keyCode.I, modifier.Meta);
++        keyDownHandler.unbind(keyCode.U, modifier.Meta);
++        keyDownHandler.unbind(keyCode.L, modifier.MetaShift);
++        keyDownHandler.unbind(keyCode.E, modifier.MetaShift);
++        keyDownHandler.unbind(keyCode.R, modifier.MetaShift);
++        keyDownHandler.unbind(keyCode.J, modifier.MetaShift);
++        keyDownHandler.unbind(keyCode.C, modifier.MetaShift);
++        keyDownHandler.unbind(keyCode.Z, modifier.Meta);
++        keyDownHandler.unbind(keyCode.Z, modifier.MetaShift);
++        keyDownHandler.unbind(keyCode.LeftMeta, modifier.Meta);
++        keyDownHandler.unbind(keyCode.MetaInMozilla, modifier.Meta);
++        keyUpHandler.unbind(keyCode.LeftMeta, modifier.None);
++        keyUpHandler.unbind(keyCode.MetaInMozilla, modifier.None)
 +      }else {
-         treeWalker = doc.createTreeWalker(lastSibling, NodeFilter.SHOW_TEXT, acceptNode, false);
-         currentNode = treeWalker.currentNode = lastNode;
-         while(currentNode && currentNode !== lastMeasuredNode) {
-           range.setStart(currentNode, 0);
-           range.setEnd(currentNode, lastOffset);
-           currentRect = range.getBoundingClientRect();
-           grownRect = checkAndGrowOrCreateRect(grownRect, currentRect);
-           currentNode = treeWalker.previousNode();
-           if(currentNode) {
-             lastOffset = currentNode.length
-           }
-         }
++        keyDownHandler.unbind(keyCode.B, modifier.Ctrl);
++        keyDownHandler.unbind(keyCode.I, modifier.Ctrl);
++        keyDownHandler.unbind(keyCode.U, modifier.Ctrl);
++        keyDownHandler.unbind(keyCode.L, modifier.CtrlShift);
++        keyDownHandler.unbind(keyCode.E, modifier.CtrlShift);
++        keyDownHandler.unbind(keyCode.R, modifier.CtrlShift);
++        keyDownHandler.unbind(keyCode.J, modifier.CtrlShift);
++        keyDownHandler.unbind(keyCode.C, modifier.CtrlAlt);
++        keyDownHandler.unbind(keyCode.Z, modifier.Ctrl);
++        keyDownHandler.unbind(keyCode.Z, modifier.CtrlShift);
++        keyDownHandler.unbind(keyCode.Ctrl, modifier.Ctrl);
++        keyUpHandler.unbind(keyCode.Ctrl, modifier.None)
++      }
++      keyPressHandler.setDefault(null);
++      keyPressHandler.unbind(keyCode.Enter, modifier.None)
++    };
++    this.getInputMemberId = function() {
++      return inputMemberId
++    };
++    this.getSession = function() {
++      return session
++    };
++    this.setUndoManager = function(manager) {
++      if(undoManager) {
++        undoManager.unsubscribe(gui.UndoManager.signalUndoStackChanged, forwardUndoStackChange)
++      }
++      undoManager = manager;
++      if(undoManager) {
++        undoManager.setDocument(odtDocument);
++        undoManager.setPlaybackFunction(session.enqueue);
++        undoManager.subscribe(gui.UndoManager.signalUndoStackChanged, forwardUndoStackChange)
 +      }
++    };
++    this.getUndoManager = function() {
++      return undoManager
++    };
++    this.getAnnotationController = function() {
++      return annotationController
++    };
++    this.getDirectFormattingController = function() {
++      return directFormattingController
++    };
++    this.getHyperlinkController = function() {
++      return hyperlinkController
++    };
++    this.getImageController = function() {
++      return imageController
++    };
++    this.getSelectionController = function() {
++      return selectionController
++    };
++    this.getTextController = function() {
++      return textController
++    };
++    this.getEventManager = function() {
++      return eventManager
++    };
++    this.getKeyboardHandlers = function() {
++      return{keydown:keyDownHandler, keypress:keyPressHandler}
++    };
++    function destroy(callback) {
++      eventManager.unsubscribe("keydown", keyDownHandler.handleEvent);
++      eventManager.unsubscribe("keypress", keyPressHandler.handleEvent);
++      eventManager.unsubscribe("keyup", keyUpHandler.handleEvent);
++      eventManager.unsubscribe("copy", handleCopy);
++      eventManager.unsubscribe("mousedown", handleMouseDown);
++      eventManager.unsubscribe("mousemove", drawShadowCursorTask.trigger);
++      eventManager.unsubscribe("mouseup", handleMouseUp);
++      eventManager.unsubscribe("contextmenu", handleContextMenu);
++      eventManager.unsubscribe("dragstart", handleDragStart);
++      eventManager.unsubscribe("dragend", handleDragEnd);
++      eventManager.unsubscribe("click", hyperlinkClickHandler.handleClick);
++      eventManager.unsubscribe("longpress", selectWordByLongPress);
++      eventManager.unsubscribe("drag", extendSelectionByDrag);
++      eventManager.unsubscribe("dragstop", updateCursorSelection);
++      odtDocument.unsubscribe(ops.OdtDocument.signalOperationEnd, redrawRegionSelectionTask.trigger);
++      odtDocument.unsubscribe(ops.Document.signalCursorAdded, inputMethodEditor.registerCursor);
++      odtDocument.unsubscribe(ops.Document.signalCursorRemoved, inputMethodEditor.removeCursor);
++      odtDocument.unsubscribe(ops.OdtDocument.signalOperationEnd, updateUndoStack);
++      callback()
 +    }
-     return grownRect
-   }
-   function getCollapsedRectOfTextRange(range, useRightEdge) {
-     var clientRect = range.getBoundingClientRect(), collapsedRect = {};
-     collapsedRect.width = 0;
-     collapsedRect.top = clientRect.top;
-     collapsedRect.bottom = clientRect.bottom;
-     collapsedRect.height = clientRect.height;
-     collapsedRect.left = collapsedRect.right = useRightEdge ? clientRect.right : clientRect.left;
-     return collapsedRect
-   }
-   function repositionOverlays(selectedRange) {
-     var extremes = getExtremeRanges(selectedRange), firstRange, lastRange, fillerRange, firstRect, fillerRect, lastRect;
-     if(selectedRange.collapsed || !extremes) {
-       showOverlays(false)
-     }else {
-       showOverlays(true);
-       firstRange = extremes.firstRange;
-       lastRange = extremes.lastRange;
-       fillerRange = extremes.fillerRange;
-       firstRect = translateRect(getCollapsedRectOfTextRange(firstRange, false));
-       lastRect = translateRect(getCollapsedRectOfTextRange(lastRange, true));
-       fillerRect = getFillerRect(fillerRange);
-       if(!fillerRect) {
-         fillerRect = getBoundingRect(firstRect, lastRect)
-       }else {
-         fillerRect = translateRect(fillerRect)
++    this.destroy = function(callback) {
++      var destroyCallbacks = [];
++      if(iOSSafariSupport) {
++        destroyCallbacks.push(iOSSafariSupport.destroy)
 +      }
-       setRect(overlayTop, {left:firstRect.left, top:firstRect.top, width:Math.max(0, fillerRect.width - (firstRect.left - fillerRect.left)), height:firstRect.height});
-       if(lastRect.top === firstRect.top || lastRect.bottom === firstRect.bottom) {
-         overlayMiddle.style.display = overlayBottom.style.display = "none"
++      destroyCallbacks = destroyCallbacks.concat([drawShadowCursorTask.destroy, redrawRegionSelectionTask.destroy, directFormattingController.destroy, inputMethodEditor.destroy, eventManager.destroy, destroy]);
++      runtime.clearTimeout(handleMouseClickTimeoutId);
++      async.destroyAll(destroyCallbacks, callback)
++    };
++    function init() {
++      drawShadowCursorTask = new core.ScheduledTask(updateShadowCursor, 0);
++      redrawRegionSelectionTask = new core.ScheduledTask(redrawRegionSelection, 0);
++      keyDownHandler.bind(keyCode.Left, modifier.None, rangeSelectionOnly(selectionController.moveCursorToLeft));
++      keyDownHandler.bind(keyCode.Right, modifier.None, rangeSelectionOnly(selectionController.moveCursorToRight));
++      keyDownHandler.bind(keyCode.Up, modifier.None, rangeSelectionOnly(selectionController.moveCursorUp));
++      keyDownHandler.bind(keyCode.Down, modifier.None, rangeSelectionOnly(selectionController.moveCursorDown));
++      keyDownHandler.bind(keyCode.Left, modifier.Shift, rangeSelectionOnly(selectionController.extendSelectionToLeft));
++      keyDownHandler.bind(keyCode.Right, modifier.Shift, rangeSelectionOnly(selectionController.extendSelectionToRight));
++      keyDownHandler.bind(keyCode.Up, modifier.Shift, rangeSelectionOnly(selectionController.extendSelectionUp));
++      keyDownHandler.bind(keyCode.Down, modifier.Shift, rangeSelectionOnly(selectionController.extendSelectionDown));
++      keyDownHandler.bind(keyCode.Home, modifier.None, rangeSelectionOnly(selectionController.moveCursorToLineStart));
++      keyDownHandler.bind(keyCode.End, modifier.None, rangeSelectionOnly(selectionController.moveCursorToLineEnd));
++      keyDownHandler.bind(keyCode.Home, modifier.Ctrl, rangeSelectionOnly(selectionController.moveCursorToDocumentStart));
++      keyDownHandler.bind(keyCode.End, modifier.Ctrl, rangeSelectionOnly(selectionController.moveCursorToDocumentEnd));
++      keyDownHandler.bind(keyCode.Home, modifier.Shift, rangeSelectionOnly(selectionController.extendSelectionToLineStart));
++      keyDownHandler.bind(keyCode.End, modifier.Shift, rangeSelectionOnly(selectionController.extendSelectionToLineEnd));
++      keyDownHandler.bind(keyCode.Up, modifier.CtrlShift, rangeSelectionOnly(selectionController.extendSelectionToParagraphStart));
++      keyDownHandler.bind(keyCode.Down, modifier.CtrlShift, rangeSelectionOnly(selectionController.extendSelectionToParagraphEnd));
++      keyDownHandler.bind(keyCode.Home, modifier.CtrlShift, rangeSelectionOnly(selectionController.extendSelectionToDocumentStart));
++      keyDownHandler.bind(keyCode.End, modifier.CtrlShift, rangeSelectionOnly(selectionController.extendSelectionToDocumentEnd));
++      if(isMacOS) {
++        keyDownHandler.bind(keyCode.Left, modifier.Alt, rangeSelectionOnly(selectionController.moveCursorBeforeWord));
++        keyDownHandler.bind(keyCode.Right, modifier.Alt, rangeSelectionOnly(selectionController.moveCursorPastWord));
++        keyDownHandler.bind(keyCode.Left, modifier.Meta, rangeSelectionOnly(selectionController.moveCursorToLineStart));
++        keyDownHandler.bind(keyCode.Right, modifier.Meta, rangeSelectionOnly(selectionController.moveCursorToLineEnd));
++        keyDownHandler.bind(keyCode.Home, modifier.Meta, rangeSelectionOnly(selectionController.moveCursorToDocumentStart));
++        keyDownHandler.bind(keyCode.End, modifier.Meta, rangeSelectionOnly(selectionController.moveCursorToDocumentEnd));
++        keyDownHandler.bind(keyCode.Left, modifier.AltShift, rangeSelectionOnly(selectionController.extendSelectionBeforeWord));
++        keyDownHandler.bind(keyCode.Right, modifier.AltShift, rangeSelectionOnly(selectionController.extendSelectionPastWord));
++        keyDownHandler.bind(keyCode.Left, modifier.MetaShift, rangeSelectionOnly(selectionController.extendSelectionToLineStart));
++        keyDownHandler.bind(keyCode.Right, modifier.MetaShift, rangeSelectionOnly(selectionController.extendSelectionToLineEnd));
++        keyDownHandler.bind(keyCode.Up, modifier.AltShift, rangeSelectionOnly(selectionController.extendSelectionToParagraphStart));
++        keyDownHandler.bind(keyCode.Down, modifier.AltShift, rangeSelectionOnly(selectionController.extendSelectionToParagraphEnd));
++        keyDownHandler.bind(keyCode.Up, modifier.MetaShift, rangeSelectionOnly(selectionController.extendSelectionToDocumentStart));
++        keyDownHandler.bind(keyCode.Down, modifier.MetaShift, rangeSelectionOnly(selectionController.extendSelectionToDocumentEnd));
++        keyDownHandler.bind(keyCode.A, modifier.Meta, rangeSelectionOnly(selectionController.extendSelectionToEntireDocument))
 +      }else {
-         setRect(overlayBottom, {left:fillerRect.left, top:lastRect.top, width:Math.max(0, lastRect.right - fillerRect.left), height:lastRect.height});
-         setRect(overlayMiddle, {left:fillerRect.left, top:firstRect.top + firstRect.height, width:Math.max(0, parseFloat(overlayTop.style.left) + parseFloat(overlayTop.style.width) - parseFloat(overlayBottom.style.left)), height:Math.max(0, lastRect.top - firstRect.bottom)})
++        keyDownHandler.bind(keyCode.Left, modifier.Ctrl, rangeSelectionOnly(selectionController.moveCursorBeforeWord));
++        keyDownHandler.bind(keyCode.Right, modifier.Ctrl, rangeSelectionOnly(selectionController.moveCursorPastWord));
++        keyDownHandler.bind(keyCode.Left, modifier.CtrlShift, rangeSelectionOnly(selectionController.extendSelectionBeforeWord));
++        keyDownHandler.bind(keyCode.Right, modifier.CtrlShift, rangeSelectionOnly(selectionController.extendSelectionPastWord));
++        keyDownHandler.bind(keyCode.A, modifier.Ctrl, rangeSelectionOnly(selectionController.extendSelectionToEntireDocument))
 +      }
-       firstRange.detach();
-       lastRange.detach();
-       fillerRange.detach()
-     }
-   }
-   function rerender() {
-     addOverlays();
-     if(cursor.getSelectionType() === ops.OdtCursor.RangeSelection) {
-       showOverlays(true);
-       repositionOverlays(cursor.getSelectedRange())
-     }else {
-       showOverlays(false)
-     }
-   }
-   this.rerender = rerender;
-   this.show = rerender;
-   this.hide = function() {
-     showOverlays(false)
-   };
-   this.visible = function() {
-     return isVisible
-   };
-   function handleCursorMove(movedCursor) {
-     if(movedCursor === cursor) {
-       rerender()
++      if(isIOS) {
++        iOSSafariSupport = new gui.IOSSafariSupport(eventManager)
++      }
++      eventManager.subscribe("keydown", keyDownHandler.handleEvent);
++      eventManager.subscribe("keypress", keyPressHandler.handleEvent);
++      eventManager.subscribe("keyup", keyUpHandler.handleEvent);
++      eventManager.subscribe("copy", handleCopy);
++      eventManager.subscribe("mousedown", handleMouseDown);
++      eventManager.subscribe("mousemove", drawShadowCursorTask.trigger);
++      eventManager.subscribe("mouseup", handleMouseUp);
++      eventManager.subscribe("contextmenu", handleContextMenu);
++      eventManager.subscribe("dragstart", handleDragStart);
++      eventManager.subscribe("dragend", handleDragEnd);
++      eventManager.subscribe("click", hyperlinkClickHandler.handleClick);
++      eventManager.subscribe("longpress", selectWordByLongPress);
++      eventManager.subscribe("drag", extendSelectionByDrag);
++      eventManager.subscribe("dragstop", updateCursorSelection);
++      odtDocument.subscribe(ops.OdtDocument.signalOperationEnd, redrawRegionSelectionTask.trigger);
++      odtDocument.subscribe(ops.Document.signalCursorAdded, inputMethodEditor.registerCursor);
++      odtDocument.subscribe(ops.Document.signalCursorRemoved, inputMethodEditor.removeCursor);
++      odtDocument.subscribe(ops.OdtDocument.signalOperationEnd, updateUndoStack)
 +    }
-   }
-   this.destroy = function(callback) {
-     root.removeChild(overlayTop);
-     root.removeChild(overlayMiddle);
-     root.removeChild(overlayBottom);
-     cursor.getOdtDocument().unsubscribe(ops.OdtDocument.signalCursorMoved, handleCursorMove);
-     callback()
++    init()
 +  };
-   function init() {
-     var editinfons = "urn:webodf:names:editinfo", memberid = cursor.getMemberId();
-     addOverlays();
-     overlayTop.setAttributeNS(editinfons, "editinfo:memberid", memberid);
-     overlayMiddle.setAttributeNS(editinfons, "editinfo:memberid", memberid);
-     overlayBottom.setAttributeNS(editinfons, "editinfo:memberid", memberid);
-     overlayTop.className = overlayMiddle.className = overlayBottom.className = "selectionOverlay";
-     cursor.getOdtDocument().subscribe(ops.OdtDocument.signalCursorMoved, handleCursorMove)
-   }
-   init()
- };
++  return gui.SessionController
++})();
 +/*
 +
-  Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
++ Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("gui.SelectionView");
- gui.SelectionViewManager = function SelectionViewManager() {
-   var selectionViews = {};
-   function getSelectionView(memberId) {
-     return selectionViews.hasOwnProperty(memberId) ? selectionViews[memberId] : null
++gui.CaretManager = function CaretManager(sessionController) {
++  var carets = {}, async = new core.Async, window = runtime.getWindow(), ensureCaretVisibleTimeoutId, scrollIntoViewScheduled = false;
++  function getCaret(memberId) {
++    return carets.hasOwnProperty(memberId) ? carets[memberId] : null
 +  }
-   this.getSelectionView = getSelectionView;
-   function getSelectionViews() {
-     return Object.keys(selectionViews).map(function(memberid) {
-       return selectionViews[memberid]
++  function getCarets() {
++    return Object.keys(carets).map(function(memberid) {
++      return carets[memberid]
 +    })
 +  }
-   this.getSelectionViews = getSelectionViews;
-   function removeSelectionView(memberId) {
-     if(selectionViews.hasOwnProperty(memberId)) {
-       selectionViews[memberId].destroy(function() {
++  function removeCaret(memberId) {
++    var caret = carets[memberId];
++    if(caret) {
++      caret.destroy(function() {
 +      });
-       delete selectionViews[memberId]
++      delete carets[memberId]
 +    }
 +  }
-   this.removeSelectionView = removeSelectionView;
-   function hideSelectionView(memberId) {
-     if(selectionViews.hasOwnProperty(memberId)) {
-       selectionViews[memberId].hide()
++  function refreshLocalCaretBlinking(cursor) {
++    var caret, memberId = cursor.getMemberId();
++    if(memberId === sessionController.getInputMemberId()) {
++      caret = getCaret(memberId);
++      if(caret) {
++        caret.refreshCursorBlinking()
++      }
 +    }
 +  }
-   this.hideSelectionView = hideSelectionView;
-   function showSelectionView(memberId) {
-     if(selectionViews.hasOwnProperty(memberId)) {
-       selectionViews[memberId].show()
++  function executeEnsureCaretVisible() {
++    var caret = getCaret(sessionController.getInputMemberId());
++    scrollIntoViewScheduled = false;
++    if(caret) {
++      caret.ensureVisible()
++    }
++  }
++  function scheduleCaretVisibilityCheck() {
++    var caret = getCaret(sessionController.getInputMemberId());
++    if(caret) {
++      caret.handleUpdate();
++      if(!scrollIntoViewScheduled) {
++        scrollIntoViewScheduled = true;
++        ensureCaretVisibleTimeoutId = runtime.setTimeout(executeEnsureCaretVisible, 50)
++      }
++    }
++  }
++  function ensureLocalCaretVisible(info) {
++    if(info.memberId === sessionController.getInputMemberId()) {
++      scheduleCaretVisibilityCheck()
++    }
++  }
++  function focusLocalCaret() {
++    var caret = getCaret(sessionController.getInputMemberId());
++    if(caret) {
++      caret.setFocus()
++    }
++  }
++  function blurLocalCaret() {
++    var caret = getCaret(sessionController.getInputMemberId());
++    if(caret) {
++      caret.removeFocus()
++    }
++  }
++  function showLocalCaret() {
++    var caret = getCaret(sessionController.getInputMemberId());
++    if(caret) {
++      caret.show()
++    }
++  }
++  function hideLocalCaret() {
++    var caret = getCaret(sessionController.getInputMemberId());
++    if(caret) {
++      caret.hide()
++    }
++  }
++  this.registerCursor = function(cursor, caretAvatarInitiallyVisible, blinkOnRangeSelect) {
++    var memberid = cursor.getMemberId(), caret = new gui.Caret(cursor, caretAvatarInitiallyVisible, blinkOnRangeSelect), eventManager = sessionController.getEventManager();
++    carets[memberid] = caret;
++    if(memberid === sessionController.getInputMemberId()) {
++      runtime.log("Starting to track input on new cursor of " + memberid);
++      cursor.subscribe(ops.OdtCursor.signalCursorUpdated, scheduleCaretVisibilityCheck);
++      caret.setOverlayElement(eventManager.getEventTrap())
++    }else {
++      cursor.subscribe(ops.OdtCursor.signalCursorUpdated, caret.handleUpdate)
++    }
++    return caret
++  };
++  this.getCaret = getCaret;
++  this.getCarets = getCarets;
++  this.destroy = function(callback) {
++    var odtDocument = sessionController.getSession().getOdtDocument(), eventManager = sessionController.getEventManager(), caretCleanup = getCarets().map(function(caret) {
++      return caret.destroy
++    });
++    runtime.clearTimeout(ensureCaretVisibleTimeoutId);
++    odtDocument.unsubscribe(ops.OdtDocument.signalParagraphChanged, ensureLocalCaretVisible);
++    odtDocument.unsubscribe(ops.Document.signalCursorMoved, refreshLocalCaretBlinking);
++    odtDocument.unsubscribe(ops.Document.signalCursorRemoved, removeCaret);
++    eventManager.unsubscribe("focus", focusLocalCaret);
++    eventManager.unsubscribe("blur", blurLocalCaret);
++    window.removeEventListener("focus", showLocalCaret, false);
++    window.removeEventListener("blur", hideLocalCaret, false);
++    carets = {};
++    async.destroyAll(caretCleanup, callback)
++  };
++  function init() {
++    var odtDocument = sessionController.getSession().getOdtDocument(), eventManager = sessionController.getEventManager();
++    odtDocument.subscribe(ops.OdtDocument.signalParagraphChanged, ensureLocalCaretVisible);
++    odtDocument.subscribe(ops.Document.signalCursorMoved, refreshLocalCaretBlinking);
++    odtDocument.subscribe(ops.Document.signalCursorRemoved, removeCaret);
++    eventManager.subscribe("focus", focusLocalCaret);
++    eventManager.subscribe("blur", blurLocalCaret);
++    window.addEventListener("focus", showLocalCaret, false);
++    window.addEventListener("blur", hideLocalCaret, false)
++  }
++  init()
++};
++gui.EditInfoHandle = function EditInfoHandle(parentElement) {
++  var edits = [], handle, document = (parentElement.ownerDocument), htmlns = document.documentElement.namespaceURI, editinfons = "urn:webodf:names:editinfo";
++  function renderEdits() {
++    var i, infoDiv, colorSpan, authorSpan, timeSpan;
++    handle.innerHTML = "";
++    for(i = 0;i < edits.length;i += 1) {
++      infoDiv = document.createElementNS(htmlns, "div");
++      infoDiv.className = "editInfo";
++      colorSpan = document.createElementNS(htmlns, "span");
++      colorSpan.className = "editInfoColor";
++      colorSpan.setAttributeNS(editinfons, "editinfo:memberid", edits[i].memberid);
++      authorSpan = document.createElementNS(htmlns, "span");
++      authorSpan.className = "editInfoAuthor";
++      authorSpan.setAttributeNS(editinfons, "editinfo:memberid", edits[i].memberid);
++      timeSpan = document.createElementNS(htmlns, "span");
++      timeSpan.className = "editInfoTime";
++      timeSpan.setAttributeNS(editinfons, "editinfo:memberid", edits[i].memberid);
++      timeSpan.innerHTML = edits[i].time;
++      infoDiv.appendChild(colorSpan);
++      infoDiv.appendChild(authorSpan);
++      infoDiv.appendChild(timeSpan);
++      handle.appendChild(infoDiv)
 +    }
 +  }
-   this.showSelectionView = showSelectionView;
-   this.rerenderSelectionViews = function() {
-     Object.keys(selectionViews).forEach(function(memberId) {
-       if(selectionViews[memberId].visible()) {
-         selectionViews[memberId].rerender()
-       }
-     })
++  this.setEdits = function(editArray) {
++    edits = editArray;
++    renderEdits()
 +  };
-   this.registerCursor = function(cursor, virtualSelectionsInitiallyVisible) {
-     var memberId = cursor.getMemberId(), selectionView = new gui.SelectionView(cursor);
-     if(virtualSelectionsInitiallyVisible) {
-       selectionView.show()
-     }else {
-       selectionView.hide()
-     }
-     selectionViews[memberId] = selectionView;
-     return selectionView
++  this.show = function() {
++    handle.style.display = "block"
++  };
++  this.hide = function() {
++    handle.style.display = "none"
 +  };
 +  this.destroy = function(callback) {
-     var selectionViewArray = getSelectionViews();
-     (function destroySelectionView(i, err) {
-       if(err) {
-         callback(err)
-       }else {
-         if(i < selectionViewArray.length) {
-           selectionViewArray[i].destroy(function(err) {
-             destroySelectionView(i + 1, err)
-           })
-         }else {
-           callback()
-         }
-       }
-     })(0, undefined)
++    parentElement.removeChild(handle);
++    callback()
++  };
++  function init() {
++    handle = (document.createElementNS(htmlns, "div"));
++    handle.setAttribute("class", "editInfoHandle");
++    handle.style.display = "none";
++    parentElement.appendChild(handle)
 +  }
++  init()
 +};
 +/*
 +
-  Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
++ Copyright (C) 2012 KO GmbH <aditya.bhatt at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("core.DomUtils");
- runtime.loadClass("gui.UndoManager");
- runtime.loadClass("gui.UndoStateRules");
- gui.TrivialUndoManager = function TrivialUndoManager(defaultRules) {
-   var self = this, cursorns = "urn:webodf:names:cursor", domUtils = new core.DomUtils, initialDoc, initialState = [], playFunc, odtDocument, currentUndoState = [], undoStates = [], redoStates = [], eventNotifier = new core.EventNotifier([gui.UndoManager.signalUndoStackChanged, gui.UndoManager.signalUndoStateCreated, gui.UndoManager.signalUndoStateModified, gui.TrivialUndoManager.signalDocumentRootReplaced]), undoRules = defaultRules || new gui.UndoStateRules;
-   function emitStackChange() {
-     eventNotifier.emit(gui.UndoManager.signalUndoStackChanged, {undoAvailable:self.hasUndoStates(), redoAvailable:self.hasRedoStates()})
-   }
-   function mostRecentUndoState() {
-     return undoStates[undoStates.length - 1]
-   }
-   function completeCurrentUndoState() {
-     if(currentUndoState !== initialState && currentUndoState !== mostRecentUndoState()) {
-       undoStates.push(currentUndoState)
-     }
-   }
-   function removeNode(node) {
-     var sibling = node.previousSibling || node.nextSibling;
-     node.parentNode.removeChild(node);
-     domUtils.normalizeTextNodes(sibling)
-   }
-   function removeCursors(root) {
-     domUtils.getElementsByTagNameNS(root, cursorns, "cursor").forEach(removeNode);
-     domUtils.getElementsByTagNameNS(root, cursorns, "anchor").forEach(removeNode)
-   }
-   function values(obj) {
-     return Object.keys(obj).map(function(key) {
-       return obj[key]
-     })
-   }
-   function extractCursorStates(undoStates) {
-     var addCursor = {}, moveCursor = {}, requiredAddOps = {}, remainingAddOps, operations = undoStates.pop();
-     odtDocument.getCursors().forEach(function(cursor) {
-       requiredAddOps[cursor.getMemberId()] = true
-     });
-     remainingAddOps = Object.keys(requiredAddOps).length;
-     function processOp(op) {
-       var spec = op.spec();
-       if(!requiredAddOps[spec.memberid]) {
-         return
-       }
-       switch(spec.optype) {
-         case "AddCursor":
-           if(!addCursor[spec.memberid]) {
-             addCursor[spec.memberid] = op;
-             delete requiredAddOps[spec.memberid];
-             remainingAddOps -= 1
-           }
-           break;
-         case "MoveCursor":
-           if(!moveCursor[spec.memberid]) {
-             moveCursor[spec.memberid] = op
-           }
-           break
++ops.EditInfo = function EditInfo(container, odtDocument) {
++  var editInfoNode, editHistory = {};
++  function sortEdits() {
++    var arr = [], memberid;
++    for(memberid in editHistory) {
++      if(editHistory.hasOwnProperty(memberid)) {
++        arr.push({"memberid":memberid, "time":editHistory[memberid].time})
 +      }
 +    }
-     while(operations && remainingAddOps > 0) {
-       operations.reverse();
-       operations.forEach(processOp);
-       operations = undoStates.pop()
-     }
-     return values(addCursor).concat(values(moveCursor))
++    arr.sort(function(a, b) {
++      return a.time - b.time
++    });
++    return arr
 +  }
-   this.subscribe = function(signal, callback) {
-     eventNotifier.subscribe(signal, callback)
-   };
-   this.unsubscribe = function(signal, callback) {
-     eventNotifier.unsubscribe(signal, callback)
-   };
-   this.hasUndoStates = function() {
-     return undoStates.length > 0
-   };
-   this.hasRedoStates = function() {
-     return redoStates.length > 0
++  this.getNode = function() {
++    return editInfoNode
 +  };
-   this.setOdtDocument = function(newDocument) {
-     odtDocument = newDocument
++  this.getOdtDocument = function() {
++    return odtDocument
 +  };
-   this.resetInitialState = function() {
-     undoStates.length = 0;
-     redoStates.length = 0;
-     initialState.length = 0;
-     currentUndoState.length = 0;
-     initialDoc = null;
-     emitStackChange()
++  this.getEdits = function() {
++    return editHistory
 +  };
-   this.saveInitialState = function() {
-     var odfContainer = odtDocument.getOdfCanvas().odfContainer(), annotationViewManager = odtDocument.getOdfCanvas().getAnnotationViewManager();
-     if(annotationViewManager) {
-       annotationViewManager.forgetAnnotations()
-     }
-     initialDoc = odfContainer.rootElement.cloneNode(true);
-     odtDocument.getOdfCanvas().refreshAnnotations();
-     removeCursors(initialDoc);
-     completeCurrentUndoState();
-     undoStates.unshift(initialState);
-     currentUndoState = initialState = extractCursorStates(undoStates);
-     undoStates.length = 0;
-     redoStates.length = 0;
-     emitStackChange()
++  this.getSortedEdits = function() {
++    return sortEdits()
 +  };
-   this.setPlaybackFunction = function(playback_func) {
-     playFunc = playback_func
++  this.addEdit = function(memberid, timestamp) {
++    editHistory[memberid] = {time:timestamp}
 +  };
-   this.onOperationExecuted = function(op) {
-     redoStates.length = 0;
-     if(undoRules.isEditOperation(op) && currentUndoState === initialState || !undoRules.isPartOfOperationSet(op, currentUndoState)) {
-       completeCurrentUndoState();
-       currentUndoState = [op];
-       undoStates.push(currentUndoState);
-       eventNotifier.emit(gui.UndoManager.signalUndoStateCreated, {operations:currentUndoState});
-       emitStackChange()
-     }else {
-       currentUndoState.push(op);
-       eventNotifier.emit(gui.UndoManager.signalUndoStateModified, {operations:currentUndoState})
-     }
++  this.clearEdits = function() {
++    editHistory = {}
 +  };
-   this.moveForward = function(states) {
-     var moved = 0, redoOperations;
-     while(states && redoStates.length) {
-       redoOperations = redoStates.pop();
-       undoStates.push(redoOperations);
-       redoOperations.forEach(playFunc);
-       states -= 1;
-       moved += 1
-     }
-     if(moved) {
-       currentUndoState = mostRecentUndoState();
-       emitStackChange()
++  this.destroy = function(callback) {
++    if(container.parentNode) {
++      container.removeChild(editInfoNode)
 +    }
-     return moved
++    callback()
 +  };
-   this.moveBackward = function(states) {
-     var odfCanvas = odtDocument.getOdfCanvas(), odfContainer = odfCanvas.odfContainer(), moved = 0;
-     while(states && undoStates.length) {
-       redoStates.push(undoStates.pop());
-       states -= 1;
-       moved += 1
-     }
-     if(moved) {
-       odfContainer.setRootElement(initialDoc.cloneNode(true));
-       odfCanvas.setOdfContainer(odfContainer, true);
-       eventNotifier.emit(gui.TrivialUndoManager.signalDocumentRootReplaced, {});
-       odtDocument.getCursors().forEach(function(cursor) {
-         odtDocument.removeCursor(cursor.getMemberId())
-       });
-       initialState.forEach(playFunc);
-       undoStates.forEach(function(ops) {
-         ops.forEach(playFunc)
-       });
-       odfCanvas.refreshCSS();
-       currentUndoState = mostRecentUndoState() || initialState;
-       emitStackChange()
-     }
-     return moved
++  function init() {
++    var editInfons = "urn:webodf:names:editinfo", dom = odtDocument.getDOMDocument();
++    editInfoNode = dom.createElementNS(editInfons, "editinfo");
++    container.insertBefore(editInfoNode, container.firstChild)
 +  }
++  init()
 +};
- gui.TrivialUndoManager.signalDocumentRootReplaced = "documentRootReplaced";
- (function() {
-   return gui.TrivialUndoManager
- })();
 +/*
 +
 + Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("ops.TrivialOperationRouter");
- runtime.loadClass("ops.OperationFactory");
- runtime.loadClass("ops.OdtDocument");
- ops.Session = function Session(odfCanvas) {
-   var self = this, operationFactory = new ops.OperationFactory, odtDocument = new ops.OdtDocument(odfCanvas), operationRouter = null;
-   this.setOperationFactory = function(opFactory) {
-     operationFactory = opFactory;
-     if(operationRouter) {
-       operationRouter.setOperationFactory(operationFactory)
++gui.EditInfoMarker = function EditInfoMarker(editInfo, initialVisibility) {
++  var self = this, editInfoNode, handle, marker, editinfons = "urn:webodf:names:editinfo", decayTimer0, decayTimer1, decayTimer2, decayTimeStep = 1E4;
++  function applyDecay(opacity, delay) {
++    return runtime.setTimeout(function() {
++      marker.style.opacity = opacity
++    }, delay)
++  }
++  function deleteDecay(timerId) {
++    runtime.clearTimeout(timerId)
++  }
++  function setLastAuthor(memberid) {
++    marker.setAttributeNS(editinfons, "editinfo:memberid", memberid)
++  }
++  this.addEdit = function(memberid, timestamp) {
++    var age = Date.now() - timestamp;
++    editInfo.addEdit(memberid, timestamp);
++    handle.setEdits(editInfo.getSortedEdits());
++    setLastAuthor(memberid);
++    deleteDecay(decayTimer1);
++    deleteDecay(decayTimer2);
++    if(age < decayTimeStep) {
++      decayTimer0 = applyDecay(1, 0);
++      decayTimer1 = applyDecay(0.5, decayTimeStep - age);
++      decayTimer2 = applyDecay(0.2, decayTimeStep * 2 - age)
++    }else {
++      if(age >= decayTimeStep && age < decayTimeStep * 2) {
++        decayTimer0 = applyDecay(0.5, 0);
++        decayTimer2 = applyDecay(0.2, decayTimeStep * 2 - age)
++      }else {
++        decayTimer0 = applyDecay(0.2, 0)
++      }
 +    }
 +  };
-   this.setOperationRouter = function(opRouter) {
-     operationRouter = opRouter;
-     opRouter.setPlaybackFunction(function(op) {
-       if(op.execute(odtDocument)) {
-         odtDocument.emit(ops.OdtDocument.signalOperationExecuted, op);
-         return true
-       }
-       return false
-     });
-     opRouter.setOperationFactory(operationFactory)
++  this.getEdits = function() {
++    return editInfo.getEdits()
++  };
++  this.clearEdits = function() {
++    editInfo.clearEdits();
++    handle.setEdits([]);
++    if(marker.hasAttributeNS(editinfons, "editinfo:memberid")) {
++      marker.removeAttributeNS(editinfons, "editinfo:memberid")
++    }
 +  };
-   this.getOperationFactory = function() {
-     return operationFactory
++  this.getEditInfo = function() {
++    return editInfo
 +  };
-   this.getOdtDocument = function() {
-     return odtDocument
++  this.show = function() {
++    marker.style.display = "block"
 +  };
-   this.enqueue = function(ops) {
-     operationRouter.push(ops)
++  this.hide = function() {
++    self.hideHandle();
++    marker.style.display = "none"
 +  };
-   this.close = function(callback) {
-     operationRouter.close(function(err) {
++  this.showHandle = function() {
++    handle.show()
++  };
++  this.hideHandle = function() {
++    handle.hide()
++  };
++  this.destroy = function(callback) {
++    deleteDecay(decayTimer0);
++    deleteDecay(decayTimer1);
++    deleteDecay(decayTimer2);
++    editInfoNode.removeChild(marker);
++    handle.destroy(function(err) {
 +      if(err) {
 +        callback(err)
 +      }else {
-         odtDocument.close(callback)
++        editInfo.destroy(callback)
 +      }
 +    })
 +  };
-   this.destroy = function(callback) {
-     odtDocument.destroy(callback)
-   };
 +  function init() {
-     self.setOperationRouter(new ops.TrivialOperationRouter)
++    var dom = editInfo.getOdtDocument().getDOMDocument(), htmlns = dom.documentElement.namespaceURI;
++    marker = (dom.createElementNS(htmlns, "div"));
++    marker.setAttribute("class", "editInfoMarker");
++    marker.onmouseover = function() {
++      self.showHandle()
++    };
++    marker.onmouseout = function() {
++      self.hideHandle()
++    };
++    editInfoNode = editInfo.getNode();
++    editInfoNode.appendChild(marker);
++    handle = new gui.EditInfoHandle(editInfoNode);
++    if(!initialVisibility) {
++      self.hide()
++    }
 +  }
 +  init()
 +};
- /*
- 
-  Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
- 
-  @licstart
-  This file is part of WebODF.
- 
-  WebODF is free software: you can redistribute it and/or modify it
-  under the terms of the GNU Affero General Public License (GNU AGPL)
-  as published by the Free Software Foundation, either version 3 of
-  the License, or (at your option) any later version.
- 
-  WebODF is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-  GNU Affero General Public License for more details.
- 
-  You should have received a copy of the GNU Affero General Public License
-  along with WebODF.  If not, see <http://www.gnu.org/licenses/>.
-  @licend
- 
-  @source: http://www.webodf.org/
-  @source: https://github.com/kogmbh/WebODF/
- */
- runtime.loadClass("core.EventNotifier");
- runtime.loadClass("core.PositionFilter");
- runtime.loadClass("ops.Session");
- runtime.loadClass("ops.OpAddAnnotation");
- runtime.loadClass("ops.OpRemoveAnnotation");
- runtime.loadClass("gui.SelectionMover");
- gui.AnnotationController = function AnnotationController(session, inputMemberId) {
-   var odtDocument = session.getOdtDocument(), isAnnotatable = false, eventNotifier = new core.EventNotifier([gui.AnnotationController.annotatableChanged]), officens = odf.Namespaces.officens;
-   function isWithinAnnotation(node, container) {
-     while(node && node !== container) {
-       if(node.namespaceURI === officens && node.localName === "annotation") {
-         return true
-       }
-       node = node.parentNode
-     }
-     return false
-   }
-   function updatedCachedValues() {
-     var cursor = odtDocument.getCursor(inputMemberId), cursorNode = cursor && cursor.getNode(), newIsAnnotatable = false;
-     if(cursorNode) {
-       newIsAnnotatable = !isWithinAnnotation(cursorNode, odtDocument.getRootNode())
-     }
-     if(newIsAnnotatable !== isAnnotatable) {
-       isAnnotatable = newIsAnnotatable;
-       eventNotifier.emit(gui.AnnotationController.annotatableChanged, isAnnotatable)
-     }
-   }
-   function onCursorAdded(cursor) {
-     if(cursor.getMemberId() === inputMemberId) {
-       updatedCachedValues()
-     }
-   }
-   function onCursorRemoved(memberId) {
-     if(memberId === inputMemberId) {
-       updatedCachedValues()
-     }
-   }
-   function onCursorMoved(cursor) {
-     if(cursor.getMemberId() === inputMemberId) {
-       updatedCachedValues()
-     }
-   }
-   this.isAnnotatable = function() {
-     return isAnnotatable
++gui.ShadowCursor = function ShadowCursor(document) {
++  var selectedRange = (document.getDOMDocument().createRange()), forwardSelection = true;
++  this.removeFromDocument = function() {
 +  };
-   this.addAnnotation = function() {
-     var op = new ops.OpAddAnnotation, selection = odtDocument.getCursorSelection(inputMemberId), length = selection.length, position = selection.position;
-     if(!isAnnotatable) {
-       return
-     }
-     position = length >= 0 ? position : position + length;
-     length = Math.abs(length);
-     op.init({memberid:inputMemberId, position:position, length:length, name:inputMemberId + Date.now()});
-     session.enqueue([op])
++  this.getMemberId = function() {
++    return gui.ShadowCursor.ShadowCursorMemberId
 +  };
-   this.removeAnnotation = function(annotationNode) {
-     var startStep, endStep, op, moveCursor;
-     startStep = odtDocument.convertDomPointToCursorStep(annotationNode, 0) + 1;
-     endStep = odtDocument.convertDomPointToCursorStep(annotationNode, annotationNode.childNodes.length);
-     op = new ops.OpRemoveAnnotation;
-     op.init({memberid:inputMemberId, position:startStep, length:endStep - startStep});
-     moveCursor = new ops.OpMoveCursor;
-     moveCursor.init({memberid:inputMemberId, position:startStep > 0 ? startStep - 1 : startStep, length:0});
-     session.enqueue([op, moveCursor])
++  this.getSelectedRange = function() {
++    return selectedRange
 +  };
-   this.subscribe = function(eventid, cb) {
-     eventNotifier.subscribe(eventid, cb)
++  this.setSelectedRange = function(range, isForwardSelection) {
++    selectedRange = range;
++    forwardSelection = isForwardSelection !== false
 +  };
-   this.unsubscribe = function(eventid, cb) {
-     eventNotifier.unsubscribe(eventid, cb)
++  this.hasForwardSelection = function() {
++    return forwardSelection
 +  };
-   this.destroy = function(callback) {
-     odtDocument.unsubscribe(ops.OdtDocument.signalCursorAdded, onCursorAdded);
-     odtDocument.unsubscribe(ops.OdtDocument.signalCursorRemoved, onCursorRemoved);
-     odtDocument.unsubscribe(ops.OdtDocument.signalCursorMoved, onCursorMoved);
-     callback()
++  this.getDocument = function() {
++    return document
++  };
++  this.getSelectionType = function() {
++    return ops.OdtCursor.RangeSelection
 +  };
 +  function init() {
-     odtDocument.subscribe(ops.OdtDocument.signalCursorAdded, onCursorAdded);
-     odtDocument.subscribe(ops.OdtDocument.signalCursorRemoved, onCursorRemoved);
-     odtDocument.subscribe(ops.OdtDocument.signalCursorMoved, onCursorMoved);
-     updatedCachedValues()
++    selectedRange.setStart(document.getRootNode(), 0)
 +  }
 +  init()
 +};
- gui.AnnotationController.annotatableChanged = "annotatable/changed";
++gui.ShadowCursor.ShadowCursorMemberId = "";
 +(function() {
-   return gui.AnnotationController
++  return gui.ShadowCursor
 +})();
++gui.SelectionView = function SelectionView(cursor) {
++};
++gui.SelectionView.prototype.rerender = function() {
++};
++gui.SelectionView.prototype.show = function() {
++};
++gui.SelectionView.prototype.hide = function() {
++};
++gui.SelectionView.prototype.destroy = function(callback) {
++};
 +/*
 +
 + Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("core.EventNotifier");
- runtime.loadClass("core.Utils");
- runtime.loadClass("odf.OdfUtils");
- runtime.loadClass("ops.OpAddStyle");
- runtime.loadClass("ops.OpSetParagraphStyle");
- runtime.loadClass("gui.StyleHelper");
- gui.DirectParagraphStyler = function DirectParagraphStyler(session, inputMemberId, objectNameGenerator) {
-   var odtDocument = session.getOdtDocument(), utils = new core.Utils, odfUtils = new odf.OdfUtils, styleHelper = new gui.StyleHelper(odtDocument.getFormatting()), eventNotifier = new core.EventNotifier([gui.DirectParagraphStyler.paragraphStylingChanged]), isAlignedLeftValue, isAlignedCenterValue, isAlignedRightValue, isAlignedJustifiedValue;
-   function updatedCachedValues() {
-     var cursor = odtDocument.getCursor(inputMemberId), range = cursor && cursor.getSelectedRange(), diffMap;
-     function noteChange(oldValue, newValue, id) {
-       if(oldValue !== newValue) {
-         if(diffMap === undefined) {
-           diffMap = {}
-         }
-         diffMap[id] = newValue
-       }
-       return newValue
-     }
-     isAlignedLeftValue = noteChange(isAlignedLeftValue, range ? styleHelper.isAlignedLeft(range) : false, "isAlignedLeft");
-     isAlignedCenterValue = noteChange(isAlignedCenterValue, range ? styleHelper.isAlignedCenter(range) : false, "isAlignedCenter");
-     isAlignedRightValue = noteChange(isAlignedRightValue, range ? styleHelper.isAlignedRight(range) : false, "isAlignedRight");
-     isAlignedJustifiedValue = noteChange(isAlignedJustifiedValue, range ? styleHelper.isAlignedJustified(range) : false, "isAlignedJustified");
-     if(diffMap) {
-       eventNotifier.emit(gui.DirectParagraphStyler.paragraphStylingChanged, diffMap)
-     }
-   }
-   function onCursorAdded(cursor) {
-     if(cursor.getMemberId() === inputMemberId) {
-       updatedCachedValues()
-     }
++gui.SelectionViewManager = function SelectionViewManager(SelectionView) {
++  var selectionViews = {};
++  function getSelectionView(memberId) {
++    return selectionViews.hasOwnProperty(memberId) ? selectionViews[memberId] : null
 +  }
-   function onCursorRemoved(memberId) {
-     if(memberId === inputMemberId) {
-       updatedCachedValues()
-     }
++  this.getSelectionView = getSelectionView;
++  function getSelectionViews() {
++    return Object.keys(selectionViews).map(function(memberid) {
++      return selectionViews[memberid]
++    })
 +  }
-   function onCursorMoved(cursor) {
-     if(cursor.getMemberId() === inputMemberId) {
-       updatedCachedValues()
++  this.getSelectionViews = getSelectionViews;
++  function removeSelectionView(memberId) {
++    if(selectionViews.hasOwnProperty(memberId)) {
++      selectionViews[memberId].destroy(function() {
++      });
++      delete selectionViews[memberId]
 +    }
 +  }
-   function onParagraphStyleModified() {
-     updatedCachedValues()
-   }
-   function onParagraphChanged(args) {
-     var cursor = odtDocument.getCursor(inputMemberId);
-     if(cursor && odtDocument.getParagraphElement(cursor.getNode()) === args.paragraphElement) {
-       updatedCachedValues()
++  this.removeSelectionView = removeSelectionView;
++  function hideSelectionView(memberId) {
++    if(selectionViews.hasOwnProperty(memberId)) {
++      selectionViews[memberId].hide()
 +    }
 +  }
-   this.isAlignedLeft = function() {
-     return isAlignedLeftValue
-   };
-   this.isAlignedCenter = function() {
-     return isAlignedCenterValue
-   };
-   this.isAlignedRight = function() {
-     return isAlignedRightValue
-   };
-   this.isAlignedJustified = function() {
-     return isAlignedJustifiedValue
-   };
-   function roundUp(step) {
-     return step === ops.StepsTranslator.NEXT_STEP
-   }
-   function applyParagraphDirectStyling(applyDirectStyling) {
-     var range = odtDocument.getCursor(inputMemberId).getSelectedRange(), paragraphs = odfUtils.getParagraphElements(range), formatting = odtDocument.getFormatting();
-     paragraphs.forEach(function(paragraph) {
-       var paragraphStartPoint = odtDocument.convertDomPointToCursorStep(paragraph, 0, roundUp), paragraphStyleName = paragraph.getAttributeNS(odf.Namespaces.textns, "style-name"), newParagraphStyleName = objectNameGenerator.generateStyleName(), opAddStyle, opSetParagraphStyle, paragraphProperties;
-       if(paragraphStyleName) {
-         paragraphProperties = formatting.createDerivedStyleObject(paragraphStyleName, "paragraph", {})
-       }
-       paragraphProperties = applyDirectStyling(paragraphProperties || {});
-       opAddStyle = new ops.OpAddStyle;
-       opAddStyle.init({memberid:inputMemberId, styleName:newParagraphStyleName, styleFamily:"paragraph", isAutomaticStyle:true, setProperties:paragraphProperties});
-       opSetParagraphStyle = new ops.OpSetParagraphStyle;
-       opSetParagraphStyle.init({memberid:inputMemberId, styleName:newParagraphStyleName, position:paragraphStartPoint});
-       session.enqueue([opAddStyle, opSetParagraphStyle])
-     })
-   }
-   function applySimpleParagraphDirectStyling(styleOverrides) {
-     applyParagraphDirectStyling(function(paragraphStyle) {
-       return utils.mergeObjects(paragraphStyle, styleOverrides)
-     })
-   }
-   function alignParagraph(alignment) {
-     applySimpleParagraphDirectStyling({"style:paragraph-properties":{"fo:text-align":alignment}})
-   }
-   this.alignParagraphLeft = function() {
-     alignParagraph("left");
-     return true
-   };
-   this.alignParagraphCenter = function() {
-     alignParagraph("center");
-     return true
-   };
-   this.alignParagraphRight = function() {
-     alignParagraph("right");
-     return true
-   };
-   this.alignParagraphJustified = function() {
-     alignParagraph("justify");
-     return true
-   };
-   function modifyParagraphIndent(direction, paragraphStyle) {
-     var tabStopDistance = odtDocument.getFormatting().getDefaultTabStopDistance(), paragraphProperties = paragraphStyle["style:paragraph-properties"], indentValue = paragraphProperties && paragraphProperties["fo:margin-left"], indent = indentValue && odfUtils.parseLength(indentValue), newIndent;
-     if(indent && indent.unit === tabStopDistance.unit) {
-       newIndent = indent.value + direction * tabStopDistance.value + indent.unit
-     }else {
-       newIndent = direction * tabStopDistance.value + tabStopDistance.unit
++  this.hideSelectionView = hideSelectionView;
++  function showSelectionView(memberId) {
++    if(selectionViews.hasOwnProperty(memberId)) {
++      selectionViews[memberId].show()
 +    }
-     return utils.mergeObjects(paragraphStyle, {"style:paragraph-properties":{"fo:margin-left":newIndent}})
 +  }
-   this.indent = function() {
-     applyParagraphDirectStyling(modifyParagraphIndent.bind(null, 1));
-     return true
-   };
-   this.outdent = function() {
-     applyParagraphDirectStyling(modifyParagraphIndent.bind(null, -1));
-     return true
-   };
-   this.subscribe = function(eventid, cb) {
-     eventNotifier.subscribe(eventid, cb)
++  this.showSelectionView = showSelectionView;
++  this.rerenderSelectionViews = function() {
++    Object.keys(selectionViews).forEach(function(memberId) {
++      selectionViews[memberId].rerender()
++    })
 +  };
-   this.unsubscribe = function(eventid, cb) {
-     eventNotifier.unsubscribe(eventid, cb)
++  this.registerCursor = function(cursor, virtualSelectionsInitiallyVisible) {
++    var memberId = cursor.getMemberId(), selectionView = new SelectionView(cursor);
++    if(virtualSelectionsInitiallyVisible) {
++      selectionView.show()
++    }else {
++      selectionView.hide()
++    }
++    selectionViews[memberId] = selectionView;
++    return selectionView
 +  };
 +  this.destroy = function(callback) {
-     odtDocument.unsubscribe(ops.OdtDocument.signalCursorAdded, onCursorAdded);
-     odtDocument.unsubscribe(ops.OdtDocument.signalCursorRemoved, onCursorRemoved);
-     odtDocument.unsubscribe(ops.OdtDocument.signalCursorMoved, onCursorMoved);
-     odtDocument.unsubscribe(ops.OdtDocument.signalParagraphStyleModified, onParagraphStyleModified);
-     odtDocument.unsubscribe(ops.OdtDocument.signalParagraphChanged, onParagraphChanged);
-     callback()
-   };
-   function init() {
-     odtDocument.subscribe(ops.OdtDocument.signalCursorAdded, onCursorAdded);
-     odtDocument.subscribe(ops.OdtDocument.signalCursorRemoved, onCursorRemoved);
-     odtDocument.subscribe(ops.OdtDocument.signalCursorMoved, onCursorMoved);
-     odtDocument.subscribe(ops.OdtDocument.signalParagraphStyleModified, onParagraphStyleModified);
-     odtDocument.subscribe(ops.OdtDocument.signalParagraphChanged, onParagraphChanged);
-     updatedCachedValues()
++    var selectionViewArray = getSelectionViews();
++    function destroySelectionView(i, err) {
++      if(err) {
++        callback(err)
++      }else {
++        if(i < selectionViewArray.length) {
++          selectionViewArray[i].destroy(function(err) {
++            destroySelectionView(i + 1, err)
++          })
++        }else {
++          callback()
++        }
++      }
++    }
++    destroySelectionView(0, undefined)
 +  }
-   init()
 +};
- gui.DirectParagraphStyler.paragraphStylingChanged = "paragraphStyling/changed";
- (function() {
-   return gui.DirectParagraphStyler
- })();
 +/*
 +
-  Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
++ Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("core.EventNotifier");
- runtime.loadClass("core.Utils");
- runtime.loadClass("ops.OpApplyDirectStyling");
- runtime.loadClass("gui.StyleHelper");
- gui.DirectTextStyler = function DirectTextStyler(session, inputMemberId) {
-   var self = this, utils = new core.Utils, odtDocument = session.getOdtDocument(), styleHelper = new gui.StyleHelper(odtDocument.getFormatting()), eventNotifier = new core.EventNotifier([gui.DirectTextStyler.textStylingChanged]), directCursorStyleProperties, currentSelectionStyles = [], isBoldValue = false, isItalicValue = false, hasUnderlineValue = false, hasStrikeThroughValue = false, fontSizeValue, fontNameValue;
-   function get(obj, keys) {
-     var i = 0, key = keys[i];
-     while(key && obj) {
-       obj = obj[key];
-       i += 1;
-       key = keys[i]
-     }
-     return keys.length === i ? obj : undefined
-   }
-   function getCommonValue(objArray, keys) {
-     var value = get(objArray[0], keys);
-     return objArray.every(function(obj) {
-       return value === get(obj, keys)
-     }) ? value : undefined
-   }
-   function getAppliedStyles() {
-     var cursor = odtDocument.getCursor(inputMemberId), range = cursor && cursor.getSelectedRange(), selectionStyles = range && styleHelper.getAppliedStyles(range) || [];
-     if(selectionStyles[0] && directCursorStyleProperties) {
-       selectionStyles[0] = utils.mergeObjects(selectionStyles[0], (directCursorStyleProperties))
++gui.SessionViewOptions = function() {
++  this.editInfoMarkersInitiallyVisible = true;
++  this.caretAvatarsInitiallyVisible = true;
++  this.caretBlinksOnRangeSelect = true
++};
++(function() {
++  function configOption(userValue, defaultValue) {
++    return userValue !== undefined ? Boolean(userValue) : defaultValue
++  }
++  gui.SessionView = function SessionView(viewOptions, localMemberId, session, caretManager, selectionViewManager) {
++    var avatarInfoStyles, editInfons = "urn:webodf:names:editinfo", editInfoMap = {}, showEditInfoMarkers = configOption(viewOptions.editInfoMarkersInitiallyVisible, true), showCaretAvatars = configOption(viewOptions.caretAvatarsInitiallyVisible, true), blinkOnRangeSelect = configOption(viewOptions.caretBlinksOnRangeSelect, true);
++    function createAvatarInfoNodeMatch(nodeName, memberId, pseudoClass) {
++      return nodeName + '[editinfo|memberid="' + memberId + '"]' + pseudoClass
++    }
++    function getAvatarInfoStyle(nodeName, memberId, pseudoClass) {
++      var node = avatarInfoStyles.firstChild, nodeMatch = createAvatarInfoNodeMatch(nodeName, memberId, pseudoClass) + "{";
++      while(node) {
++        if(node.nodeType === Node.TEXT_NODE && (node).data.indexOf(nodeMatch) === 0) {
++          return node
++        }
++        node = node.nextSibling
++      }
++      return null
++    }
++    function setAvatarInfoStyle(memberId, name, color) {
++      function setStyle(nodeName, rule, pseudoClass) {
++        var styleRule = createAvatarInfoNodeMatch(nodeName, memberId, pseudoClass) + rule, styleNode = getAvatarInfoStyle(nodeName, memberId, pseudoClass);
++        if(styleNode) {
++          styleNode.data = styleRule
++        }else {
++          avatarInfoStyles.appendChild(document.createTextNode(styleRule))
++        }
++      }
++      setStyle("div.editInfoMarker", "{ background-color: " + color + "; }", "");
++      setStyle("span.editInfoColor", "{ background-color: " + color + "; }", "");
++      setStyle("span.editInfoAuthor", '{ content: "' + name + '"; }', ":before");
++      setStyle("dc|creator", "{ background-color: " + color + "; }", "");
++      setStyle(".selectionOverlay", "{ fill: " + color + "; stroke: " + color + ";}", "");
++      if(memberId === gui.ShadowCursor.ShadowCursorMemberId || memberId === localMemberId) {
++        setStyle(".webodf-touchEnabled .selectionOverlay", "{ display: block; }", " > .draggable")
++      }
++    }
++    function highlightEdit(element, memberId, timestamp) {
++      var editInfo, editInfoMarker, id = "", editInfoNode = element.getElementsByTagNameNS(editInfons, "editinfo").item(0);
++      if(editInfoNode) {
++        id = (editInfoNode).getAttributeNS(editInfons, "id");
++        editInfoMarker = editInfoMap[id]
++      }else {
++        id = Math.random().toString();
++        editInfo = new ops.EditInfo(element, session.getOdtDocument());
++        editInfoMarker = new gui.EditInfoMarker(editInfo, showEditInfoMarkers);
++        editInfoNode = (element.getElementsByTagNameNS(editInfons, "editinfo").item(0));
++        editInfoNode.setAttributeNS(editInfons, "id", id);
++        editInfoMap[id] = editInfoMarker
++      }
++      editInfoMarker.addEdit(memberId, new Date(timestamp))
++    }
++    function setEditInfoMarkerVisibility(visible) {
++      var editInfoMarker, keyname;
++      for(keyname in editInfoMap) {
++        if(editInfoMap.hasOwnProperty(keyname)) {
++          editInfoMarker = editInfoMap[keyname];
++          if(visible) {
++            editInfoMarker.show()
++          }else {
++            editInfoMarker.hide()
++          }
++        }
++      }
++    }
++    function setCaretAvatarVisibility(visible) {
++      caretManager.getCarets().forEach(function(caret) {
++        if(visible) {
++          caret.showHandle()
++        }else {
++          caret.hideHandle()
++        }
++      })
++    }
++    this.showEditInfoMarkers = function() {
++      if(showEditInfoMarkers) {
++        return
++      }
++      showEditInfoMarkers = true;
++      setEditInfoMarkerVisibility(showEditInfoMarkers)
++    };
++    this.hideEditInfoMarkers = function() {
++      if(!showEditInfoMarkers) {
++        return
++      }
++      showEditInfoMarkers = false;
++      setEditInfoMarkerVisibility(showEditInfoMarkers)
++    };
++    this.showCaretAvatars = function() {
++      if(showCaretAvatars) {
++        return
++      }
++      showCaretAvatars = true;
++      setCaretAvatarVisibility(showCaretAvatars)
++    };
++    this.hideCaretAvatars = function() {
++      if(!showCaretAvatars) {
++        return
++      }
++      showCaretAvatars = false;
++      setCaretAvatarVisibility(showCaretAvatars)
++    };
++    this.getSession = function() {
++      return session
++    };
++    this.getCaret = function(memberid) {
++      return caretManager.getCaret(memberid)
++    };
++    function renderMemberData(member) {
++      var memberId = member.getMemberId(), properties = member.getProperties();
++      setAvatarInfoStyle(memberId, properties.fullName, properties.color);
++      if(localMemberId === memberId) {
++        setAvatarInfoStyle("", "", properties.color)
++      }
++    }
++    function onCursorAdded(cursor) {
++      var memberId = cursor.getMemberId(), properties = session.getOdtDocument().getMember(memberId).getProperties(), caret;
++      caretManager.registerCursor(cursor, showCaretAvatars, blinkOnRangeSelect);
++      selectionViewManager.registerCursor(cursor, true);
++      caret = caretManager.getCaret(memberId);
++      if(caret) {
++        caret.setAvatarImageUrl(properties.imageUrl);
++        caret.setColor(properties.color)
++      }
++      runtime.log("+++ View here +++ eagerly created an Caret for '" + memberId + "'! +++")
++    }
++    function onCursorMoved(cursor) {
++      var memberId = cursor.getMemberId(), localSelectionView = selectionViewManager.getSelectionView(localMemberId), shadowSelectionView = selectionViewManager.getSelectionView(gui.ShadowCursor.ShadowCursorMemberId), localCaret = caretManager.getCaret(localMemberId);
++      if(memberId === localMemberId) {
++        shadowSelectionView.hide();
++        if(localSelectionView) {
++          localSelectionView.show()
++        }
++        if(localCaret) {
++          localCaret.show()
++        }
++      }else {
++        if(memberId === gui.ShadowCursor.ShadowCursorMemberId) {
++          shadowSelectionView.show();
++          if(localSelectionView) {
++            localSelectionView.hide()
++          }
++          if(localCaret) {
++            localCaret.hide()
++          }
++        }
++      }
++    }
++    function onCursorRemoved(memberid) {
++      selectionViewManager.removeSelectionView(memberid)
++    }
++    function onParagraphChanged(info) {
++      highlightEdit(info.paragraphElement, info.memberId, info.timeStamp)
++    }
++    this.destroy = function(callback) {
++      var odtDocument = session.getOdtDocument(), editInfoArray = Object.keys(editInfoMap).map(function(keyname) {
++        return editInfoMap[keyname]
++      });
++      odtDocument.unsubscribe(ops.Document.signalMemberAdded, renderMemberData);
++      odtDocument.unsubscribe(ops.Document.signalMemberUpdated, renderMemberData);
++      odtDocument.unsubscribe(ops.Document.signalCursorAdded, onCursorAdded);
++      odtDocument.unsubscribe(ops.Document.signalCursorRemoved, onCursorRemoved);
++      odtDocument.unsubscribe(ops.OdtDocument.signalParagraphChanged, onParagraphChanged);
++      odtDocument.unsubscribe(ops.Document.signalCursorMoved, onCursorMoved);
++      odtDocument.unsubscribe(ops.OdtDocument.signalParagraphChanged, selectionViewManager.rerenderSelectionViews);
++      odtDocument.unsubscribe(ops.OdtDocument.signalTableAdded, selectionViewManager.rerenderSelectionViews);
++      odtDocument.unsubscribe(ops.OdtDocument.signalParagraphStyleModified, selectionViewManager.rerenderSelectionViews);
++      avatarInfoStyles.parentNode.removeChild(avatarInfoStyles);
++      (function destroyEditInfo(i, err) {
++        if(err) {
++          callback(err)
++        }else {
++          if(i < editInfoArray.length) {
++            editInfoArray[i].destroy(function(err) {
++              destroyEditInfo(i + 1, err)
++            })
++          }else {
++            callback()
++          }
++        }
++      })(0, undefined)
++    };
++    function init() {
++      var odtDocument = session.getOdtDocument(), head = document.getElementsByTagName("head").item(0);
++      odtDocument.subscribe(ops.Document.signalMemberAdded, renderMemberData);
++      odtDocument.subscribe(ops.Document.signalMemberUpdated, renderMemberData);
++      odtDocument.subscribe(ops.Document.signalCursorAdded, onCursorAdded);
++      odtDocument.subscribe(ops.Document.signalCursorRemoved, onCursorRemoved);
++      odtDocument.subscribe(ops.OdtDocument.signalParagraphChanged, onParagraphChanged);
++      odtDocument.subscribe(ops.Document.signalCursorMoved, onCursorMoved);
++      odtDocument.subscribe(ops.OdtDocument.signalParagraphChanged, selectionViewManager.rerenderSelectionViews);
++      odtDocument.subscribe(ops.OdtDocument.signalTableAdded, selectionViewManager.rerenderSelectionViews);
++      odtDocument.subscribe(ops.OdtDocument.signalParagraphStyleModified, selectionViewManager.rerenderSelectionViews);
++      avatarInfoStyles = (document.createElementNS(head.namespaceURI, "style"));
++      avatarInfoStyles.type = "text/css";
++      avatarInfoStyles.media = "screen, print, handheld, projection";
++      avatarInfoStyles.appendChild(document.createTextNode("@namespace editinfo url(urn:webodf:names:editinfo);"));
++      avatarInfoStyles.appendChild(document.createTextNode("@namespace dc url(http://purl.org/dc/elements/1.1/);"));
++      head.appendChild(avatarInfoStyles)
++    }
++    init()
++  }
++})();
++gui.SvgSelectionView = function SvgSelectionView(cursor) {
++  var document = cursor.getDocument(), documentRoot, root, doc = document.getDOMDocument(), async = new core.Async, svgns = "http://www.w3.org/2000/svg", overlay = doc.createElementNS(svgns, "svg"), polygon = doc.createElementNS(svgns, "polygon"), handle1 = doc.createElementNS(svgns, "circle"), handle2 = doc.createElementNS(svgns, "circle"), odfUtils = new odf.OdfUtils, domUtils = new core.DomUtils, zoomHelper = document.getCanvas().getZoomHelper(), isVisible = true, positionIterator =  [...]
++  FILTER_ACCEPT = NodeFilter.FILTER_ACCEPT, FILTER_REJECT = NodeFilter.FILTER_REJECT, HANDLE_RADIUS = 8, renderTask;
++  function addOverlay() {
++    var newDocumentRoot = document.getRootNode();
++    if(documentRoot !== newDocumentRoot) {
++      documentRoot = newDocumentRoot;
++      root = (documentRoot.parentNode.parentNode.parentNode);
++      root.appendChild(overlay);
++      overlay.setAttribute("class", "selectionOverlay");
++      handle1.setAttribute("class", "draggable");
++      handle2.setAttribute("class", "draggable");
++      handle1.setAttribute("end", "left");
++      handle2.setAttribute("end", "right");
++      handle1.setAttribute("r", HANDLE_RADIUS);
++      handle2.setAttribute("r", HANDLE_RADIUS);
++      overlay.appendChild(polygon);
++      overlay.appendChild(handle1);
++      overlay.appendChild(handle2)
++    }
++  }
++  function translateRect(rect) {
++    var rootRect = domUtils.getBoundingClientRect(root), zoomLevel = zoomHelper.getZoomLevel(), resultRect = {};
++    resultRect.top = domUtils.adaptRangeDifferenceToZoomLevel(rect.top - rootRect.top, zoomLevel);
++    resultRect.left = domUtils.adaptRangeDifferenceToZoomLevel(rect.left - rootRect.left, zoomLevel);
++    resultRect.bottom = domUtils.adaptRangeDifferenceToZoomLevel(rect.bottom - rootRect.top, zoomLevel);
++    resultRect.right = domUtils.adaptRangeDifferenceToZoomLevel(rect.right - rootRect.left, zoomLevel);
++    resultRect.width = domUtils.adaptRangeDifferenceToZoomLevel(rect.width, zoomLevel);
++    resultRect.height = domUtils.adaptRangeDifferenceToZoomLevel(rect.height, zoomLevel);
++    return resultRect
++  }
++  function isRangeVisible(range) {
++    var bcr = range.getBoundingClientRect();
++    return Boolean(bcr && bcr.height !== 0)
++  }
++  function lastVisibleRect(range, nodes) {
++    var nextNodeIndex = nodes.length - 1, node = nodes[nextNodeIndex], startOffset, endOffset;
++    if(range.endContainer === node) {
++      startOffset = range.endOffset
++    }else {
++      if(node.nodeType === Node.TEXT_NODE) {
++        startOffset = node.length
++      }else {
++        startOffset = node.childNodes.length
++      }
++    }
++    endOffset = startOffset;
++    range.setStart(node, startOffset);
++    range.setEnd(node, endOffset);
++    while(!isRangeVisible(range)) {
++      if(node.nodeType === Node.ELEMENT_NODE && startOffset > 0) {
++        startOffset = 0
++      }else {
++        if(node.nodeType === Node.TEXT_NODE && startOffset > 0) {
++          startOffset -= 1
++        }else {
++          if(nodes[nextNodeIndex]) {
++            node = nodes[nextNodeIndex];
++            nextNodeIndex -= 1;
++            startOffset = endOffset = node.length || node.childNodes.length
++          }else {
++            return false
++          }
++        }
++      }
++      range.setStart(node, startOffset);
++      range.setEnd(node, endOffset)
 +    }
-     return selectionStyles
++    return true
 +  }
-   function updatedCachedValues() {
-     var fontSize, diffMap;
-     currentSelectionStyles = getAppliedStyles();
-     function noteChange(oldValue, newValue, id) {
-       if(oldValue !== newValue) {
-         if(diffMap === undefined) {
-           diffMap = {}
++  function firstVisibleRect(range, nodes) {
++    var nextNodeIndex = 0, node = nodes[nextNodeIndex], startOffset = range.startContainer === node ? range.startOffset : 0, endOffset = startOffset;
++    range.setStart(node, startOffset);
++    range.setEnd(node, endOffset);
++    while(!isRangeVisible(range)) {
++      if(node.nodeType === Node.ELEMENT_NODE && endOffset < node.childNodes.length) {
++        endOffset = node.childNodes.length
++      }else {
++        if(node.nodeType === Node.TEXT_NODE && endOffset < node.length) {
++          endOffset += 1
++        }else {
++          if(nodes[nextNodeIndex]) {
++            node = nodes[nextNodeIndex];
++            nextNodeIndex += 1;
++            startOffset = endOffset = 0
++          }else {
++            return false
++          }
 +        }
-         diffMap[id] = newValue
 +      }
-       return newValue
-     }
-     isBoldValue = noteChange(isBoldValue, currentSelectionStyles ? styleHelper.isBold(currentSelectionStyles) : false, "isBold");
-     isItalicValue = noteChange(isItalicValue, currentSelectionStyles ? styleHelper.isItalic(currentSelectionStyles) : false, "isItalic");
-     hasUnderlineValue = noteChange(hasUnderlineValue, currentSelectionStyles ? styleHelper.hasUnderline(currentSelectionStyles) : false, "hasUnderline");
-     hasStrikeThroughValue = noteChange(hasStrikeThroughValue, currentSelectionStyles ? styleHelper.hasStrikeThrough(currentSelectionStyles) : false, "hasStrikeThrough");
-     fontSize = currentSelectionStyles && getCommonValue(currentSelectionStyles, ["style:text-properties", "fo:font-size"]);
-     fontSizeValue = noteChange(fontSizeValue, fontSize && parseFloat(fontSize), "fontSize");
-     fontNameValue = noteChange(fontNameValue, currentSelectionStyles && getCommonValue(currentSelectionStyles, ["style:text-properties", "style:font-name"]), "fontName");
-     if(diffMap) {
-       eventNotifier.emit(gui.DirectTextStyler.textStylingChanged, diffMap)
++      range.setStart(node, startOffset);
++      range.setEnd(node, endOffset)
 +    }
++    return true
 +  }
-   function onCursorAdded(cursor) {
-     if(cursor.getMemberId() === inputMemberId) {
-       updatedCachedValues()
++  function getExtremeRanges(range) {
++    var nodes = odfUtils.getTextElements(range, true, false), firstRange = (range.cloneRange()), lastRange = (range.cloneRange()), fillerRange = range.cloneRange();
++    if(!nodes.length) {
++      return null
 +    }
-   }
-   function onCursorRemoved(memberId) {
-     if(memberId === inputMemberId) {
-       updatedCachedValues()
++    if(!firstVisibleRect(firstRange, nodes)) {
++      return null
 +    }
-   }
-   function onCursorMoved(cursor) {
-     if(cursor.getMemberId() === inputMemberId) {
-       updatedCachedValues()
++    if(!lastVisibleRect(lastRange, nodes)) {
++      return null
 +    }
++    fillerRange.setStart(firstRange.startContainer, firstRange.startOffset);
++    fillerRange.setEnd(lastRange.endContainer, lastRange.endOffset);
++    return{firstRange:firstRange, lastRange:lastRange, fillerRange:fillerRange}
 +  }
-   function onParagraphStyleModified() {
-     updatedCachedValues()
++  function getBoundingRect(rect1, rect2) {
++    var resultRect = {};
++    resultRect.top = Math.min(rect1.top, rect2.top);
++    resultRect.left = Math.min(rect1.left, rect2.left);
++    resultRect.right = Math.max(rect1.right, rect2.right);
++    resultRect.bottom = Math.max(rect1.bottom, rect2.bottom);
++    resultRect.width = resultRect.right - resultRect.left;
++    resultRect.height = resultRect.bottom - resultRect.top;
++    return resultRect
 +  }
-   function onParagraphChanged(args) {
-     var cursor = odtDocument.getCursor(inputMemberId);
-     if(cursor && odtDocument.getParagraphElement(cursor.getNode()) === args.paragraphElement) {
-       updatedCachedValues()
++  function checkAndGrowOrCreateRect(originalRect, newRect) {
++    if(newRect && (newRect.width > 0 && newRect.height > 0)) {
++      if(!originalRect) {
++        originalRect = newRect
++      }else {
++        originalRect = getBoundingRect(originalRect, newRect)
++      }
 +    }
++    return originalRect
 +  }
-   function toggle(predicate, toggleMethod) {
-     var cursor = odtDocument.getCursor(inputMemberId), appliedStyles;
-     if(!cursor) {
-       return false
++  function getFillerRect(fillerRange) {
++    var containerNode = fillerRange.commonAncestorContainer, firstNode = (fillerRange.startContainer), lastNode = (fillerRange.endContainer), firstOffset = fillerRange.startOffset, lastOffset = fillerRange.endOffset, currentNode, lastMeasuredNode, firstSibling, lastSibling, grownRect = null, currentRect, range = doc.createRange(), rootFilter, odfNodeFilter = new odf.OdfNodeFilter, treeWalker;
++    function acceptNode(node) {
++      positionIterator.setUnfilteredPosition(node, 0);
++      if(odfNodeFilter.acceptNode(node) === FILTER_ACCEPT && rootFilter.acceptPosition(positionIterator) === FILTER_ACCEPT) {
++        return FILTER_ACCEPT
++      }
++      return FILTER_REJECT
 +    }
-     appliedStyles = styleHelper.getAppliedStyles(cursor.getSelectedRange());
-     toggleMethod(!predicate(appliedStyles));
-     return true
-   }
-   function formatTextSelection(textProperties) {
-     var selection = odtDocument.getCursorSelection(inputMemberId), op, properties = {"style:text-properties":textProperties};
-     if(selection.length !== 0) {
-       op = new ops.OpApplyDirectStyling;
-       op.init({memberid:inputMemberId, position:selection.position, length:selection.length, setProperties:properties});
-       session.enqueue([op])
++    function getRectFromNodeAfterFiltering(node) {
++      var rect = null;
++      if(acceptNode(node) === FILTER_ACCEPT) {
++        rect = domUtils.getBoundingClientRect(node)
++      }
++      return rect
++    }
++    if(firstNode === containerNode || lastNode === containerNode) {
++      range = fillerRange.cloneRange();
++      grownRect = range.getBoundingClientRect();
++      range.detach();
++      return grownRect
++    }
++    firstSibling = firstNode;
++    while(firstSibling.parentNode !== containerNode) {
++      firstSibling = firstSibling.parentNode
++    }
++    lastSibling = lastNode;
++    while(lastSibling.parentNode !== containerNode) {
++      lastSibling = lastSibling.parentNode
++    }
++    rootFilter = document.createRootFilter(firstNode);
++    currentNode = firstSibling.nextSibling;
++    while(currentNode && currentNode !== lastSibling) {
++      currentRect = getRectFromNodeAfterFiltering(currentNode);
++      grownRect = checkAndGrowOrCreateRect(grownRect, currentRect);
++      currentNode = currentNode.nextSibling
++    }
++    if(odfUtils.isParagraph(firstSibling)) {
++      grownRect = checkAndGrowOrCreateRect(grownRect, domUtils.getBoundingClientRect(firstSibling))
 +    }else {
-       directCursorStyleProperties = utils.mergeObjects(directCursorStyleProperties || {}, properties);
-       updatedCachedValues()
++      if(firstSibling.nodeType === Node.TEXT_NODE) {
++        currentNode = firstSibling;
++        range.setStart(currentNode, firstOffset);
++        range.setEnd(currentNode, currentNode === lastSibling ? lastOffset : (currentNode).length);
++        currentRect = range.getBoundingClientRect();
++        grownRect = checkAndGrowOrCreateRect(grownRect, currentRect)
++      }else {
++        treeWalker = doc.createTreeWalker(firstSibling, NodeFilter.SHOW_TEXT, acceptNode, false);
++        currentNode = treeWalker.currentNode = firstNode;
++        while(currentNode && currentNode !== lastNode) {
++          range.setStart(currentNode, firstOffset);
++          range.setEnd(currentNode, (currentNode).length);
++          currentRect = range.getBoundingClientRect();
++          grownRect = checkAndGrowOrCreateRect(grownRect, currentRect);
++          lastMeasuredNode = currentNode;
++          firstOffset = 0;
++          currentNode = treeWalker.nextNode()
++        }
++      }
 +    }
-   }
-   this.formatTextSelection = formatTextSelection;
-   function applyTextPropertyToSelection(propertyName, propertyValue) {
-     var textProperties = {};
-     textProperties[propertyName] = propertyValue;
-     formatTextSelection(textProperties)
-   }
-   this.createCursorStyleOp = function(position, length) {
-     var styleOp = null;
-     if(directCursorStyleProperties) {
-       styleOp = new ops.OpApplyDirectStyling;
-       styleOp.init({memberid:inputMemberId, position:position, length:length, setProperties:directCursorStyleProperties});
-       directCursorStyleProperties = null;
-       updatedCachedValues()
++    if(!lastMeasuredNode) {
++      lastMeasuredNode = firstNode
 +    }
-     return styleOp
-   };
-   function clearCursorStyle(op) {
-     var spec = op.spec();
-     if(directCursorStyleProperties && spec.memberid === inputMemberId) {
-       if(spec.optype !== "SplitParagraph") {
-         directCursorStyleProperties = null;
-         updatedCachedValues()
++    if(odfUtils.isParagraph(lastSibling)) {
++      grownRect = checkAndGrowOrCreateRect(grownRect, domUtils.getBoundingClientRect(lastSibling))
++    }else {
++      if(lastSibling.nodeType === Node.TEXT_NODE) {
++        currentNode = lastSibling;
++        range.setStart(currentNode, currentNode === firstSibling ? firstOffset : 0);
++        range.setEnd(currentNode, lastOffset);
++        currentRect = range.getBoundingClientRect();
++        grownRect = checkAndGrowOrCreateRect(grownRect, currentRect)
++      }else {
++        treeWalker = doc.createTreeWalker(lastSibling, NodeFilter.SHOW_TEXT, acceptNode, false);
++        currentNode = treeWalker.currentNode = lastNode;
++        while(currentNode && currentNode !== lastMeasuredNode) {
++          range.setStart(currentNode, 0);
++          range.setEnd(currentNode, lastOffset);
++          currentRect = range.getBoundingClientRect();
++          grownRect = checkAndGrowOrCreateRect(grownRect, currentRect);
++          currentNode = treeWalker.previousNode();
++          if(currentNode) {
++            lastOffset = (currentNode).length
++          }
++        }
 +      }
 +    }
++    return grownRect
 +  }
-   function setBold(checked) {
-     var value = checked ? "bold" : "normal";
-     applyTextPropertyToSelection("fo:font-weight", value)
-   }
-   this.setBold = setBold;
-   function setItalic(checked) {
-     var value = checked ? "italic" : "normal";
-     applyTextPropertyToSelection("fo:font-style", value)
-   }
-   this.setItalic = setItalic;
-   function setHasUnderline(checked) {
-     var value = checked ? "solid" : "none";
-     applyTextPropertyToSelection("style:text-underline-style", value)
++  function getCollapsedRectOfTextRange(range, useRightEdge) {
++    var clientRect = range.getBoundingClientRect(), collapsedRect = {};
++    collapsedRect.width = 0;
++    collapsedRect.top = clientRect.top;
++    collapsedRect.bottom = clientRect.bottom;
++    collapsedRect.height = clientRect.height;
++    collapsedRect.left = collapsedRect.right = useRightEdge ? clientRect.right : clientRect.left;
++    return collapsedRect
 +  }
-   this.setHasUnderline = setHasUnderline;
-   function setHasStrikethrough(checked) {
-     var value = checked ? "solid" : "none";
-     applyTextPropertyToSelection("style:text-line-through-style", value)
++  function setPoints(points) {
++    var pointsString = "", i;
++    for(i = 0;i < points.length;i += 1) {
++      pointsString += points[i].x + "," + points[i].y + " "
++    }
++    polygon.setAttribute("points", pointsString)
 +  }
-   this.setHasStrikethrough = setHasStrikethrough;
-   function setFontSize(value) {
-     applyTextPropertyToSelection("fo:font-size", value + "pt")
++  function repositionOverlays(selectedRange) {
++    var extremes = getExtremeRanges(selectedRange), firstRange, lastRange, fillerRange, firstRect, fillerRect, lastRect, left, right, top, bottom;
++    if(extremes) {
++      firstRange = extremes.firstRange;
++      lastRange = extremes.lastRange;
++      fillerRange = extremes.fillerRange;
++      firstRect = translateRect(getCollapsedRectOfTextRange(firstRange, false));
++      lastRect = translateRect(getCollapsedRectOfTextRange(lastRange, true));
++      fillerRect = getFillerRect(fillerRange);
++      if(!fillerRect) {
++        fillerRect = getBoundingRect(firstRect, lastRect)
++      }else {
++        fillerRect = translateRect(fillerRect)
++      }
++      left = fillerRect.left;
++      right = firstRect.left + Math.max(0, fillerRect.width - (firstRect.left - fillerRect.left));
++      top = Math.min(firstRect.top, lastRect.top);
++      bottom = lastRect.top + lastRect.height;
++      setPoints([{x:firstRect.left, y:top + firstRect.height}, {x:firstRect.left, y:top}, {x:right, y:top}, {x:right, y:bottom - lastRect.height}, {x:lastRect.right, y:bottom - lastRect.height}, {x:lastRect.right, y:bottom}, {x:left, y:bottom}, {x:left, y:top + firstRect.height}, {x:firstRect.left, y:top + firstRect.height}]);
++      handle1.setAttribute("cx", firstRect.left);
++      handle1.setAttribute("cy", top + firstRect.height / 2);
++      handle2.setAttribute("cx", lastRect.right);
++      handle2.setAttribute("cy", bottom - lastRect.height / 2);
++      firstRange.detach();
++      lastRange.detach();
++      fillerRange.detach()
++    }
++    return Boolean(extremes)
 +  }
-   this.setFontSize = setFontSize;
-   function setFontName(value) {
-     applyTextPropertyToSelection("style:font-name", value)
++  function rerender() {
++    var range = cursor.getSelectedRange(), shouldShow;
++    shouldShow = isVisible && (cursor.getSelectionType() === ops.OdtCursor.RangeSelection && !range.collapsed);
++    if(shouldShow) {
++      addOverlay();
++      shouldShow = repositionOverlays(range)
++    }
++    if(shouldShow) {
++      overlay.style.display = "block"
++    }else {
++      overlay.style.display = "none"
++    }
 +  }
-   this.setFontName = setFontName;
-   this.getAppliedStyles = function() {
-     return currentSelectionStyles
-   };
-   this.toggleBold = toggle.bind(self, styleHelper.isBold, setBold);
-   this.toggleItalic = toggle.bind(self, styleHelper.isItalic, setItalic);
-   this.toggleUnderline = toggle.bind(self, styleHelper.hasUnderline, setHasUnderline);
-   this.toggleStrikethrough = toggle.bind(self, styleHelper.hasStrikeThrough, setHasStrikethrough);
-   this.isBold = function() {
-     return isBoldValue
-   };
-   this.isItalic = function() {
-     return isItalicValue
-   };
-   this.hasUnderline = function() {
-     return hasUnderlineValue
-   };
-   this.hasStrikeThrough = function() {
-     return hasStrikeThroughValue
-   };
-   this.fontSize = function() {
-     return fontSizeValue
-   };
-   this.fontName = function() {
-     return fontNameValue
-   };
-   this.subscribe = function(eventid, cb) {
-     eventNotifier.subscribe(eventid, cb)
++  this.rerender = function() {
++    if(isVisible) {
++      renderTask.trigger()
++    }
 +  };
-   this.unsubscribe = function(eventid, cb) {
-     eventNotifier.unsubscribe(eventid, cb)
++  this.show = function() {
++    isVisible = true;
++    renderTask.trigger()
 +  };
-   this.destroy = function(callback) {
-     odtDocument.unsubscribe(ops.OdtDocument.signalCursorAdded, onCursorAdded);
-     odtDocument.unsubscribe(ops.OdtDocument.signalCursorRemoved, onCursorRemoved);
-     odtDocument.unsubscribe(ops.OdtDocument.signalCursorMoved, onCursorMoved);
-     odtDocument.unsubscribe(ops.OdtDocument.signalParagraphStyleModified, onParagraphStyleModified);
-     odtDocument.unsubscribe(ops.OdtDocument.signalParagraphChanged, onParagraphChanged);
-     odtDocument.unsubscribe(ops.OdtDocument.signalOperationExecuted, clearCursorStyle);
++  this.hide = function() {
++    isVisible = false;
++    renderTask.trigger()
++  };
++  function handleCursorMove(movedCursor) {
++    if(isVisible && movedCursor === cursor) {
++      renderTask.trigger()
++    }
++  }
++  function scaleHandles(zoomLevel) {
++    var radius = HANDLE_RADIUS / zoomLevel;
++    handle1.setAttribute("r", radius);
++    handle2.setAttribute("r", radius)
++  }
++  function destroy(callback) {
++    root.removeChild(overlay);
++    cursor.getDocument().unsubscribe(ops.Document.signalCursorMoved, handleCursorMove);
++    zoomHelper.unsubscribe(gui.ZoomHelper.signalZoomChanged, scaleHandles);
 +    callback()
++  }
++  this.destroy = function(callback) {
++    async.destroyAll([renderTask.destroy, destroy], callback)
 +  };
 +  function init() {
-     odtDocument.subscribe(ops.OdtDocument.signalCursorAdded, onCursorAdded);
-     odtDocument.subscribe(ops.OdtDocument.signalCursorRemoved, onCursorRemoved);
-     odtDocument.subscribe(ops.OdtDocument.signalCursorMoved, onCursorMoved);
-     odtDocument.subscribe(ops.OdtDocument.signalParagraphStyleModified, onParagraphStyleModified);
-     odtDocument.subscribe(ops.OdtDocument.signalParagraphChanged, onParagraphChanged);
-     odtDocument.subscribe(ops.OdtDocument.signalOperationExecuted, clearCursorStyle);
-     updatedCachedValues()
++    var editinfons = "urn:webodf:names:editinfo", memberid = cursor.getMemberId();
++    renderTask = new core.ScheduledTask(rerender, 0);
++    addOverlay();
++    overlay.setAttributeNS(editinfons, "editinfo:memberid", memberid);
++    cursor.getDocument().subscribe(ops.Document.signalCursorMoved, handleCursorMove);
++    zoomHelper.subscribe(gui.ZoomHelper.signalZoomChanged, scaleHandles);
++    scaleHandles(zoomHelper.getZoomLevel())
 +  }
 +  init()
 +};
- gui.DirectTextStyler.textStylingChanged = "textStyling/changed";
- (function() {
-   return gui.DirectTextStyler
- })();
- runtime.loadClass("odf.Namespaces");
- runtime.loadClass("odf.ObjectNameGenerator");
- gui.ImageManager = function ImageManager(session, inputMemberId, objectNameGenerator) {
-   var cmPerPixel = 0.0264583333333334, fileExtensionByMimetype = {"image/gif":".gif", "image/jpeg":".jpg", "image/png":".png"}, textns = odf.Namespaces.textns, odtDocument = session.getOdtDocument(), formatting = odtDocument.getFormatting(), paragraphStyleToPageContentSizeMap = {};
-   function createAddGraphicsStyleOp(name) {
-     var op = new ops.OpAddStyle;
-     op.init({memberid:inputMemberId, styleName:name, styleFamily:"graphic", isAutomaticStyle:false, setProperties:{"style:graphic-properties":{"text:anchor-type":"paragraph", "svg:x":"0cm", "svg:y":"0cm", "style:wrap":"dynamic", "style:number-wrapped-paragraphs":"no-limit", "style:wrap-contour":"false", "style:vertical-pos":"top", "style:vertical-rel":"paragraph", "style:horizontal-pos":"center", "style:horizontal-rel":"paragraph"}}});
-     return op
++/*
++
++ Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
++
++ @licstart
++ The JavaScript code in this page is free software: you can redistribute it
++ and/or modify it under the terms of the GNU Affero General Public License
++ (GNU AGPL) as published by the Free Software Foundation, either version 3 of
++ the License, or (at your option) any later version.  The code is distributed
++ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
++
++ You should have received a copy of the GNU Affero General Public License
++ along with this code.  If not, see <http://www.gnu.org/licenses/>.
++
++ As additional permission under GNU AGPL version 3 section 7, you
++ may distribute non-source (e.g., minimized or compacted) forms of
++ that code without the copy of the GNU GPL normally required by
++ section 4, provided you include this license notice and a URL
++ through which recipients can access the Corresponding Source.
++
++ As a special exception to the AGPL, any HTML file which merely makes function
++ calls to this code, and for that purpose includes it by reference shall be
++ deemed a separate work for copyright law purposes. In addition, the copyright
++ holders of this code give you permission to combine this code with free
++ software libraries that are released under the GNU LGPL. You may copy and
++ distribute such a system following the terms of the GNU AGPL for this code
++ and the LGPL for the libraries. If you modify this code, you may extend this
++ exception to your version of the code, but you are not obligated to do so.
++ If you do not wish to do so, delete this exception statement from your
++ version.
++
++ This license applies to this entire compilation.
++ @licend
++ @source: http://www.webodf.org/
++ @source: https://github.com/kogmbh/WebODF/
++*/
++gui.UndoStateRules = function UndoStateRules() {
++  function ReverseIterator(array, predicate) {
++    var index = array.length;
++    this.previous = function() {
++      for(index = index - 1;index >= 0;index -= 1) {
++        if(predicate(array[index])) {
++          return array[index]
++        }
++      }
++      return null
++    }
 +  }
-   function createAddFrameStyleOp(styleName, parentStyleName) {
-     var op = new ops.OpAddStyle;
-     op.init({memberid:inputMemberId, styleName:styleName, styleFamily:"graphic", isAutomaticStyle:true, setProperties:{"style:parent-style-name":parentStyleName, "style:graphic-properties":{"style:vertical-pos":"top", "style:vertical-rel":"baseline", "style:horizontal-pos":"center", "style:horizontal-rel":"paragraph", "fo:background-color":"transparent", "style:background-transparency":"100%", "style:shadow":"none", "style:mirror":"none", "fo:clip":"rect(0cm, 0cm, 0cm, 0cm)", "draw:lumi [...]
-     "draw:contrast":"0%", "draw:red":"0%", "draw:green":"0%", "draw:blue":"0%", "draw:gamma":"100%", "draw:color-inversion":"false", "draw:image-opacity":"100%", "draw:color-mode":"standard"}}});
-     return op
++  function getOpType(op) {
++    return op.spec().optype
 +  }
-   function getFileExtension(mimetype) {
-     mimetype = mimetype.toLowerCase();
-     return fileExtensionByMimetype.hasOwnProperty(mimetype) ? fileExtensionByMimetype[mimetype] : null
++  function getOpPosition(op) {
++    var key = "position", spec = op.spec(), value;
++    if(spec.hasOwnProperty(key)) {
++      value = (spec[key])
++    }
++    return value
 +  }
-   function insertImageInternal(mimetype, content, widthInCm, heightInCm) {
-     var graphicsStyleName = "Graphics", stylesElement = odtDocument.getOdfCanvas().odfContainer().rootElement.styles, fileExtension = getFileExtension(mimetype), fileName, graphicsStyleElement, frameStyleName, op, operations = [];
-     runtime.assert(fileExtension !== null, "Image type is not supported: " + mimetype);
-     fileName = "Pictures/" + objectNameGenerator.generateImageName() + fileExtension;
-     op = new ops.OpSetBlob;
-     op.init({memberid:inputMemberId, filename:fileName, mimetype:mimetype, content:content});
-     operations.push(op);
-     graphicsStyleElement = formatting.getStyleElement(graphicsStyleName, "graphic", [stylesElement]);
-     if(!graphicsStyleElement) {
-       op = createAddGraphicsStyleOp(graphicsStyleName);
-       operations.push(op)
++  function isEditOperation(op) {
++    return op.isEdit
++  }
++  this.isEditOperation = isEditOperation;
++  function canAggregateOperation(op) {
++    switch(getOpType(op)) {
++      case "RemoveText":
++      ;
++      case "InsertText":
++        return true;
++      default:
++        return false
 +    }
-     frameStyleName = objectNameGenerator.generateStyleName();
-     op = createAddFrameStyleOp(frameStyleName, graphicsStyleName);
-     operations.push(op);
-     op = new ops.OpInsertImage;
-     op.init({memberid:inputMemberId, position:odtDocument.getCursorPosition(inputMemberId), filename:fileName, frameWidth:widthInCm + "cm", frameHeight:heightInCm + "cm", frameStyleName:frameStyleName, frameName:objectNameGenerator.generateFrameName()});
-     operations.push(op);
-     session.enqueue(operations)
 +  }
-   function trimmedSize(originalSize, pageContentSize) {
-     var widthRatio = 1, heightRatio = 1, ratio;
-     if(originalSize.width > pageContentSize.width) {
-       widthRatio = pageContentSize.width / originalSize.width
++  function isSameDirectionOfTravel(thisOp, lastEditOp, secondLastEditOp) {
++    var thisPosition = getOpPosition(thisOp), lastPosition = getOpPosition(lastEditOp), secondLastPosition = getOpPosition(secondLastEditOp), diffLastToSecondLast = lastPosition - secondLastPosition, diffThisToLast = thisPosition - lastPosition;
++    return diffThisToLast === diffLastToSecondLast
++  }
++  function isAdjacentOperation(thisOp, lastEditOp) {
++    var positionDifference = getOpPosition(thisOp) - getOpPosition(lastEditOp);
++    return positionDifference === 0 || Math.abs(positionDifference) === 1
++  }
++  function continuesOperations(thisOp, lastEditOp, secondLastEditOp) {
++    if(!secondLastEditOp) {
++      return isAdjacentOperation(thisOp, lastEditOp)
 +    }
-     if(originalSize.height > pageContentSize.height) {
-       heightRatio = pageContentSize.height / originalSize.height
++    return isSameDirectionOfTravel(thisOp, lastEditOp, secondLastEditOp)
++  }
++  function continuesMostRecentEditOperation(thisOp, recentOperations) {
++    var thisOpType = getOpType(thisOp), editOpsFinder = new ReverseIterator(recentOperations, isEditOperation), lastEditOp = editOpsFinder.previous();
++    runtime.assert(Boolean(lastEditOp), "No edit operations found in state");
++    if(thisOpType === getOpType((lastEditOp))) {
++      return continuesOperations(thisOp, (lastEditOp), editOpsFinder.previous())
 +    }
-     ratio = Math.min(widthRatio, heightRatio);
-     return{width:originalSize.width * ratio, height:originalSize.height * ratio}
++    return false
 +  }
-   this.insertImage = function(mimetype, content, widthInPx, heightInPx) {
-     var paragraphElement, styleName, pageContentSize, originalSize, newSize;
-     runtime.assert(widthInPx > 0 && heightInPx > 0, "Both width and height of the image should be greater than 0px.");
-     paragraphElement = odtDocument.getParagraphElement(odtDocument.getCursor(inputMemberId).getNode());
-     styleName = paragraphElement.getAttributeNS(textns, "style-name");
-     if(!paragraphStyleToPageContentSizeMap.hasOwnProperty(styleName)) {
-       paragraphStyleToPageContentSizeMap[styleName] = formatting.getContentSize(styleName, "paragraph")
++  function continuesMostRecentEditGroup(thisOp, recentOperations) {
++    var thisOpType = getOpType(thisOp), editOpsFinder = new ReverseIterator(recentOperations, isEditOperation), candidateOp = editOpsFinder.previous(), lastEditOp, secondLastEditOp = null, inspectedGroupsCount, groupId;
++    runtime.assert(Boolean(candidateOp), "No edit operations found in state");
++    groupId = candidateOp.group;
++    runtime.assert(groupId !== undefined, "Operation has no group");
++    inspectedGroupsCount = 1;
++    while(candidateOp && candidateOp.group === groupId) {
++      if(thisOpType === getOpType(candidateOp)) {
++        lastEditOp = candidateOp;
++        break
++      }
++      candidateOp = editOpsFinder.previous()
 +    }
-     pageContentSize = paragraphStyleToPageContentSizeMap[styleName];
-     originalSize = {width:widthInPx * cmPerPixel, height:heightInPx * cmPerPixel};
-     newSize = trimmedSize(originalSize, pageContentSize);
-     insertImageInternal(mimetype, content, newSize.width, newSize.height)
++    if(lastEditOp) {
++      candidateOp = editOpsFinder.previous();
++      while(candidateOp) {
++        if(candidateOp.group !== groupId) {
++          if(inspectedGroupsCount === 2) {
++            break
++          }
++          groupId = candidateOp.group;
++          inspectedGroupsCount += 1
++        }
++        if(thisOpType === getOpType(candidateOp)) {
++          secondLastEditOp = candidateOp;
++          break
++        }
++        candidateOp = editOpsFinder.previous()
++      }
++      return continuesOperations(thisOp, (lastEditOp), secondLastEditOp)
++    }
++    return false
++  }
++  function isPartOfOperationSet(operation, recentOperations) {
++    var areOperationsGrouped = operation.group !== undefined, lastOperation;
++    if(!isEditOperation(operation)) {
++      return true
++    }
++    if(recentOperations.length === 0) {
++      return true
++    }
++    lastOperation = recentOperations[recentOperations.length - 1];
++    if(areOperationsGrouped && operation.group === lastOperation.group) {
++      return true
++    }
++    if(canAggregateOperation(operation) && recentOperations.some(isEditOperation)) {
++      if(areOperationsGrouped) {
++        return continuesMostRecentEditGroup(operation, recentOperations)
++      }
++      return continuesMostRecentEditOperation(operation, recentOperations)
++    }
++    return false
 +  }
++  this.isPartOfOperationSet = isPartOfOperationSet
 +};
 +/*
 +
 + Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("core.PositionFilter");
- gui.TextManipulator = function TextManipulator(session, inputMemberId, directStyleOp) {
-   var odtDocument = session.getOdtDocument(), FILTER_ACCEPT = core.PositionFilter.FilterResult.FILTER_ACCEPT;
-   function createOpRemoveSelection(selection) {
-     var op = new ops.OpRemoveText;
-     op.init({memberid:inputMemberId, position:selection.position, length:selection.length});
-     return op
-   }
-   function toForwardSelection(selection) {
-     if(selection.length < 0) {
-       selection.position += selection.length;
-       selection.length = -selection.length
++gui.TrivialUndoManager = function TrivialUndoManager(defaultRules) {
++  var self = this, cursorns = "urn:webodf:names:cursor", domUtils = new core.DomUtils, initialDoc, initialState = [], playFunc, document, currentUndoState = [], undoStates = [], redoStates = [], eventNotifier = new core.EventNotifier([gui.UndoManager.signalUndoStackChanged, gui.UndoManager.signalUndoStateCreated, gui.UndoManager.signalUndoStateModified, gui.TrivialUndoManager.signalDocumentRootReplaced]), undoRules = defaultRules || new gui.UndoStateRules, isExecutingOps = false;
++  function executeOperations(operations) {
++    if(operations.length > 0) {
++      isExecutingOps = true;
++      playFunc(operations);
++      isExecutingOps = false
 +    }
-     return selection
 +  }
-   this.enqueueParagraphSplittingOps = function() {
-     var selection = toForwardSelection(odtDocument.getCursorSelection(inputMemberId)), op, operations = [];
-     if(selection.length > 0) {
-       op = createOpRemoveSelection(selection);
-       operations.push(op)
++  function emitStackChange() {
++    eventNotifier.emit(gui.UndoManager.signalUndoStackChanged, {undoAvailable:self.hasUndoStates(), redoAvailable:self.hasRedoStates()})
++  }
++  function mostRecentUndoState() {
++    return undoStates[undoStates.length - 1]
++  }
++  function completeCurrentUndoState() {
++    if(currentUndoState !== initialState && currentUndoState !== mostRecentUndoState()) {
++      undoStates.push(currentUndoState)
 +    }
-     op = new ops.OpSplitParagraph;
-     op.init({memberid:inputMemberId, position:selection.position, moveCursor:true});
-     operations.push(op);
-     session.enqueue(operations);
-     return true
-   };
-   function hasPositionInDirection(cursorNode, forward) {
-     var rootConstrainedFilter = new core.PositionFilterChain, iterator = gui.SelectionMover.createPositionIterator(odtDocument.getRootElement(cursorNode)), nextPosition = (forward ? iterator.nextPosition : iterator.previousPosition);
-     rootConstrainedFilter.addFilter("BaseFilter", odtDocument.getPositionFilter());
-     rootConstrainedFilter.addFilter("RootFilter", odtDocument.createRootFilter(inputMemberId));
-     iterator.setUnfilteredPosition(cursorNode, 0);
-     while(nextPosition()) {
-       if(rootConstrainedFilter.acceptPosition(iterator) === FILTER_ACCEPT) {
-         return true
++  }
++  function removeNode(node) {
++    var sibling = node.previousSibling || node.nextSibling;
++    node.parentNode.removeChild(node);
++    domUtils.normalizeTextNodes(sibling)
++  }
++  function removeCursors(root) {
++    domUtils.getElementsByTagNameNS(root, cursorns, "cursor").forEach(removeNode);
++    domUtils.getElementsByTagNameNS(root, cursorns, "anchor").forEach(removeNode)
++  }
++  function values(obj) {
++    return Object.keys(obj).map(function(key) {
++      return obj[key]
++    })
++  }
++  function extractCursorStates(undoStates) {
++    var addCursor = {}, moveCursor = {}, requiredAddOps = {}, remainingAddOps, operations = undoStates.pop();
++    document.getMemberIds().forEach(function(memberid) {
++      requiredAddOps[memberid] = true
++    });
++    remainingAddOps = Object.keys(requiredAddOps).length;
++    function processOp(op) {
++      var spec = op.spec();
++      if(!requiredAddOps[spec.memberid]) {
++        return
++      }
++      switch(spec.optype) {
++        case "AddCursor":
++          if(!addCursor[spec.memberid]) {
++            addCursor[spec.memberid] = op;
++            delete requiredAddOps[spec.memberid];
++            remainingAddOps -= 1
++          }
++          break;
++        case "MoveCursor":
++          if(!moveCursor[spec.memberid]) {
++            moveCursor[spec.memberid] = op
++          }
++          break
 +      }
 +    }
-     return false
++    while(operations && remainingAddOps > 0) {
++      operations.reverse();
++      operations.forEach(processOp);
++      operations = undoStates.pop()
++    }
++    return values(addCursor).concat(values(moveCursor))
++  }
++  this.subscribe = function(signal, callback) {
++    eventNotifier.subscribe(signal, callback)
++  };
++  this.unsubscribe = function(signal, callback) {
++    eventNotifier.unsubscribe(signal, callback)
++  };
++  this.hasUndoStates = function() {
++    return undoStates.length > 0
++  };
++  this.hasRedoStates = function() {
++    return redoStates.length > 0
++  };
++  this.setDocument = function(newDocument) {
++    document = newDocument
++  };
++  this.purgeInitialState = function() {
++    undoStates.length = 0;
++    redoStates.length = 0;
++    initialState.length = 0;
++    currentUndoState.length = 0;
++    initialDoc = null;
++    emitStackChange()
++  };
++  function setInitialState() {
++    initialDoc = document.cloneDocumentElement();
++    removeCursors(initialDoc);
++    completeCurrentUndoState();
++    currentUndoState = initialState = extractCursorStates([initialState].concat(undoStates));
++    undoStates.length = 0;
++    redoStates.length = 0;
++    emitStackChange()
 +  }
-   this.removeTextByBackspaceKey = function() {
-     var cursor = odtDocument.getCursor(inputMemberId), selection = toForwardSelection(odtDocument.getCursorSelection(inputMemberId)), op = null;
-     if(selection.length === 0) {
-       if(hasPositionInDirection(cursor.getNode(), false)) {
-         op = new ops.OpRemoveText;
-         op.init({memberid:inputMemberId, position:selection.position - 1, length:1});
-         session.enqueue([op])
-       }
-     }else {
-       op = createOpRemoveSelection(selection);
-       session.enqueue([op])
++  this.setInitialState = setInitialState;
++  this.initialize = function() {
++    if(!initialDoc) {
++      setInitialState()
 +    }
-     return op !== null
 +  };
-   this.removeTextByDeleteKey = function() {
-     var cursor = odtDocument.getCursor(inputMemberId), selection = toForwardSelection(odtDocument.getCursorSelection(inputMemberId)), op = null;
-     if(selection.length === 0) {
-       if(hasPositionInDirection(cursor.getNode(), true)) {
-         op = new ops.OpRemoveText;
-         op.init({memberid:inputMemberId, position:selection.position, length:1});
-         session.enqueue([op])
-       }
++  this.setPlaybackFunction = function(playback_func) {
++    playFunc = playback_func
++  };
++  this.onOperationExecuted = function(op) {
++    if(isExecutingOps) {
++      return
++    }
++    if(undoRules.isEditOperation(op) && (currentUndoState === initialState || redoStates.length > 0) || !undoRules.isPartOfOperationSet(op, currentUndoState)) {
++      redoStates.length = 0;
++      completeCurrentUndoState();
++      currentUndoState = [op];
++      undoStates.push(currentUndoState);
++      eventNotifier.emit(gui.UndoManager.signalUndoStateCreated, {operations:currentUndoState});
++      emitStackChange()
 +    }else {
-       op = createOpRemoveSelection(selection);
-       session.enqueue([op])
++      currentUndoState.push(op);
++      eventNotifier.emit(gui.UndoManager.signalUndoStateModified, {operations:currentUndoState})
 +    }
-     return op !== null
 +  };
-   this.removeCurrentSelection = function() {
-     var selection = toForwardSelection(odtDocument.getCursorSelection(inputMemberId)), op;
-     if(selection.length !== 0) {
-       op = createOpRemoveSelection(selection);
-       session.enqueue([op])
++  this.moveForward = function(states) {
++    var moved = 0, redoOperations;
++    while(states && redoStates.length) {
++      redoOperations = redoStates.pop();
++      undoStates.push(redoOperations);
++      executeOperations(redoOperations);
++      states -= 1;
++      moved += 1
 +    }
-     return true
++    if(moved) {
++      currentUndoState = mostRecentUndoState();
++      emitStackChange()
++    }
++    return moved
 +  };
-   function insertText(text) {
-     var selection = toForwardSelection(odtDocument.getCursorSelection(inputMemberId)), op, stylingOp, operations = [];
-     if(selection.length > 0) {
-       op = createOpRemoveSelection(selection);
-       operations.push(op)
++  this.moveBackward = function(states) {
++    var moved = 0;
++    while(states && undoStates.length) {
++      redoStates.push(undoStates.pop());
++      states -= 1;
++      moved += 1
 +    }
-     op = new ops.OpInsertText;
-     op.init({memberid:inputMemberId, position:selection.position, text:text, moveCursor:true});
-     operations.push(op);
-     if(directStyleOp) {
-       stylingOp = directStyleOp(selection.position, text.length);
-       if(stylingOp) {
-         operations.push(stylingOp)
-       }
++    if(moved) {
++      document.setDocumentElement((initialDoc.cloneNode(true)));
++      eventNotifier.emit(gui.TrivialUndoManager.signalDocumentRootReplaced, {});
++      document.getMemberIds().forEach(function(memberid) {
++        document.removeCursor(memberid)
++      });
++      executeOperations(initialState);
++      undoStates.forEach(executeOperations);
++      currentUndoState = mostRecentUndoState() || initialState;
++      emitStackChange()
 +    }
-     session.enqueue(operations)
++    return moved
 +  }
-   this.insertText = insertText
 +};
++gui.TrivialUndoManager.signalDocumentRootReplaced = "documentRootReplaced";
 +(function() {
-   return gui.TextManipulator
++  return gui.TrivialUndoManager
 +})();
- runtime.loadClass("core.DomUtils");
- runtime.loadClass("core.Async");
- runtime.loadClass("core.ScheduledTask");
- runtime.loadClass("odf.OdfUtils");
- runtime.loadClass("odf.ObjectNameGenerator");
- runtime.loadClass("ops.OdtCursor");
- runtime.loadClass("ops.OpAddCursor");
- runtime.loadClass("ops.OpRemoveCursor");
- runtime.loadClass("gui.Clipboard");
- runtime.loadClass("gui.DirectTextStyler");
- runtime.loadClass("gui.DirectParagraphStyler");
- runtime.loadClass("gui.KeyboardHandler");
- runtime.loadClass("gui.ImageManager");
- runtime.loadClass("gui.ImageSelector");
- runtime.loadClass("gui.TextManipulator");
- runtime.loadClass("gui.AnnotationController");
- runtime.loadClass("gui.EventManager");
- runtime.loadClass("gui.PlainTextPasteboard");
- gui.SessionController = function() {
-   var FILTER_ACCEPT = core.PositionFilter.FilterResult.FILTER_ACCEPT;
-   gui.SessionController = function SessionController(session, inputMemberId, shadowCursor, args) {
-     var window = (runtime.getWindow()), odtDocument = session.getOdtDocument(), async = new core.Async, domUtils = new core.DomUtils, odfUtils = new odf.OdfUtils, clipboard = new gui.Clipboard, keyDownHandler = new gui.KeyboardHandler, keyPressHandler = new gui.KeyboardHandler, keyboardMovementsFilter = new core.PositionFilterChain, baseFilter = odtDocument.getPositionFilter(), clickStartedWithinContainer = false, objectNameGenerator = new odf.ObjectNameGenerator(odtDocument.getOdfCanva [...]
-     inputMemberId), isMouseMoved = false, mouseDownRootFilter = null, undoManager = null, eventManager = new gui.EventManager(odtDocument), annotationController = new gui.AnnotationController(session, inputMemberId), directTextStyler = new gui.DirectTextStyler(session, inputMemberId), directParagraphStyler = args && args.directParagraphStylingEnabled ? new gui.DirectParagraphStyler(session, inputMemberId, objectNameGenerator) : null, createCursorStyleOp = (directTextStyler.createCursorS [...]
-     new gui.TextManipulator(session, inputMemberId, createCursorStyleOp), imageManager = new gui.ImageManager(session, inputMemberId, objectNameGenerator), imageSelector = new gui.ImageSelector(odtDocument.getOdfCanvas()), shadowCursorIterator = gui.SelectionMover.createPositionIterator(odtDocument.getRootNode()), drawShadowCursorTask, redrawRegionSelectionTask, pasteHandler = new gui.PlainTextPasteboard(odtDocument, inputMemberId), clickCount = 0;
-     runtime.assert(window !== null, "Expected to be run in an environment which has a global window, like a browser.");
-     keyboardMovementsFilter.addFilter("BaseFilter", baseFilter);
-     keyboardMovementsFilter.addFilter("RootFilter", odtDocument.createRootFilter(inputMemberId));
-     function getTarget(e) {
-       return e.target || e.srcElement
-     }
-     function cancelEvent(event) {
-       if(event.preventDefault) {
-         event.preventDefault()
-       }else {
-         event.returnValue = false
-       }
-     }
-     function dummyHandler(e) {
-       cancelEvent(e)
-     }
-     function createOpMoveCursor(position, length, selectionType) {
-       var op = new ops.OpMoveCursor;
-       op.init({memberid:inputMemberId, position:position, length:length || 0, selectionType:selectionType});
-       return op
++/*
++
++ Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
++
++ @licstart
++ This file is part of WebODF.
++
++ WebODF is free software: you can redistribute it and/or modify it
++ under the terms of the GNU Affero General Public License (GNU AGPL)
++ as published by the Free Software Foundation, either version 3 of
++ the License, or (at your option) any later version.
++
++ WebODF is distributed in the hope that it will be useful, but
++ WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ GNU Affero General Public License for more details.
++
++ You should have received a copy of the GNU Affero General Public License
++ along with WebODF.  If not, see <http://www.gnu.org/licenses/>.
++ @licend
++
++ @source: http://www.webodf.org/
++ @source: https://github.com/kogmbh/WebODF/
++*/
++ops.OperationTransformMatrix = function OperationTransformMatrix() {
++  function invertMoveCursorSpecRange(moveCursorSpec) {
++    moveCursorSpec.position = moveCursorSpec.position + moveCursorSpec.length;
++    moveCursorSpec.length *= -1
++  }
++  function invertMoveCursorSpecRangeOnNegativeLength(moveCursorSpec) {
++    var isBackwards = moveCursorSpec.length < 0;
++    if(isBackwards) {
++      invertMoveCursorSpecRange(moveCursorSpec)
 +    }
-     function caretPositionFromPoint(x, y) {
-       var doc = odtDocument.getDOM(), c, result = null;
-       if(doc.caretRangeFromPoint) {
-         c = doc.caretRangeFromPoint(x, y);
-         result = {container:c.startContainer, offset:c.startOffset}
-       }else {
-         if(doc.caretPositionFromPoint) {
-           c = doc.caretPositionFromPoint(x, y);
-           if(c && c.offsetNode) {
-             result = {container:c.offsetNode, offset:c.offset}
-           }
-         }
++    return isBackwards
++  }
++  function getStyleReferencingAttributes(setProperties, styleName) {
++    var attributes = [];
++    function check(attributeName) {
++      if(setProperties[attributeName] === styleName) {
++        attributes.push(attributeName)
 +      }
-       return result
 +    }
-     function expandToWordBoundaries(range) {
-       var alphaNumeric = /[A-Za-z0-9]/, iterator = gui.SelectionMover.createPositionIterator(odtDocument.getRootNode()), currentNode, c;
-       iterator.setUnfilteredPosition((range.startContainer), range.startOffset);
-       while(iterator.previousPosition()) {
-         currentNode = iterator.getCurrentNode();
-         if(currentNode.nodeType === Node.TEXT_NODE) {
-           c = currentNode.data[iterator.unfilteredDomOffset()];
-           if(!alphaNumeric.test(c)) {
-             break
-           }
-         }else {
-           if(!odfUtils.isTextSpan(currentNode)) {
-             break
-           }
-         }
-         range.setStart(iterator.container(), iterator.unfilteredDomOffset())
-       }
-       iterator.setUnfilteredPosition((range.endContainer), range.endOffset);
-       do {
-         currentNode = iterator.getCurrentNode();
-         if(currentNode.nodeType === Node.TEXT_NODE) {
-           c = currentNode.data[iterator.unfilteredDomOffset()];
-           if(!alphaNumeric.test(c)) {
-             break
-           }
-         }else {
-           if(!odfUtils.isTextSpan(currentNode)) {
-             break
-           }
-         }
-       }while(iterator.nextPosition());
-       range.setEnd(iterator.container(), iterator.unfilteredDomOffset())
++    if(setProperties) {
++      ["style:parent-style-name", "style:next-style-name"].forEach(check)
 +    }
-     function expandToParagraphBoundaries(range) {
-       var startParagraph = odtDocument.getParagraphElement(range.startContainer), endParagraph = odtDocument.getParagraphElement(range.endContainer);
-       if(startParagraph) {
-         range.setStart(startParagraph, 0)
-       }
-       if(endParagraph) {
-         if(odfUtils.isParagraph(range.endContainer) && range.endOffset === 0) {
-           range.setEndBefore(endParagraph)
-         }else {
-           range.setEnd(endParagraph, endParagraph.childNodes.length)
-         }
++    return attributes
++  }
++  function dropStyleReferencingAttributes(setProperties, deletedStyleName) {
++    function del(attributeName) {
++      if(setProperties[attributeName] === deletedStyleName) {
++        delete setProperties[attributeName]
 +      }
 +    }
-     function selectImage(frameNode) {
-       var stepsToAnchor = odtDocument.getDistanceFromCursor(inputMemberId, frameNode, 0), stepsToFocus = stepsToAnchor !== null ? stepsToAnchor + 1 : null, oldPosition, op;
-       if(stepsToFocus || stepsToAnchor) {
-         oldPosition = odtDocument.getCursorPosition(inputMemberId);
-         op = createOpMoveCursor(oldPosition + stepsToAnchor, stepsToFocus - stepsToAnchor, ops.OdtCursor.RegionSelection);
-         session.enqueue([op])
-       }
-       eventManager.focus()
++    if(setProperties) {
++      ["style:parent-style-name", "style:next-style-name"].forEach(del)
 +    }
-     function selectionToRange(selection) {
-       var hasForwardSelection = domUtils.comparePoints((selection.anchorNode), selection.anchorOffset, (selection.focusNode), selection.focusOffset) >= 0, range = selection.focusNode.ownerDocument.createRange();
-       if(hasForwardSelection) {
-         range.setStart(selection.anchorNode, selection.anchorOffset);
-         range.setEnd(selection.focusNode, selection.focusOffset)
++  }
++  function cloneOpspec(opspec) {
++    var result = {};
++    Object.keys(opspec).forEach(function(key) {
++      if(typeof opspec[key] === "object") {
++        result[key] = cloneOpspec(opspec[key])
 +      }else {
-         range.setStart(selection.focusNode, selection.focusOffset);
-         range.setEnd(selection.anchorNode, selection.anchorOffset)
-       }
-       return{range:range, hasForwardSelection:hasForwardSelection}
-     }
-     function rangeToSelection(range, hasForwardSelection) {
-       if(hasForwardSelection) {
-         return{anchorNode:(range.startContainer), anchorOffset:range.startOffset, focusNode:(range.endContainer), focusOffset:range.endOffset}
-       }
-       return{anchorNode:(range.endContainer), anchorOffset:range.endOffset, focusNode:(range.startContainer), focusOffset:range.startOffset}
-     }
-     function constrain(lookup) {
-       return function(originalNode) {
-         var originalContainer = lookup(originalNode);
-         return function(step, node) {
-           return lookup(node) === originalContainer
-         }
++        result[key] = opspec[key]
 +      }
++    });
++    return result
++  }
++  function dropOverruledAndUnneededAttributes(minorSetProperties, minorRemovedProperties, majorSetProperties, majorRemovedProperties) {
++    var i, name, majorChanged = false, minorChanged = false, removedPropertyNames, majorRemovedPropertyNames = [];
++    if(majorRemovedProperties && majorRemovedProperties.attributes) {
++      majorRemovedPropertyNames = majorRemovedProperties.attributes.split(",")
 +    }
-     function selectRange(range, hasForwardSelection, clickCount) {
-       var canvasElement = odtDocument.getOdfCanvas().getElement(), validSelection, startInsideCanvas, endInsideCanvas, existingSelection, newSelection, op;
-       startInsideCanvas = domUtils.containsNode(canvasElement, range.startContainer);
-       endInsideCanvas = domUtils.containsNode(canvasElement, range.endContainer);
-       if(!startInsideCanvas && !endInsideCanvas) {
-         return
-       }
-       if(startInsideCanvas && endInsideCanvas) {
-         if(clickCount === 2) {
-           expandToWordBoundaries(range)
-         }else {
-           if(clickCount >= 3) {
-             expandToParagraphBoundaries(range)
++    if(minorSetProperties && (majorSetProperties || majorRemovedPropertyNames.length > 0)) {
++      Object.keys(minorSetProperties).forEach(function(key) {
++        var value = minorSetProperties[key], overrulingPropertyValue;
++        if(typeof value !== "object") {
++          if(majorSetProperties) {
++            overrulingPropertyValue = majorSetProperties[key]
++          }
++          if(overrulingPropertyValue !== undefined) {
++            delete minorSetProperties[key];
++            minorChanged = true;
++            if(overrulingPropertyValue === value) {
++              delete majorSetProperties[key];
++              majorChanged = true
++            }
++          }else {
++            if(majorRemovedPropertyNames.indexOf(key) !== -1) {
++              delete minorSetProperties[key];
++              minorChanged = true
++            }
 +          }
 +        }
-       }
-       validSelection = rangeToSelection(range, hasForwardSelection);
-       newSelection = odtDocument.convertDomToCursorRange(validSelection, constrain(odfUtils.getParagraphElement));
-       existingSelection = odtDocument.getCursorSelection(inputMemberId);
-       if(newSelection.position !== existingSelection.position || newSelection.length !== existingSelection.length) {
-         op = createOpMoveCursor(newSelection.position, newSelection.length, ops.OdtCursor.RangeSelection);
-         session.enqueue([op])
-       }
-     }
-     this.selectRange = selectRange;
-     function extendCursorByAdjustment(lengthAdjust) {
-       var selection = odtDocument.getCursorSelection(inputMemberId), stepCounter = odtDocument.getCursor(inputMemberId).getStepCounter(), newLength;
-       if(lengthAdjust !== 0) {
-         lengthAdjust = lengthAdjust > 0 ? stepCounter.convertForwardStepsBetweenFilters(lengthAdjust, keyboardMovementsFilter, baseFilter) : -stepCounter.convertBackwardStepsBetweenFilters(-lengthAdjust, keyboardMovementsFilter, baseFilter);
-         newLength = selection.length + lengthAdjust;
-         session.enqueue([createOpMoveCursor(selection.position, newLength)])
-       }
-     }
-     function moveCursorByAdjustment(positionAdjust) {
-       var position = odtDocument.getCursorPosition(inputMemberId), stepCounter = odtDocument.getCursor(inputMemberId).getStepCounter();
-       if(positionAdjust !== 0) {
-         positionAdjust = positionAdjust > 0 ? stepCounter.convertForwardStepsBetweenFilters(positionAdjust, keyboardMovementsFilter, baseFilter) : -stepCounter.convertBackwardStepsBetweenFilters(-positionAdjust, keyboardMovementsFilter, baseFilter);
-         position = position + positionAdjust;
-         session.enqueue([createOpMoveCursor(position, 0)])
-       }
-     }
-     function moveCursorToLeft() {
-       moveCursorByAdjustment(-1);
-       return true
-     }
-     this.moveCursorToLeft = moveCursorToLeft;
-     function moveCursorToRight() {
-       moveCursorByAdjustment(1);
-       return true
-     }
-     function extendSelectionToLeft() {
-       extendCursorByAdjustment(-1);
-       return true
-     }
-     function extendSelectionToRight() {
-       extendCursorByAdjustment(1);
-       return true
++      })
 +    }
-     function moveCursorByLine(direction, extend) {
-       var paragraphNode = odtDocument.getParagraphElement(odtDocument.getCursor(inputMemberId).getNode()), steps;
-       runtime.assert(Boolean(paragraphNode), "SessionController: Cursor outside paragraph");
-       steps = odtDocument.getCursor(inputMemberId).getStepCounter().countLinesSteps(direction, keyboardMovementsFilter);
-       if(extend) {
-         extendCursorByAdjustment(steps)
-       }else {
-         moveCursorByAdjustment(steps)
++    if(minorRemovedProperties && (minorRemovedProperties.attributes && (majorSetProperties || majorRemovedPropertyNames.length > 0))) {
++      removedPropertyNames = minorRemovedProperties.attributes.split(",");
++      for(i = 0;i < removedPropertyNames.length;i += 1) {
++        name = removedPropertyNames[i];
++        if(majorSetProperties && majorSetProperties[name] !== undefined || majorRemovedPropertyNames && majorRemovedPropertyNames.indexOf(name) !== -1) {
++          removedPropertyNames.splice(i, 1);
++          i -= 1;
++          minorChanged = true
++        }
 +      }
-     }
-     function moveCursorUp() {
-       moveCursorByLine(-1, false);
-       return true
-     }
-     function moveCursorDown() {
-       moveCursorByLine(1, false);
-       return true
-     }
-     function extendSelectionUp() {
-       moveCursorByLine(-1, true);
-       return true
-     }
-     function extendSelectionDown() {
-       moveCursorByLine(1, true);
-       return true
-     }
-     function moveCursorToLineBoundary(direction, extend) {
-       var steps = odtDocument.getCursor(inputMemberId).getStepCounter().countStepsToLineBoundary(direction, keyboardMovementsFilter);
-       if(extend) {
-         extendCursorByAdjustment(steps)
++      if(removedPropertyNames.length > 0) {
++        minorRemovedProperties.attributes = removedPropertyNames.join(",")
 +      }else {
-         moveCursorByAdjustment(steps)
++        delete minorRemovedProperties.attributes
 +      }
 +    }
-     function moveCursorToLineStart() {
-       moveCursorToLineBoundary(-1, false);
-       return true
-     }
-     function moveCursorToLineEnd() {
-       moveCursorToLineBoundary(1, false);
-       return true
-     }
-     function extendSelectionToLineStart() {
-       moveCursorToLineBoundary(-1, true);
-       return true
-     }
-     function extendSelectionToLineEnd() {
-       moveCursorToLineBoundary(1, true);
-       return true
-     }
-     function extendSelectionToParagraphStart() {
-       var paragraphNode = (odtDocument.getParagraphElement(odtDocument.getCursor(inputMemberId).getNode())), iterator, node, steps;
-       runtime.assert(Boolean(paragraphNode), "SessionController: Cursor outside paragraph");
-       steps = odtDocument.getDistanceFromCursor(inputMemberId, paragraphNode, 0);
-       iterator = gui.SelectionMover.createPositionIterator(odtDocument.getRootNode());
-       iterator.setUnfilteredPosition(paragraphNode, 0);
-       while(steps === 0 && iterator.previousPosition()) {
-         node = iterator.getCurrentNode();
-         if(odfUtils.isParagraph(node)) {
-           steps = odtDocument.getDistanceFromCursor(inputMemberId, node, 0)
-         }
++    return{majorChanged:majorChanged, minorChanged:minorChanged}
++  }
++  function hasProperties(properties) {
++    var key;
++    for(key in properties) {
++      if(properties.hasOwnProperty(key)) {
++        return true
 +      }
-       extendCursorByAdjustment(steps);
-       return true
 +    }
-     function extendSelectionToParagraphEnd() {
-       var paragraphNode = (odtDocument.getParagraphElement(odtDocument.getCursor(inputMemberId).getNode())), iterator, node, steps;
-       runtime.assert(Boolean(paragraphNode), "SessionController: Cursor outside paragraph");
-       iterator = gui.SelectionMover.createPositionIterator(odtDocument.getRootNode());
-       iterator.moveToEndOfNode(paragraphNode);
-       steps = odtDocument.getDistanceFromCursor(inputMemberId, iterator.container(), iterator.unfilteredDomOffset());
-       while(steps === 0 && iterator.nextPosition()) {
-         node = iterator.getCurrentNode();
-         if(odfUtils.isParagraph(node)) {
-           iterator.moveToEndOfNode(node);
-           steps = odtDocument.getDistanceFromCursor(inputMemberId, iterator.container(), iterator.unfilteredDomOffset())
++    return false
++  }
++  function hasRemovedProperties(properties) {
++    var key;
++    for(key in properties) {
++      if(properties.hasOwnProperty(key)) {
++        if(key !== "attributes" || properties.attributes.length > 0) {
++          return true
 +        }
 +      }
-       extendCursorByAdjustment(steps);
-       return true
-     }
-     function moveCursorToDocumentBoundary(direction, extend) {
-       var iterator = gui.SelectionMover.createPositionIterator(odtDocument.getRootNode()), steps;
-       if(direction > 0) {
-         iterator.moveToEnd()
-       }
-       steps = odtDocument.getDistanceFromCursor(inputMemberId, iterator.container(), iterator.unfilteredDomOffset());
-       if(extend) {
-         extendCursorByAdjustment(steps)
-       }else {
-         moveCursorByAdjustment(steps)
-       }
-     }
-     this.moveCursorToDocumentBoundary = moveCursorToDocumentBoundary;
-     function moveCursorToDocumentStart() {
-       moveCursorToDocumentBoundary(-1, false);
-       return true
 +    }
-     function moveCursorToDocumentEnd() {
-       moveCursorToDocumentBoundary(1, false);
-       return true
++    return false
++  }
++  function dropOverruledAndUnneededProperties(minorSet, minorRem, majorSet, majorRem, propertiesName) {
++    var minorSP = minorSet ? minorSet[propertiesName] : null, minorRP = minorRem ? minorRem[propertiesName] : null, majorSP = majorSet ? majorSet[propertiesName] : null, majorRP = majorRem ? majorRem[propertiesName] : null, result;
++    result = dropOverruledAndUnneededAttributes(minorSP, minorRP, majorSP, majorRP);
++    if(minorSP && !hasProperties(minorSP)) {
++      delete minorSet[propertiesName]
 +    }
-     function extendSelectionToDocumentStart() {
-       moveCursorToDocumentBoundary(-1, true);
-       return true
++    if(minorRP && !hasRemovedProperties(minorRP)) {
++      delete minorRem[propertiesName]
 +    }
-     function extendSelectionToDocumentEnd() {
-       moveCursorToDocumentBoundary(1, true);
-       return true
++    if(majorSP && !hasProperties(majorSP)) {
++      delete majorSet[propertiesName]
 +    }
-     function extendSelectionToEntireDocument() {
-       var rootNode = odtDocument.getRootNode(), lastWalkableStep = odtDocument.convertDomPointToCursorStep(rootNode, rootNode.childNodes.length);
-       session.enqueue([createOpMoveCursor(0, lastWalkableStep)]);
-       return true
++    if(majorRP && !hasRemovedProperties(majorRP)) {
++      delete majorRem[propertiesName]
 +    }
-     this.extendSelectionToEntireDocument = extendSelectionToEntireDocument;
-     function redrawRegionSelection() {
-       var cursor = odtDocument.getCursor(inputMemberId), imageElement;
-       if(cursor && cursor.getSelectionType() === ops.OdtCursor.RegionSelection) {
-         imageElement = odfUtils.getImageElements(cursor.getSelectedRange())[0];
-         if(imageElement) {
-           imageSelector.select((imageElement.parentNode));
-           return
-         }
++    return result
++  }
++  function transformAddStyleRemoveStyle(addStyleSpec, removeStyleSpec) {
++    var setAttributes, helperOpspec, addStyleSpecResult = [addStyleSpec], removeStyleSpecResult = [removeStyleSpec];
++    if(addStyleSpec.styleFamily === removeStyleSpec.styleFamily) {
++      setAttributes = getStyleReferencingAttributes(addStyleSpec.setProperties, removeStyleSpec.styleName);
++      if(setAttributes.length > 0) {
++        helperOpspec = {optype:"UpdateParagraphStyle", memberid:removeStyleSpec.memberid, timestamp:removeStyleSpec.timestamp, styleName:addStyleSpec.styleName, removedProperties:{attributes:setAttributes.join(",")}};
++        removeStyleSpecResult.unshift(helperOpspec)
 +      }
-       imageSelector.clearSelection()
++      dropStyleReferencingAttributes(addStyleSpec.setProperties, removeStyleSpec.styleName)
 +    }
-     function stringFromKeyPress(event) {
-       if(event.which === null || event.which === undefined) {
-         return String.fromCharCode(event.keyCode)
++    return{opSpecsA:addStyleSpecResult, opSpecsB:removeStyleSpecResult}
++  }
++  function transformApplyDirectStylingApplyDirectStyling(applyDirectStylingSpecA, applyDirectStylingSpecB, hasAPriority) {
++    var majorSpec, minorSpec, majorSpecResult, minorSpecResult, majorSpecEnd, minorSpecEnd, dropResult, originalMajorSpec, originalMinorSpec, helperOpspecBefore, helperOpspecAfter, applyDirectStylingSpecAResult = [applyDirectStylingSpecA], applyDirectStylingSpecBResult = [applyDirectStylingSpecB];
++    if(!(applyDirectStylingSpecA.position + applyDirectStylingSpecA.length <= applyDirectStylingSpecB.position || applyDirectStylingSpecA.position >= applyDirectStylingSpecB.position + applyDirectStylingSpecB.length)) {
++      majorSpec = hasAPriority ? applyDirectStylingSpecA : applyDirectStylingSpecB;
++      minorSpec = hasAPriority ? applyDirectStylingSpecB : applyDirectStylingSpecA;
++      if(applyDirectStylingSpecA.position !== applyDirectStylingSpecB.position || applyDirectStylingSpecA.length !== applyDirectStylingSpecB.length) {
++        originalMajorSpec = cloneOpspec(majorSpec);
++        originalMinorSpec = cloneOpspec(minorSpec)
 +      }
-       if(event.which !== 0 && event.charCode !== 0) {
-         return String.fromCharCode(event.which)
++      dropResult = dropOverruledAndUnneededProperties(minorSpec.setProperties, null, majorSpec.setProperties, null, "style:text-properties");
++      if(dropResult.majorChanged || dropResult.minorChanged) {
++        majorSpecResult = [];
++        minorSpecResult = [];
++        majorSpecEnd = majorSpec.position + majorSpec.length;
++        minorSpecEnd = minorSpec.position + minorSpec.length;
++        if(minorSpec.position < majorSpec.position) {
++          if(dropResult.minorChanged) {
++            helperOpspecBefore = cloneOpspec((originalMinorSpec));
++            helperOpspecBefore.length = majorSpec.position - minorSpec.position;
++            minorSpecResult.push(helperOpspecBefore);
++            minorSpec.position = majorSpec.position;
++            minorSpec.length = minorSpecEnd - minorSpec.position
++          }
++        }else {
++          if(majorSpec.position < minorSpec.position) {
++            if(dropResult.majorChanged) {
++              helperOpspecBefore = cloneOpspec((originalMajorSpec));
++              helperOpspecBefore.length = minorSpec.position - majorSpec.position;
++              majorSpecResult.push(helperOpspecBefore);
++              majorSpec.position = minorSpec.position;
++              majorSpec.length = majorSpecEnd - majorSpec.position
++            }
++          }
++        }
++        if(minorSpecEnd > majorSpecEnd) {
++          if(dropResult.minorChanged) {
++            helperOpspecAfter = originalMinorSpec;
++            helperOpspecAfter.position = majorSpecEnd;
++            helperOpspecAfter.length = minorSpecEnd - majorSpecEnd;
++            minorSpecResult.push(helperOpspecAfter);
++            minorSpec.length = majorSpecEnd - minorSpec.position
++          }
++        }else {
++          if(majorSpecEnd > minorSpecEnd) {
++            if(dropResult.majorChanged) {
++              helperOpspecAfter = originalMajorSpec;
++              helperOpspecAfter.position = minorSpecEnd;
++              helperOpspecAfter.length = majorSpecEnd - minorSpecEnd;
++              majorSpecResult.push(helperOpspecAfter);
++              majorSpec.length = minorSpecEnd - majorSpec.position
++            }
++          }
++        }
++        if(majorSpec.setProperties && hasProperties(majorSpec.setProperties)) {
++          majorSpecResult.push(majorSpec)
++        }
++        if(minorSpec.setProperties && hasProperties(minorSpec.setProperties)) {
++          minorSpecResult.push(minorSpec)
++        }
++        if(hasAPriority) {
++          applyDirectStylingSpecAResult = majorSpecResult;
++          applyDirectStylingSpecBResult = minorSpecResult
++        }else {
++          applyDirectStylingSpecAResult = minorSpecResult;
++          applyDirectStylingSpecBResult = majorSpecResult
++        }
 +      }
-       return null
 +    }
-     function handleCut(e) {
-       var cursor = odtDocument.getCursor(inputMemberId), selectedRange = cursor.getSelectedRange();
-       if(selectedRange.collapsed) {
-         e.preventDefault();
-         return
-       }
-       if(clipboard.setDataFromRange(e, selectedRange)) {
-         textManipulator.removeCurrentSelection()
-       }else {
-         runtime.log("Cut operation failed")
++    return{opSpecsA:applyDirectStylingSpecAResult, opSpecsB:applyDirectStylingSpecBResult}
++  }
++  function transformApplyDirectStylingInsertText(applyDirectStylingSpec, insertTextSpec) {
++    if(insertTextSpec.position <= applyDirectStylingSpec.position) {
++      applyDirectStylingSpec.position += insertTextSpec.text.length
++    }else {
++      if(insertTextSpec.position <= applyDirectStylingSpec.position + applyDirectStylingSpec.length) {
++        applyDirectStylingSpec.length += insertTextSpec.text.length
 +      }
 +    }
-     function handleBeforeCut() {
-       var cursor = odtDocument.getCursor(inputMemberId), selectedRange = cursor.getSelectedRange();
-       return selectedRange.collapsed !== false
-     }
-     function handleCopy(e) {
-       var cursor = odtDocument.getCursor(inputMemberId), selectedRange = cursor.getSelectedRange();
-       if(selectedRange.collapsed) {
-         e.preventDefault();
-         return
++    return{opSpecsA:[applyDirectStylingSpec], opSpecsB:[insertTextSpec]}
++  }
++  function transformApplyDirectStylingRemoveText(applyDirectStylingSpec, removeTextSpec) {
++    var applyDirectStylingSpecEnd = applyDirectStylingSpec.position + applyDirectStylingSpec.length, removeTextSpecEnd = removeTextSpec.position + removeTextSpec.length, applyDirectStylingSpecResult = [applyDirectStylingSpec], removeTextSpecResult = [removeTextSpec];
++    if(removeTextSpecEnd <= applyDirectStylingSpec.position) {
++      applyDirectStylingSpec.position -= removeTextSpec.length
++    }else {
++      if(removeTextSpec.position < applyDirectStylingSpecEnd) {
++        if(applyDirectStylingSpec.position < removeTextSpec.position) {
++          if(removeTextSpecEnd < applyDirectStylingSpecEnd) {
++            applyDirectStylingSpec.length -= removeTextSpec.length
++          }else {
++            applyDirectStylingSpec.length = removeTextSpec.position - applyDirectStylingSpec.position
++          }
++        }else {
++          applyDirectStylingSpec.position = removeTextSpec.position;
++          if(removeTextSpecEnd < applyDirectStylingSpecEnd) {
++            applyDirectStylingSpec.length = applyDirectStylingSpecEnd - removeTextSpecEnd
++          }else {
++            applyDirectStylingSpecResult = []
++          }
++        }
 +      }
-       if(!clipboard.setDataFromRange(e, selectedRange)) {
-         runtime.log("Copy operation failed")
++    }
++    return{opSpecsA:applyDirectStylingSpecResult, opSpecsB:removeTextSpecResult}
++  }
++  function transformApplyDirectStylingSplitParagraph(applyDirectStylingSpec, splitParagraphSpec) {
++    if(splitParagraphSpec.position < applyDirectStylingSpec.position) {
++      applyDirectStylingSpec.position += 1
++    }else {
++      if(splitParagraphSpec.position < applyDirectStylingSpec.position + applyDirectStylingSpec.length) {
++        applyDirectStylingSpec.length += 1
 +      }
 +    }
-     function handlePaste(e) {
-       var plainText;
-       if(window.clipboardData && window.clipboardData.getData) {
-         plainText = window.clipboardData.getData("Text")
++    return{opSpecsA:[applyDirectStylingSpec], opSpecsB:[splitParagraphSpec]}
++  }
++  function transformInsertTextInsertText(insertTextSpecA, insertTextSpecB, hasAPriority) {
++    if(insertTextSpecA.position < insertTextSpecB.position) {
++      insertTextSpecB.position += insertTextSpecA.text.length
++    }else {
++      if(insertTextSpecA.position > insertTextSpecB.position) {
++        insertTextSpecA.position += insertTextSpecB.text.length
 +      }else {
-         if(e.clipboardData && e.clipboardData.getData) {
-           plainText = e.clipboardData.getData("text/plain")
++        if(hasAPriority) {
++          insertTextSpecB.position += insertTextSpecA.text.length
++        }else {
++          insertTextSpecA.position += insertTextSpecB.text.length
 +        }
 +      }
-       if(plainText) {
-         textManipulator.removeCurrentSelection();
-         session.enqueue(pasteHandler.createPasteOps(plainText))
-       }
-       cancelEvent(e)
-     }
-     function handleBeforePaste() {
-       return false
-     }
-     function updateUndoStack(op) {
-       if(undoManager) {
-         undoManager.onOperationExecuted(op)
-       }
-     }
-     function forwardUndoStackChange(e) {
-       odtDocument.emit(ops.OdtDocument.signalUndoStackChanged, e)
 +    }
-     function undo() {
-       if(undoManager) {
-         undoManager.moveBackward(1);
-         redrawRegionSelectionTask.trigger();
-         return true
++    return{opSpecsA:[insertTextSpecA], opSpecsB:[insertTextSpecB]}
++  }
++  function transformInsertTextMoveCursor(insertTextSpec, moveCursorSpec) {
++    var isMoveCursorSpecRangeInverted = invertMoveCursorSpecRangeOnNegativeLength(moveCursorSpec);
++    if(insertTextSpec.position < moveCursorSpec.position) {
++      moveCursorSpec.position += insertTextSpec.text.length
++    }else {
++      if(insertTextSpec.position < moveCursorSpec.position + moveCursorSpec.length) {
++        moveCursorSpec.length += insertTextSpec.text.length
 +      }
-       return false
 +    }
-     function redo() {
-       if(undoManager) {
-         undoManager.moveForward(1);
-         redrawRegionSelectionTask.trigger();
-         return true
-       }
-       return false
++    if(isMoveCursorSpecRangeInverted) {
++      invertMoveCursorSpecRange(moveCursorSpec)
 +    }
-     function updateShadowCursor() {
-       var selection = window.getSelection(), selectionRange = selection.rangeCount > 0 && selectionToRange(selection);
-       if(clickStartedWithinContainer && selectionRange) {
-         isMouseMoved = true;
-         imageSelector.clearSelection();
-         shadowCursorIterator.setUnfilteredPosition((selection.focusNode), selection.focusOffset);
-         if(mouseDownRootFilter.acceptPosition(shadowCursorIterator) === FILTER_ACCEPT) {
-           if(clickCount === 2) {
-             expandToWordBoundaries(selectionRange.range)
-           }else {
-             if(clickCount >= 3) {
-               expandToParagraphBoundaries(selectionRange.range)
-             }
-           }
-           shadowCursor.setSelectedRange(selectionRange.range, selectionRange.hasForwardSelection);
-           odtDocument.emit(ops.OdtDocument.signalCursorMoved, shadowCursor)
-         }
++    return{opSpecsA:[insertTextSpec], opSpecsB:[moveCursorSpec]}
++  }
++  function transformInsertTextRemoveText(insertTextSpec, removeTextSpec) {
++    var helperOpspec, removeTextSpecEnd = removeTextSpec.position + removeTextSpec.length, insertTextSpecResult = [insertTextSpec], removeTextSpecResult = [removeTextSpec];
++    if(removeTextSpecEnd <= insertTextSpec.position) {
++      insertTextSpec.position -= removeTextSpec.length
++    }else {
++      if(insertTextSpec.position <= removeTextSpec.position) {
++        removeTextSpec.position += insertTextSpec.text.length
++      }else {
++        removeTextSpec.length = insertTextSpec.position - removeTextSpec.position;
++        helperOpspec = {optype:"RemoveText", memberid:removeTextSpec.memberid, timestamp:removeTextSpec.timestamp, position:insertTextSpec.position + insertTextSpec.text.length, length:removeTextSpecEnd - insertTextSpec.position};
++        removeTextSpecResult.unshift(helperOpspec);
++        insertTextSpec.position = removeTextSpec.position
 +      }
 +    }
-     function synchronizeWindowSelection(cursor) {
-       var selection = window.getSelection(), range = cursor.getSelectedRange();
-       if(selection.extend) {
-         if(cursor.hasForwardSelection()) {
-           selection.collapse(range.startContainer, range.startOffset);
-           selection.extend(range.endContainer, range.endOffset)
++    return{opSpecsA:insertTextSpecResult, opSpecsB:removeTextSpecResult}
++  }
++  function transformInsertTextSplitParagraph(insertTextSpec, splitParagraphSpec, hasAPriority) {
++    if(insertTextSpec.position < splitParagraphSpec.position) {
++      splitParagraphSpec.position += insertTextSpec.text.length
++    }else {
++      if(insertTextSpec.position > splitParagraphSpec.position) {
++        insertTextSpec.position += 1
++      }else {
++        if(hasAPriority) {
++          splitParagraphSpec.position += insertTextSpec.text.length
 +        }else {
-           selection.collapse(range.endContainer, range.endOffset);
-           selection.extend(range.startContainer, range.startOffset)
++          insertTextSpec.position += 1
 +        }
-       }else {
-         selection.removeAllRanges();
-         selection.addRange(range.cloneRange());
-         (odtDocument.getOdfCanvas().getElement()).setActive()
++        return null
 +      }
 +    }
-     function handleMouseDown(e) {
-       var target = getTarget(e), cursor = odtDocument.getCursor(inputMemberId);
-       clickStartedWithinContainer = target && domUtils.containsNode(odtDocument.getOdfCanvas().getElement(), target);
-       if(clickStartedWithinContainer) {
-         isMouseMoved = false;
-         mouseDownRootFilter = odtDocument.createRootFilter(target);
-         clickCount = e.detail;
-         if(cursor && e.shiftKey) {
-           window.getSelection().collapse(cursor.getAnchorNode(), 0)
++    return{opSpecsA:[insertTextSpec], opSpecsB:[splitParagraphSpec]}
++  }
++  function transformUpdateParagraphStyleUpdateParagraphStyle(updateParagraphStyleSpecA, updateParagraphStyleSpecB, hasAPriority) {
++    var majorSpec, minorSpec, updateParagraphStyleSpecAResult = [updateParagraphStyleSpecA], updateParagraphStyleSpecBResult = [updateParagraphStyleSpecB];
++    if(updateParagraphStyleSpecA.styleName === updateParagraphStyleSpecB.styleName) {
++      majorSpec = hasAPriority ? updateParagraphStyleSpecA : updateParagraphStyleSpecB;
++      minorSpec = hasAPriority ? updateParagraphStyleSpecB : updateParagraphStyleSpecA;
++      dropOverruledAndUnneededProperties(minorSpec.setProperties, minorSpec.removedProperties, majorSpec.setProperties, majorSpec.removedProperties, "style:paragraph-properties");
++      dropOverruledAndUnneededProperties(minorSpec.setProperties, minorSpec.removedProperties, majorSpec.setProperties, majorSpec.removedProperties, "style:text-properties");
++      dropOverruledAndUnneededAttributes(minorSpec.setProperties || null, (minorSpec.removedProperties) || null, majorSpec.setProperties || null, (majorSpec.removedProperties) || null);
++      if(!(majorSpec.setProperties && hasProperties(majorSpec.setProperties)) && !(majorSpec.removedProperties && hasRemovedProperties(majorSpec.removedProperties))) {
++        if(hasAPriority) {
++          updateParagraphStyleSpecAResult = []
 +        }else {
-           synchronizeWindowSelection(cursor)
++          updateParagraphStyleSpecBResult = []
 +        }
-         if(clickCount > 1) {
-           updateShadowCursor()
++      }
++      if(!(minorSpec.setProperties && hasProperties(minorSpec.setProperties)) && !(minorSpec.removedProperties && hasRemovedProperties(minorSpec.removedProperties))) {
++        if(hasAPriority) {
++          updateParagraphStyleSpecBResult = []
++        }else {
++          updateParagraphStyleSpecAResult = []
 +        }
 +      }
 +    }
-     function mutableSelection(selection) {
-       if(selection) {
-         return{anchorNode:selection.anchorNode, anchorOffset:selection.anchorOffset, focusNode:selection.focusNode, focusOffset:selection.focusOffset}
++    return{opSpecsA:updateParagraphStyleSpecAResult, opSpecsB:updateParagraphStyleSpecBResult}
++  }
++  function transformUpdateMetadataUpdateMetadata(updateMetadataSpecA, updateMetadataSpecB, hasAPriority) {
++    var majorSpec, minorSpec, updateMetadataSpecAResult = [updateMetadataSpecA], updateMetadataSpecBResult = [updateMetadataSpecB];
++    majorSpec = hasAPriority ? updateMetadataSpecA : updateMetadataSpecB;
++    minorSpec = hasAPriority ? updateMetadataSpecB : updateMetadataSpecA;
++    dropOverruledAndUnneededAttributes(minorSpec.setProperties || null, minorSpec.removedProperties || null, majorSpec.setProperties || null, majorSpec.removedProperties || null);
++    if(!(majorSpec.setProperties && hasProperties(majorSpec.setProperties)) && !(majorSpec.removedProperties && hasRemovedProperties(majorSpec.removedProperties))) {
++      if(hasAPriority) {
++        updateMetadataSpecAResult = []
++      }else {
++        updateMetadataSpecBResult = []
 +      }
-       return null
 +    }
-     function handleMouseClickEvent(event) {
-       var target = getTarget(event), eventDetails = {detail:event.detail, clientX:event.clientX, clientY:event.clientY, target:target};
-       drawShadowCursorTask.processRequests();
-       if(odfUtils.isImage(target) && odfUtils.isCharacterFrame(target.parentNode)) {
-         selectImage(target.parentNode);
-         eventManager.focus()
++    if(!(minorSpec.setProperties && hasProperties(minorSpec.setProperties)) && !(minorSpec.removedProperties && hasRemovedProperties(minorSpec.removedProperties))) {
++      if(hasAPriority) {
++        updateMetadataSpecBResult = []
 +      }else {
-         if(clickStartedWithinContainer && !imageSelector.isSelectorElement(target)) {
-           if(isMouseMoved) {
-             selectRange(shadowCursor.getSelectedRange(), shadowCursor.hasForwardSelection(), event.detail);
-             eventManager.focus()
++        updateMetadataSpecAResult = []
++      }
++    }
++    return{opSpecsA:updateMetadataSpecAResult, opSpecsB:updateMetadataSpecBResult}
++  }
++  function transformSplitParagraphSplitParagraph(splitParagraphSpecA, splitParagraphSpecB, hasAPriority) {
++    if(splitParagraphSpecA.position < splitParagraphSpecB.position) {
++      splitParagraphSpecB.position += 1
++    }else {
++      if(splitParagraphSpecA.position > splitParagraphSpecB.position) {
++        splitParagraphSpecA.position += 1
++      }else {
++        if(splitParagraphSpecA.position === splitParagraphSpecB.position) {
++          if(hasAPriority) {
++            splitParagraphSpecB.position += 1
 +          }else {
-             runtime.setTimeout(function() {
-               var selection = mutableSelection(window.getSelection()), selectionRange, caretPos;
-               if(!selection.anchorNode && !selection.focusNode) {
-                 caretPos = caretPositionFromPoint(eventDetails.clientX, eventDetails.clientY);
-                 if(caretPos) {
-                   selection.anchorNode = (caretPos.container);
-                   selection.anchorOffset = caretPos.offset;
-                   selection.focusNode = selection.anchorNode;
-                   selection.focusOffset = selection.anchorOffset
-                 }
-               }
-               if(selection.anchorNode && selection.focusNode) {
-                 selectionRange = selectionToRange(selection);
-                 selectRange(selectionRange.range, selectionRange.hasForwardSelection, eventDetails.detail)
-               }
-               eventManager.focus()
-             }, 0)
++            splitParagraphSpecA.position += 1
 +          }
 +        }
 +      }
-       clickCount = 0;
-       clickStartedWithinContainer = false;
-       isMouseMoved = false
 +    }
-     function handleDragEnd() {
-       if(clickStartedWithinContainer) {
-         eventManager.focus()
++    return{opSpecsA:[splitParagraphSpecA], opSpecsB:[splitParagraphSpecB]}
++  }
++  function transformMoveCursorRemoveCursor(moveCursorSpec, removeCursorSpec) {
++    var isSameCursorRemoved = moveCursorSpec.memberid === removeCursorSpec.memberid;
++    return{opSpecsA:isSameCursorRemoved ? [] : [moveCursorSpec], opSpecsB:[removeCursorSpec]}
++  }
++  function transformMoveCursorRemoveText(moveCursorSpec, removeTextSpec) {
++    var isMoveCursorSpecRangeInverted = invertMoveCursorSpecRangeOnNegativeLength(moveCursorSpec), moveCursorSpecEnd = moveCursorSpec.position + moveCursorSpec.length, removeTextSpecEnd = removeTextSpec.position + removeTextSpec.length;
++    if(removeTextSpecEnd <= moveCursorSpec.position) {
++      moveCursorSpec.position -= removeTextSpec.length
++    }else {
++      if(removeTextSpec.position < moveCursorSpecEnd) {
++        if(moveCursorSpec.position < removeTextSpec.position) {
++          if(removeTextSpecEnd < moveCursorSpecEnd) {
++            moveCursorSpec.length -= removeTextSpec.length
++          }else {
++            moveCursorSpec.length = removeTextSpec.position - moveCursorSpec.position
++          }
++        }else {
++          moveCursorSpec.position = removeTextSpec.position;
++          if(removeTextSpecEnd < moveCursorSpecEnd) {
++            moveCursorSpec.length = moveCursorSpecEnd - removeTextSpecEnd
++          }else {
++            moveCursorSpec.length = 0
++          }
++        }
 +      }
-       clickCount = 0;
-       clickStartedWithinContainer = false;
-       isMouseMoved = false
 +    }
-     function handleContextMenu(e) {
-       handleMouseClickEvent(e)
++    if(isMoveCursorSpecRangeInverted) {
++      invertMoveCursorSpecRange(moveCursorSpec)
 +    }
-     function handleMouseUp(event) {
-       var target = getTarget(event), annotationNode = null;
-       if(target.className === "annotationRemoveButton") {
-         annotationNode = domUtils.getElementsByTagNameNS(target.parentNode, odf.Namespaces.officens, "annotation")[0];
-         annotationController.removeAnnotation(annotationNode)
-       }else {
-         handleMouseClickEvent(event)
++    return{opSpecsA:[moveCursorSpec], opSpecsB:[removeTextSpec]}
++  }
++  function transformMoveCursorSplitParagraph(moveCursorSpec, splitParagraphSpec) {
++    var isMoveCursorSpecRangeInverted = invertMoveCursorSpecRangeOnNegativeLength(moveCursorSpec);
++    if(splitParagraphSpec.position < moveCursorSpec.position) {
++      moveCursorSpec.position += 1
++    }else {
++      if(splitParagraphSpec.position < moveCursorSpec.position + moveCursorSpec.length) {
++        moveCursorSpec.length += 1
 +      }
 +    }
-     this.startEditing = function() {
-       var op;
-       odtDocument.getOdfCanvas().getElement().classList.add("virtualSelections");
-       eventManager.subscribe("keydown", keyDownHandler.handleEvent);
-       eventManager.subscribe("keypress", keyPressHandler.handleEvent);
-       eventManager.subscribe("keyup", dummyHandler);
-       eventManager.subscribe("beforecut", handleBeforeCut);
-       eventManager.subscribe("cut", handleCut);
-       eventManager.subscribe("copy", handleCopy);
-       eventManager.subscribe("beforepaste", handleBeforePaste);
-       eventManager.subscribe("paste", handlePaste);
-       eventManager.subscribe("mousedown", handleMouseDown);
-       eventManager.subscribe("mousemove", drawShadowCursorTask.trigger);
-       eventManager.subscribe("mouseup", handleMouseUp);
-       eventManager.subscribe("contextmenu", handleContextMenu);
-       eventManager.subscribe("dragend", handleDragEnd);
-       odtDocument.subscribe(ops.OdtDocument.signalOperationExecuted, redrawRegionSelectionTask.trigger);
-       odtDocument.subscribe(ops.OdtDocument.signalOperationExecuted, updateUndoStack);
-       op = new ops.OpAddCursor;
-       op.init({memberid:inputMemberId});
-       session.enqueue([op]);
-       if(undoManager) {
-         undoManager.saveInitialState()
-       }
-     };
-     this.endEditing = function() {
-       var op;
-       op = new ops.OpRemoveCursor;
-       op.init({memberid:inputMemberId});
-       session.enqueue([op]);
-       if(undoManager) {
-         undoManager.resetInitialState()
++    if(isMoveCursorSpecRangeInverted) {
++      invertMoveCursorSpecRange(moveCursorSpec)
++    }
++    return{opSpecsA:[moveCursorSpec], opSpecsB:[splitParagraphSpec]}
++  }
++  function transformRemoveCursorRemoveCursor(removeCursorSpecA, removeCursorSpecB) {
++    var isSameMemberid = removeCursorSpecA.memberid === removeCursorSpecB.memberid;
++    return{opSpecsA:isSameMemberid ? [] : [removeCursorSpecA], opSpecsB:isSameMemberid ? [] : [removeCursorSpecB]}
++  }
++  function transformRemoveStyleRemoveStyle(removeStyleSpecA, removeStyleSpecB) {
++    var isSameStyle = removeStyleSpecA.styleName === removeStyleSpecB.styleName && removeStyleSpecA.styleFamily === removeStyleSpecB.styleFamily;
++    return{opSpecsA:isSameStyle ? [] : [removeStyleSpecA], opSpecsB:isSameStyle ? [] : [removeStyleSpecB]}
++  }
++  function transformRemoveStyleSetParagraphStyle(removeStyleSpec, setParagraphStyleSpec) {
++    var helperOpspec, removeStyleSpecResult = [removeStyleSpec], setParagraphStyleSpecResult = [setParagraphStyleSpec];
++    if(removeStyleSpec.styleFamily === "paragraph" && removeStyleSpec.styleName === setParagraphStyleSpec.styleName) {
++      helperOpspec = {optype:"SetParagraphStyle", memberid:removeStyleSpec.memberid, timestamp:removeStyleSpec.timestamp, position:setParagraphStyleSpec.position, styleName:""};
++      removeStyleSpecResult.unshift(helperOpspec);
++      setParagraphStyleSpec.styleName = ""
++    }
++    return{opSpecsA:removeStyleSpecResult, opSpecsB:setParagraphStyleSpecResult}
++  }
++  function transformRemoveStyleUpdateParagraphStyle(removeStyleSpec, updateParagraphStyleSpec) {
++    var setAttributes, helperOpspec, removeStyleSpecResult = [removeStyleSpec], updateParagraphStyleSpecResult = [updateParagraphStyleSpec];
++    if(removeStyleSpec.styleFamily === "paragraph") {
++      setAttributes = getStyleReferencingAttributes(updateParagraphStyleSpec.setProperties, removeStyleSpec.styleName);
++      if(setAttributes.length > 0) {
++        helperOpspec = {optype:"UpdateParagraphStyle", memberid:removeStyleSpec.memberid, timestamp:removeStyleSpec.timestamp, styleName:updateParagraphStyleSpec.styleName, removedProperties:{attributes:setAttributes.join(",")}};
++        removeStyleSpecResult.unshift(helperOpspec)
 +      }
-       odtDocument.unsubscribe(ops.OdtDocument.signalOperationExecuted, updateUndoStack);
-       odtDocument.unsubscribe(ops.OdtDocument.signalOperationExecuted, redrawRegionSelectionTask.trigger);
-       eventManager.unsubscribe("keydown", keyDownHandler.handleEvent);
-       eventManager.unsubscribe("keypress", keyPressHandler.handleEvent);
-       eventManager.unsubscribe("keyup", dummyHandler);
-       eventManager.unsubscribe("cut", handleCut);
-       eventManager.unsubscribe("beforecut", handleBeforeCut);
-       eventManager.unsubscribe("copy", handleCopy);
-       eventManager.unsubscribe("paste", handlePaste);
-       eventManager.unsubscribe("beforepaste", handleBeforePaste);
-       eventManager.unsubscribe("mousemove", drawShadowCursorTask.trigger);
-       eventManager.unsubscribe("mousedown", handleMouseDown);
-       eventManager.unsubscribe("mouseup", handleMouseUp);
-       eventManager.unsubscribe("contextmenu", handleContextMenu);
-       eventManager.unsubscribe("dragend", handleDragEnd);
-       odtDocument.getOdfCanvas().getElement().classList.remove("virtualSelections")
-     };
-     this.getInputMemberId = function() {
-       return inputMemberId
-     };
-     this.getSession = function() {
-       return session
-     };
-     this.setUndoManager = function(manager) {
-       if(undoManager) {
-         undoManager.unsubscribe(gui.UndoManager.signalUndoStackChanged, forwardUndoStackChange)
++      if(removeStyleSpec.styleName === updateParagraphStyleSpec.styleName) {
++        updateParagraphStyleSpecResult = []
++      }else {
++        dropStyleReferencingAttributes(updateParagraphStyleSpec.setProperties, removeStyleSpec.styleName)
 +      }
-       undoManager = manager;
-       if(undoManager) {
-         undoManager.setOdtDocument(odtDocument);
-         undoManager.setPlaybackFunction(function(op) {
-           op.execute(odtDocument)
-         });
-         undoManager.subscribe(gui.UndoManager.signalUndoStackChanged, forwardUndoStackChange)
++    }
++    return{opSpecsA:removeStyleSpecResult, opSpecsB:updateParagraphStyleSpecResult}
++  }
++  function transformRemoveTextRemoveText(removeTextSpecA, removeTextSpecB) {
++    var removeTextSpecAEnd = removeTextSpecA.position + removeTextSpecA.length, removeTextSpecBEnd = removeTextSpecB.position + removeTextSpecB.length, removeTextSpecAResult = [removeTextSpecA], removeTextSpecBResult = [removeTextSpecB];
++    if(removeTextSpecBEnd <= removeTextSpecA.position) {
++      removeTextSpecA.position -= removeTextSpecB.length
++    }else {
++      if(removeTextSpecAEnd <= removeTextSpecB.position) {
++        removeTextSpecB.position -= removeTextSpecA.length
++      }else {
++        if(removeTextSpecB.position < removeTextSpecAEnd) {
++          if(removeTextSpecA.position < removeTextSpecB.position) {
++            if(removeTextSpecBEnd < removeTextSpecAEnd) {
++              removeTextSpecA.length = removeTextSpecA.length - removeTextSpecB.length
++            }else {
++              removeTextSpecA.length = removeTextSpecB.position - removeTextSpecA.position
++            }
++            if(removeTextSpecAEnd < removeTextSpecBEnd) {
++              removeTextSpecB.position = removeTextSpecA.position;
++              removeTextSpecB.length = removeTextSpecBEnd - removeTextSpecAEnd
++            }else {
++              removeTextSpecBResult = []
++            }
++          }else {
++            if(removeTextSpecAEnd < removeTextSpecBEnd) {
++              removeTextSpecB.length = removeTextSpecB.length - removeTextSpecA.length
++            }else {
++              if(removeTextSpecB.position < removeTextSpecA.position) {
++                removeTextSpecB.length = removeTextSpecA.position - removeTextSpecB.position
++              }else {
++                removeTextSpecBResult = []
++              }
++            }
++            if(removeTextSpecBEnd < removeTextSpecAEnd) {
++              removeTextSpecA.position = removeTextSpecB.position;
++              removeTextSpecA.length = removeTextSpecAEnd - removeTextSpecBEnd
++            }else {
++              removeTextSpecAResult = []
++            }
++          }
++        }
 +      }
-     };
-     this.getUndoManager = function() {
-       return undoManager
-     };
-     this.getAnnotationController = function() {
-       return annotationController
-     };
-     this.getDirectTextStyler = function() {
-       return directTextStyler
-     };
-     this.getDirectParagraphStyler = function() {
-       return directParagraphStyler
-     };
-     this.getImageManager = function() {
-       return imageManager
-     };
-     this.getTextManipulator = function() {
-       return textManipulator
-     };
-     this.getEventManager = function() {
-       return eventManager
-     };
-     this.getKeyboardHandlers = function() {
-       return{keydown:keyDownHandler, keypress:keyPressHandler}
-     };
-     this.destroy = function(callback) {
-       var destroyCallbacks = [drawShadowCursorTask.destroy, directTextStyler.destroy];
-       if(directParagraphStyler) {
-         destroyCallbacks.push(directParagraphStyler.destroy)
++    }
++    return{opSpecsA:removeTextSpecAResult, opSpecsB:removeTextSpecBResult}
++  }
++  function transformRemoveTextSplitParagraph(removeTextSpec, splitParagraphSpec) {
++    var removeTextSpecEnd = removeTextSpec.position + removeTextSpec.length, helperOpspec, removeTextSpecResult = [removeTextSpec], splitParagraphSpecResult = [splitParagraphSpec];
++    if(splitParagraphSpec.position <= removeTextSpec.position) {
++      removeTextSpec.position += 1
++    }else {
++      if(splitParagraphSpec.position < removeTextSpecEnd) {
++        removeTextSpec.length = splitParagraphSpec.position - removeTextSpec.position;
++        helperOpspec = {optype:"RemoveText", memberid:removeTextSpec.memberid, timestamp:removeTextSpec.timestamp, position:splitParagraphSpec.position + 1, length:removeTextSpecEnd - splitParagraphSpec.position};
++        removeTextSpecResult.unshift(helperOpspec)
 +      }
-       async.destroyAll(destroyCallbacks, callback)
-     };
-     function returnTrue(fn) {
-       return function() {
-         fn();
-         return true
++    }
++    if(removeTextSpec.position + removeTextSpec.length <= splitParagraphSpec.position) {
++      splitParagraphSpec.position -= removeTextSpec.length
++    }else {
++      if(removeTextSpec.position < splitParagraphSpec.position) {
++        splitParagraphSpec.position = removeTextSpec.position
 +      }
 +    }
-     function rangeSelectionOnly(fn) {
-       return function(e) {
-         var selectionType = odtDocument.getCursor(inputMemberId).getSelectionType();
-         if(selectionType === ops.OdtCursor.RangeSelection) {
-           return fn(e)
-         }
-         return true
++    return{opSpecsA:removeTextSpecResult, opSpecsB:splitParagraphSpecResult}
++  }
++  function passUnchanged(opSpecA, opSpecB) {
++    return{opSpecsA:[opSpecA], opSpecsB:[opSpecB]}
++  }
++  var transformations;
++  transformations = {"AddCursor":{"AddCursor":passUnchanged, "AddMember":passUnchanged, "AddStyle":passUnchanged, "ApplyDirectStyling":passUnchanged, "InsertText":passUnchanged, "MoveCursor":passUnchanged, "RemoveCursor":passUnchanged, "RemoveMember":passUnchanged, "RemoveStyle":passUnchanged, "RemoveText":passUnchanged, "SetParagraphStyle":passUnchanged, "SplitParagraph":passUnchanged, "UpdateMember":passUnchanged, "UpdateMetadata":passUnchanged, "UpdateParagraphStyle":passUnchanged},  [...]
++  "InsertText":passUnchanged, "MoveCursor":passUnchanged, "RemoveCursor":passUnchanged, "RemoveStyle":passUnchanged, "RemoveText":passUnchanged, "SetParagraphStyle":passUnchanged, "SplitParagraph":passUnchanged, "UpdateMetadata":passUnchanged, "UpdateParagraphStyle":passUnchanged}, "AddStyle":{"AddStyle":passUnchanged, "ApplyDirectStyling":passUnchanged, "InsertText":passUnchanged, "MoveCursor":passUnchanged, "RemoveCursor":passUnchanged, "RemoveMember":passUnchanged, "RemoveStyle":tran [...]
++  "RemoveText":passUnchanged, "SetParagraphStyle":passUnchanged, "SplitParagraph":passUnchanged, "UpdateMember":passUnchanged, "UpdateMetadata":passUnchanged, "UpdateParagraphStyle":passUnchanged}, "ApplyDirectStyling":{"ApplyDirectStyling":transformApplyDirectStylingApplyDirectStyling, "InsertText":transformApplyDirectStylingInsertText, "MoveCursor":passUnchanged, "RemoveCursor":passUnchanged, "RemoveStyle":passUnchanged, "RemoveText":transformApplyDirectStylingRemoveText, "SetParagrap [...]
++  "SplitParagraph":transformApplyDirectStylingSplitParagraph, "UpdateMetadata":passUnchanged, "UpdateParagraphStyle":passUnchanged}, "InsertText":{"InsertText":transformInsertTextInsertText, "MoveCursor":transformInsertTextMoveCursor, "RemoveCursor":passUnchanged, "RemoveMember":passUnchanged, "RemoveStyle":passUnchanged, "RemoveText":transformInsertTextRemoveText, "SplitParagraph":transformInsertTextSplitParagraph, "UpdateMember":passUnchanged, "UpdateMetadata":passUnchanged, "UpdatePa [...]
++  "MoveCursor":{"MoveCursor":passUnchanged, "RemoveCursor":transformMoveCursorRemoveCursor, "RemoveMember":passUnchanged, "RemoveStyle":passUnchanged, "RemoveText":transformMoveCursorRemoveText, "SetParagraphStyle":passUnchanged, "SplitParagraph":transformMoveCursorSplitParagraph, "UpdateMember":passUnchanged, "UpdateMetadata":passUnchanged, "UpdateParagraphStyle":passUnchanged}, "RemoveCursor":{"RemoveCursor":transformRemoveCursorRemoveCursor, "RemoveMember":passUnchanged, "RemoveStyle [...]
++  "RemoveText":passUnchanged, "SetParagraphStyle":passUnchanged, "SplitParagraph":passUnchanged, "UpdateMember":passUnchanged, "UpdateMetadata":passUnchanged, "UpdateParagraphStyle":passUnchanged}, "RemoveMember":{"RemoveStyle":passUnchanged, "RemoveText":passUnchanged, "SetParagraphStyle":passUnchanged, "SplitParagraph":passUnchanged, "UpdateMetadata":passUnchanged, "UpdateParagraphStyle":passUnchanged}, "RemoveStyle":{"RemoveStyle":transformRemoveStyleRemoveStyle, "RemoveText":passUnc [...]
++  "SplitParagraph":passUnchanged, "UpdateMember":passUnchanged, "UpdateMetadata":passUnchanged, "UpdateParagraphStyle":transformRemoveStyleUpdateParagraphStyle}, "RemoveText":{"RemoveText":transformRemoveTextRemoveText, "SplitParagraph":transformRemoveTextSplitParagraph, "UpdateMember":passUnchanged, "UpdateMetadata":passUnchanged, "UpdateParagraphStyle":passUnchanged}, "SetParagraphStyle":{"UpdateMember":passUnchanged, "UpdateMetadata":passUnchanged, "UpdateParagraphStyle":passUnchange [...]
++  "UpdateMember":passUnchanged, "UpdateMetadata":passUnchanged, "UpdateParagraphStyle":passUnchanged}, "UpdateMember":{"UpdateMetadata":passUnchanged, "UpdateParagraphStyle":passUnchanged}, "UpdateMetadata":{"UpdateMetadata":transformUpdateMetadataUpdateMetadata, "UpdateParagraphStyle":passUnchanged}, "UpdateParagraphStyle":{"UpdateParagraphStyle":transformUpdateParagraphStyleUpdateParagraphStyle}};
++  this.passUnchanged = passUnchanged;
++  this.extendTransformations = function(moreTransformations) {
++    Object.keys(moreTransformations).forEach(function(optypeA) {
++      var moreTransformationsOptypeAMap = moreTransformations[optypeA], optypeAMap, isExtendingOptypeAMap = transformations.hasOwnProperty(optypeA);
++      runtime.log((isExtendingOptypeAMap ? "Extending" : "Adding") + " map for optypeA: " + optypeA);
++      if(!isExtendingOptypeAMap) {
++        transformations[optypeA] = {}
 +      }
++      optypeAMap = transformations[optypeA];
++      Object.keys(moreTransformationsOptypeAMap).forEach(function(optypeB) {
++        var isOverwritingOptypeBEntry = optypeAMap.hasOwnProperty(optypeB);
++        runtime.assert(optypeA <= optypeB, "Wrong order:" + optypeA + ", " + optypeB);
++        runtime.log("  " + (isOverwritingOptypeBEntry ? "Overwriting" : "Adding") + " entry for optypeB: " + optypeB);
++        optypeAMap[optypeB] = moreTransformationsOptypeAMap[optypeB]
++      })
++    })
++  };
++  this.transformOpspecVsOpspec = function(opSpecA, opSpecB) {
++    var isOptypeAAlphaNumericSmaller = opSpecA.optype <= opSpecB.optype, helper, transformationFunctionMap, transformationFunction, result;
++    runtime.log("Crosstransforming:");
++    runtime.log(runtime.toJson(opSpecA));
++    runtime.log(runtime.toJson(opSpecB));
++    if(!isOptypeAAlphaNumericSmaller) {
++      helper = opSpecA;
++      opSpecA = opSpecB;
++      opSpecB = helper
 +    }
-     function init() {
-       var isMacOS = window.navigator.appVersion.toLowerCase().indexOf("mac") !== -1, modifier = gui.KeyboardHandler.Modifier, keyCode = gui.KeyboardHandler.KeyCode;
-       drawShadowCursorTask = new core.ScheduledTask(updateShadowCursor, 0);
-       redrawRegionSelectionTask = new core.ScheduledTask(redrawRegionSelection, 0);
-       keyDownHandler.bind(keyCode.Tab, modifier.None, rangeSelectionOnly(function() {
-         textManipulator.insertText("\t");
-         return true
-       }));
-       keyDownHandler.bind(keyCode.Left, modifier.None, rangeSelectionOnly(moveCursorToLeft));
-       keyDownHandler.bind(keyCode.Right, modifier.None, rangeSelectionOnly(moveCursorToRight));
-       keyDownHandler.bind(keyCode.Up, modifier.None, rangeSelectionOnly(moveCursorUp));
-       keyDownHandler.bind(keyCode.Down, modifier.None, rangeSelectionOnly(moveCursorDown));
-       keyDownHandler.bind(keyCode.Backspace, modifier.None, returnTrue(textManipulator.removeTextByBackspaceKey));
-       keyDownHandler.bind(keyCode.Delete, modifier.None, textManipulator.removeTextByDeleteKey);
-       keyDownHandler.bind(keyCode.Left, modifier.Shift, rangeSelectionOnly(extendSelectionToLeft));
-       keyDownHandler.bind(keyCode.Right, modifier.Shift, rangeSelectionOnly(extendSelectionToRight));
-       keyDownHandler.bind(keyCode.Up, modifier.Shift, rangeSelectionOnly(extendSelectionUp));
-       keyDownHandler.bind(keyCode.Down, modifier.Shift, rangeSelectionOnly(extendSelectionDown));
-       keyDownHandler.bind(keyCode.Home, modifier.None, rangeSelectionOnly(moveCursorToLineStart));
-       keyDownHandler.bind(keyCode.End, modifier.None, rangeSelectionOnly(moveCursorToLineEnd));
-       keyDownHandler.bind(keyCode.Home, modifier.Ctrl, rangeSelectionOnly(moveCursorToDocumentStart));
-       keyDownHandler.bind(keyCode.End, modifier.Ctrl, rangeSelectionOnly(moveCursorToDocumentEnd));
-       keyDownHandler.bind(keyCode.Home, modifier.Shift, rangeSelectionOnly(extendSelectionToLineStart));
-       keyDownHandler.bind(keyCode.End, modifier.Shift, rangeSelectionOnly(extendSelectionToLineEnd));
-       keyDownHandler.bind(keyCode.Up, modifier.CtrlShift, rangeSelectionOnly(extendSelectionToParagraphStart));
-       keyDownHandler.bind(keyCode.Down, modifier.CtrlShift, rangeSelectionOnly(extendSelectionToParagraphEnd));
-       keyDownHandler.bind(keyCode.Home, modifier.CtrlShift, rangeSelectionOnly(extendSelectionToDocumentStart));
-       keyDownHandler.bind(keyCode.End, modifier.CtrlShift, rangeSelectionOnly(extendSelectionToDocumentEnd));
-       if(isMacOS) {
-         keyDownHandler.bind(keyCode.Clear, modifier.None, textManipulator.removeCurrentSelection);
-         keyDownHandler.bind(keyCode.Left, modifier.Meta, rangeSelectionOnly(moveCursorToLineStart));
-         keyDownHandler.bind(keyCode.Right, modifier.Meta, rangeSelectionOnly(moveCursorToLineEnd));
-         keyDownHandler.bind(keyCode.Home, modifier.Meta, rangeSelectionOnly(moveCursorToDocumentStart));
-         keyDownHandler.bind(keyCode.End, modifier.Meta, rangeSelectionOnly(moveCursorToDocumentEnd));
-         keyDownHandler.bind(keyCode.Left, modifier.MetaShift, rangeSelectionOnly(extendSelectionToLineStart));
-         keyDownHandler.bind(keyCode.Right, modifier.MetaShift, rangeSelectionOnly(extendSelectionToLineEnd));
-         keyDownHandler.bind(keyCode.Up, modifier.AltShift, rangeSelectionOnly(extendSelectionToParagraphStart));
-         keyDownHandler.bind(keyCode.Down, modifier.AltShift, rangeSelectionOnly(extendSelectionToParagraphEnd));
-         keyDownHandler.bind(keyCode.Up, modifier.MetaShift, rangeSelectionOnly(extendSelectionToDocumentStart));
-         keyDownHandler.bind(keyCode.Down, modifier.MetaShift, rangeSelectionOnly(extendSelectionToDocumentEnd));
-         keyDownHandler.bind(keyCode.A, modifier.Meta, rangeSelectionOnly(extendSelectionToEntireDocument));
-         keyDownHandler.bind(keyCode.B, modifier.Meta, rangeSelectionOnly(directTextStyler.toggleBold));
-         keyDownHandler.bind(keyCode.I, modifier.Meta, rangeSelectionOnly(directTextStyler.toggleItalic));
-         keyDownHandler.bind(keyCode.U, modifier.Meta, rangeSelectionOnly(directTextStyler.toggleUnderline));
-         if(directParagraphStyler) {
-           keyDownHandler.bind(keyCode.L, modifier.MetaShift, rangeSelectionOnly(directParagraphStyler.alignParagraphLeft));
-           keyDownHandler.bind(keyCode.E, modifier.MetaShift, rangeSelectionOnly(directParagraphStyler.alignParagraphCenter));
-           keyDownHandler.bind(keyCode.R, modifier.MetaShift, rangeSelectionOnly(directParagraphStyler.alignParagraphRight));
-           keyDownHandler.bind(keyCode.J, modifier.MetaShift, rangeSelectionOnly(directParagraphStyler.alignParagraphJustified))
-         }
-         if(annotationController) {
-           keyDownHandler.bind(keyCode.C, modifier.MetaShift, annotationController.addAnnotation)
-         }
-         keyDownHandler.bind(keyCode.Z, modifier.Meta, undo);
-         keyDownHandler.bind(keyCode.Z, modifier.MetaShift, redo)
-       }else {
-         keyDownHandler.bind(keyCode.A, modifier.Ctrl, rangeSelectionOnly(extendSelectionToEntireDocument));
-         keyDownHandler.bind(keyCode.B, modifier.Ctrl, rangeSelectionOnly(directTextStyler.toggleBold));
-         keyDownHandler.bind(keyCode.I, modifier.Ctrl, rangeSelectionOnly(directTextStyler.toggleItalic));
-         keyDownHandler.bind(keyCode.U, modifier.Ctrl, rangeSelectionOnly(directTextStyler.toggleUnderline));
-         if(directParagraphStyler) {
-           keyDownHandler.bind(keyCode.L, modifier.CtrlShift, rangeSelectionOnly(directParagraphStyler.alignParagraphLeft));
-           keyDownHandler.bind(keyCode.E, modifier.CtrlShift, rangeSelectionOnly(directParagraphStyler.alignParagraphCenter));
-           keyDownHandler.bind(keyCode.R, modifier.CtrlShift, rangeSelectionOnly(directParagraphStyler.alignParagraphRight));
-           keyDownHandler.bind(keyCode.J, modifier.CtrlShift, rangeSelectionOnly(directParagraphStyler.alignParagraphJustified))
-         }
-         if(annotationController) {
-           keyDownHandler.bind(keyCode.C, modifier.CtrlAlt, annotationController.addAnnotation)
-         }
-         keyDownHandler.bind(keyCode.Z, modifier.Ctrl, undo);
-         keyDownHandler.bind(keyCode.Z, modifier.CtrlShift, redo)
++    transformationFunctionMap = transformations[opSpecA.optype];
++    transformationFunction = transformationFunctionMap && transformationFunctionMap[opSpecB.optype];
++    if(transformationFunction) {
++      result = transformationFunction(opSpecA, opSpecB, !isOptypeAAlphaNumericSmaller);
++      if(!isOptypeAAlphaNumericSmaller && result !== null) {
++        result = {opSpecsA:result.opSpecsB, opSpecsB:result.opSpecsA}
 +      }
-       keyPressHandler.setDefault(rangeSelectionOnly(function(e) {
-         var text = stringFromKeyPress(e);
-         if(text && !(e.altKey || (e.ctrlKey || e.metaKey))) {
-           textManipulator.insertText(text);
-           return true
-         }
-         return false
-       }));
-       keyPressHandler.bind(keyCode.Enter, modifier.None, rangeSelectionOnly(textManipulator.enqueueParagraphSplittingOps))
++    }else {
++      result = null
 +    }
-     init()
-   };
-   return gui.SessionController
- }();
++    runtime.log("result:");
++    if(result) {
++      runtime.log(runtime.toJson(result.opSpecsA));
++      runtime.log(runtime.toJson(result.opSpecsB))
++    }else {
++      runtime.log("null")
++    }
++    return result
++  }
++};
 +/*
 +
-  Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
++ Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
-  The JavaScript code in this page is free software: you can redistribute it
-  and/or modify it under the terms of the GNU Affero General Public License
-  (GNU AGPL) as published by the Free Software Foundation, either version 3 of
-  the License, or (at your option) any later version.  The code is distributed
-  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
- 
-  You should have received a copy of the GNU Affero General Public License
-  along with this code.  If not, see <http://www.gnu.org/licenses/>.
++ This file is part of WebODF.
 +
-  As additional permission under GNU AGPL version 3 section 7, you
-  may distribute non-source (e.g., minimized or compacted) forms of
-  that code without the copy of the GNU GPL normally required by
-  section 4, provided you include this license notice and a URL
-  through which recipients can access the Corresponding Source.
++ WebODF is free software: you can redistribute it and/or modify it
++ under the terms of the GNU Affero General Public License (GNU AGPL)
++ as published by the Free Software Foundation, either version 3 of
++ the License, or (at your option) any later version.
 +
-  As a special exception to the AGPL, any HTML file which merely makes function
-  calls to this code, and for that purpose includes it by reference shall be
-  deemed a separate work for copyright law purposes. In addition, the copyright
-  holders of this code give you permission to combine this code with free
-  software libraries that are released under the GNU LGPL. You may copy and
-  distribute such a system following the terms of the GNU AGPL for this code
-  and the LGPL for the libraries. If you modify this code, you may extend this
-  exception to your version of the code, but you are not obligated to do so.
-  If you do not wish to do so, delete this exception statement from your
-  version.
++ WebODF is distributed in the hope that it will be useful, but
++ WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ GNU Affero General Public License for more details.
 +
-  This license applies to this entire compilation.
++ You should have received a copy of the GNU Affero General Public License
++ along with WebODF.  If not, see <http://www.gnu.org/licenses/>.
 + @licend
++
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("gui.Caret");
- gui.CaretManager = function CaretManager(sessionController) {
-   var carets = {}, window = runtime.getWindow(), scrollIntoViewScheduled = false;
-   function getCaret(memberId) {
-     return carets.hasOwnProperty(memberId) ? carets[memberId] : null
-   }
-   function getCarets() {
-     return Object.keys(carets).map(function(memberid) {
-       return carets[memberid]
-     })
-   }
-   function getCanvasElement() {
-     return sessionController.getSession().getOdtDocument().getOdfCanvas().getElement()
++ops.OperationTransformer = function OperationTransformer() {
++  var operationFactory, operationTransformMatrix = new ops.OperationTransformMatrix;
++  function operations(opspecs) {
++    var ops = [];
++    opspecs.forEach(function(opspec) {
++      ops.push(operationFactory.create(opspec))
++    });
++    return ops
 +  }
-   function removeCaret(memberId) {
-     if(memberId === sessionController.getInputMemberId()) {
-       getCanvasElement().removeAttribute("tabindex")
-     }
-     delete carets[memberId]
++  function transformOpVsOp(opSpecA, opSpecB) {
++    return operationTransformMatrix.transformOpspecVsOpspec(opSpecA, opSpecB)
 +  }
-   function refreshLocalCaretBlinking(cursor) {
-     var caret, memberId = cursor.getMemberId();
-     if(memberId === sessionController.getInputMemberId()) {
-       caret = getCaret(memberId);
-       if(caret) {
-         caret.refreshCursorBlinking()
++  function transformOpListVsOp(opSpecsA, opSpecB) {
++    var transformResult, transformListResult, transformedOpspecsA = [], transformedOpspecsB = [];
++    while(opSpecsA.length > 0 && opSpecB) {
++      transformResult = transformOpVsOp(opSpecsA.shift(), opSpecB);
++      if(!transformResult) {
++        return null
 +      }
-     }
-   }
-   function executeEnsureCaretVisible() {
-     var caret = getCaret(sessionController.getInputMemberId());
-     scrollIntoViewScheduled = false;
-     if(caret) {
-       caret.ensureVisible()
-     }
-   }
-   function scheduleCaretVisibilityCheck() {
-     var caret = getCaret(sessionController.getInputMemberId());
-     if(caret) {
-       caret.handleUpdate();
-       if(!scrollIntoViewScheduled) {
-         scrollIntoViewScheduled = true;
-         runtime.setTimeout(executeEnsureCaretVisible, 50)
++      transformedOpspecsA = transformedOpspecsA.concat(transformResult.opSpecsA);
++      if(transformResult.opSpecsB.length === 0) {
++        transformedOpspecsA = transformedOpspecsA.concat(opSpecsA);
++        opSpecB = null;
++        break
 +      }
++      while(transformResult.opSpecsB.length > 1) {
++        transformListResult = transformOpListVsOp(opSpecsA, transformResult.opSpecsB.shift());
++        if(!transformListResult) {
++          return null
++        }
++        transformedOpspecsB = transformedOpspecsB.concat(transformListResult.opSpecsB);
++        opSpecsA = transformListResult.opSpecsA
++      }
++      opSpecB = transformResult.opSpecsB.pop()
 +    }
-   }
-   function ensureLocalCaretVisible(info) {
-     if(info.memberId === sessionController.getInputMemberId()) {
-       scheduleCaretVisibilityCheck()
-     }
-   }
-   function focusLocalCaret() {
-     var caret = getCaret(sessionController.getInputMemberId());
-     if(caret) {
-       caret.setFocus()
-     }
-   }
-   function blurLocalCaret() {
-     var caret = getCaret(sessionController.getInputMemberId());
-     if(caret) {
-       caret.removeFocus()
-     }
-   }
-   function showLocalCaret() {
-     var caret = getCaret(sessionController.getInputMemberId());
-     if(caret) {
-       caret.show()
-     }
-   }
-   function hideLocalCaret() {
-     var caret = getCaret(sessionController.getInputMemberId());
-     if(caret) {
-       caret.hide()
++    if(opSpecB) {
++      transformedOpspecsB.push(opSpecB)
 +    }
++    return{opSpecsA:transformedOpspecsA, opSpecsB:transformedOpspecsB}
 +  }
-   this.registerCursor = function(cursor, caretAvatarInitiallyVisible, blinkOnRangeSelect) {
-     var memberid = cursor.getMemberId(), caret = new gui.Caret(cursor, caretAvatarInitiallyVisible, blinkOnRangeSelect);
-     carets[memberid] = caret;
-     if(memberid === sessionController.getInputMemberId()) {
-       runtime.log("Starting to track input on new cursor of " + memberid);
-       cursor.handleUpdate = scheduleCaretVisibilityCheck;
-       getCanvasElement().setAttribute("tabindex", -1);
-       sessionController.getEventManager().focus()
-     }else {
-       cursor.handleUpdate = caret.handleUpdate
-     }
-     return caret
++  this.setOperationFactory = function(f) {
++    operationFactory = f
 +  };
-   this.getCaret = getCaret;
-   this.getCarets = getCarets;
-   this.destroy = function(callback) {
-     var odtDocument = sessionController.getSession().getOdtDocument(), eventManager = sessionController.getEventManager(), caretArray = getCarets();
-     odtDocument.unsubscribe(ops.OdtDocument.signalParagraphChanged, ensureLocalCaretVisible);
-     odtDocument.unsubscribe(ops.OdtDocument.signalCursorMoved, refreshLocalCaretBlinking);
-     odtDocument.unsubscribe(ops.OdtDocument.signalCursorRemoved, removeCaret);
-     eventManager.unsubscribe("focus", focusLocalCaret);
-     eventManager.unsubscribe("blur", blurLocalCaret);
-     window.removeEventListener("focus", showLocalCaret, false);
-     window.removeEventListener("blur", hideLocalCaret, false);
-     (function destroyCaret(i, err) {
-       if(err) {
-         callback(err)
-       }else {
-         if(i < caretArray.length) {
-           caretArray[i].destroy(function(err) {
-             destroyCaret(i + 1, err)
-           })
-         }else {
-           callback()
-         }
-       }
-     })(0, undefined);
-     carets = {}
++  this.getOperationTransformMatrix = function() {
++    return operationTransformMatrix
 +  };
-   function init() {
-     var odtDocument = sessionController.getSession().getOdtDocument(), eventManager = sessionController.getEventManager();
-     odtDocument.subscribe(ops.OdtDocument.signalParagraphChanged, ensureLocalCaretVisible);
-     odtDocument.subscribe(ops.OdtDocument.signalCursorMoved, refreshLocalCaretBlinking);
-     odtDocument.subscribe(ops.OdtDocument.signalCursorRemoved, removeCaret);
-     eventManager.subscribe("focus", focusLocalCaret);
-     eventManager.subscribe("blur", blurLocalCaret);
-     window.addEventListener("focus", showLocalCaret, false);
-     window.addEventListener("blur", hideLocalCaret, false)
++  this.transform = function(opSpecsA, opSpecsB) {
++    var transformResult, transformedOpspecsB = [];
++    while(opSpecsB.length > 0) {
++      transformResult = transformOpListVsOp(opSpecsA, opSpecsB.shift());
++      if(!transformResult) {
++        return null
++      }
++      opSpecsA = transformResult.opSpecsA;
++      transformedOpspecsB = transformedOpspecsB.concat(transformResult.opSpecsB)
++    }
++    return{opsA:operations(opSpecsA), opsB:operations(transformedOpspecsB)}
 +  }
-   init()
 +};
 +/*
 +
-  Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
++ Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("gui.Caret");
- runtime.loadClass("ops.EditInfo");
- runtime.loadClass("gui.EditInfoMarker");
- gui.SessionViewOptions = function() {
-   this.editInfoMarkersInitiallyVisible = true;
-   this.caretAvatarsInitiallyVisible = true;
-   this.caretBlinksOnRangeSelect = true
++ops.Server = function Server() {
 +};
- gui.SessionView = function() {
-   function configOption(userValue, defaultValue) {
-     return userValue !== undefined ? Boolean(userValue) : defaultValue
-   }
-   function SessionView(viewOptions, localMemberId, session, caretManager, selectionViewManager) {
-     var avatarInfoStyles, editInfons = "urn:webodf:names:editinfo", editInfoMap = {}, showEditInfoMarkers = configOption(viewOptions.editInfoMarkersInitiallyVisible, true), showCaretAvatars = configOption(viewOptions.caretAvatarsInitiallyVisible, true), blinkOnRangeSelect = configOption(viewOptions.caretBlinksOnRangeSelect, true), rerenderIntervalId, rerenderSelectionViews = false, RERENDER_INTERVAL = 200;
-     function createAvatarInfoNodeMatch(nodeName, memberId, pseudoClass) {
-       return nodeName + '[editinfo|memberid="' + memberId + '"]' + pseudoClass
-     }
-     function getAvatarInfoStyle(nodeName, memberId, pseudoClass) {
-       var node = avatarInfoStyles.firstChild, nodeMatch = createAvatarInfoNodeMatch(nodeName, memberId, pseudoClass) + "{";
-       while(node) {
-         if(node.nodeType === Node.TEXT_NODE && node.data.indexOf(nodeMatch) === 0) {
-           return node
-         }
-         node = node.nextSibling
-       }
-       return null
-     }
-     function setAvatarInfoStyle(memberId, name, color) {
-       function setStyle(nodeName, rule, pseudoClass) {
-         var styleRule = createAvatarInfoNodeMatch(nodeName, memberId, pseudoClass) + rule, styleNode = getAvatarInfoStyle(nodeName, memberId, pseudoClass);
-         if(styleNode) {
-           styleNode.data = styleRule
-         }else {
-           avatarInfoStyles.appendChild(document.createTextNode(styleRule))
-         }
-       }
-       setStyle("div.editInfoMarker", "{ background-color: " + color + "; }", "");
-       setStyle("span.editInfoColor", "{ background-color: " + color + "; }", "");
-       setStyle("span.editInfoAuthor", '{ content: "' + name + '"; }', ":before");
-       setStyle("dc|creator", "{ background-color: " + color + "; }", "");
-       setStyle("div.selectionOverlay", "{ background-color: " + color + ";}", "")
-     }
-     function highlightEdit(element, memberId, timestamp) {
-       var editInfo, editInfoMarker, id = "", editInfoNode = element.getElementsByTagNameNS(editInfons, "editinfo")[0];
-       if(editInfoNode) {
-         id = editInfoNode.getAttributeNS(editInfons, "id");
-         editInfoMarker = editInfoMap[id]
-       }else {
-         id = Math.random().toString();
-         editInfo = new ops.EditInfo(element, session.getOdtDocument());
-         editInfoMarker = new gui.EditInfoMarker(editInfo, showEditInfoMarkers);
-         editInfoNode = element.getElementsByTagNameNS(editInfons, "editinfo")[0];
-         editInfoNode.setAttributeNS(editInfons, "id", id);
-         editInfoMap[id] = editInfoMarker
-       }
-       editInfoMarker.addEdit(memberId, new Date(timestamp))
-     }
-     function setEditInfoMarkerVisibility(visible) {
-       var editInfoMarker, keyname;
-       for(keyname in editInfoMap) {
-         if(editInfoMap.hasOwnProperty(keyname)) {
-           editInfoMarker = editInfoMap[keyname];
-           if(visible) {
-             editInfoMarker.show()
-           }else {
-             editInfoMarker.hide()
-           }
-         }
-       }
-     }
-     function setCaretAvatarVisibility(visible) {
-       caretManager.getCarets().forEach(function(caret) {
-         if(visible) {
-           caret.showHandle()
-         }else {
-           caret.hideHandle()
-         }
-       })
-     }
-     this.showEditInfoMarkers = function() {
-       if(showEditInfoMarkers) {
-         return
-       }
-       showEditInfoMarkers = true;
-       setEditInfoMarkerVisibility(showEditInfoMarkers)
-     };
-     this.hideEditInfoMarkers = function() {
-       if(!showEditInfoMarkers) {
-         return
-       }
-       showEditInfoMarkers = false;
-       setEditInfoMarkerVisibility(showEditInfoMarkers)
-     };
-     this.showCaretAvatars = function() {
-       if(showCaretAvatars) {
-         return
-       }
-       showCaretAvatars = true;
-       setCaretAvatarVisibility(showCaretAvatars)
-     };
-     this.hideCaretAvatars = function() {
-       if(!showCaretAvatars) {
-         return
-       }
-       showCaretAvatars = false;
-       setCaretAvatarVisibility(showCaretAvatars)
-     };
-     this.getSession = function() {
-       return session
-     };
-     this.getCaret = function(memberid) {
-       return caretManager.getCaret(memberid)
-     };
-     function renderMemberData(member) {
-       var memberId = member.getMemberId(), properties = member.getProperties();
-       setAvatarInfoStyle(memberId, properties.fullName, properties.color);
-       if(localMemberId === memberId) {
-         setAvatarInfoStyle("", "", properties.color)
-       }
-     }
-     function onCursorAdded(cursor) {
-       var memberId = cursor.getMemberId(), properties = session.getOdtDocument().getMember(memberId).getProperties(), caret;
-       caretManager.registerCursor(cursor, showCaretAvatars, blinkOnRangeSelect);
-       selectionViewManager.registerCursor(cursor, true);
-       caret = caretManager.getCaret(memberId);
-       if(caret) {
-         caret.setAvatarImageUrl(properties.imageUrl);
-         caret.setColor(properties.color)
-       }
-       runtime.log("+++ View here +++ eagerly created an Caret for '" + memberId + "'! +++")
-     }
-     function onCursorMoved(cursor) {
-       var memberId = cursor.getMemberId(), localSelectionView = selectionViewManager.getSelectionView(localMemberId), shadowSelectionView = selectionViewManager.getSelectionView(gui.ShadowCursor.ShadowCursorMemberId), localCaret = caretManager.getCaret(localMemberId);
-       if(memberId === localMemberId) {
-         shadowSelectionView.hide();
-         if(localSelectionView) {
-           localSelectionView.show()
-         }
-         if(localCaret) {
-           localCaret.show()
-         }
-       }else {
-         if(memberId === gui.ShadowCursor.ShadowCursorMemberId) {
-           shadowSelectionView.show();
-           if(localSelectionView) {
-             localSelectionView.hide()
-           }
-           if(localCaret) {
-             localCaret.hide()
-           }
-         }
-       }
-     }
-     function onCursorRemoved(memberid) {
-       selectionViewManager.removeSelectionView(memberid)
-     }
-     function onParagraphChanged(info) {
-       highlightEdit(info.paragraphElement, info.memberId, info.timeStamp)
-     }
-     function requestRerenderOfSelectionViews() {
-       rerenderSelectionViews = true
-     }
-     function startRerenderLoop() {
-       rerenderIntervalId = runtime.getWindow().setInterval(function() {
-         if(rerenderSelectionViews) {
-           selectionViewManager.rerenderSelectionViews();
-           rerenderSelectionViews = false
-         }
-       }, RERENDER_INTERVAL)
-     }
-     function stopRerenderLoop() {
-       runtime.getWindow().clearInterval(rerenderIntervalId)
-     }
-     this.destroy = function(callback) {
-       var odtDocument = session.getOdtDocument(), editInfoArray = Object.keys(editInfoMap).map(function(keyname) {
-         return editInfoMap[keyname]
-       });
-       odtDocument.unsubscribe(ops.OdtDocument.signalMemberAdded, renderMemberData);
-       odtDocument.unsubscribe(ops.OdtDocument.signalMemberUpdated, renderMemberData);
-       odtDocument.unsubscribe(ops.OdtDocument.signalCursorAdded, onCursorAdded);
-       odtDocument.unsubscribe(ops.OdtDocument.signalCursorRemoved, onCursorRemoved);
-       odtDocument.unsubscribe(ops.OdtDocument.signalParagraphChanged, onParagraphChanged);
-       odtDocument.unsubscribe(ops.OdtDocument.signalCursorMoved, onCursorMoved);
-       odtDocument.unsubscribe(ops.OdtDocument.signalParagraphChanged, requestRerenderOfSelectionViews);
-       odtDocument.unsubscribe(ops.OdtDocument.signalTableAdded, requestRerenderOfSelectionViews);
-       odtDocument.unsubscribe(ops.OdtDocument.signalParagraphStyleModified, requestRerenderOfSelectionViews);
-       stopRerenderLoop();
-       avatarInfoStyles.parentNode.removeChild(avatarInfoStyles);
-       (function destroyEditInfo(i, err) {
-         if(err) {
-           callback(err)
-         }else {
-           if(i < editInfoArray.length) {
-             editInfoArray[i].destroy(function(err) {
-               destroyEditInfo(i + 1, err)
-             })
-           }else {
-             callback()
-           }
-         }
-       })(0, undefined)
-     };
-     function init() {
-       var odtDocument = session.getOdtDocument(), head = document.getElementsByTagName("head")[0];
-       odtDocument.subscribe(ops.OdtDocument.signalMemberAdded, renderMemberData);
-       odtDocument.subscribe(ops.OdtDocument.signalMemberUpdated, renderMemberData);
-       odtDocument.subscribe(ops.OdtDocument.signalCursorAdded, onCursorAdded);
-       odtDocument.subscribe(ops.OdtDocument.signalCursorRemoved, onCursorRemoved);
-       odtDocument.subscribe(ops.OdtDocument.signalParagraphChanged, onParagraphChanged);
-       odtDocument.subscribe(ops.OdtDocument.signalCursorMoved, onCursorMoved);
-       startRerenderLoop();
-       odtDocument.subscribe(ops.OdtDocument.signalParagraphChanged, requestRerenderOfSelectionViews);
-       odtDocument.subscribe(ops.OdtDocument.signalTableAdded, requestRerenderOfSelectionViews);
-       odtDocument.subscribe(ops.OdtDocument.signalParagraphStyleModified, requestRerenderOfSelectionViews);
-       avatarInfoStyles = document.createElementNS(head.namespaceURI, "style");
-       avatarInfoStyles.type = "text/css";
-       avatarInfoStyles.media = "screen, print, handheld, projection";
-       avatarInfoStyles.appendChild(document.createTextNode("@namespace editinfo url(urn:webodf:names:editinfo);"));
-       avatarInfoStyles.appendChild(document.createTextNode("@namespace dc url(http://purl.org/dc/elements/1.1/);"));
-       head.appendChild(avatarInfoStyles)
-     }
-     init()
-   }
-   return SessionView
- }();
- var webodf_css = "@namespace draw url(urn:oasis:names:tc:opendocument:xmlns:drawing:1.0);\n at namespace fo url(urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0);\n at namespace office url(urn:oasis:names:tc:opendocument:xmlns:office:1.0);\n at namespace presentation url(urn:oasis:names:tc:opendocument:xmlns:presentation:1.0);\n at namespace style url(urn:oasis:names:tc:opendocument:xmlns:style:1.0);\n at namespace svg url(urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0);\n at namespa [...]
++ops.Server.prototype.connect = function(timeout, cb) {
++};
++ops.Server.prototype.networkStatus = function() {
++};
++ops.Server.prototype.login = function(login, password, successCb, failCb) {
++};
++ops.Server.prototype.joinSession = function(userId, sessionId, successCb, failCb) {
++};
++ops.Server.prototype.leaveSession = function(sessionId, memberId, successCb, failCb) {
++};
++ops.Server.prototype.getGenesisUrl = function(sessionId) {
++};
++var webodf_css = '@namespace draw url(urn:oasis:names:tc:opendocument:xmlns:drawing:1.0);\n at namespace fo url(urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0);\n at namespace office url(urn:oasis:names:tc:opendocument:xmlns:office:1.0);\n at namespace presentation url(urn:oasis:names:tc:opendocument:xmlns:presentation:1.0);\n at namespace style url(urn:oasis:names:tc:opendocument:xmlns:style:1.0);\n at namespace svg url(urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0);\n at namespa [...]
 +
diff --cc apps/documents/js/3rdparty/webodf/webodf.js
index 688b4a1,0000000..40d0bda
mode 100644,000000..100644
--- a/apps/documents/js/3rdparty/webodf/webodf.js
+++ b/apps/documents/js/3rdparty/webodf/webodf.js
@@@ -1,3078 -1,0 +1,3382 @@@
 +// Input 0
- var webodf_version="0.4.2-1579-gfc3a4e6";
++var webodf_version="0.4.2-2050-g8d8fc02";
 +// Input 1
- function Runtime(){}Runtime.prototype.getVariable=function(g){};Runtime.prototype.toJson=function(g){};Runtime.prototype.fromJson=function(g){};Runtime.prototype.byteArrayFromString=function(g,l){};Runtime.prototype.byteArrayToString=function(g,l){};Runtime.prototype.read=function(g,l,f,p){};Runtime.prototype.readFile=function(g,l,f){};Runtime.prototype.readFileSync=function(g,l){};Runtime.prototype.loadXML=function(g,l){};Runtime.prototype.writeFile=function(g,l,f){};
- Runtime.prototype.isFile=function(g,l){};Runtime.prototype.getFileSize=function(g,l){};Runtime.prototype.deleteFile=function(g,l){};Runtime.prototype.log=function(g,l){};Runtime.prototype.setTimeout=function(g,l){};Runtime.prototype.clearTimeout=function(g){};Runtime.prototype.libraryPaths=function(){};Runtime.prototype.currentDirectory=function(){};Runtime.prototype.setCurrentDirectory=function(g){};Runtime.prototype.type=function(){};Runtime.prototype.getDOMImplementation=function(){};
- Runtime.prototype.parseXML=function(g){};Runtime.prototype.exit=function(g){};Runtime.prototype.getWindow=function(){};Runtime.prototype.assert=function(g,l,f){};var IS_COMPILED_CODE=!0;
- Runtime.byteArrayToString=function(g,l){function f(f){var h="",d,m=f.length;for(d=0;d<m;d+=1)h+=String.fromCharCode(f[d]&255);return h}function p(f){var h="",d,m=f.length,c=[],e,a,b,q;for(d=0;d<m;d+=1)e=f[d],128>e?c.push(e):(d+=1,a=f[d],194<=e&&224>e?c.push((e&31)<<6|a&63):(d+=1,b=f[d],224<=e&&240>e?c.push((e&15)<<12|(a&63)<<6|b&63):(d+=1,q=f[d],240<=e&&245>e&&(e=(e&7)<<18|(a&63)<<12|(b&63)<<6|q&63,e-=65536,c.push((e>>10)+55296,(e&1023)+56320))))),1E3===c.length&&(h+=String.fromCharCode [...]
- c),c.length=0);return h+String.fromCharCode.apply(null,c)}var r;"utf8"===l?r=p(g):("binary"!==l&&this.log("Unsupported encoding: "+l),r=f(g));return r};Runtime.getVariable=function(g){try{return eval(g)}catch(l){}};Runtime.toJson=function(g){return JSON.stringify(g)};Runtime.fromJson=function(g){return JSON.parse(g)};Runtime.getFunctionName=function(g){return void 0===g.name?(g=/function\s+(\w+)/.exec(g))&&g[1]:g.name};
- function BrowserRuntime(g){function l(d,m){var c,e,a;void 0!==m?a=d:m=d;g?(e=g.ownerDocument,a&&(c=e.createElement("span"),c.className=a,c.appendChild(e.createTextNode(a)),g.appendChild(c),g.appendChild(e.createTextNode(" "))),c=e.createElement("span"),0<m.length&&"<"===m[0]?c.innerHTML=m:c.appendChild(e.createTextNode(m)),g.appendChild(c),g.appendChild(e.createElement("br"))):console&&console.log(m);"alert"===a&&alert(m)}function f(d,m,c){if(0!==c.status||c.responseText)if(200===c.stat [...]
- "string"!==typeof c.response)"binary"===m?(m=c.response,m=new Uint8Array(m)):m=String(c.response);else if("binary"===m)if(null!==c.responseBody&&"undefined"!==String(typeof VBArray)){m=(new VBArray(c.responseBody)).toArray();c=m.length;var e,a=new Uint8Array(new ArrayBuffer(c));for(e=0;e<c;e+=1)a[e]=m[e];m=a}else m=n.byteArrayFromString(c.responseText,"binary");else m=c.responseText;h[d]=m;d={err:null,data:m}}else d={err:c.responseText||c.statusText,data:null};else d={err:"File "+d+" is [...]
- return d}function p(d,m,c){var e=new XMLHttpRequest;e.open("GET",d,c);e.overrideMimeType&&("binary"!==m?e.overrideMimeType("text/plain; charset="+m):e.overrideMimeType("text/plain; charset=x-user-defined"));return e}function r(d,m,c){function e(){var b;4===a.readyState&&(b=f(d,m,a),c(b.err,b.data))}if(h.hasOwnProperty(d))c(null,h[d]);else{var a=p(d,m,!0);a.onreadystatechange=e;try{a.send(null)}catch(b){c(b.message,null)}}}var n=this,h={};this.byteArrayFromString=function(d,m){var c;if(" [...]
- d.length;var e,a,b,q=0;for(a=0;a<c;a+=1)b=d.charCodeAt(a),q+=1+(128<b)+(2048<b);e=new Uint8Array(new ArrayBuffer(q));for(a=q=0;a<c;a+=1)b=d.charCodeAt(a),128>b?(e[q]=b,q+=1):2048>b?(e[q]=192|b>>>6,e[q+1]=128|b&63,q+=2):(e[q]=224|b>>>12&15,e[q+1]=128|b>>>6&63,e[q+2]=128|b&63,q+=3)}else for("binary"!==m&&n.log("unknown encoding: "+m),c=d.length,e=new Uint8Array(new ArrayBuffer(c)),a=0;a<c;a+=1)e[a]=d.charCodeAt(a)&255;return c=e};this.byteArrayToString=Runtime.byteArrayToString;this.getVa [...]
- this.fromJson=Runtime.fromJson;this.toJson=Runtime.toJson;this.readFile=r;this.read=function(d,m,c,e){r(d,"binary",function(a,b){var q=null;if(b){if("string"===typeof b)throw"This should not happen.";q=b.subarray(m,m+c)}e(a,q)})};this.readFileSync=function(d,m){var c=p(d,m,!1),e;try{c.send(null);e=f(d,m,c);if(e.err)throw e.err;if(null===e.data)throw"No data read from "+d+".";}catch(a){throw a;}return e.data};this.writeFile=function(d,m,c){h[d]=m;var e=new XMLHttpRequest,a;e.open("PUT",d [...]
- function(){4===e.readyState&&(0!==e.status||e.responseText?200<=e.status&&300>e.status||0===e.status?c(null):c("Status "+String(e.status)+": "+e.responseText||e.statusText):c("File "+d+" is empty."))};a=m.buffer&&!e.sendAsBinary?m.buffer:n.byteArrayToString(m,"binary");try{e.sendAsBinary?e.sendAsBinary(a):e.send(a)}catch(b){n.log("HUH? "+b+" "+m),c(b.message)}};this.deleteFile=function(d,m){delete h[d];var c=new XMLHttpRequest;c.open("DELETE",d,!0);c.onreadystatechange=function(){4===c. [...]
- (200>c.status&&300<=c.status?m(c.responseText):m(null))};c.send(null)};this.loadXML=function(d,m){var c=new XMLHttpRequest;c.open("GET",d,!0);c.overrideMimeType&&c.overrideMimeType("text/xml");c.onreadystatechange=function(){4===c.readyState&&(0!==c.status||c.responseText?200===c.status||0===c.status?m(null,c.responseXML):m(c.responseText,null):m("File "+d+" is empty.",null))};try{c.send(null)}catch(e){m(e.message,null)}};this.isFile=function(d,m){n.getFileSize(d,function(c){m(-1!==c)}) [...]
- function(d,m){if(h.hasOwnProperty(d)&&"string"!==typeof h[d])m(h[d].length);else{var c=new XMLHttpRequest;c.open("HEAD",d,!0);c.onreadystatechange=function(){if(4===c.readyState){var e=c.getResponseHeader("Content-Length");e?m(parseInt(e,10)):r(d,"binary",function(a,b){a?m(-1):m(b.length)})}};c.send(null)}};this.log=l;this.assert=function(d,m,c){if(!d)throw l("alert","ASSERTION FAILED:\n"+m),c&&c(),m;};this.setTimeout=function(d,m){return setTimeout(function(){d()},m)};this.clearTimeout [...]
- this.libraryPaths=function(){return["lib"]};this.setCurrentDirectory=function(){};this.currentDirectory=function(){return""};this.type=function(){return"BrowserRuntime"};this.getDOMImplementation=function(){return window.document.implementation};this.parseXML=function(d){return(new DOMParser).parseFromString(d,"text/xml")};this.exit=function(d){l("Calling exit with code "+String(d)+", but exit() is not implemented.")};this.getWindow=function(){return window}}
- function NodeJSRuntime(){function g(d){var c=d.length,e,a=new Uint8Array(new ArrayBuffer(c));for(e=0;e<c;e+=1)a[e]=d[e];return a}function l(d,c,e){function a(a,c){if(a)return e(a,null);if(!c)return e("No data for "+d+".",null);if("string"===typeof c)return e(a,c);e(a,g(c))}d=r.resolve(n,d);"binary"!==c?p.readFile(d,c,a):p.readFile(d,null,a)}var f=this,p=require("fs"),r=require("path"),n="",h,d;this.byteArrayFromString=function(d,c){var e=new Buffer(d,c),a,b=e.length,q=new Uint8Array(new [...]
- for(a=0;a<b;a+=1)q[a]=e[a];return q};this.byteArrayToString=Runtime.byteArrayToString;this.getVariable=Runtime.getVariable;this.fromJson=Runtime.fromJson;this.toJson=Runtime.toJson;this.readFile=l;this.loadXML=function(d,c){l(d,"utf-8",function(e,a){if(e)return c(e,null);if(!a)return c("No data for "+d+".",null);c(null,f.parseXML(a))})};this.writeFile=function(d,c,e){c=new Buffer(c);d=r.resolve(n,d);p.writeFile(d,c,"binary",function(a){e(a||null)})};this.deleteFile=function(d,c){d=r.res [...]
- p.unlink(d,c)};this.read=function(d,c,e,a){d=r.resolve(n,d);p.open(d,"r+",666,function(b,q){if(b)a(b,null);else{var k=new Buffer(e);p.read(q,k,0,e,c,function(b){p.close(q);a(b,g(k))})}})};this.readFileSync=function(d,c){var e;e=p.readFileSync(d,"binary"===c?null:c);if(null===e)throw"File "+d+" could not be read.";"binary"===c&&(e=g(e));return e};this.isFile=function(d,c){d=r.resolve(n,d);p.stat(d,function(e,a){c(!e&&a.isFile())})};this.getFileSize=function(d,c){d=r.resolve(n,d);p.stat(d [...]
- a){e?c(-1):c(a.size)})};this.log=function(d,c){var e;void 0!==c?e=d:c=d;"alert"===e&&process.stderr.write("\n!!!!! ALERT !!!!!\n");process.stderr.write(c+"\n");"alert"===e&&process.stderr.write("!!!!! ALERT !!!!!\n")};this.assert=function(d,c,e){d||(process.stderr.write("ASSERTION FAILED: "+c),e&&e())};this.setTimeout=function(d,c){return setTimeout(function(){d()},c)};this.clearTimeout=function(d){clearTimeout(d)};this.libraryPaths=function(){return[__dirname]};this.setCurrentDirectory [...]
- d};this.currentDirectory=function(){return n};this.type=function(){return"NodeJSRuntime"};this.getDOMImplementation=function(){return d};this.parseXML=function(d){return h.parseFromString(d,"text/xml")};this.exit=process.exit;this.getWindow=function(){return null};h=new (require("xmldom").DOMParser);d=f.parseXML("<a/>").implementation}
- function RhinoRuntime(){function g(d,h){var c;void 0!==h?c=d:h=d;"alert"===c&&print("\n!!!!! ALERT !!!!!");print(h);"alert"===c&&print("!!!!! ALERT !!!!!")}var l=this,f={},p=f.javax.xml.parsers.DocumentBuilderFactory.newInstance(),r,n,h="";p.setValidating(!1);p.setNamespaceAware(!0);p.setExpandEntityReferences(!1);p.setSchema(null);n=f.org.xml.sax.EntityResolver({resolveEntity:function(d,h){var c=new f.java.io.FileReader(h);return new f.org.xml.sax.InputSource(c)}});r=p.newDocumentBuild [...]
- this.byteArrayFromString=function(d,h){var c,e=d.length,a=new Uint8Array(new ArrayBuffer(e));for(c=0;c<e;c+=1)a[c]=d.charCodeAt(c)&255;return a};this.byteArrayToString=Runtime.byteArrayToString;this.getVariable=Runtime.getVariable;this.fromJson=Runtime.fromJson;this.toJson=Runtime.toJson;this.loadXML=function(d,h){var c=new f.java.io.File(d),e=null;try{e=r.parse(c)}catch(a){return print(a),h(a,null)}h(null,e)};this.readFile=function(d,m,c){h&&(d=h+"/"+d);var e=new f.java.io.File(d),a="b [...]
- "latin1":m;e.isFile()?((d=readFile(d,a))&&"binary"===m&&(d=l.byteArrayFromString(d,"binary")),c(null,d)):c(d+" is not a file.",null)};this.writeFile=function(d,m,c){h&&(d=h+"/"+d);d=new f.java.io.FileOutputStream(d);var e,a=m.length;for(e=0;e<a;e+=1)d.write(m[e]);d.close();c(null)};this.deleteFile=function(d,m){h&&(d=h+"/"+d);var c=new f.java.io.File(d),e=d+Math.random(),e=new f.java.io.File(e);c.rename(e)?(e.deleteOnExit(),m(null)):m("Could not delete "+d)};this.read=function(d,m,c,e){ [...]
- d);var a;a=d;var b="binary";(new f.java.io.File(a)).isFile()?("binary"===b&&(b="latin1"),a=readFile(a,b)):a=null;a?e(null,this.byteArrayFromString(a.substring(m,m+c),"binary")):e("Cannot read "+d,null)};this.readFileSync=function(d,h){if(!h)return"";var c=readFile(d,h);if(null===c)throw"File could not be read.";return c};this.isFile=function(d,m){h&&(d=h+"/"+d);var c=new f.java.io.File(d);m(c.isFile())};this.getFileSize=function(d,m){h&&(d=h+"/"+d);var c=new f.java.io.File(d);m(c.length [...]
- g;this.assert=function(d,h,c){d||(g("alert","ASSERTION FAILED: "+h),c&&c())};this.setTimeout=function(d){d();return 0};this.clearTimeout=function(){};this.libraryPaths=function(){return["lib"]};this.setCurrentDirectory=function(d){h=d};this.currentDirectory=function(){return h};this.type=function(){return"RhinoRuntime"};this.getDOMImplementation=function(){return r.getDOMImplementation()};this.parseXML=function(d){d=new f.java.io.StringReader(d);d=new f.org.xml.sax.InputSource(d);return [...]
- this.exit=quit;this.getWindow=function(){return null}}Runtime.create=function(){return"undefined"!==String(typeof window)?new BrowserRuntime(window.document.getElementById("logoutput")):"undefined"!==String(typeof require)?new NodeJSRuntime:new RhinoRuntime};var runtime=Runtime.create(),core={},gui={},xmldom={},odf={},ops={};
- (function(){function g(h,d){var f=h+"/manifest.json",c,e;if(!n.hasOwnProperty(f)){n[f]=1;try{c=runtime.readFileSync(f,"utf-8")}catch(a){console.log(String(a));return}f=JSON.parse(c);for(e in f)f.hasOwnProperty(e)&&(d[e]={dir:h,deps:f[e]})}}function l(h,d,f){var c=d[h].deps,e={};f[h]=e;c.forEach(function(a){e[a]=1});c.forEach(function(a){f[a]||l(a,d,f)});c.forEach(function(a){Object.keys(f[a]).forEach(function(a){e[a]=1})})}function f(h,d){function f(a,b){var c,k=d[a];if(-1===e.indexOf(a [...]
- for(c=0;c<h.length;c+=1)k[h[c]]&&f(h[c],b);b.pop();e.push(a)}}var c,e=[];for(c=0;c<h.length;c+=1)f(h[c],[]);return e}function p(h,d){for(var f=0;f<h.length&&void 0!==d[f];)null!==d[f]&&(eval(d[f]),d[f]=null),f+=1}var r={},n={};runtime.loadClass=function(h){if(!IS_COMPILED_CODE){var d=h.replace(".","/")+".js";if(!n.hasOwnProperty(d)){if(!(0<Object.keys(r).length)){var m=runtime.libraryPaths(),d={},c;runtime.currentDirectory()&&g(runtime.currentDirectory(),d);for(c=0;c<m.length;c+=1)g(m[c [...]
- c={};for(e in d)d.hasOwnProperty(e)&&l(e,d,c);for(e in d)d.hasOwnProperty(e)&&(m=Object.keys(c[e]),d[e].deps=f(m,c),d[e].deps.push(e));r=d}e=h.replace(".","/")+".js";h=[];e=r[e].deps;for(d=0;d<e.length;d+=1)n.hasOwnProperty(e[d])||h.push(e[d]);e=[];e.length=h.length;for(d=h.length-1;0<=d;d-=1)n[h[d]]=1,void 0===e[d]&&(m=h[d],m=r[m].dir+"/"+m,c=runtime.readFileSync(m,"utf-8"),c+="\n//# sourceURL="+m,c+="\n//@ sourceURL="+m,e[d]=c);p(h,e)}}}})();
- (function(){var g=function(g){return g};runtime.getTranslator=function(){return g};runtime.setTranslator=function(l){g=l};runtime.tr=function(l){var f=g(l);return f&&"string"===String(typeof f)?f:l}})();
- (function(g){function l(f){if(f.length){var g=f[0];runtime.readFile(g,"utf8",function(l,n){function h(){var c;(c=eval(m))&&runtime.exit(c)}var d="",m=n;-1!==g.indexOf("/")&&(d=g.substring(0,g.indexOf("/")));runtime.setCurrentDirectory(d);l?(runtime.log(l),runtime.exit(1)):null===m?(runtime.log("No code found for "+g),runtime.exit(1)):h.apply(null,f)})}}g=g?Array.prototype.slice.call(g):[];"NodeJSRuntime"===runtime.type()?l(process.argv.slice(2)):"RhinoRuntime"===runtime.type()?l(g):l(g. [...]
++function Runtime(){}Runtime.prototype.getVariable=function(m){};Runtime.prototype.toJson=function(m){};Runtime.prototype.fromJson=function(m){};Runtime.prototype.byteArrayFromString=function(m,h){};Runtime.prototype.byteArrayToString=function(m,h){};Runtime.prototype.read=function(m,h,b,g){};Runtime.prototype.readFile=function(m,h,b){};Runtime.prototype.readFileSync=function(m,h){};Runtime.prototype.loadXML=function(m,h){};Runtime.prototype.writeFile=function(m,h,b){};
++Runtime.prototype.isFile=function(m,h){};Runtime.prototype.getFileSize=function(m,h){};Runtime.prototype.deleteFile=function(m,h){};Runtime.prototype.log=function(m,h){};Runtime.prototype.setTimeout=function(m,h){};Runtime.prototype.clearTimeout=function(m){};Runtime.prototype.libraryPaths=function(){};Runtime.prototype.currentDirectory=function(){};Runtime.prototype.setCurrentDirectory=function(m){};Runtime.prototype.type=function(){};Runtime.prototype.getDOMImplementation=function(){};
++Runtime.prototype.parseXML=function(m){};Runtime.prototype.exit=function(m){};Runtime.prototype.getWindow=function(){};Runtime.prototype.requestAnimationFrame=function(m){};Runtime.prototype.cancelAnimationFrame=function(m){};Runtime.prototype.assert=function(m,h,b){};var IS_COMPILED_CODE=!0;
++Runtime.byteArrayToString=function(m,h){function b(b){var p="",k,d=b.length;for(k=0;k<d;k+=1)p+=String.fromCharCode(b[k]&255);return p}function g(b){var d="",k,g=b.length,e=[],r,a,c,l;for(k=0;k<g;k+=1)r=b[k],128>r?e.push(r):(k+=1,a=b[k],194<=r&&224>r?e.push((r&31)<<6|a&63):(k+=1,c=b[k],224<=r&&240>r?e.push((r&15)<<12|(a&63)<<6|c&63):(k+=1,l=b[k],240<=r&&245>r&&(r=(r&7)<<18|(a&63)<<12|(c&63)<<6|l&63,r-=65536,e.push((r>>10)+55296,(r&1023)+56320))))),1E3===e.length&&(d+=String.fromCharCode [...]
++e),e.length=0);return d+String.fromCharCode.apply(null,e)}var d;"utf8"===h?d=g(m):("binary"!==h&&this.log("Unsupported encoding: "+h),d=b(m));return d};Runtime.getVariable=function(m){try{return eval(m)}catch(h){}};Runtime.toJson=function(m){return JSON.stringify(m)};Runtime.fromJson=function(m){return JSON.parse(m)};Runtime.getFunctionName=function(m){return void 0===m.name?(m=/function\s+(\w+)/.exec(m))&&m[1]:m.name};
++function BrowserRuntime(m){function h(r){var a=r.length,c,l,f=0;for(c=0;c<a;c+=1)l=r.charCodeAt(c),f+=1+(128<l)+(2048<l),55040<l&&57344>l&&(f+=1,c+=1);return f}function b(r,a,c){var l=r.length,f,b;a=new Uint8Array(new ArrayBuffer(a));c?(a[0]=239,a[1]=187,a[2]=191,b=3):b=0;for(c=0;c<l;c+=1)f=r.charCodeAt(c),128>f?(a[b]=f,b+=1):2048>f?(a[b]=192|f>>>6,a[b+1]=128|f&63,b+=2):55040>=f||57344<=f?(a[b]=224|f>>>12&15,a[b+1]=128|f>>>6&63,a[b+2]=128|f&63,b+=3):(c+=1,f=(f-55296<<10|r.charCodeAt(c)- [...]
++a[b]=240|f>>>18&7,a[b+1]=128|f>>>12&63,a[b+2]=128|f>>>6&63,a[b+3]=128|f&63,b+=4);return a}function g(b){var a=b.length,c=new Uint8Array(new ArrayBuffer(a)),l;for(l=0;l<a;l+=1)c[l]=b.charCodeAt(l)&255;return c}function d(b,a){var c,l,f;void 0!==a?f=b:a=b;m?(l=m.ownerDocument,f&&(c=l.createElement("span"),c.className=f,c.appendChild(l.createTextNode(f)),m.appendChild(c),m.appendChild(l.createTextNode(" "))),c=l.createElement("span"),0<a.length&&"<"===a[0]?c.innerHTML=a:c.appendChild(l.cre [...]
++m.appendChild(c),m.appendChild(l.createElement("br"))):console&&console.log(a);"alert"===f&&alert(a)}function n(r,a,c){if(0!==c.status||c.responseText)if(200===c.status||0===c.status){if(c.response&&"string"!==typeof c.response)"binary"===a?(c=c.response,c=new Uint8Array(c)):c=String(c.response);else if("binary"===a)if(null!==c.responseBody&&"undefined"!==String(typeof VBArray)){c=(new VBArray(c.responseBody)).toArray();var l=c.length,f=new Uint8Array(new ArrayBuffer(l));for(a=0;a<l;a+= [...]
++c=f}else{(a=c.getResponseHeader("Content-Length"))&&(a=parseInt(a,10));if(a&&a!==c.responseText.length)a:{var l=c.responseText,f=!1,k=h(l);if("number"===typeof a){if(a!==k&&a!==k+3){l=void 0;break a}f=k+3===a;k=a}l=b(l,k,f)}void 0===l&&(l=g(c.responseText));c=l}else c=c.responseText;e[r]=c;r={err:null,data:c}}else r={err:c.responseText||c.statusText,data:null};else r={err:"File "+r+" is empty.",data:null};return r}function p(b,a,c){var l=new XMLHttpRequest;l.open("GET",b,c);l.overrideMi [...]
++a?l.overrideMimeType("text/plain; charset="+a):l.overrideMimeType("text/plain; charset=x-user-defined"));return l}function k(b,a,c){function l(){var l;4===f.readyState&&(l=n(b,a,f),c(l.err,l.data))}if(e.hasOwnProperty(b))c(null,e[b]);else{var f=p(b,a,!0);f.onreadystatechange=l;try{f.send(null)}catch(k){c(k.message,null)}}}var q=this,e={};this.byteArrayFromString=function(r,a){var c;"utf8"===a?c=b(r,h(r),!1):("binary"!==a&&q.log("unknown encoding: "+a),c=g(r));return c};this.byteArrayToS [...]
++this.getVariable=Runtime.getVariable;this.fromJson=Runtime.fromJson;this.toJson=Runtime.toJson;this.readFile=k;this.read=function(b,a,c,l){k(b,"binary",function(f,b){var r=null;if(b){if("string"===typeof b)throw"This should not happen.";r=b.subarray(a,a+c)}l(f,r)})};this.readFileSync=function(b,a){var c=p(b,a,!1),l;try{c.send(null);l=n(b,a,c);if(l.err)throw l.err;if(null===l.data)throw"No data read from "+b+".";}catch(f){throw f;}return l.data};this.writeFile=function(b,a,c){e[b]=a;var  [...]
++f;l.open("PUT",b,!0);l.onreadystatechange=function(){4===l.readyState&&(0!==l.status||l.responseText?200<=l.status&&300>l.status||0===l.status?c(null):c("Status "+String(l.status)+": "+l.responseText||l.statusText):c("File "+b+" is empty."))};f=a.buffer&&!l.sendAsBinary?a.buffer:q.byteArrayToString(a,"binary");try{l.sendAsBinary?l.sendAsBinary(f):l.send(f)}catch(k){q.log("HUH? "+k+" "+a),c(k.message)}};this.deleteFile=function(b,a){delete e[b];var c=new XMLHttpRequest;c.open("DELETE",b, [...]
++function(){4===c.readyState&&(200>c.status&&300<=c.status?a(c.responseText):a(null))};c.send(null)};this.loadXML=function(b,a){var c=new XMLHttpRequest;c.open("GET",b,!0);c.overrideMimeType&&c.overrideMimeType("text/xml");c.onreadystatechange=function(){4===c.readyState&&(0!==c.status||c.responseText?200===c.status||0===c.status?a(null,c.responseXML):a(c.responseText,null):a("File "+b+" is empty.",null))};try{c.send(null)}catch(l){a(l.message,null)}};this.isFile=function(b,a){q.getFileS [...]
++c)})};this.getFileSize=function(b,a){if(e.hasOwnProperty(b)&&"string"!==typeof e[b])a(e[b].length);else{var c=new XMLHttpRequest;c.open("HEAD",b,!0);c.onreadystatechange=function(){if(4===c.readyState){var l=c.getResponseHeader("Content-Length");l?a(parseInt(l,10)):k(b,"binary",function(c,l){c?a(-1):a(l.length)})}};c.send(null)}};this.log=d;this.assert=function(b,a,c){if(!b)throw d("alert","ASSERTION FAILED:\n"+a),c&&c(),a;};this.setTimeout=function(b,a){return setTimeout(function(){b() [...]
++function(b){clearTimeout(b)};this.libraryPaths=function(){return["lib"]};this.setCurrentDirectory=function(){};this.currentDirectory=function(){return""};this.type=function(){return"BrowserRuntime"};this.getDOMImplementation=function(){return window.document.implementation};this.parseXML=function(b){return(new DOMParser).parseFromString(b,"text/xml")};this.exit=function(b){d("Calling exit with code "+String(b)+", but exit() is not implemented.")};this.getWindow=function(){return window} [...]
++function(b){var a=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.msRequestAnimationFrame,c=0;if(a)a.bind(window),c=a(b);else return setTimeout(b,15);return c};this.cancelAnimationFrame=function(b){var a=window.cancelAnimationFrame||window.webkitCancelAnimationFrame||window.mozCancelAnimationFrame||window.msCancelAnimationFrame;a?(a.bind(window),a(b)):clearTimeout(b)}}
++function NodeJSRuntime(){function m(b){var e=b.length,k,a=new Uint8Array(new ArrayBuffer(e));for(k=0;k<e;k+=1)a[k]=b[k];return a}function h(b,e,k){function a(a,l){if(a)return k(a,null);if(!l)return k("No data for "+b+".",null);if("string"===typeof l)return k(a,l);k(a,m(l))}b=d.resolve(n,b);"binary"!==e?g.readFile(b,e,a):g.readFile(b,null,a)}var b=this,g=require("fs"),d=require("path"),n="",p,k;this.byteArrayFromString=function(b,e){var k=new Buffer(b,e),a,c=k.length,l=new Uint8Array(new [...]
++for(a=0;a<c;a+=1)l[a]=k[a];return l};this.byteArrayToString=Runtime.byteArrayToString;this.getVariable=Runtime.getVariable;this.fromJson=Runtime.fromJson;this.toJson=Runtime.toJson;this.readFile=h;this.loadXML=function(k,e){h(k,"utf-8",function(d,a){if(d)return e(d,null);if(!a)return e("No data for "+k+".",null);e(null,b.parseXML(a))})};this.writeFile=function(b,e,k){e=new Buffer(e);b=d.resolve(n,b);g.writeFile(b,e,"binary",function(a){k(a||null)})};this.deleteFile=function(b,e){b=d.res [...]
++g.unlink(b,e)};this.read=function(b,e,k,a){b=d.resolve(n,b);g.open(b,"r+",666,function(c,l){if(c)a(c,null);else{var f=new Buffer(k);g.read(l,f,0,k,e,function(c){g.close(l);a(c,m(f))})}})};this.readFileSync=function(b,e){var k;k=g.readFileSync(b,"binary"===e?null:e);if(null===k)throw"File "+b+" could not be read.";"binary"===e&&(k=m(k));return k};this.isFile=function(b,k){b=d.resolve(n,b);g.stat(b,function(b,a){k(!b&&a.isFile())})};this.getFileSize=function(b,k){b=d.resolve(n,b);g.stat(b [...]
++a){b?k(-1):k(a.size)})};this.log=function(b,k){var d;void 0!==k?d=b:k=b;"alert"===d&&process.stderr.write("\n!!!!! ALERT !!!!!\n");process.stderr.write(k+"\n");"alert"===d&&process.stderr.write("!!!!! ALERT !!!!!\n")};this.assert=function(b,k,d){b||(process.stderr.write("ASSERTION FAILED: "+k),d&&d())};this.setTimeout=function(b,k){return setTimeout(function(){b()},k)};this.clearTimeout=function(b){clearTimeout(b)};this.libraryPaths=function(){return[__dirname]};this.setCurrentDirectory [...]
++b};this.currentDirectory=function(){return n};this.type=function(){return"NodeJSRuntime"};this.getDOMImplementation=function(){return k};this.parseXML=function(b){return p.parseFromString(b,"text/xml")};this.exit=process.exit;this.getWindow=function(){return null};this.requestAnimationFrame=function(b){return setTimeout(b,15)};this.cancelAnimationFrame=function(b){clearTimeout(b)};p=new (require("xmldom").DOMParser);k=b.parseXML("<a/>").implementation}
++function RhinoRuntime(){function m(b,d){var e;void 0!==d?e=b:d=b;"alert"===e&&print("\n!!!!! ALERT !!!!!");print(d);"alert"===e&&print("!!!!! ALERT !!!!!")}var h=this,b={},g=b.javax.xml.parsers.DocumentBuilderFactory.newInstance(),d,n,p="";g.setValidating(!1);g.setNamespaceAware(!0);g.setExpandEntityReferences(!1);g.setSchema(null);n=b.org.xml.sax.EntityResolver({resolveEntity:function(k,d){var e=new b.java.io.FileReader(d);return new b.org.xml.sax.InputSource(e)}});d=g.newDocumentBuild [...]
++this.byteArrayFromString=function(b,d){var e,g=b.length,a=new Uint8Array(new ArrayBuffer(g));for(e=0;e<g;e+=1)a[e]=b.charCodeAt(e)&255;return a};this.byteArrayToString=Runtime.byteArrayToString;this.getVariable=Runtime.getVariable;this.fromJson=Runtime.fromJson;this.toJson=Runtime.toJson;this.loadXML=function(k,g){var e=new b.java.io.File(k),p=null;try{p=d.parse(e)}catch(a){return print(a),g(a,null)}g(null,p)};this.readFile=function(k,d,e){p&&(k=p+"/"+k);var g=new b.java.io.File(k),a="b [...]
++"latin1":d;g.isFile()?((k=readFile(k,a))&&"binary"===d&&(k=h.byteArrayFromString(k,"binary")),e(null,k)):e(k+" is not a file.",null)};this.writeFile=function(k,d,e){p&&(k=p+"/"+k);k=new b.java.io.FileOutputStream(k);var g,a=d.length;for(g=0;g<a;g+=1)k.write(d[g]);k.close();e(null)};this.deleteFile=function(k,d){p&&(k=p+"/"+k);var e=new b.java.io.File(k),g=k+Math.random(),g=new b.java.io.File(g);e.rename(g)?(g.deleteOnExit(),d(null)):d("Could not delete "+k)};this.read=function(k,d,e,g){ [...]
++k);var a;a=k;var c="binary";(new b.java.io.File(a)).isFile()?("binary"===c&&(c="latin1"),a=readFile(a,c)):a=null;a?g(null,this.byteArrayFromString(a.substring(d,d+e),"binary")):g("Cannot read "+k,null)};this.readFileSync=function(b,d){if(!d)return"";var e=readFile(b,d);if(null===e)throw"File could not be read.";return e};this.isFile=function(k,d){p&&(k=p+"/"+k);var e=new b.java.io.File(k);d(e.isFile())};this.getFileSize=function(k,d){p&&(k=p+"/"+k);var e=new b.java.io.File(k);d(e.length [...]
++m;this.assert=function(b,d,e){b||(m("alert","ASSERTION FAILED: "+d),e&&e())};this.setTimeout=function(b){b();return 0};this.clearTimeout=function(){};this.libraryPaths=function(){return["lib"]};this.setCurrentDirectory=function(b){p=b};this.currentDirectory=function(){return p};this.type=function(){return"RhinoRuntime"};this.getDOMImplementation=function(){return d.getDOMImplementation()};this.parseXML=function(k){k=new b.java.io.StringReader(k);k=new b.org.xml.sax.InputSource(k);return [...]
++this.exit=quit;this.getWindow=function(){return null};this.requestAnimationFrame=function(b){b();return 0};this.cancelAnimationFrame=function(){}}Runtime.create=function(){return"undefined"!==String(typeof window)?new BrowserRuntime(window.document.getElementById("logoutput")):"undefined"!==String(typeof require)?new NodeJSRuntime:new RhinoRuntime};var runtime=Runtime.create(),core={},gui={},xmldom={},odf={},ops={};
++(function(){function m(b,d,e){var g=b+"/manifest.json",a,c;runtime.log("Loading manifest: "+g);try{a=runtime.readFileSync(g,"utf-8")}catch(l){if(e)runtime.log("No loadable manifest found.");else throw console.log(String(l)),l;return}e=JSON.parse(a);for(c in e)e.hasOwnProperty(c)&&(d[c]={dir:b,deps:e[c]})}function h(b,d,e){function g(b){if(!l[b]&&!e(b)){if(c[b])throw"Circular dependency detected for "+b+".";c[b]=!0;if(!d[b])throw"Missing dependency information for class "+b+".";var k=d[b [...]
++h,n=p.length;for(h=0;h<n;h+=1)g(p[h]);c[b]=!1;l[b]=!0;a.push(k.dir+"/"+b.replace(".","/")+".js")}}var a=[],c={},l={};b.forEach(g);return a}function b(b,d){return d=d+("\n//# sourceURL="+b)+("\n//@ sourceURL="+b)}function g(d){var g,e;for(g=0;g<d.length;g+=1)e=runtime.readFileSync(d[g],"utf-8"),e=b(d[g],e),eval(e)}function d(b){b=b.split(".");var d,e=p,g=b.length;for(d=0;d<g;d+=1){if(!e.hasOwnProperty(b[d]))return!1;e=e[b[d]]}return!0}var n,p={core:core,gui:gui,xmldom:xmldom,odf:odf,ops: [...]
++function(b,p){if(IS_COMPILED_CODE||0===b.length)return p&&p();var e;if(!(e=n)){e=[];var r=runtime.libraryPaths(),a;runtime.currentDirectory()&&-1===r.indexOf(runtime.currentDirectory())&&m(runtime.currentDirectory(),e,!0);for(a=0;a<r.length;a+=1)m(r[a],e)}n=e;b=h(b,n,d);if(0===b.length)return p&&p();if("BrowserRuntime"===runtime.type()&&p){e=b;r=document.currentScript||document.documentElement.lastChild;a=document.createDocumentFragment();var c,l;for(l=0;l<e.length;l+=1)c=document.creat [...]
++c.type="text/javascript",c.charset="utf-8",c.async=!1,c.setAttribute("src",e[l]),a.appendChild(c);p&&(c.onload=p);r.parentNode.insertBefore(a,r)}else g(b),p&&p()};runtime.loadClass=function(b,d){runtime.loadClasses([b],d)}})();(function(){var m=function(h){return h};runtime.getTranslator=function(){return m};runtime.setTranslator=function(h){m=h};runtime.tr=function(h){var b=m(h);return b&&"string"===String(typeof b)?b:h}})();
++(function(m){function h(b){if(b.length){var g=b[0];runtime.readFile(g,"utf8",function(d,h){function p(){var b;(b=eval(m))&&runtime.exit(b)}var k="",k=g.lastIndexOf("/"),m=h,k=-1!==k?g.substring(0,k):".";runtime.setCurrentDirectory(k);d?(runtime.log(d),runtime.exit(1)):null===m?(runtime.log("No code found for "+g),runtime.exit(1)):p.apply(null,b)})}}m=m?Array.prototype.slice.call(m):[];"NodeJSRuntime"===runtime.type()?h(process.argv.slice(2)):"RhinoRuntime"===runtime.type()?h(m):h(m.slic [...]
 +String(typeof arguments)&&arguments);
 +// Input 2
- core.Async=function(){this.forEach=function(g,l,f){function p(d){h!==n&&(d?(h=n,f(d)):(h+=1,h===n&&f(null)))}var r,n=g.length,h=0;for(r=0;r<n;r+=1)l(g[r],p)};this.destroyAll=function(g,l){function f(p,r){if(r)l(r);else if(p<g.length)g[p](function(g){f(p+1,g)});else l()}f(0,void 0)}};
++core.Async=function(){this.forEach=function(m,h,b){function g(d){p!==n&&(d?(p=n,b(d)):(p+=1,p===n&&b(null)))}var d,n=m.length,p=0;for(d=0;d<n;d+=1)h(m[d],g)};this.destroyAll=function(m,h){function b(g,d){if(d)h(d);else if(g<m.length)m[g](function(d){b(g+1,d)});else h()}b(0,void 0)}};
 +// Input 3
- function makeBase64(){function g(a){var b,c=a.length,e=new Uint8Array(new ArrayBuffer(c));for(b=0;b<c;b+=1)e[b]=a.charCodeAt(b)&255;return e}function l(a){var b,c="",e,q=a.length-2;for(e=0;e<q;e+=3)b=a[e]<<16|a[e+1]<<8|a[e+2],c+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[b>>>18],c+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[b>>>12&63],c+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[b>>>6&63],c+="ABCDEFGHIJKLMNOPQRSTUV [...]
- 63];e===q+1?(b=a[e]<<4,c+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[b>>>6],c+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[b&63],c+="=="):e===q&&(b=a[e]<<10|a[e+1]<<2,c+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[b>>>12],c+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[b>>>6&63],c+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[b&63],c+="=");return c}function f(a){a=a.replace( [...]
- "");var b=a.length,c=new Uint8Array(new ArrayBuffer(3*b)),e=a.length%4,q=0,d,f;for(d=0;d<b;d+=4)f=(k[a.charAt(d)]||0)<<18|(k[a.charAt(d+1)]||0)<<12|(k[a.charAt(d+2)]||0)<<6|(k[a.charAt(d+3)]||0),c[q]=f>>16,c[q+1]=f>>8&255,c[q+2]=f&255,q+=3;b=3*b-[0,0,2,1][e];return c.subarray(0,b)}function p(a){var b,c,e=a.length,q=0,k=new Uint8Array(new ArrayBuffer(3*e));for(b=0;b<e;b+=1)c=a[b],128>c?k[q++]=c:(2048>c?k[q++]=192|c>>>6:(k[q++]=224|c>>>12&15,k[q++]=128|c>>>6&63),k[q++]=128|c&63);return k. [...]
- q)}function r(a){var b,c,e,q,k=a.length,d=new Uint8Array(new ArrayBuffer(k)),f=0;for(b=0;b<k;b+=1)c=a[b],128>c?d[f++]=c:(b+=1,e=a[b],224>c?d[f++]=(c&31)<<6|e&63:(b+=1,q=a[b],d[f++]=(c&15)<<12|(e&63)<<6|q&63));return d.subarray(0,f)}function n(a){return l(g(a))}function h(a){return String.fromCharCode.apply(String,f(a))}function d(a){return r(g(a))}function m(a){a=r(a);for(var b="",c=0;c<a.length;)b+=String.fromCharCode.apply(String,a.subarray(c,c+45E3)),c+=45E3;return b}function c(a,b,c [...]
- k,d="";for(k=b;k<c;k+=1)b=a.charCodeAt(k)&255,128>b?d+=String.fromCharCode(b):(k+=1,e=a.charCodeAt(k)&255,224>b?d+=String.fromCharCode((b&31)<<6|e&63):(k+=1,q=a.charCodeAt(k)&255,d+=String.fromCharCode((b&15)<<12|(e&63)<<6|q&63)));return d}function e(a,b){function e(){var d=k+1E5;d>a.length&&(d=a.length);q+=c(a,k,d);k=d;d=k===a.length;b(q,d)&&!d&&runtime.setTimeout(e,0)}var q="",k=0;1E5>a.length?b(c(a,0,a.length),!0):("string"!==typeof a&&(a=a.slice()),e())}function a(a){return p(g(a))} [...]
- p(a))}function q(a){return String.fromCharCode.apply(String,p(g(a)))}var k=function(a){var b={},c,e;c=0;for(e=a.length;c<e;c+=1)b[a.charAt(c)]=c;return b}("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"),t,A,w=runtime.getWindow(),x,v;w&&w.btoa?(x=w.btoa,t=function(a){return x(q(a))}):(x=n,t=function(b){return l(a(b))});w&&w.atob?(v=w.atob,A=function(a){a=v(a);return c(a,0,a.length)}):(v=h,A=function(a){return m(f(a))});core.Base64=function(){this.convertByteArrayToBas [...]
- l;this.convertBase64ToByteArray=this.convertBase64ToUTF8Array=f;this.convertUTF16ArrayToByteArray=this.convertUTF16ArrayToUTF8Array=p;this.convertByteArrayToUTF16Array=this.convertUTF8ArrayToUTF16Array=r;this.convertUTF8StringToBase64=n;this.convertBase64ToUTF8String=h;this.convertUTF8StringToUTF16Array=d;this.convertByteArrayToUTF16String=this.convertUTF8ArrayToUTF16String=m;this.convertUTF8StringToUTF16String=e;this.convertUTF16StringToByteArray=this.convertUTF16StringToUTF8Array=a;th [...]
- b;this.convertUTF16StringToUTF8String=q;this.convertUTF16StringToBase64=t;this.convertBase64ToUTF16String=A;this.fromBase64=h;this.toBase64=n;this.atob=v;this.btoa=x;this.utob=q;this.btou=e;this.encode=t;this.encodeURI=function(a){return t(a).replace(/[+\/]/g,function(a){return"+"===a?"-":"_"}).replace(/\\=+$/,"")};this.decode=function(a){return A(a.replace(/[\-_]/g,function(a){return"-"===a?"+":"/"}))};return this};return core.Base64}core.Base64=makeBase64();
++function makeBase64(){function m(a){var c,b=a.length,l=new Uint8Array(new ArrayBuffer(b));for(c=0;c<b;c+=1)l[c]=a.charCodeAt(c)&255;return l}function h(a){var c,b="",l,f=a.length-2;for(l=0;l<f;l+=3)c=a[l]<<16|a[l+1]<<8|a[l+2],b+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[c>>>18],b+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[c>>>12&63],b+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[c>>>6&63],b+="ABCDEFGHIJKLMNOPQRSTUV [...]
++63];l===f+1?(c=a[l]<<4,b+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[c>>>6],b+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[c&63],b+="=="):l===f&&(c=a[l]<<10|a[l+1]<<2,b+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[c>>>12],b+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[c>>>6&63],b+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[c&63],b+="=");return b}function b(a){a=a.replace( [...]
++"");var c=a.length,b=new Uint8Array(new ArrayBuffer(3*c)),l=a.length%4,d=0,e,g;for(e=0;e<c;e+=4)g=(f[a.charAt(e)]||0)<<18|(f[a.charAt(e+1)]||0)<<12|(f[a.charAt(e+2)]||0)<<6|(f[a.charAt(e+3)]||0),b[d]=g>>16,b[d+1]=g>>8&255,b[d+2]=g&255,d+=3;c=3*c-[0,0,2,1][l];return b.subarray(0,c)}function g(a){var c,b,l=a.length,f=0,d=new Uint8Array(new ArrayBuffer(3*l));for(c=0;c<l;c+=1)b=a[c],128>b?d[f++]=b:(2048>b?d[f++]=192|b>>>6:(d[f++]=224|b>>>12&15,d[f++]=128|b>>>6&63),d[f++]=128|b&63);return d. [...]
++f)}function d(a){var c,b,l,f,d=a.length,e=new Uint8Array(new ArrayBuffer(d)),g=0;for(c=0;c<d;c+=1)b=a[c],128>b?e[g++]=b:(c+=1,l=a[c],224>b?e[g++]=(b&31)<<6|l&63:(c+=1,f=a[c],e[g++]=(b&15)<<12|(l&63)<<6|f&63));return e.subarray(0,g)}function n(a){return h(m(a))}function p(a){return String.fromCharCode.apply(String,b(a))}function k(a){return d(m(a))}function q(a){a=d(a);for(var c="",b=0;b<a.length;)c+=String.fromCharCode.apply(String,a.subarray(b,b+45E3)),b+=45E3;return c}function e(a,c,b [...]
++d,e="";for(d=c;d<b;d+=1)c=a.charCodeAt(d)&255,128>c?e+=String.fromCharCode(c):(d+=1,l=a.charCodeAt(d)&255,224>c?e+=String.fromCharCode((c&31)<<6|l&63):(d+=1,f=a.charCodeAt(d)&255,e+=String.fromCharCode((c&15)<<12|(l&63)<<6|f&63)));return e}function r(a,c){function b(){var d=f+1E5;d>a.length&&(d=a.length);l+=e(a,f,d);f=d;d=f===a.length;c(l,d)&&!d&&runtime.setTimeout(b,0)}var l="",f=0;1E5>a.length?c(e(a,0,a.length),!0):("string"!==typeof a&&(a=a.slice()),b())}function a(a){return g(m(a))} [...]
++g(a))}function l(a){return String.fromCharCode.apply(String,g(m(a)))}var f=function(a){var c={},b,l;b=0;for(l=a.length;b<l;b+=1)c[a.charAt(b)]=b;return c}("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"),v,w,z=runtime.getWindow(),x,t;z&&z.btoa?(x=z.btoa,v=function(a){return x(l(a))}):(x=n,v=function(c){return h(a(c))});z&&z.atob?(t=z.atob,w=function(a){a=t(a);return e(a,0,a.length)}):(t=p,w=function(a){return q(b(a))});core.Base64=function(){this.convertByteArrayToBas [...]
++h;this.convertBase64ToByteArray=this.convertBase64ToUTF8Array=b;this.convertUTF16ArrayToByteArray=this.convertUTF16ArrayToUTF8Array=g;this.convertByteArrayToUTF16Array=this.convertUTF8ArrayToUTF16Array=d;this.convertUTF8StringToBase64=n;this.convertBase64ToUTF8String=p;this.convertUTF8StringToUTF16Array=k;this.convertByteArrayToUTF16String=this.convertUTF8ArrayToUTF16String=q;this.convertUTF8StringToUTF16String=r;this.convertUTF16StringToByteArray=this.convertUTF16StringToUTF8Array=a;th [...]
++c;this.convertUTF16StringToUTF8String=l;this.convertUTF16StringToBase64=v;this.convertBase64ToUTF16String=w;this.fromBase64=p;this.toBase64=n;this.atob=t;this.btoa=x;this.utob=l;this.btou=r;this.encode=v;this.encodeURI=function(a){return v(a).replace(/[+\/]/g,function(a){return"+"===a?"-":"_"}).replace(/\\=+$/,"")};this.decode=function(a){return w(a.replace(/[\-_]/g,function(a){return"-"===a?"+":"/"}))};return this};return core.Base64}core.Base64=makeBase64();
 +// Input 4
- core.ByteArray=function(g){this.pos=0;this.data=g;this.readUInt32LE=function(){this.pos+=4;var g=this.data,f=this.pos;return g[--f]<<24|g[--f]<<16|g[--f]<<8|g[--f]};this.readUInt16LE=function(){this.pos+=2;var g=this.data,f=this.pos;return g[--f]<<8|g[--f]}};
++core.ByteArray=function(m){this.pos=0;this.data=m;this.readUInt32LE=function(){this.pos+=4;var h=this.data,b=this.pos;return h[--b]<<24|h[--b]<<16|h[--b]<<8|h[--b]};this.readUInt16LE=function(){this.pos+=2;var h=this.data,b=this.pos;return h[--b]<<8|h[--b]}};
 +// Input 5
- core.ByteArrayWriter=function(g){function l(f){f>r-p&&(r=Math.max(2*r,p+f),f=new Uint8Array(new ArrayBuffer(r)),f.set(n),n=f)}var f=this,p=0,r=1024,n=new Uint8Array(new ArrayBuffer(r));this.appendByteArrayWriter=function(h){f.appendByteArray(h.getByteArray())};this.appendByteArray=function(f){var d=f.length;l(d);n.set(f,p);p+=d};this.appendArray=function(f){var d=f.length;l(d);n.set(f,p);p+=d};this.appendUInt16LE=function(h){f.appendArray([h&255,h>>8&255])};this.appendUInt32LE=function( [...]
- 255,h>>8&255,h>>16&255,h>>24&255])};this.appendString=function(h){f.appendByteArray(runtime.byteArrayFromString(h,g))};this.getLength=function(){return p};this.getByteArray=function(){var f=new Uint8Array(new ArrayBuffer(p));f.set(n.subarray(0,p));return f}};
++core.ByteArrayWriter=function(m){function h(b){b>d-g&&(d=Math.max(2*d,g+b),b=new Uint8Array(new ArrayBuffer(d)),b.set(n),n=b)}var b=this,g=0,d=1024,n=new Uint8Array(new ArrayBuffer(d));this.appendByteArrayWriter=function(d){b.appendByteArray(d.getByteArray())};this.appendByteArray=function(b){var d=b.length;h(d);n.set(b,g);g+=d};this.appendArray=function(b){var d=b.length;h(d);n.set(b,g);g+=d};this.appendUInt16LE=function(d){b.appendArray([d&255,d>>8&255])};this.appendUInt32LE=function( [...]
++255,d>>8&255,d>>16&255,d>>24&255])};this.appendString=function(d){b.appendByteArray(runtime.byteArrayFromString(d,m))};this.getLength=function(){return g};this.getByteArray=function(){var b=new Uint8Array(new ArrayBuffer(g));b.set(n.subarray(0,g));return b}};
 +// Input 6
- core.CSSUnits=function(){var g=this,l={"in":1,cm:2.54,mm:25.4,pt:72,pc:12};this.convert=function(f,g,r){return f*l[r]/l[g]};this.convertMeasure=function(f,l){var r,n;f&&l?(r=parseFloat(f),n=f.replace(r.toString(),""),r=g.convert(r,n,l).toString()):r="";return r};this.getUnits=function(f){return f.substr(f.length-2,f.length)}};
++core.CSSUnits=function(){var m=this,h={"in":1,cm:2.54,mm:25.4,pt:72,pc:12};this.convert=function(b,g,d){return b*h[d]/h[g]};this.convertMeasure=function(b,g){var d,h;b&&g?(d=parseFloat(b),h=b.replace(d.toString(),""),d=m.convert(d,h,g).toString()):d="";return d};this.getUnits=function(b){return b.substr(b.length-2,b.length)}};
 +// Input 7
 +/*
 +
 + Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- (function(){function g(){var f,g,r,n,h;void 0===l&&(h=(f=runtime.getWindow())&&f.document,l={rangeBCRIgnoresElementBCR:!1,unscaledRangeClientRects:!1},h&&(n=h.createElement("div"),n.style.position="absolute",n.style.left="-99999px",n.style.transform="scale(2)",n.style["-webkit-transform"]="scale(2)",g=h.createElement("div"),n.appendChild(g),h.body.appendChild(n),f=h.createRange(),f.selectNode(g),l.rangeBCRIgnoresElementBCR=0===f.getClientRects().length,g.appendChild(h.createTextNode("Re [...]
- g=g.getBoundingClientRect(),r=f.getBoundingClientRect(),l.unscaledRangeClientRects=2<Math.abs(g.height-r.height),f.detach(),h.body.removeChild(n),f=Object.keys(l).map(function(d){return d+":"+String(l[d])}).join(", "),runtime.log("Detected browser quirks - "+f)));return l}var l;core.DomUtils=function(){function f(a,b){return 0>=a.compareBoundaryPoints(Range.START_TO_START,b)&&0<=a.compareBoundaryPoints(Range.END_TO_END,b)}function l(a,b){return 0>=a.compareBoundaryPoints(Range.END_TO_ST [...]
- a.compareBoundaryPoints(Range.START_TO_END,b)}function r(a,b){var c=null;a.nodeType===Node.TEXT_NODE&&(0===a.length?(a.parentNode.removeChild(a),b.nodeType===Node.TEXT_NODE&&(c=b)):(b.nodeType===Node.TEXT_NODE&&(a.appendData(b.data),b.parentNode.removeChild(b)),c=a));return c}function n(a){for(var b=a.parentNode;a.firstChild;)b.insertBefore(a.firstChild,a);b.removeChild(a);return b}function h(a,b){for(var c=a.parentNode,e=a.firstChild,d;e;)d=e.nextSibling,h(e,b),e=d;b(a)&&(c=n(a));retur [...]
- b){return a===b||Boolean(a.compareDocumentPosition(b)&Node.DOCUMENT_POSITION_CONTAINED_BY)}function m(a,b){for(var c=0,e;a.parentNode!==b;)runtime.assert(null!==a.parentNode,"parent is null"),a=a.parentNode;for(e=b.firstChild;e!==a;)c+=1,e=e.nextSibling;return c}function c(a,b,e){Object.keys(b).forEach(function(k){var d=k.split(":"),f=d[1],h=e(d[0]),d=b[k];"object"===typeof d&&Object.keys(d).length?(k=h?a.getElementsByTagNameNS(h,f)[0]||a.ownerDocument.createElementNS(h,k):a.getElements [...]
- a.ownerDocument.createElement(k),a.appendChild(k),c(k,d,e)):h&&a.setAttributeNS(h,k,String(d))})}var e=null;this.splitBoundaries=function(a){var b=[],c,e;if(a.startContainer.nodeType===Node.TEXT_NODE||a.endContainer.nodeType===Node.TEXT_NODE){if(c=a.endContainer){c=a.endOffset;e=a.endContainer;if(c<e.childNodes.length)for(e=e.childNodes.item(c),c=0;e.firstChild;)e=e.firstChild;else for(;e.lastChild;)e=e.lastChild,c=e.nodeType===Node.TEXT_NODE?e.textContent.length:e.childNodes.length;c={ [...]
- offset:c}}a.setEnd(c.container,c.offset);c=a.endContainer;0!==a.endOffset&&c.nodeType===Node.TEXT_NODE&&(e=c,a.endOffset!==e.length&&(b.push(e.splitText(a.endOffset)),b.push(e)));c=a.startContainer;0!==a.startOffset&&c.nodeType===Node.TEXT_NODE&&(e=c,a.startOffset!==e.length&&(c=e.splitText(a.startOffset),b.push(e),b.push(c),a.setStart(c,0)))}return b};this.containsRange=f;this.rangesIntersect=l;this.getNodesInRange=function(a,b){for(var c=[],e=a.commonAncestorContainer,d,f=a.startConta [...]
- Node.TEXT_NODE?e.parentNode:e,NodeFilter.SHOW_ALL,b,!1),e=f.currentNode=a.startContainer;e;){d=b(e);if(d===NodeFilter.FILTER_ACCEPT)c.push(e);else if(d===NodeFilter.FILTER_REJECT)break;e=e.parentNode}c.reverse();for(e=f.nextNode();e;)c.push(e),e=f.nextNode();return c};this.normalizeTextNodes=function(a){a&&a.nextSibling&&(a=r(a,a.nextSibling));a&&a.previousSibling&&r(a.previousSibling,a)};this.rangeContainsNode=function(a,b){var c=b.ownerDocument.createRange(),e=b.ownerDocument.createRa [...]
- a.startOffset);c.setEnd(a.endContainer,a.endOffset);e.selectNodeContents(b);d=f(c,e);c.detach();e.detach();return d};this.mergeIntoParent=n;this.removeUnwantedNodes=h;this.getElementsByTagNameNS=function(a,b,c){var e=[];a=a.getElementsByTagNameNS(b,c);e.length=c=a.length;for(b=0;b<c;b+=1)e[b]=a.item(b);return e};this.rangeIntersectsNode=function(a,b){var c=b.ownerDocument.createRange(),e;c.selectNodeContents(b);e=l(a,c);c.detach();return e};this.containsNode=function(a,b){return a===b|| [...]
- this.comparePoints=function(a,b,c,e){if(a===c)return e-b;var d=a.compareDocumentPosition(c);2===d?d=-1:4===d?d=1:10===d?(b=m(a,c),d=b<e?1:-1):(e=m(c,a),d=e<b?-1:1);return d};this.adaptRangeDifferenceToZoomLevel=function(a,b){return g().unscaledRangeClientRects?a:a/b};this.getBoundingClientRect=function(a){var b=a.ownerDocument,c=g();if((!1===c.unscaledRangeClientRects||c.rangeBCRIgnoresElementBCR)&&a.nodeType===Node.ELEMENT_NODE)return a.getBoundingClientRect();var d;e?d=e:e=d=b.createR [...]
- b.selectNode(a);return b.getBoundingClientRect()};this.mapKeyValObjOntoNode=function(a,b,c){Object.keys(b).forEach(function(e){var d=e.split(":"),f=d[1],d=c(d[0]),h=b[e];d?(f=a.getElementsByTagNameNS(d,f)[0],f||(f=a.ownerDocument.createElementNS(d,e),a.appendChild(f)),f.textContent=h):runtime.log("Key ignored: "+e)})};this.removeKeyElementsFromNode=function(a,b,c){b.forEach(function(b){var e=b.split(":"),d=e[1];(e=c(e[0]))?(d=a.getElementsByTagNameNS(e,d)[0])?d.parentNode.removeChild(d) [...]
- b+" not found."):runtime.log("Property Name ignored: "+b)})};this.getKeyValRepresentationOfNode=function(a,b){for(var c={},e=a.firstElementChild,d;e;){if(d=b(e.namespaceURI))c[d+":"+e.localName]=e.textContent;e=e.nextElementSibling}return c};this.mapObjOntoNode=c;(function(a){var b,c;c=runtime.getWindow();null!==c&&(b=c.navigator.appVersion.toLowerCase(),c=-1===b.indexOf("chrome")&&(-1!==b.indexOf("applewebkit")||-1!==b.indexOf("safari")),b=b.indexOf("msie"),c||b)&&(a.containsNode=d)})( [...]
++(function(){function m(){var g,d,h,p,k,m,e,r,a;void 0===b&&(d=(g=runtime.getWindow())&&g.document,m=d.documentElement,e=d.body,b={rangeBCRIgnoresElementBCR:!1,unscaledRangeClientRects:!1,elementBCRIgnoresBodyScroll:!1},d&&(p=d.createElement("div"),p.style.position="absolute",p.style.left="-99999px",p.style.transform="scale(2)",p.style["-webkit-transform"]="scale(2)",k=d.createElement("div"),p.appendChild(k),e.appendChild(p),g=d.createRange(),g.selectNode(k),b.rangeBCRIgnoresElementBCR=0 [...]
++k.appendChild(d.createTextNode("Rect transform test")),d=k.getBoundingClientRect(),h=g.getBoundingClientRect(),b.unscaledRangeClientRects=2<Math.abs(d.height-h.height),p.style.transform="",p.style["-webkit-transform"]="",d=m.style.overflow,h=e.style.overflow,r=e.style.height,a=e.scrollTop,m.style.overflow="visible",e.style.overflow="visible",e.style.height="200%",e.scrollTop=e.scrollHeight,b.elementBCRIgnoresBodyScroll=g.getBoundingClientRect().top!==k.getBoundingClientRect().top,e.scro [...]
++r,e.style.overflow=h,m.style.overflow=d,g.detach(),e.removeChild(p),g=Object.keys(b).map(function(a){return a+":"+String(b[a])}).join(", "),runtime.log("Detected browser quirks - "+g)));return b}function h(b,d,h){for(b=b?b.firstElementChild:null;b;){if(b.localName===h&&b.namespaceURI===d)return b;b=b.nextElementSibling}return null}var b;core.DomUtils=function(){function b(a,c){for(var l=0,f;a.parentNode!==c;)runtime.assert(null!==a.parentNode,"parent is null"),a=a.parentNode;for(f=c.fir [...]
++a;)l+=1,f=f.nextSibling;return l}function d(a,c){return 0>=a.compareBoundaryPoints(Range.START_TO_START,c)&&0<=a.compareBoundaryPoints(Range.END_TO_END,c)}function n(a,c){var b=null;a.nodeType===Node.TEXT_NODE&&(0===a.length?(a.parentNode.removeChild(a),c.nodeType===Node.TEXT_NODE&&(b=c)):(c.nodeType===Node.TEXT_NODE&&(a.appendData(c.data),c.parentNode.removeChild(c)),b=a));return b}function p(a){for(var c=a.parentNode;a.firstChild;)c.insertBefore(a.firstChild,a);c.removeChild(a);return [...]
++c){for(var b=a.parentNode,f=a.firstChild,d;f;)d=f.nextSibling,k(f,c),f=d;b&&c(a)&&p(a);return b}function q(a,c){return a===c||Boolean(a.compareDocumentPosition(c)&Node.DOCUMENT_POSITION_CONTAINED_BY)}function e(a,c,b){Object.keys(c).forEach(function(f){var d=f.split(":"),g=d[1],k=b(d[0]),d=c[f],h=typeof d;"object"===h?Object.keys(d).length&&(f=k?a.getElementsByTagNameNS(k,g)[0]||a.ownerDocument.createElementNS(k,f):a.getElementsByTagName(g)[0]||a.ownerDocument.createElement(f),a.appendC [...]
++d,b)):k&&(runtime.assert("number"===h||"string"===h,"attempting to map unsupported type '"+h+"' (key: "+f+")"),a.setAttributeNS(k,f,String(d)))})}var r=null;this.splitBoundaries=function(a){var c,l=[],f,d,e;if(a.startContainer.nodeType===Node.TEXT_NODE||a.endContainer.nodeType===Node.TEXT_NODE){f=a.endContainer;d=a.endContainer.nodeType!==Node.TEXT_NODE?a.endOffset===a.endContainer.childNodes.length:!1;e=a.endOffset;c=a.endContainer;if(e<c.childNodes.length)for(c=c.childNodes.item(e),e= [...]
++c.firstChild;else for(;c.lastChild;)c=c.lastChild,e=c.nodeType===Node.TEXT_NODE?c.textContent.length:c.childNodes.length;c===f&&(f=null);a.setEnd(c,e);e=a.endContainer;0!==a.endOffset&&e.nodeType===Node.TEXT_NODE&&(c=e,a.endOffset!==c.length&&(l.push(c.splitText(a.endOffset)),l.push(c)));e=a.startContainer;0!==a.startOffset&&e.nodeType===Node.TEXT_NODE&&(c=e,a.startOffset!==c.length&&(e=c.splitText(a.startOffset),l.push(c),l.push(e),a.setStart(e,0)));if(null!==f){for(e=a.endContainer;e. [...]
++e.parentNode!==f;)e=e.parentNode;d=d?f.childNodes.length:b(e,f);a.setEnd(f,d)}}return l};this.containsRange=d;this.rangesIntersect=function(a,c){return 0>=a.compareBoundaryPoints(Range.END_TO_START,c)&&0<=a.compareBoundaryPoints(Range.START_TO_END,c)};this.getNodesInRange=function(a,c,b){var f=[],d=a.commonAncestorContainer;b=a.startContainer.ownerDocument.createTreeWalker(d.nodeType===Node.TEXT_NODE?d.parentNode:d,b,c,!1);var e;a.endContainer.childNodes[a.endOffset-1]?(d=a.endContainer [...]
++1],e=Node.DOCUMENT_POSITION_PRECEDING|Node.DOCUMENT_POSITION_CONTAINED_BY):(d=a.endContainer,e=Node.DOCUMENT_POSITION_PRECEDING);a.startContainer.childNodes[a.startOffset]?(a=a.startContainer.childNodes[a.startOffset],b.currentNode=a):a.startOffset===(a.startContainer.nodeType===Node.TEXT_NODE?a.startContainer.length:a.startContainer.childNodes.length)?(a=a.startContainer,b.currentNode=a,b.lastChild(),a=b.nextNode()):(a=a.startContainer,b.currentNode=a);a&&c(a)===NodeFilter.FILTER_ACCEP [...]
++for(a=b.nextNode();a;){c=d.compareDocumentPosition(a);if(0!==c&&0===(c&e))break;f.push(a);a=b.nextNode()}return f};this.normalizeTextNodes=function(a){a&&a.nextSibling&&(a=n(a,a.nextSibling));a&&a.previousSibling&&n(a.previousSibling,a)};this.rangeContainsNode=function(a,c){var b=c.ownerDocument.createRange(),f=c.ownerDocument.createRange(),e;b.setStart(a.startContainer,a.startOffset);b.setEnd(a.endContainer,a.endOffset);f.selectNodeContents(c);e=d(b,f);b.detach();f.detach();return e};t [...]
++p;this.removeUnwantedNodes=k;this.getElementsByTagNameNS=function(a,c,b){var f=[];a=a.getElementsByTagNameNS(c,b);f.length=b=a.length;for(c=0;c<b;c+=1)f[c]=a.item(c);return f};this.containsNode=function(a,c){return a===c||a.contains(c)};this.comparePoints=function(a,c,l,f){if(a===l)return f-c;var d=a.compareDocumentPosition(l);2===d?d=-1:4===d?d=1:10===d?(c=b(a,l),d=c<f?1:-1):(f=b(l,a),d=f<c?-1:1);return d};this.adaptRangeDifferenceToZoomLevel=function(a,c){return m().unscaledRangeClien [...]
++c};this.getBoundingClientRect=function(a){var c=a.ownerDocument,b=m(),f=c.body;if((!1===b.unscaledRangeClientRects||b.rangeBCRIgnoresElementBCR)&&a.nodeType===Node.ELEMENT_NODE)return a=a.getBoundingClientRect(),b.elementBCRIgnoresBodyScroll?{left:a.left+f.scrollLeft,right:a.right+f.scrollLeft,top:a.top+f.scrollTop,bottom:a.bottom+f.scrollTop,width:a.width,height:a.height}:a;var d;r?d=r:r=d=c.createRange();b=d;b.selectNode(a);return b.getBoundingClientRect()};this.mapKeyValObjOntoNode=f [...]
++c,b){Object.keys(c).forEach(function(f){var d=f.split(":"),e=d[1],d=b(d[0]),g=c[f];d?(e=a.getElementsByTagNameNS(d,e)[0],e||(e=a.ownerDocument.createElementNS(d,f),a.appendChild(e)),e.textContent=g):runtime.log("Key ignored: "+f)})};this.removeKeyElementsFromNode=function(a,c,b){c.forEach(function(c){var d=c.split(":"),e=d[1];(d=b(d[0]))?(e=a.getElementsByTagNameNS(d,e)[0])?e.parentNode.removeChild(e):runtime.log("Element for "+c+" not found."):runtime.log("Property Name ignored: "+c)}) [...]
++function(a,c){for(var b={},f=a.firstElementChild,d;f;){if(d=c(f.namespaceURI))b[d+":"+f.localName]=f.textContent;f=f.nextElementSibling}return b};this.mapObjOntoNode=e;this.getDirectChild=h;(function(a){var c,b;b=runtime.getWindow();null!==b&&(c=b.navigator.appVersion.toLowerCase(),b=-1===c.indexOf("chrome")&&(-1!==c.indexOf("applewebkit")||-1!==c.indexOf("safari")),c=c.indexOf("msie"),b||c)&&(a.containsNode=q)})(this)};return core.DomUtils})();
 +// Input 8
++core.Cursor=function(m,h){function b(a){a.parentNode&&(k.push(a.previousSibling),k.push(a.nextSibling),a.parentNode.removeChild(a))}function g(a,c,b){if(c.nodeType===Node.TEXT_NODE){runtime.assert(Boolean(c),"putCursorIntoTextNode: invalid container");var d=c.parentNode;runtime.assert(Boolean(d),"putCursorIntoTextNode: container without parent");runtime.assert(0<=b&&b<=c.length,"putCursorIntoTextNode: offset is out of bounds");0===b?d.insertBefore(a,c):(b!==c.length&&c.splitText(b),d.in [...]
++c.nextSibling))}else c.nodeType===Node.ELEMENT_NODE&&c.insertBefore(a,c.childNodes.item(b));k.push(a.previousSibling);k.push(a.nextSibling)}var d=m.createElementNS("urn:webodf:names:cursor","cursor"),n=m.createElementNS("urn:webodf:names:cursor","anchor"),p,k=[],q=m.createRange(),e,r=new core.DomUtils;this.getNode=function(){return d};this.getAnchorNode=function(){return n.parentNode?n:d};this.getSelectedRange=function(){e?(q.setStartBefore(d),q.collapse(!0)):(q.setStartAfter(p?n:d),q.s [...]
++d:n));return q};this.setSelectedRange=function(a,c){q&&q!==a&&q.detach();q=a;p=!1!==c;(e=a.collapsed)?(b(n),b(d),g(d,a.startContainer,a.startOffset)):(b(n),b(d),g(p?d:n,a.endContainer,a.endOffset),g(p?n:d,a.startContainer,a.startOffset));k.forEach(r.normalizeTextNodes);k.length=0};this.hasForwardSelection=function(){return p};this.remove=function(){b(d);k.forEach(r.normalizeTextNodes);k.length=0};d.setAttributeNS("urn:webodf:names:cursor","memberId",h);n.setAttributeNS("urn:webodf:names [...]
++h)};
++// Input 9
++/*
++
++ Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
++
++ @licstart
++ The JavaScript code in this page is free software: you can redistribute it
++ and/or modify it under the terms of the GNU Affero General Public License
++ (GNU AGPL) as published by the Free Software Foundation, either version 3 of
++ the License, or (at your option) any later version.  The code is distributed
++ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
++
++ You should have received a copy of the GNU Affero General Public License
++ along with this code.  If not, see <http://www.gnu.org/licenses/>.
++
++ As additional permission under GNU AGPL version 3 section 7, you
++ may distribute non-source (e.g., minimized or compacted) forms of
++ that code without the copy of the GNU GPL normally required by
++ section 4, provided you include this license notice and a URL
++ through which recipients can access the Corresponding Source.
++
++ As a special exception to the AGPL, any HTML file which merely makes function
++ calls to this code, and for that purpose includes it by reference shall be
++ deemed a separate work for copyright law purposes. In addition, the copyright
++ holders of this code give you permission to combine this code with free
++ software libraries that are released under the GNU LGPL. You may copy and
++ distribute such a system following the terms of the GNU AGPL for this code
++ and the LGPL for the libraries. If you modify this code, you may extend this
++ exception to your version of the code, but you are not obligated to do so.
++ If you do not wish to do so, delete this exception statement from your
++ version.
++
++ This license applies to this entire compilation.
++ @licend
++ @source: http://www.webodf.org/
++ @source: https://github.com/kogmbh/WebODF/
++*/
++core.Destroyable=function(){};core.Destroyable.prototype.destroy=function(m){};
++// Input 10
 +/*
 +
 + Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- core.EventNotifier=function(g){var l={};this.emit=function(f,g){var r,n;runtime.assert(l.hasOwnProperty(f),'unknown event fired "'+f+'"');n=l[f];for(r=0;r<n.length;r+=1)n[r](g)};this.subscribe=function(f,g){runtime.assert(l.hasOwnProperty(f),'tried to subscribe to unknown event "'+f+'"');l[f].push(g);runtime.log('event "'+f+'" subscribed.')};this.unsubscribe=function(f,g){var r;runtime.assert(l.hasOwnProperty(f),'tried to unsubscribe from unknown event "'+f+'"');r=l[f].indexOf(g);runtim [...]
- r,'tried to unsubscribe unknown callback from event "'+f+'"');-1!==r&&l[f].splice(r,1);runtime.log('event "'+f+'" unsubscribed.')};(function(){var f,p;for(f=0;f<g.length;f+=1)p=g[f],runtime.assert(!l.hasOwnProperty(p),'Duplicated event ids: "'+p+'" registered more than once.'),l[p]=[]})()};
- // Input 9
++core.EventNotifier=function(m){var h={};this.emit=function(b,g){var d,n;runtime.assert(h.hasOwnProperty(b),'unknown event fired "'+b+'"');n=h[b];for(d=0;d<n.length;d+=1)n[d](g)};this.subscribe=function(b,g){runtime.assert(h.hasOwnProperty(b),'tried to subscribe to unknown event "'+b+'"');h[b].push(g)};this.unsubscribe=function(b,g){var d;runtime.assert(h.hasOwnProperty(b),'tried to unsubscribe from unknown event "'+b+'"');d=h[b].indexOf(g);runtime.assert(-1!==d,'tried to unsubscribe unk [...]
++b+'"');-1!==d&&h[b].splice(d,1)};(function(){var b,g;for(b=0;b<m.length;b+=1)g=m[b],runtime.assert(!h.hasOwnProperty(g),'Duplicated event ids: "'+g+'" registered more than once.'),h[g]=[]})()};
++// Input 11
 +/*
 +
 + Copyright (C) 2012 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- core.LoopWatchDog=function(g,l){var f=Date.now(),p=0;this.check=function(){var r;if(g&&(r=Date.now(),r-f>g))throw runtime.log("alert","watchdog timeout"),"timeout!";if(0<l&&(p+=1,p>l))throw runtime.log("alert","watchdog loop overflow"),"loop overflow";}};
- // Input 10
- core.PositionIterator=function(g,l,f,p){function r(){this.acceptNode=function(a){return!a||a.nodeType===b&&0===a.length?t:k}}function n(a){this.acceptNode=function(c){return!c||c.nodeType===b&&0===c.length?t:a.acceptNode(c)}}function h(){var a=c.currentNode,d=a.nodeType;e=d===b?a.length-1:d===q?1:0}function d(){if(null===c.previousSibling()){if(!c.parentNode()||c.currentNode===g)return c.firstChild(),!1;e=0}else h();return!0}var m=this,c,e,a,b=Node.TEXT_NODE,q=Node.ELEMENT_NODE,k=NodeFi [...]
- t=NodeFilter.FILTER_REJECT;this.nextPosition=function(){var a=c.currentNode,d=a.nodeType;if(a===g)return!1;if(0===e&&d===q)null===c.firstChild()&&(e=1);else if(d===b&&e+1<a.length)e+=1;else if(null!==c.nextSibling())e=0;else if(c.parentNode())e=1;else return!1;return!0};this.previousPosition=function(){var a=!0,q=c.currentNode;0===e?a=d():q.nodeType===b?e-=1:null!==c.lastChild()?h():q===g?a=!1:e=0;return a};this.previousNode=d;this.container=function(){var a=c.currentNode,d=a.nodeType;0 [...]
- b&&(a=a.parentNode);return a};this.rightNode=function(){var d=c.currentNode,f=d.nodeType;if(f===b&&e===d.length)for(d=d.nextSibling;d&&a(d)!==k;)d=d.nextSibling;else f===q&&1===e&&(d=null);return d};this.leftNode=function(){var b=c.currentNode;if(0===e)for(b=b.previousSibling;b&&a(b)!==k;)b=b.previousSibling;else if(b.nodeType===q)for(b=b.lastChild;b&&a(b)!==k;)b=b.previousSibling;return b};this.getCurrentNode=function(){return c.currentNode};this.unfilteredDomOffset=function(){if(c.cur [...]
- b)return e;for(var a=0,d=c.currentNode,d=1===e?d.lastChild:d.previousSibling;d;)a+=1,d=d.previousSibling;return a};this.getPreviousSibling=function(){var a=c.currentNode,b=c.previousSibling();c.currentNode=a;return b};this.getNextSibling=function(){var a=c.currentNode,b=c.nextSibling();c.currentNode=a;return b};this.setUnfilteredPosition=function(d,q){var f,h;runtime.assert(null!==d&&void 0!==d,"PositionIterator.setUnfilteredPosition called without container");c.currentNode=d;if(d.nodeT [...]
- q,runtime.assert(q<=d.length,"Error in setPosition: "+q+" > "+d.length),runtime.assert(0<=q,"Error in setPosition: "+q+" < 0"),q===d.length&&(c.nextSibling()?e=0:c.parentNode()?e=1:runtime.assert(!1,"Error in setUnfilteredPosition: position not valid.")),!0;f=a(d);for(h=d.parentNode;h&&h!==g&&f===k;)f=a(h),f!==k&&(c.currentNode=h),h=h.parentNode;q<d.childNodes.length&&f!==NodeFilter.FILTER_REJECT?(c.currentNode=d.childNodes.item(q),f=a(c.currentNode),e=0):e=1;f===NodeFilter.FILTER_REJEC [...]
- k)return m.nextPosition();runtime.assert(a(c.currentNode)===k,"PositionIterater.setUnfilteredPosition call resulted in an non-visible node being set");return!0};this.moveToEnd=function(){c.currentNode=g;e=1};this.moveToEndOfNode=function(a){a.nodeType===b?m.setUnfilteredPosition(a,a.length):(c.currentNode=a,e=1)};this.getNodeFilter=function(){return a};a=(f?new n(f):new r).acceptNode;a.acceptNode=a;l=l||4294967295;runtime.assert(g.nodeType!==Node.TEXT_NODE,"Internet Explorer doesn't all [...]
- c=g.ownerDocument.createTreeWalker(g,l,a,p);e=0;null===c.firstChild()&&(e=1)};
- // Input 11
- core.zip_HuftNode=function(){this.n=this.b=this.e=0;this.t=null};core.zip_HuftList=function(){this.list=this.next=null};
- core.RawInflate=function(){function g(a,b,c,e,d,q){this.BMAX=16;this.N_MAX=288;this.status=0;this.root=null;this.m=0;var f=Array(this.BMAX+1),k,h,I,g,m,s,l,n=Array(this.BMAX+1),r,p,v,t=new core.zip_HuftNode,W=Array(this.BMAX);g=Array(this.N_MAX);var u,y=Array(this.BMAX+1),z,Q,B;B=this.root=null;for(m=0;m<f.length;m++)f[m]=0;for(m=0;m<n.length;m++)n[m]=0;for(m=0;m<W.length;m++)W[m]=null;for(m=0;m<g.length;m++)g[m]=0;for(m=0;m<y.length;m++)y[m]=0;k=256<b?a[256]:this.BMAX;r=a;p=0;m=b;do f[ [...]
- while(0<--m);if(f[0]===b)this.root=null,this.status=this.m=0;else{for(s=1;s<=this.BMAX&&0===f[s];s++);l=s;q<s&&(q=s);for(m=this.BMAX;0!==m&&0===f[m];m--);I=m;q>m&&(q=m);for(z=1<<s;s<m;s++,z<<=1)if(z-=f[s],0>z){this.status=2;this.m=q;return}z-=f[m];if(0>z)this.status=2,this.m=q;else{f[m]+=z;y[1]=s=0;r=f;p=1;for(v=2;0<--m;)s+=r[p++],y[v++]=s;r=a;m=p=0;do s=r[p++],0!==s&&(g[y[s]++]=m);while(++m<b);b=y[I];y[0]=m=0;r=g;p=0;g=-1;u=n[0]=0;v=null;Q=0;for(l=l-1+1;l<=I;l++)for(a=f[l];0<a--;){for( [...]
- n[1+g];g++;Q=I-u;Q=Q>q?q:Q;s=l-u;h=1<<s;if(h>a+1)for(h-=a+1,v=l;++s<Q;){h<<=1;if(h<=f[++v])break;h-=f[v]}u+s>k&&u<k&&(s=k-u);Q=1<<s;n[1+g]=s;v=Array(Q);for(h=0;h<Q;h++)v[h]=new core.zip_HuftNode;B=null===B?this.root=new core.zip_HuftList:B.next=new core.zip_HuftList;B.next=null;B.list=v;W[g]=v;0<g&&(y[g]=m,t.b=n[g],t.e=16+s,t.t=v,s=(m&(1<<u)-1)>>u-n[g],W[g-1][s].e=t.e,W[g-1][s].b=t.b,W[g-1][s].n=t.n,W[g-1][s].t=t.t)}t.b=l-u;p>=b?t.e=99:r[p]<c?(t.e=256>r[p]?16:15,t.n=r[p++]):(t.e=d[r[p]- [...]
- c]);h=1<<l-u;for(s=m>>u;s<Q;s+=h)v[s].e=t.e,v[s].b=t.b,v[s].n=t.n,v[s].t=t.t;for(s=1<<l-1;0!==(m&s);s>>=1)m^=s;for(m^=s;(m&(1<<u)-1)!==y[g];)u-=n[g],g--}this.m=n[1];this.status=0!==z&&1!==I?1:0}}}function l(c){for(;b<c;){var e=a,d;d=s.length===H?-1:s[H++];a=e|d<<b;b+=8}}function f(b){return a&y[b]}function p(c){a>>=c;b-=c}function r(a,b,c){var e,k,I;if(0===c)return 0;for(I=0;;){l(v);k=w.list[f(v)];for(e=k.e;16<e;){if(99===e)return-1;p(k.b);e-=16;l(e);k=k.t[f(e)];e=k.e}p(k.b);if(16===e)d [...]
- I++]=h[d++]=k.n;else{if(15===e)break;l(e);t=k.n+f(e);p(e);l(u);k=x.list[f(u)];for(e=k.e;16<e;){if(99===e)return-1;p(k.b);e-=16;l(e);k=k.t[f(e)];e=k.e}p(k.b);l(e);A=d-k.n-f(e);for(p(e);0<t&&I<c;)t--,A&=32767,d&=32767,a[b+I++]=h[d++]=h[A++]}if(I===c)return c}q=-1;return I}function n(a,b,c){var e,d,q,k,h,m,s,n=Array(316);for(e=0;e<n.length;e++)n[e]=0;l(5);m=257+f(5);p(5);l(5);s=1+f(5);p(5);l(4);e=4+f(4);p(4);if(286<m||30<s)return-1;for(d=0;d<e;d++)l(3),n[Q[d]]=f(3),p(3);for(d=e;19>d;d++)n[ [...]
- 7;d=new g(n,19,19,null,null,v);if(0!==d.status)return-1;w=d.root;v=d.m;k=m+s;for(e=q=0;e<k;)if(l(v),h=w.list[f(v)],d=h.b,p(d),d=h.n,16>d)n[e++]=q=d;else if(16===d){l(2);d=3+f(2);p(2);if(e+d>k)return-1;for(;0<d--;)n[e++]=q}else{17===d?(l(3),d=3+f(3),p(3)):(l(7),d=11+f(7),p(7));if(e+d>k)return-1;for(;0<d--;)n[e++]=0;q=0}v=9;d=new g(n,m,257,B,L,v);0===v&&(d.status=1);if(0!==d.status)return-1;w=d.root;v=d.m;for(e=0;e<s;e++)n[e]=n[e+m];u=6;d=new g(n,s,0,I,W,u);x=d.root;u=d.m;return 0===u&&25 [...]
- -1:r(a,b,c)}var h=[],d,m=null,c,e,a,b,q,k,t,A,w,x,v,u,s,H,y=[0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535],B=[3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258,0,0],L=[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,99,99],I=[1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577],W=[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13],Q=[16,17,18, [...]
- 10,5,11,4,12,3,13,2,14,1,15],z;this.inflate=function(y,Q){h.length=65536;b=a=d=0;q=-1;k=!1;t=A=0;w=null;s=y;H=0;var G=new Uint8Array(new ArrayBuffer(Q));a:for(var Z=0,O;Z<Q&&(!k||-1!==q);){if(0<t){if(0!==q)for(;0<t&&Z<Q;)t--,A&=32767,d&=32767,G[0+Z]=h[d]=h[A],Z+=1,d+=1,A+=1;else{for(;0<t&&Z<Q;)t-=1,d&=32767,l(8),G[0+Z]=h[d]=f(8),Z+=1,d+=1,p(8);0===t&&(q=-1)}if(Z===Q)break}if(-1===q){if(k)break;l(1);0!==f(1)&&(k=!0);p(1);l(2);q=f(2);p(2);w=null;t=0}switch(q){case 0:O=G;var aa=0+Z,J=Q-Z,F [...]
- b&7;p(F);l(16);F=f(16);p(16);l(16);if(F!==(~a&65535))O=-1;else{p(16);t=F;for(F=0;0<t&&F<J;)t--,d&=32767,l(8),O[aa+F++]=h[d++]=f(8),p(8);0===t&&(q=-1);O=F}break;case 1:if(null!==w)O=r(G,0+Z,Q-Z);else b:{O=G;aa=0+Z;J=Q-Z;if(null===m){for(var C=void 0,F=Array(288),C=void 0,C=0;144>C;C++)F[C]=8;for(C=144;256>C;C++)F[C]=9;for(C=256;280>C;C++)F[C]=7;for(C=280;288>C;C++)F[C]=8;e=7;C=new g(F,288,257,B,L,e);if(0!==C.status){alert("HufBuild error: "+C.status);O=-1;break b}m=C.root;e=C.m;for(C=0;3 [...]
- 5;z=5;C=new g(F,30,0,I,W,z);if(1<C.status){m=null;alert("HufBuild error: "+C.status);O=-1;break b}c=C.root;z=C.m}w=m;x=c;v=e;u=z;O=r(O,aa,J)}break;case 2:O=null!==w?r(G,0+Z,Q-Z):n(G,0+Z,Q-Z);break;default:O=-1}if(-1===O)break a;Z+=O}s=new Uint8Array(new ArrayBuffer(0));return G}};
++core.LoopWatchDog=function(m,h){var b=Date.now(),g=0;this.check=function(){var d;if(m&&(d=Date.now(),d-b>m))throw runtime.log("alert","watchdog timeout"),"timeout!";if(0<h&&(g+=1,g>h))throw runtime.log("alert","watchdog loop overflow"),"loop overflow";}};
 +// Input 12
- core.ScheduledTask=function(g,l){function f(){n&&(runtime.clearTimeout(r),n=!1)}function p(){f();g.apply(void 0,h);h=null}var r,n=!1,h=[];this.trigger=function(){h=Array.prototype.slice.call(arguments);n||(n=!0,r=runtime.setTimeout(p,l))};this.triggerImmediate=function(){h=Array.prototype.slice.call(arguments);p()};this.processRequests=function(){n&&p()};this.cancel=f;this.destroy=function(d){f();d()}};
++core.PositionIterator=function(m,h,b,g){function d(){this.acceptNode=function(a){return!a||a.nodeType===l&&0===a.length?w:v}}function n(a){this.acceptNode=function(c){return!c||c.nodeType===l&&0===c.length?w:a.acceptNode(c)}}function p(){var c=r.currentNode,b=c.nodeType;a=b===l?c.length-1:b===f?1:0}function k(){if(null===r.previousSibling()){if(!r.parentNode()||r.currentNode===m)return r.firstChild(),!1;a=0}else p();return!0}function q(){var b=r.currentNode,l;l=c(b);if(b!==m)for(b=b.par [...]
++b!==m;)c(b)===w&&(r.currentNode=b,l=w),b=b.parentNode;l===w?(a=1,b=e.nextPosition()):b=l===v?!0:e.nextPosition();b&&runtime.assert(c(r.currentNode)===v,"moveToAcceptedNode did not result in walker being on an accepted node");return b}var e=this,r,a,c,l=Node.TEXT_NODE,f=Node.ELEMENT_NODE,v=NodeFilter.FILTER_ACCEPT,w=NodeFilter.FILTER_REJECT;this.nextPosition=function(){var c=r.currentNode,b=c.nodeType;if(c===m)return!1;if(0===a&&b===f)null===r.firstChild()&&(a=1);else if(b===l&&a+1<c.len [...]
++r.nextSibling())a=0;else if(r.parentNode())a=1;else return!1;return!0};this.previousPosition=function(){var c=!0,b=r.currentNode;0===a?c=k():b.nodeType===l?a-=1:null!==r.lastChild()?p():b===m?c=!1:a=0;return c};this.previousNode=k;this.container=function(){var c=r.currentNode,b=c.nodeType;0===a&&b!==l&&(c=c.parentNode);return c};this.rightNode=function(){var b=r.currentNode,d=b.nodeType;if(d===l&&a===b.length)for(b=b.nextSibling;b&&c(b)!==v;)b=b.nextSibling;else d===f&&1===a&&(b=null);r [...]
++function(){var b=r.currentNode;if(0===a)for(b=b.previousSibling;b&&c(b)!==v;)b=b.previousSibling;else if(b.nodeType===f)for(b=b.lastChild;b&&c(b)!==v;)b=b.previousSibling;return b};this.getCurrentNode=function(){return r.currentNode};this.unfilteredDomOffset=function(){if(r.currentNode.nodeType===l)return a;for(var c=0,b=r.currentNode,b=1===a?b.lastChild:b.previousSibling;b;)c+=1,b=b.previousSibling;return c};this.getPreviousSibling=function(){var a=r.currentNode,c=r.previousSibling();r [...]
++a;return c};this.getNextSibling=function(){var a=r.currentNode,c=r.nextSibling();r.currentNode=a;return c};this.setPositionBeforeElement=function(c){runtime.assert(Boolean(c),"setPositionBeforeElement called without element");r.currentNode=c;a=0;return q()};this.setUnfilteredPosition=function(c,b){runtime.assert(Boolean(c),"PositionIterator.setUnfilteredPosition called without container");r.currentNode=c;if(c.nodeType===l)return a=b,runtime.assert(b<=c.length,"Error in setPosition: "+b+ [...]
++runtime.assert(0<=b,"Error in setPosition: "+b+" < 0"),b===c.length&&(r.nextSibling()?a=0:r.parentNode()?a=1:runtime.assert(!1,"Error in setUnfilteredPosition: position not valid.")),!0;b<c.childNodes.length?(r.currentNode=c.childNodes.item(b),a=0):a=1;return q()};this.moveToEnd=function(){r.currentNode=m;a=1};this.moveToEndOfNode=function(c){c.nodeType===l?e.setUnfilteredPosition(c,c.length):(r.currentNode=c,a=1)};this.isBeforeNode=function(){return 0===a};this.getNodeFilter=function() [...]
++c=(b?new n(b):new d).acceptNode;c.acceptNode=c;h=h||NodeFilter.SHOW_ALL;runtime.assert(m.nodeType!==Node.TEXT_NODE,"Internet Explorer doesn't allow tree walker roots to be text nodes");r=m.ownerDocument.createTreeWalker(m,h,c,g);a=0;null===r.firstChild()&&(a=1)};
 +// Input 13
- core.UnitTest=function(){};core.UnitTest.prototype.setUp=function(){};core.UnitTest.prototype.tearDown=function(){};core.UnitTest.prototype.description=function(){};core.UnitTest.prototype.tests=function(){};core.UnitTest.prototype.asyncTests=function(){};
- core.UnitTest.provideTestAreaDiv=function(){var g=runtime.getWindow().document,l=g.getElementById("testarea");runtime.assert(!l,'Unclean test environment, found a div with id "testarea".');l=g.createElement("div");l.setAttribute("id","testarea");g.body.appendChild(l);return l};
- core.UnitTest.cleanupTestAreaDiv=function(){var g=runtime.getWindow().document,l=g.getElementById("testarea");runtime.assert(!!l&&l.parentNode===g.body,'Test environment broken, found no div with id "testarea" below body.');g.body.removeChild(l)};core.UnitTest.createOdtDocument=function(g,l){var f="<?xml version='1.0' encoding='UTF-8'?>",f=f+"<office:document";Object.keys(l).forEach(function(g){f+=" xmlns:"+g+'="'+l[g]+'"'});f+=">";f+=g;f+="</office:document>";return runtime.parseXML(f)};
- core.UnitTestRunner=function(){function g(d){h+=1;runtime.log("fail",d)}function l(d,c){var e;try{if(d.length!==c.length)return g("array of length "+d.length+" should be "+c.length+" long"),!1;for(e=0;e<d.length;e+=1)if(d[e]!==c[e])return g(d[e]+" should be "+c[e]+" at array index "+e),!1}catch(a){return!1}return!0}function f(d,c,e){var a=d.attributes,b=a.length,q,k,h;for(q=0;q<b;q+=1)if(k=a.item(q),"xmlns"!==k.prefix&&"urn:webodf:names:steps"!==k.namespaceURI){h=c.getAttributeNS(k.name [...]
- if(!c.hasAttributeNS(k.namespaceURI,k.localName))return g("Attribute "+k.localName+" with value "+k.value+" was not present"),!1;if(h!==k.value)return g("Attribute "+k.localName+" was "+h+" should be "+k.value),!1}return e?!0:f(c,d,!0)}function p(d,c){var e,a;e=d.nodeType;a=c.nodeType;if(e!==a)return g("Nodetype '"+e+"' should be '"+a+"'"),!1;if(e===Node.TEXT_NODE){if(d.data===c.data)return!0;g("Textnode data '"+d.data+"' should be '"+c.data+"'");return!1}runtime.assert(e===Node.ELEMENT [...]
- if(d.namespaceURI!==c.namespaceURI)return g("namespace '"+d.namespaceURI+"' should be '"+c.namespaceURI+"'"),!1;if(d.localName!==c.localName)return g("localName '"+d.localName+"' should be '"+c.localName+"'"),!1;if(!f(d,c,!1))return!1;e=d.firstChild;for(a=c.firstChild;e;){if(!a)return g("Nodetype '"+e.nodeType+"' is unexpected here."),!1;if(!p(e,a))return!1;e=e.nextSibling;a=a.nextSibling}return a?(g("Nodetype '"+a.nodeType+"' is missing here."),!1):!0}function r(f,c){return 0===c?f===c [...]
- c:f===c?!0:"number"===typeof c&&isNaN(c)?"number"===typeof f&&isNaN(f):Object.prototype.toString.call(c)===Object.prototype.toString.call([])?l(f,c):"object"===typeof c&&"object"===typeof f?c.constructor===Element||c.constructor===Node?p(c,f):d(c,f):!1}function n(d,c,e){"string"===typeof c&&"string"===typeof e||runtime.log("WARN: shouldBe() expects string arguments");var a,b;try{b=eval(c)}catch(q){a=q}d=eval(e);a?g(c+" should be "+d+". Threw exception "+a):r(b,d)?runtime.log("pass",c+"  [...]
- String(typeof d)?(e=0===b&&0>1/b?"-0":String(b),g(c+" should be "+d+". Was "+e+".")):g(c+" should be "+d+" (of type "+typeof d+"). Was "+b+" (of type "+typeof b+").")}var h=0,d;d=function(d,c){var e=Object.keys(d),a=Object.keys(c);e.sort();a.sort();return l(e,a)&&Object.keys(d).every(function(a){var e=d[a],f=c[a];return r(e,f)?!0:(g(e+" should be "+f+" for key "+a),!1)})};this.areNodesEqual=p;this.shouldBeNull=function(d,c){n(d,c,"null")};this.shouldBeNonNull=function(d,c){var e,a;try{a [...]
- b}e?g(c+" should be non-null. Threw exception "+e):null!==a?runtime.log("pass",c+" is non-null."):g(c+" should be non-null. Was "+a)};this.shouldBe=n;this.countFailedTests=function(){return h};this.name=function(d){var c,e,a=[],b=d.length;a.length=b;for(c=0;c<b;c+=1){e=Runtime.getFunctionName(d[c])||"";if(""===e)throw"Found a function without a name.";a[c]={f:d[c],name:e}}return a}};
- core.UnitTester=function(){function g(f,g){return"<span style='color:blue;cursor:pointer' onclick='"+g+"'>"+f+"</span>"}var l=0,f={};this.runTests=function(p,r,n){function h(a){if(0===a.length)f[d]=e,l+=m.countFailedTests(),r();else{b=a[0].f;var q=a[0].name;runtime.log("Running "+q);k=m.countFailedTests();c.setUp();b(function(){c.tearDown();e[q]=k===m.countFailedTests();h(a.slice(1))})}}var d=Runtime.getFunctionName(p)||"",m=new core.UnitTestRunner,c=new p(m),e={},a,b,q,k,t="BrowserRunt [...]
- if(f.hasOwnProperty(d))runtime.log("Test "+d+" has already run.");else{t?runtime.log("<span>Running "+g(d,'runSuite("'+d+'");')+": "+c.description()+"</span>"):runtime.log("Running "+d+": "+c.description);q=c.tests();for(a=0;a<q.length;a+=1)b=q[a].f,p=q[a].name,n.length&&-1===n.indexOf(p)||(t?runtime.log("<span>Running "+g(p,'runTest("'+d+'","'+p+'")')+"</span>"):runtime.log("Running "+p),k=m.countFailedTests(),c.setUp(),b(),c.tearDown(),e[p]=k===m.countFailedTests());h(c.asyncTests())} [...]
- function(){return l};this.results=function(){return f}};
++core.PositionFilter=function(){};core.PositionFilter.FilterResult={FILTER_ACCEPT:1,FILTER_REJECT:2,FILTER_SKIP:3};core.PositionFilter.prototype.acceptPosition=function(m){};(function(){return core.PositionFilter})();
 +// Input 14
- core.Utils=function(){function g(l,f){if(f&&Array.isArray(f)){l=l||[];if(!Array.isArray(l))throw"Destination is not an array.";l=l.concat(f.map(function(f){return g(null,f)}))}else if(f&&"object"===typeof f){l=l||{};if("object"!==typeof l)throw"Destination is not an object.";Object.keys(f).forEach(function(p){l[p]=g(l[p],f[p])})}else l=f;return l}this.hashString=function(g){var f=0,p,r;p=0;for(r=g.length;p<r;p+=1)f=(f<<5)-f+g.charCodeAt(p),f|=0;return f};this.mergeObjects=function(l,f){ [...]
- g(l[p],f[p])});return l}};
++core.PositionFilterChain=function(){var m=[],h=core.PositionFilter.FilterResult.FILTER_ACCEPT,b=core.PositionFilter.FilterResult.FILTER_REJECT;this.acceptPosition=function(g){var d;for(d=0;d<m.length;d+=1)if(m[d].acceptPosition(g)===b)return b;return h};this.addFilter=function(b){m.push(b)}};
 +// Input 15
++core.zip_HuftNode=function(){this.n=this.b=this.e=0;this.t=null};core.zip_HuftList=function(){this.list=this.next=null};
++core.RawInflate=function(){function m(a,c,b,l,d,f){this.BMAX=16;this.N_MAX=288;this.status=0;this.root=null;this.m=0;var e=Array(this.BMAX+1),g,k,h,p,n,y,m,r=Array(this.BMAX+1),s,H,L,q=new core.zip_HuftNode,v=Array(this.BMAX);p=Array(this.N_MAX);var F,t=Array(this.BMAX+1),u,O,w;w=this.root=null;for(n=0;n<e.length;n++)e[n]=0;for(n=0;n<r.length;n++)r[n]=0;for(n=0;n<v.length;n++)v[n]=null;for(n=0;n<p.length;n++)p[n]=0;for(n=0;n<t.length;n++)t[n]=0;g=256<c?a[256]:this.BMAX;s=a;H=0;n=c;do e[ [...]
++while(0<--n);if(e[0]===c)this.root=null,this.status=this.m=0;else{for(y=1;y<=this.BMAX&&0===e[y];y++);m=y;f<y&&(f=y);for(n=this.BMAX;0!==n&&0===e[n];n--);h=n;f>n&&(f=n);for(u=1<<y;y<n;y++,u<<=1)if(u-=e[y],0>u){this.status=2;this.m=f;return}u-=e[n];if(0>u)this.status=2,this.m=f;else{e[n]+=u;t[1]=y=0;s=e;H=1;for(L=2;0<--n;)y+=s[H++],t[L++]=y;s=a;n=H=0;do y=s[H++],0!==y&&(p[t[y]++]=n);while(++n<c);c=t[h];t[0]=n=0;s=p;H=0;p=-1;F=r[0]=0;L=null;O=0;for(m=m-1+1;m<=h;m++)for(a=e[m];0<a--;){for( [...]
++r[1+p];p++;O=h-F;O=O>f?f:O;y=m-F;k=1<<y;if(k>a+1)for(k-=a+1,L=m;++y<O;){k<<=1;if(k<=e[++L])break;k-=e[L]}F+y>g&&F<g&&(y=g-F);O=1<<y;r[1+p]=y;L=Array(O);for(k=0;k<O;k++)L[k]=new core.zip_HuftNode;w=null===w?this.root=new core.zip_HuftList:w.next=new core.zip_HuftList;w.next=null;w.list=L;v[p]=L;0<p&&(t[p]=n,q.b=r[p],q.e=16+y,q.t=L,y=(n&(1<<F)-1)>>F-r[p],v[p-1][y].e=q.e,v[p-1][y].b=q.b,v[p-1][y].n=q.n,v[p-1][y].t=q.t)}q.b=m-F;H>=c?q.e=99:s[H]<b?(q.e=256>s[H]?16:15,q.n=s[H++]):(q.e=d[s[H]- [...]
++b]);k=1<<m-F;for(y=n>>F;y<O;y+=k)L[y].e=q.e,L[y].b=q.b,L[y].n=q.n,L[y].t=q.t;for(y=1<<m-1;0!==(n&y);y>>=1)n^=y;for(n^=y;(n&(1<<F)-1)!==t[p];)F-=r[p],p--}this.m=r[1];this.status=0!==u&&1!==h?1:0}}}function h(b){for(;c<b;){var l=a,d;d=s.length===y?-1:s[y++];a=l|d<<c;c+=8}}function b(c){return a&F[c]}function g(b){a>>=b;c-=b}function d(a,c,d){var f,e,n;if(0===d)return 0;for(n=0;;){h(t);e=z.list[b(t)];for(f=e.e;16<f;){if(99===f)return-1;g(e.b);f-=16;h(f);e=e.t[b(f)];f=e.e}g(e.b);if(16===f)k [...]
++n++]=p[k++]=e.n;else{if(15===f)break;h(f);v=e.n+b(f);g(f);h(u);e=x.list[b(u)];for(f=e.e;16<f;){if(99===f)return-1;g(e.b);f-=16;h(f);e=e.t[b(f)];f=e.e}g(e.b);h(f);w=k-e.n-b(f);for(g(f);0<v&&n<d;)v--,w&=32767,k&=32767,a[c+n++]=p[k++]=p[w++]}if(n===d)return d}l=-1;return n}function n(a,c,l){var f,e,k,n,p,y,r,s=Array(316);for(f=0;f<s.length;f++)s[f]=0;h(5);y=257+b(5);g(5);h(5);r=1+b(5);g(5);h(4);f=4+b(4);g(4);if(286<y||30<r)return-1;for(e=0;e<f;e++)h(3),s[T[e]]=b(3),g(3);for(e=f;19>e;e++)s[ [...]
++7;e=new m(s,19,19,null,null,t);if(0!==e.status)return-1;z=e.root;t=e.m;n=y+r;for(f=k=0;f<n;)if(h(t),p=z.list[b(t)],e=p.b,g(e),e=p.n,16>e)s[f++]=k=e;else if(16===e){h(2);e=3+b(2);g(2);if(f+e>n)return-1;for(;0<e--;)s[f++]=k}else{17===e?(h(3),e=3+b(3),g(3)):(h(7),e=11+b(7),g(7));if(f+e>n)return-1;for(;0<e--;)s[f++]=0;k=0}t=9;e=new m(s,y,257,L,O,t);0===t&&(e.status=1);if(0!==e.status)return-1;z=e.root;t=e.m;for(f=0;f<r;f++)s[f]=s[f+y];u=6;e=new m(s,r,0,H,U,u);x=e.root;u=e.m;return 0===u&&25 [...]
++-1:d(a,c,l)}var p=[],k,q=null,e,r,a,c,l,f,v,w,z,x,t,u,s,y,F=[0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535],L=[3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258,0,0],O=[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,99,99],H=[1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577],U=[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13],T=[16,17,18, [...]
++10,5,11,4,12,3,13,2,14,1,15],X;this.inflate=function(F,T){p.length=65536;c=a=k=0;l=-1;f=!1;v=w=0;z=null;s=F;y=0;var G=new Uint8Array(new ArrayBuffer(T));a:for(var J=0,Q;J<T&&(!f||-1!==l);){if(0<v){if(0!==l)for(;0<v&&J<T;)v--,w&=32767,k&=32767,G[0+J]=p[k]=p[w],J+=1,k+=1,w+=1;else{for(;0<v&&J<T;)v-=1,k&=32767,h(8),G[0+J]=p[k]=b(8),J+=1,k+=1,g(8);0===v&&(l=-1)}if(J===T)break}if(-1===l){if(f)break;h(1);0!==b(1)&&(f=!0);g(1);h(2);l=b(2);g(2);z=null;v=0}switch(l){case 0:Q=G;var ea=0+J,P=T-J,N [...]
++c&7;g(N);h(16);N=b(16);g(16);h(16);if(N!==(~a&65535))Q=-1;else{g(16);v=N;for(N=0;0<v&&N<P;)v--,k&=32767,h(8),Q[ea+N++]=p[k++]=b(8),g(8);0===v&&(l=-1);Q=N}break;case 1:if(null!==z)Q=d(G,0+J,T-J);else b:{Q=G;ea=0+J;P=T-J;if(null===q){for(var I=void 0,N=Array(288),I=void 0,I=0;144>I;I++)N[I]=8;for(I=144;256>I;I++)N[I]=9;for(I=256;280>I;I++)N[I]=7;for(I=280;288>I;I++)N[I]=8;r=7;I=new m(N,288,257,L,O,r);if(0!==I.status){alert("HufBuild error: "+I.status);Q=-1;break b}q=I.root;r=I.m;for(I=0;3 [...]
++5;X=5;I=new m(N,30,0,H,U,X);if(1<I.status){q=null;alert("HufBuild error: "+I.status);Q=-1;break b}e=I.root;X=I.m}z=q;x=e;t=r;u=X;Q=d(Q,ea,P)}break;case 2:Q=null!==z?d(G,0+J,T-J):n(G,0+J,T-J);break;default:Q=-1}if(-1===Q)break a;J+=Q}s=new Uint8Array(new ArrayBuffer(0));return G}};
++// Input 16
++core.ScheduledTask=function(m,h){function b(){n&&(runtime.clearTimeout(d),n=!1)}function g(){b();m.apply(void 0,p);p=null}var d,n=!1,p=[];this.trigger=function(){p=Array.prototype.slice.call(arguments);n||(n=!0,d=runtime.setTimeout(g,h))};this.triggerImmediate=function(){p=Array.prototype.slice.call(arguments);g()};this.processRequests=function(){n&&g()};this.cancel=b;this.destroy=function(d){b();d()}};
++// Input 17
++/*
++
++ Copyright (C) 2014 KO GmbH <copyright at kogmbh.com>
++
++ @licstart
++ The JavaScript code in this page is free software: you can redistribute it
++ and/or modify it under the terms of the GNU Affero General Public License
++ (GNU AGPL) as published by the Free Software Foundation, either version 3 of
++ the License, or (at your option) any later version.  The code is distributed
++ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
++
++ You should have received a copy of the GNU Affero General Public License
++ along with this code.  If not, see <http://www.gnu.org/licenses/>.
++
++ As additional permission under GNU AGPL version 3 section 7, you
++ may distribute non-source (e.g., minimized or compacted) forms of
++ that code without the copy of the GNU GPL normally required by
++ section 4, provided you include this license notice and a URL
++ through which recipients can access the Corresponding Source.
++
++ As a special exception to the AGPL, any HTML file which merely makes function
++ calls to this code, and for that purpose includes it by reference shall be
++ deemed a separate work for copyright law purposes. In addition, the copyright
++ holders of this code give you permission to combine this code with free
++ software libraries that are released under the GNU LGPL. You may copy and
++ distribute such a system following the terms of the GNU AGPL for this code
++ and the LGPL for the libraries. If you modify this code, you may extend this
++ exception to your version of the code, but you are not obligated to do so.
++ If you do not wish to do so, delete this exception statement from your
++ version.
++
++ This license applies to this entire compilation.
++ @licend
++ @source: http://www.webodf.org/
++ @source: https://github.com/kogmbh/WebODF/
++*/
++core.StepIterator=function(m,h){function b(){r=null;c=a=void 0}function g(){void 0===c&&(c=m.acceptPosition(h)===e);return c}function d(a,c){b();return h.setUnfilteredPosition(a,c)}function n(){r||(r=h.container());return r}function p(){void 0===a&&(a=h.unfilteredDomOffset());return a}function k(){for(b();h.nextPosition();)if(b(),g())return!0;return!1}function q(){for(b();h.previousPosition();)if(b(),g())return!0;return!1}var e=core.PositionFilter.FilterResult.FILTER_ACCEPT,r,a,c;this.i [...]
++d;this.container=n;this.offset=p;this.nextStep=k;this.previousStep=q;this.roundToClosestStep=function(){var a=n(),c=p(),b=g();b||(b=q(),b||(d(a,c),b=k()));return b};this.roundToPreviousStep=function(){var a=g();a||(a=q());return a};this.roundToNextStep=function(){var a=g();a||(a=k());return a}};
++// Input 18
++core.UnitTest=function(){};core.UnitTest.prototype.setUp=function(){};core.UnitTest.prototype.tearDown=function(){};core.UnitTest.prototype.description=function(){};core.UnitTest.prototype.tests=function(){};core.UnitTest.prototype.asyncTests=function(){};
++core.UnitTest.provideTestAreaDiv=function(){var m=runtime.getWindow().document,h=m.getElementById("testarea");runtime.assert(!h,'Unclean test environment, found a div with id "testarea".');h=m.createElement("div");h.setAttribute("id","testarea");m.body.appendChild(h);return h};
++core.UnitTest.cleanupTestAreaDiv=function(){var m=runtime.getWindow().document,h=m.getElementById("testarea");runtime.assert(!!h&&h.parentNode===m.body,'Test environment broken, found no div with id "testarea" below body.');m.body.removeChild(h)};core.UnitTest.createOdtDocument=function(m,h){var b="<?xml version='1.0' encoding='UTF-8'?>",b=b+"<office:document";Object.keys(h).forEach(function(g){b+=" xmlns:"+g+'="'+h[g]+'"'});b+=">";b+=m;b+="</office:document>";return runtime.parseXML(b)};
++core.UnitTestLogger=function(){var m=[],h=0,b=0,g="",d="";this.startTest=function(n,p){m=[];h=0;g=n;d=p;b=(new Date).getTime()};this.endTest=function(){var n=(new Date).getTime();return{description:d,suite:[g,d],success:0===h,log:m,time:n-b}};this.debug=function(b){m.push({category:"debug",message:b})};this.fail=function(b){h+=1;m.push({category:"fail",message:b})};this.pass=function(b){m.push({category:"pass",message:b})}};
++core.UnitTestRunner=function(m,h){function b(c){q+=1;a?h.debug(c):h.fail(c)}function g(a,l){var f;try{if(a.length!==l.length)return b("array of length "+a.length+" should be "+l.length+" long"),!1;for(f=0;f<a.length;f+=1)if(a[f]!==l[f])return b(a[f]+" should be "+l[f]+" at array index "+f),!1}catch(d){return!1}return!0}function d(a,l,f){var e=a.attributes,k=e.length,g,n,h;for(g=0;g<k;g+=1)if(n=e.item(g),"xmlns"!==n.prefix&&"urn:webodf:names:steps"!==n.namespaceURI){h=l.getAttributeNS(n. [...]
++n.localName);if(!l.hasAttributeNS(n.namespaceURI,n.localName))return b("Attribute "+n.localName+" with value "+n.value+" was not present"),!1;if(h!==n.value)return b("Attribute "+n.localName+" was "+h+" should be "+n.value),!1}return f?!0:d(l,a,!0)}function n(a,l){var f,e;f=a.nodeType;e=l.nodeType;if(f!==e)return b("Nodetype '"+f+"' should be '"+e+"'"),!1;if(f===Node.TEXT_NODE){if(a.data===l.data)return!0;b("Textnode data '"+a.data+"' should be '"+l.data+"'");return!1}runtime.assert(f== [...]
++"Only textnodes and elements supported.");if(a.namespaceURI!==l.namespaceURI)return b("namespace '"+a.namespaceURI+"' should be '"+l.namespaceURI+"'"),!1;if(a.localName!==l.localName)return b("localName '"+a.localName+"' should be '"+l.localName+"'"),!1;if(!d(a,l,!1))return!1;f=a.firstChild;for(e=l.firstChild;f;){if(!e)return b("Nodetype '"+f.nodeType+"' is unexpected here."),!1;if(!n(f,e))return!1;f=f.nextSibling;e=e.nextSibling}return e?(b("Nodetype '"+e.nodeType+"' is missing here.") [...]
++b){return 0===b?a===b&&1/a===1/b:a===b?!0:null===a||null===b?!1:"number"===typeof b&&isNaN(b)?"number"===typeof a&&isNaN(a):Object.prototype.toString.call(b)===Object.prototype.toString.call([])?g(a,b):"object"===typeof b&&"object"===typeof a?b.constructor===Element||b.constructor===Node?n(a,b):r(a,b):!1}function k(a,l,f){"string"===typeof l&&"string"===typeof f||h.debug("WARN: shouldBe() expects string arguments");var d,e;try{e=eval(l)}catch(k){d=k}a=eval(f);d?b(l+" should be "+a+". Th [...]
++d):p(e,a)?h.pass(l+" is "+f):String(typeof e)===String(typeof a)?(f=0===e&&0>1/e?"-0":String(e),b(l+" should be "+a+". Was "+f+".")):b(l+" should be "+a+" (of type "+typeof a+"). Was "+e+" (of type "+typeof e+").")}var q=0,e,r,a=!1;this.resourcePrefix=function(){return m};this.beginExpectFail=function(){e=q;a=!0};this.endExpectFail=function(){var c=e===q;a=!1;q=e;c&&(q+=1,h.fail("Expected at least one failed test, but none registered."))};r=function(a,l){var f=Object.keys(a),d=Object.ke [...]
++d.sort();return g(f,d)&&Object.keys(a).every(function(f){var d=a[f],e=l[f];return p(d,e)?!0:(b(d+" should be "+e+" for key "+f),!1)})};this.areNodesEqual=n;this.shouldBeNull=function(a,b){k(a,b,"null")};this.shouldBeNonNull=function(a,l){var f,d;try{d=eval(l)}catch(e){f=e}f?b(l+" should be non-null. Threw exception "+f):null!==d?h.pass(l+" is non-null."):b(l+" should be non-null. Was "+d)};this.shouldBe=k;this.testFailed=b;this.countFailedTests=function(){return q};this.name=function(a) [...]
++[],e=a.length;d.length=e;for(b=0;b<e;b+=1){f=Runtime.getFunctionName(a[b])||"";if(""===f)throw"Found a function without a name.";d[b]={f:a[b],name:f}}return d}};
++core.UnitTester=function(){function m(b,d){return"<span style='color:blue;cursor:pointer' onclick='"+d+"'>"+b+"</span>"}function h(d){b.reporter&&b.reporter(d)}var b=this,g=0,d=new core.UnitTestLogger,n={},p="BrowserRuntime"===runtime.type();this.resourcePrefix="";this.reporter=function(b){var d,e;p?runtime.log("<span>Running "+m(b.description,'runTest("'+b.suite[0]+'","'+b.description+'")')+"</span>"):runtime.log("Running "+b.description);if(!b.success)for(d=0;d<b.log.length;d+=1)e=b.l [...]
++e.message)};this.runTests=function(k,q,e){function r(b){if(0===b.length)n[a]=f,g+=c.countFailedTests(),q();else{w=b[0].f;var k=b[0].name,p=!0===b[0].expectFail;t=c.countFailedTests();e.length&&-1===e.indexOf(k)?r(b.slice(1)):(l.setUp(),d.startTest(a,k),p&&c.beginExpectFail(),w(function(){p&&c.endExpectFail();h(d.endTest());l.tearDown();f[k]=t===c.countFailedTests();r(b.slice(1))}))}}var a=Runtime.getFunctionName(k)||"",c=new core.UnitTestRunner(b.resourcePrefix,d),l=new k(c),f={},v,w,z, [...]
++a+" has already run.");else{p?runtime.log("<span>Running "+m(a,'runSuite("'+a+'");')+": "+l.description()+"</span>"):runtime.log("Running "+a+": "+l.description);z=l.tests();for(v=0;v<z.length;v+=1)if(w=z[v].f,k=z[v].name,x=!0===z[v].expectFail,!e.length||-1!==e.indexOf(k)){t=c.countFailedTests();l.setUp();d.startTest(a,k);x&&c.beginExpectFail();try{w()}catch(u){c.testFailed("Unexpected exception encountered: "+u.toString()+"\n"+u.stack)}x&&c.endExpectFail();h(d.endTest());l.tearDown(); [...]
++this.countFailedTests=function(){return g};this.results=function(){return n}};
++// Input 19
++core.Utils=function(){function m(h,b){if(b&&Array.isArray(b)){h=h||[];if(!Array.isArray(h))throw"Destination is not an array.";h=h.concat(b.map(function(b){return m(null,b)}))}else if(b&&"object"===typeof b){h=h||{};if("object"!==typeof h)throw"Destination is not an object.";Object.keys(b).forEach(function(g){h[g]=m(h[g],b[g])})}else h=b;return h}this.hashString=function(h){var b=0,g,d;g=0;for(d=h.length;g<d;g+=1)b=(b<<5)-b+h.charCodeAt(g),b|=0;return b};this.mergeObjects=function(h,b){ [...]
++m(h[g],b[g])});return h}};
++// Input 20
 +/*
 +
 + WebODF
 + Copyright (c) 2010 Jos van den Oever
 + Licensed under the ... License:
 +
 + Project home: http://www.webodf.org/
 +*/
- runtime.loadClass("core.RawInflate");runtime.loadClass("core.ByteArray");runtime.loadClass("core.ByteArrayWriter");runtime.loadClass("core.Base64");
- core.Zip=function(g,l){function f(a){var b=[0,1996959894,3993919788,2567524794,124634137,1886057615,3915621685,2657392035,249268274,2044508324,3772115230,2547177864,162941995,2125561021,3887607047,2428444049,498536548,1789927666,4089016648,2227061214,450548861,1843258603,4107580753,2211677639,325883990,1684777152,4251122042,2321926636,335633487,1661365465,4195302755,2366115317,997073096,1281953886,3579855332,2724688242,1006888145,1258607687,3524101629,2768942443,901097722,1119000684,368 [...]
++core.Zip=function(m,h){function b(a){var c=[0,1996959894,3993919788,2567524794,124634137,1886057615,3915621685,2657392035,249268274,2044508324,3772115230,2547177864,162941995,2125561021,3887607047,2428444049,498536548,1789927666,4089016648,2227061214,450548861,1843258603,4107580753,2211677639,325883990,1684777152,4251122042,2321926636,335633487,1661365465,4195302755,2366115317,997073096,1281953886,3579855332,2724688242,1006888145,1258607687,3524101629,2768942443,901097722,1119000684,368 [...]
 +853044451,1172266101,3705015759,2882616665,651767980,1373503546,3369554304,3218104598,565507253,1454621731,3485111705,3099436303,671266974,1594198024,3322730930,2970347812,795835527,1483230225,3244367275,3060149565,1994146192,31158534,2563907772,4023717930,1907459465,112637215,2680153253,3904427059,2013776290,251722036,2517215374,3775830040,2137656763,141376813,2439277719,3865271297,1802195444,476864866,2238001368,4066508878,1812370925,453092731,2181625025,4111451223,1706088902,31404270 [...]
 +4240017532,1658658271,366619977,2362670323,4224994405,1303535960,984961486,2747007092,3569037538,1256170817,1037604311,2765210733,3554079995,1131014506,879679996,2909243462,3663771856,1141124467,855842277,2852801631,3708648649,1342533948,654459306,3188396048,3373015174,1466479909,544179635,3110523913,3462522015,1591671054,702138776,2966460450,3352799412,1504918807,783551873,3082640443,3233442989,3988292384,2596254646,62317068,1957810842,3939845945,2647816111,81470997,1943803523,38149189 [...]
 +225274430,2053790376,3826175755,2466906013,167816743,2097651377,4027552580,2265490386,503444072,1762050814,4150417245,2154129355,426522225,1852507879,4275313526,2312317920,282753626,1742555852,4189708143,2394877945,397917763,1622183637,3604390888,2714866558,953729732,1340076626,3518719985,2797360999,1068828381,1219638859,3624741850,2936675148,906185462,1090812512,3747672003,2825379669,829329135,1181335161,3412177804,3160834842,628085408,1382605366,3423369109,3138078467,570562233,1426400 [...]
 +2998733608,733239954,1555261956,3268935591,3050360625,752459403,1541320221,2607071920,3965973030,1969922972,40735498,2617837225,3943577151,1913087877,83908371,2512341634,3803740692,2075208622,213261112,2463272603,3855990285,2094854071,198958881,2262029012,4057260610,1759359992,534414190,2176718541,4139329115,1873836001,414664567,2282248934,4279200368,1711684554,285281116,2405801727,4167216745,1634467795,376229701,2685067896,3608007406,1308918612,956543938,2808555105,3495958263,123163630 [...]
- 2932959818,3654703836,1088359270,936918E3,2847714899,3736837829,1202900863,817233897,3183342108,3401237130,1404277552,615818150,3134207493,3453421203,1423857449,601450431,3009837614,3294710456,1567103746,711928724,3020668471,3272380065,1510334235,755167117],c,e,d=a.length,q=0,q=0;c=-1;for(e=0;e<d;e+=1)q=(c^a[e])&255,q=b[q],c=c>>>8^q;return c^-1}function p(a){return new Date((a>>25&127)+1980,(a>>21&15)-1,a>>16&31,a>>11&15,a>>5&63,(a&31)<<1)}function r(a){var b=a.getFullYear();return 1980 [...]
- 25|a.getMonth()+1<<21|a.getDate()<<16|a.getHours()<<11|a.getMinutes()<<5|a.getSeconds()>>1}function n(a,b){var c,e,d,q,f,h,g,m=this;this.load=function(b){if(null!==m.data)b(null,m.data);else{var c=f+34+e+d+256;c+g>k&&(c=k-g);runtime.read(a,g,c,function(c,e){if(c||null===e)b(c,e);else a:{var d=e,k=new core.ByteArray(d),g=k.readUInt32LE(),s;if(67324752!==g)b("File entry signature is wrong."+g.toString()+" "+d.length.toString(),null);else{k.pos+=22;g=k.readUInt16LE();s=k.readUInt16LE();k.p [...]
- d.subarray(k.pos,k.pos+f);if(f!==d.length){b("The amount of compressed bytes read was "+d.length.toString()+" instead of "+f.toString()+" for "+m.filename+" in "+a+".",null);break a}d=A(d,h)}else d=d.subarray(k.pos,k.pos+h);h!==d.length?b("The amount of bytes read was "+d.length.toString()+" instead of "+h.toString()+" for "+m.filename+" in "+a+".",null):(m.data=d,b(null,d))}}})}};this.set=function(a,b,c,e){m.filename=a;m.data=b;m.compressed=c;m.date=e};this.error=null;b&&(c=b.readUInt3 [...]
- c?this.error="Central directory entry has wrong signature at position "+(b.pos-4).toString()+' for file "'+a+'": '+b.data.length.toString():(b.pos+=6,q=b.readUInt16LE(),this.date=p(b.readUInt32LE()),b.readUInt32LE(),f=b.readUInt32LE(),h=b.readUInt32LE(),e=b.readUInt16LE(),d=b.readUInt16LE(),c=b.readUInt16LE(),b.pos+=8,g=b.readUInt32LE(),this.filename=runtime.byteArrayToString(b.data.subarray(b.pos,b.pos+e),"utf8"),this.data=null,b.pos+=e+d+c))}function h(a,b){if(22!==a.length)b("Central [...]
- w);else{var c=new core.ByteArray(a),e;e=c.readUInt32LE();101010256!==e?b("Central directory signature is wrong: "+e.toString(),w):(e=c.readUInt16LE(),0!==e?b("Zip files with non-zero disk numbers are not supported.",w):(e=c.readUInt16LE(),0!==e?b("Zip files with non-zero disk numbers are not supported.",w):(e=c.readUInt16LE(),t=c.readUInt16LE(),e!==t?b("Number of entries is inconsistent.",w):(e=c.readUInt32LE(),c=c.readUInt16LE(),c=k-22-e,runtime.read(g,c,k-c,function(a,c){if(a||null=== [...]
- new core.ByteArray(c),d,f;q=[];for(d=0;d<t;d+=1){f=new n(g,e);if(f.error){b(f.error,w);break a}q[q.length]=f}b(null,w)}})))))}}function d(a,b){var c=null,e,d;for(d=0;d<q.length;d+=1)if(e=q[d],e.filename===a){c=e;break}c?c.data?b(null,c.data):c.load(b):b(a+" not found.",null)}function m(a){var b=new core.ByteArrayWriter("utf8"),c=0;b.appendArray([80,75,3,4,20,0,0,0,0,0]);a.data&&(c=a.data.length);b.appendUInt32LE(r(a.date));b.appendUInt32LE(a.data?f(a.data):0);b.appendUInt32LE(c);b.appen [...]
- b.appendUInt16LE(a.filename.length);b.appendUInt16LE(0);b.appendString(a.filename);a.data&&b.appendByteArray(a.data);return b}function c(a,b){var c=new core.ByteArrayWriter("utf8"),e=0;c.appendArray([80,75,1,2,20,0,20,0,0,0,0,0]);a.data&&(e=a.data.length);c.appendUInt32LE(r(a.date));c.appendUInt32LE(a.data?f(a.data):0);c.appendUInt32LE(e);c.appendUInt32LE(e);c.appendUInt16LE(a.filename.length);c.appendArray([0,0,0,0,0,0,0,0,0,0,0,0]);c.appendUInt32LE(b);c.appendString(a.filename);return [...]
- b){if(a===q.length)b(null);else{var c=q[a];null!==c.data?e(a+1,b):c.load(function(c){c?b(c):e(a+1,b)})}}function a(a,b){e(0,function(e){if(e)b(e);else{var d,f,k=new core.ByteArrayWriter("utf8"),h=[0];for(d=0;d<q.length;d+=1)k.appendByteArrayWriter(m(q[d])),h.push(k.getLength());e=k.getLength();for(d=0;d<q.length;d+=1)f=q[d],k.appendByteArrayWriter(c(f,h[d]));d=k.getLength()-e;k.appendArray([80,75,5,6,0,0,0,0]);k.appendUInt16LE(q.length);k.appendUInt16LE(q.length);k.appendUInt32LE(d);k.a [...]
- k.appendArray([0,0]);a(k.getByteArray())}})}function b(b,c){a(function(a){runtime.writeFile(b,a,c)},c)}var q,k,t,A=(new core.RawInflate).inflate,w=this,x=new core.Base64;this.load=d;this.save=function(a,b,c,e){var d,f;for(d=0;d<q.length;d+=1)if(f=q[d],f.filename===a){f.set(a,b,c,e);return}f=new n(g);f.set(a,b,c,e);q.push(f)};this.remove=function(a){var b,c;for(b=0;b<q.length;b+=1)if(c=q[b],c.filename===a)return q.splice(b,1),!0;return!1};this.write=function(a){b(g,a)};this.writeAs=b;thi [...]
- a;this.loadContentXmlAsFragments=function(a,b){w.loadAsString(a,function(a,c){if(a)return b.rootElementReady(a);b.rootElementReady(null,c,!0)})};this.loadAsString=function(a,b){d(a,function(a,c){if(a||null===c)return b(a,null);var e=runtime.byteArrayToString(c,"utf8");b(null,e)})};this.loadAsDOM=function(a,b){w.loadAsString(a,function(a,c){if(a||null===c)b(a,null);else{var e=(new DOMParser).parseFromString(c,"text/xml");b(null,e)}})};this.loadAsDataURL=function(a,b,c){d(a,function(a,e){ [...]
- null);var d=0,f;b||(b=80===e[1]&&78===e[2]&&71===e[3]?"image/png":255===e[0]&&216===e[1]&&255===e[2]?"image/jpeg":71===e[0]&&73===e[1]&&70===e[2]?"image/gif":"");for(f="data:"+b+";base64,";d<e.length;)f+=x.convertUTF8ArrayToBase64(e.subarray(d,Math.min(d+45E3,e.length))),d+=45E3;c(null,f)})};this.getEntries=function(){return q.slice()};k=-1;null===l?q=[]:runtime.getFileSize(g,function(a){k=a;0>k?l("File '"+g+"' cannot be read.",w):runtime.read(g,k-22,22,function(a,b){a||null===l||null== [...]
- h(b,l)})})};
- // Input 16
- gui.Avatar=function(g,l){var f=this,p,r,n;this.setColor=function(f){r.style.borderColor=f};this.setImageUrl=function(h){f.isVisible()?r.src=h:n=h};this.isVisible=function(){return"block"===p.style.display};this.show=function(){n&&(r.src=n,n=void 0);p.style.display="block"};this.hide=function(){p.style.display="none"};this.markAsFocussed=function(f){p.className=f?"active":""};this.destroy=function(f){g.removeChild(p);f()};(function(){var f=g.ownerDocument,d=f.documentElement.namespaceURI [...]
- "div");r=f.createElementNS(d,"img");r.width=64;r.height=64;p.appendChild(r);p.style.width="64px";p.style.height="70px";p.style.position="absolute";p.style.top="-80px";p.style.left="-34px";p.style.display=l?"block":"none";g.appendChild(p)})()};
- // Input 17
- gui.EditInfoHandle=function(g){var l=[],f,p=g.ownerDocument,r=p.documentElement.namespaceURI;this.setEdits=function(g){l=g;var h,d,m,c;f.innerHTML="";for(g=0;g<l.length;g+=1)h=p.createElementNS(r,"div"),h.className="editInfo",d=p.createElementNS(r,"span"),d.className="editInfoColor",d.setAttributeNS("urn:webodf:names:editinfo","editinfo:memberid",l[g].memberid),m=p.createElementNS(r,"span"),m.className="editInfoAuthor",m.setAttributeNS("urn:webodf:names:editinfo","editinfo:memberid",l[g [...]
- c=p.createElementNS(r,"span"),c.className="editInfoTime",c.setAttributeNS("urn:webodf:names:editinfo","editinfo:memberid",l[g].memberid),c.innerHTML=l[g].time,h.appendChild(d),h.appendChild(m),h.appendChild(c),f.appendChild(h)};this.show=function(){f.style.display="block"};this.hide=function(){f.style.display="none"};this.destroy=function(l){g.removeChild(f);l()};f=p.createElementNS(r,"div");f.setAttribute("class","editInfoHandle");f.style.display="none";g.appendChild(f)};
- // Input 18
++2932959818,3654703836,1088359270,936918E3,2847714899,3736837829,1202900863,817233897,3183342108,3401237130,1404277552,615818150,3134207493,3453421203,1423857449,601450431,3009837614,3294710456,1567103746,711928724,3020668471,3272380065,1510334235,755167117],b,f,d=a.length,l=0,l=0;b=-1;for(f=0;f<d;f+=1)l=(b^a[f])&255,l=c[l],b=b>>>8^l;return b^-1}function g(a){return new Date((a>>25&127)+1980,(a>>21&15)-1,a>>16&31,a>>11&15,a>>5&63,(a&31)<<1)}function d(a){var c=a.getFullYear();return 1980 [...]
++25|a.getMonth()+1<<21|a.getDate()<<16|a.getHours()<<11|a.getMinutes()<<5|a.getSeconds()>>1}function n(a,c){var b,d,l,e,k,n,h,p=this;this.load=function(c){if(null!==p.data)c(null,p.data);else{var b=k+34+d+l+256;b+h>f&&(b=f-h);runtime.read(a,h,b,function(b,f){if(b||null===f)c(b,f);else a:{var d=f,l=new core.ByteArray(d),g=l.readUInt32LE(),h;if(67324752!==g)c("File entry signature is wrong."+g.toString()+" "+d.length.toString(),null);else{l.pos+=22;g=l.readUInt16LE();h=l.readUInt16LE();l.p [...]
++d.subarray(l.pos,l.pos+k);if(k!==d.length){c("The amount of compressed bytes read was "+d.length.toString()+" instead of "+k.toString()+" for "+p.filename+" in "+a+".",null);break a}d=w(d,n)}else d=d.subarray(l.pos,l.pos+n);n!==d.length?c("The amount of bytes read was "+d.length.toString()+" instead of "+n.toString()+" for "+p.filename+" in "+a+".",null):(p.data=d,c(null,d))}}})}};this.set=function(a,c,b,d){p.filename=a;p.data=c;p.compressed=b;p.date=d};this.error=null;c&&(b=c.readUInt3 [...]
++b?this.error="Central directory entry has wrong signature at position "+(c.pos-4).toString()+' for file "'+a+'": '+c.data.length.toString():(c.pos+=6,e=c.readUInt16LE(),this.date=g(c.readUInt32LE()),c.readUInt32LE(),k=c.readUInt32LE(),n=c.readUInt32LE(),d=c.readUInt16LE(),l=c.readUInt16LE(),b=c.readUInt16LE(),c.pos+=8,h=c.readUInt32LE(),this.filename=runtime.byteArrayToString(c.data.subarray(c.pos,c.pos+d),"utf8"),this.data=null,c.pos+=d+l+b))}function p(a,c){if(22!==a.length)c("Central [...]
++z);else{var b=new core.ByteArray(a),d;d=b.readUInt32LE();101010256!==d?c("Central directory signature is wrong: "+d.toString(),z):(d=b.readUInt16LE(),0!==d?c("Zip files with non-zero disk numbers are not supported.",z):(d=b.readUInt16LE(),0!==d?c("Zip files with non-zero disk numbers are not supported.",z):(d=b.readUInt16LE(),v=b.readUInt16LE(),d!==v?c("Number of entries is inconsistent.",z):(d=b.readUInt32LE(),b=b.readUInt16LE(),b=f-22-d,runtime.read(m,b,f-b,function(a,b){if(a||null=== [...]
++new core.ByteArray(b),f,e;l=[];for(f=0;f<v;f+=1){e=new n(m,d);if(e.error){c(e.error,z);break a}l[l.length]=e}c(null,z)}})))))}}function k(a,c){var b=null,d,f;for(f=0;f<l.length;f+=1)if(d=l[f],d.filename===a){b=d;break}b?b.data?c(null,b.data):b.load(c):c(a+" not found.",null)}function q(a){var c=new core.ByteArrayWriter("utf8"),f=0;c.appendArray([80,75,3,4,20,0,0,0,0,0]);a.data&&(f=a.data.length);c.appendUInt32LE(d(a.date));c.appendUInt32LE(a.data?b(a.data):0);c.appendUInt32LE(f);c.appen [...]
++c.appendUInt16LE(a.filename.length);c.appendUInt16LE(0);c.appendString(a.filename);a.data&&c.appendByteArray(a.data);return c}function e(a,c){var f=new core.ByteArrayWriter("utf8"),l=0;f.appendArray([80,75,1,2,20,0,20,0,0,0,0,0]);a.data&&(l=a.data.length);f.appendUInt32LE(d(a.date));f.appendUInt32LE(a.data?b(a.data):0);f.appendUInt32LE(l);f.appendUInt32LE(l);f.appendUInt16LE(a.filename.length);f.appendArray([0,0,0,0,0,0,0,0,0,0,0,0]);f.appendUInt32LE(c);f.appendString(a.filename);return [...]
++c){if(a===l.length)c(null);else{var b=l[a];null!==b.data?r(a+1,c):b.load(function(b){b?c(b):r(a+1,c)})}}function a(a,c){r(0,function(b){if(b)c(b);else{var d,f,g=new core.ByteArrayWriter("utf8"),k=[0];for(d=0;d<l.length;d+=1)g.appendByteArrayWriter(q(l[d])),k.push(g.getLength());b=g.getLength();for(d=0;d<l.length;d+=1)f=l[d],g.appendByteArrayWriter(e(f,k[d]));d=g.getLength()-b;g.appendArray([80,75,5,6,0,0,0,0]);g.appendUInt16LE(l.length);g.appendUInt16LE(l.length);g.appendUInt32LE(d);g.a [...]
++g.appendArray([0,0]);a(g.getByteArray())}})}function c(c,b){a(function(a){runtime.writeFile(c,a,b)},b)}var l,f,v,w=(new core.RawInflate).inflate,z=this,x=new core.Base64;this.load=k;this.save=function(a,c,b,d){var f,e;for(f=0;f<l.length;f+=1)if(e=l[f],e.filename===a){e.set(a,c,b,d);return}e=new n(m);e.set(a,c,b,d);l.push(e)};this.remove=function(a){var c,b;for(c=0;c<l.length;c+=1)if(b=l[c],b.filename===a)return l.splice(c,1),!0;return!1};this.write=function(a){c(m,a)};this.writeAs=c;thi [...]
++a;this.loadContentXmlAsFragments=function(a,c){z.loadAsString(a,function(a,b){if(a)return c.rootElementReady(a);c.rootElementReady(null,b,!0)})};this.loadAsString=function(a,c){k(a,function(a,b){if(a||null===b)return c(a,null);var d=runtime.byteArrayToString(b,"utf8");c(null,d)})};this.loadAsDOM=function(a,c){z.loadAsString(a,function(a,b){if(a||null===b)c(a,null);else{var d=(new DOMParser).parseFromString(b,"text/xml");c(null,d)}})};this.loadAsDataURL=function(a,c,b){k(a,function(a,d){ [...]
++null);var f=0,l;c||(c=80===d[1]&&78===d[2]&&71===d[3]?"image/png":255===d[0]&&216===d[1]&&255===d[2]?"image/jpeg":71===d[0]&&73===d[1]&&70===d[2]?"image/gif":"");for(l="data:"+c+";base64,";f<d.length;)l+=x.convertUTF8ArrayToBase64(d.subarray(f,Math.min(f+45E3,d.length))),f+=45E3;b(null,l)})};this.getEntries=function(){return l.slice()};f=-1;null===h?l=[]:runtime.getFileSize(m,function(a){f=a;0>f?h("File '"+m+"' cannot be read.",z):runtime.read(m,f-22,22,function(a,c){a||null===h||null== [...]
++p(c,h)})})};
++// Input 21
++xmldom.LSSerializerFilter=function(){};xmldom.LSSerializerFilter.prototype.acceptNode=function(m){};
++// Input 22
 +/*
 +
-  Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
++ Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- gui.KeyboardHandler=function(){function g(f,g){g||(g=l.None);return f+":"+g}var l=gui.KeyboardHandler.Modifier,f=null,p={};this.setDefault=function(g){f=g};this.bind=function(f,l,h){f=g(f,l);runtime.assert(!1===p.hasOwnProperty(f),"tried to overwrite the callback handler of key combo: "+f);p[f]=h};this.unbind=function(f,l){var h=g(f,l);delete p[h]};this.reset=function(){f=null;p={}};this.handleEvent=function(r){var n=r.keyCode,h=l.None;r.metaKey&&(h|=l.Meta);r.ctrlKey&&(h|=l.Ctrl);r.alt [...]
- r.shiftKey&&(h|=l.Shift);n=g(n,h);n=p[n];h=!1;n?h=n():null!==f&&(h=f(r));h&&(r.preventDefault?r.preventDefault():r.returnValue=!1)}};gui.KeyboardHandler.Modifier={None:0,Meta:1,Ctrl:2,Alt:4,CtrlAlt:6,Shift:8,MetaShift:9,CtrlShift:10,AltShift:12};gui.KeyboardHandler.KeyCode={Backspace:8,Tab:9,Clear:12,Enter:13,End:35,Home:36,Left:37,Up:38,Right:39,Down:40,Delete:46,A:65,B:66,C:67,D:68,E:69,F:70,G:71,H:72,I:73,J:74,K:75,L:76,M:77,N:78,O:79,P:80,Q:81,R:82,S:83,T:84,U:85,V:86,W:87,X:88,Y:89 [...]
- // Input 19
++odf.OdfNodeFilter=function(){this.acceptNode=function(m){return"http://www.w3.org/1999/xhtml"===m.namespaceURI?NodeFilter.FILTER_SKIP:m.namespaceURI&&m.namespaceURI.match(/^urn:webodf:/)?NodeFilter.FILTER_REJECT:NodeFilter.FILTER_ACCEPT}};
++// Input 23
 +/*
 +
 + Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
 +odf.Namespaces={namespaceMap:{db:"urn:oasis:names:tc:opendocument:xmlns:database:1.0",dc:"http://purl.org/dc/elements/1.1/",dr3d:"urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0",draw:"urn:oasis:names:tc:opendocument:xmlns:drawing:1.0",chart:"urn:oasis:names:tc:opendocument:xmlns:chart:1.0",fo:"urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0",form:"urn:oasis:names:tc:opendocument:xmlns:form:1.0",meta:"urn:oasis:names:tc:opendocument:xmlns:meta:1.0",number:"urn:oasis:names:tc: [...]
 +office:"urn:oasis:names:tc:opendocument:xmlns:office:1.0",presentation:"urn:oasis:names:tc:opendocument:xmlns:presentation:1.0",style:"urn:oasis:names:tc:opendocument:xmlns:style:1.0",svg:"urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0",table:"urn:oasis:names:tc:opendocument:xmlns:table:1.0",text:"urn:oasis:names:tc:opendocument:xmlns:text:1.0",xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace"},prefixMap:{},dbns:"urn:oasis:names:tc:opendocument:xm [...]
 +dcns:"http://purl.org/dc/elements/1.1/",dr3dns:"urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0",drawns:"urn:oasis:names:tc:opendocument:xmlns:drawing:1.0",chartns:"urn:oasis:names:tc:opendocument:xmlns:chart:1.0",fons:"urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0",formns:"urn:oasis:names:tc:opendocument:xmlns:form:1.0",metans:"urn:oasis:names:tc:opendocument:xmlns:meta:1.0",numberns:"urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0",officens:"urn:oasis:names:tc:opendoc [...]
 +presentationns:"urn:oasis:names:tc:opendocument:xmlns:presentation:1.0",stylens:"urn:oasis:names:tc:opendocument:xmlns:style:1.0",svgns:"urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0",tablens:"urn:oasis:names:tc:opendocument:xmlns:table:1.0",textns:"urn:oasis:names:tc:opendocument:xmlns:text:1.0",xlinkns:"http://www.w3.org/1999/xlink",xmlns:"http://www.w3.org/XML/1998/namespace"};
- (function(){var g=odf.Namespaces.namespaceMap,l=odf.Namespaces.prefixMap,f;for(f in g)g.hasOwnProperty(f)&&(l[g[f]]=f)})();odf.Namespaces.forEachPrefix=function(g){var l=odf.Namespaces.namespaceMap,f;for(f in l)l.hasOwnProperty(f)&&g(f,l[f])};odf.Namespaces.lookupNamespaceURI=function(g){var l=null;odf.Namespaces.namespaceMap.hasOwnProperty(g)&&(l=odf.Namespaces.namespaceMap[g]);return l};odf.Namespaces.lookupPrefix=function(g){var l=odf.Namespaces.prefixMap;return l.hasOwnProperty(g)?l [...]
++(function(){var m=odf.Namespaces.namespaceMap,h=odf.Namespaces.prefixMap,b;for(b in m)m.hasOwnProperty(b)&&(h[m[b]]=b)})();odf.Namespaces.forEachPrefix=function(m){var h=odf.Namespaces.namespaceMap,b;for(b in h)h.hasOwnProperty(b)&&m(b,h[b])};odf.Namespaces.lookupNamespaceURI=function(m){var h=null;odf.Namespaces.namespaceMap.hasOwnProperty(m)&&(h=odf.Namespaces.namespaceMap[m]);return h};odf.Namespaces.lookupPrefix=function(m){var h=odf.Namespaces.prefixMap;return h.hasOwnProperty(m)?h [...]
 +odf.Namespaces.lookupNamespaceURI.lookupNamespaceURI=odf.Namespaces.lookupNamespaceURI;
- // Input 20
++// Input 24
++xmldom.XPathIterator=function(){};xmldom.XPathIterator.prototype.next=function(){};xmldom.XPathIterator.prototype.reset=function(){};
++function createXPathSingleton(){function m(b,a,c){return-1!==b&&(b<a||-1===a)&&(b<c||-1===c)}function h(b){for(var a=[],c=0,d=b.length,f;c<d;){var g=b,k=d,n=a,h="",p=[],q=g.indexOf("[",c),s=g.indexOf("/",c),y=g.indexOf("=",c);m(s,q,y)?(h=g.substring(c,s),c=s+1):m(q,s,y)?(h=g.substring(c,q),c=e(g,q,p)):m(y,s,q)?(h=g.substring(c,y),c=y):(h=g.substring(c,k),c=k);n.push({location:h,predicates:p});if(c<d&&"="===b[c]){f=b.substring(c+1,d);if(2<f.length&&("'"===f[0]||'"'===f[0]))f=f.slice(1,f. [...]
++else try{f=parseInt(f,10)}catch(F){}c=d}}return{steps:a,value:f}}function b(){var b=null,a=!1;this.setNode=function(a){b=a};this.reset=function(){a=!1};this.next=function(){var c=a?null:b;a=!0;return c}}function g(b,a,c){this.reset=function(){b.reset()};this.next=function(){for(var d=b.next();d;){d.nodeType===Node.ELEMENT_NODE&&(d=d.getAttributeNodeNS(a,c));if(d)break;d=b.next()}return d}}function d(b,a){var c=b.next(),d=null;this.reset=function(){b.reset();c=b.next();d=null};this.next= [...]
++d.firstChild)d=d.firstChild;else{for(;!d.nextSibling&&d!==c;)d=d.parentNode;d===c?c=b.next():d=d.nextSibling}else{do(d=c.firstChild)||(c=b.next());while(c&&!d)}if(d&&d.nodeType===Node.ELEMENT_NODE)return d}return null}}function n(b,a){this.reset=function(){b.reset()};this.next=function(){for(var c=b.next();c&&!a(c);)c=b.next();return c}}function p(b,a,c){a=a.split(":",2);var d=c(a[0]),f=a[1];return new n(b,function(a){return a.localName===f&&a.namespaceURI===d})}function k(d,a,c){var e= [...]
++a,c),g=a.value;return void 0===g?new n(d,function(a){e.setNode(a);f.reset();return null!==f.next()}):new n(d,function(a){e.setNode(a);f.reset();return(a=f.next())?a.nodeValue===g:!1})}var q,e;e=function(b,a,c){for(var d=a,f=b.length,e=0;d<f;)"]"===b[d]?(e-=1,0>=e&&c.push(h(b.substring(a,d)))):"["===b[d]&&(0>=e&&(a=d+1),e+=1),d+=1;return d};q=function(b,a,c){var e,f,n,h;for(e=0;e<a.steps.length;e+=1){n=a.steps[e];f=n.location;if(""===f)b=new d(b,!1);else if("@"===f[0]){f=f.substr(1).spli [...]
++c(f[0]);if(!h)throw"No namespace associated with the prefix "+f[0];b=new g(b,h,f[1])}else"."!==f&&(b=new d(b,!1),-1!==f.indexOf(":")&&(b=p(b,f,c)));for(f=0;f<n.predicates.length;f+=1)h=n.predicates[f],b=k(b,h,c)}return b};return{getODFElementsWithXPath:function(d,a,c){var e=d.ownerDocument,f=[],g=null;if(e&&"function"===typeof e.evaluate)for(c=e.evaluate(a,d,c,XPathResult.UNORDERED_NODE_ITERATOR_TYPE,null),g=c.iterateNext();null!==g;)g.nodeType===Node.ELEMENT_NODE&&f.push(g),g=c.iterate [...]
++new b;f.setNode(d);d=h(a);f=q(f,d,c);d=[];for(c=f.next();c;)d.push(c),c=f.next();f=d}return f}}}xmldom.XPath=createXPathSingleton();
++// Input 25
 +/*
 +
 + Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("core.DomUtils");runtime.loadClass("odf.Namespaces");
- odf.OdfUtils=function(){function g(a){return"image"===(a&&a.localName)&&a.namespaceURI===y}function l(a){return null!==a&&a.nodeType===Node.ELEMENT_NODE&&"frame"===a.localName&&a.namespaceURI===y&&"as-char"===a.getAttributeNS(H,"anchor-type")}function f(a){var b;(b="annotation"===(a&&a.localName)&&a.namespaceURI===odf.Namespaces.officens)||(b="div"===(a&&a.localName)&&"annotationWrapper"===a.className);return b}function p(a){var b=a&&a.localName;return("p"===b||"h"===b)&&a.namespaceURI= [...]
- !p(a);)a=a.parentNode;return a}function n(a){return/^[ \t\r\n]+$/.test(a)}function h(a){if(null===a||a.nodeType!==Node.ELEMENT_NODE)return!1;var b=a.localName;return/^(span|p|h|a|meta)$/.test(b)&&a.namespaceURI===H||"span"===b&&"annotationHighlight"===a.className}function d(a){var b=a&&a.localName,c=!1;b&&(a=a.namespaceURI,a===H&&(c="s"===b||"tab"===b||"line-break"===b));return c}function m(a){return d(a)||l(a)||f(a)}function c(a){var b=a&&a.localName,c=!1;b&&(a=a.namespaceURI,a===H&&(c [...]
- return c}function e(a){for(;null!==a.firstChild&&h(a);)a=a.firstChild;return a}function a(a){for(;null!==a.lastChild&&h(a);)a=a.lastChild;return a}function b(b){for(;!p(b)&&null===b.previousSibling;)b=b.parentNode;return p(b)?null:a(b.previousSibling)}function q(a){for(;!p(a)&&null===a.nextSibling;)a=a.parentNode;return p(a)?null:e(a.nextSibling)}function k(a){for(var e=!1;a;)if(a.nodeType===Node.TEXT_NODE)if(0===a.length)a=b(a);else return!n(a.data.substr(a.length-1,1));else m(a)?(e=!1 [...]
- null):a=b(a);return e}function t(a){var b=!1,c;for(a=a&&e(a);a;){c=a.nodeType===Node.TEXT_NODE?a.length:0;if(0<c&&!n(a.data)){b=!0;break}if(m(a)){b=!0;break}a=q(a)}return b}function A(a,b){return n(a.data.substr(b))?!t(q(a)):!1}function w(a,c){var e=a.data,d;if(!n(e[c])||m(a.parentNode))return!1;0<c?n(e[c-1])||(d=!0):k(b(a))&&(d=!0);return!0===d?A(a,c)?!1:!0:!1}function x(a){return(a=/(-?[0-9]*[0-9][0-9]*(\.[0-9]*)?|0+\.[0-9]*[1-9][0-9]*|\.[0-9]*[1-9][0-9]*)((cm)|(mm)|(in)|(pt)|(pc)|(px [...]
- {value:parseFloat(a[1]),unit:a[3]}:null}function v(a){return(a=x(a))&&(0>a.value||"%"===a.unit)?null:a}function u(a){return(a=x(a))&&"%"!==a.unit?null:a}function s(a){switch(a.namespaceURI){case odf.Namespaces.drawns:case odf.Namespaces.svgns:case odf.Namespaces.dr3dns:return!1;case odf.Namespaces.textns:switch(a.localName){case "note-body":case "ruby-text":return!1}break;case odf.Namespaces.officens:switch(a.localName){case "annotation":case "binary-data":case "event-listeners":return! [...]
- var H=odf.Namespaces.textns,y=odf.Namespaces.drawns,B=/^\s*$/,L=new core.DomUtils;this.isImage=g;this.isCharacterFrame=l;this.isInlineRoot=f;this.isTextSpan=function(a){return"span"===(a&&a.localName)&&a.namespaceURI===H};this.isParagraph=p;this.getParagraphElement=r;this.isWithinTrackedChanges=function(a,b){for(;a&&a!==b;){if(a.namespaceURI===H&&"tracked-changes"===a.localName)return!0;a=a.parentNode}return!1};this.isListItem=function(a){return"list-item"===(a&&a.localName)&&a.namespac [...]
- this.isLineBreak=function(a){return"line-break"===(a&&a.localName)&&a.namespaceURI===H};this.isODFWhitespace=n;this.isGroupingElement=h;this.isCharacterElement=d;this.isAnchoredAsCharacterElement=m;this.isSpaceElement=c;this.firstChild=e;this.lastChild=a;this.previousNode=b;this.nextNode=q;this.scanLeftForNonSpace=k;this.lookLeftForCharacter=function(a){var c,e=c=0;a.nodeType===Node.TEXT_NODE&&(e=a.length);0<e?(c=a.data,c=n(c.substr(e-1,1))?1===e?k(b(a))?2:0:n(c.substr(e-2,1))?0:2:1):m( [...]
- return c};this.lookRightForCharacter=function(a){var b=!1,c=0;a&&a.nodeType===Node.TEXT_NODE&&(c=a.length);0<c?b=!n(a.data.substr(0,1)):m(a)&&(b=!0);return b};this.scanLeftForAnyCharacter=function(c){var e=!1,d;for(c=c&&a(c);c;){d=c.nodeType===Node.TEXT_NODE?c.length:0;if(0<d&&!n(c.data)){e=!0;break}if(m(c)){e=!0;break}c=b(c)}return e};this.scanRightForAnyCharacter=t;this.isTrailingWhitespace=A;this.isSignificantWhitespace=w;this.isDowngradableSpaceElement=function(a){return a.namespace [...]
- a.localName?k(b(a))&&t(q(a)):!1};this.getFirstNonWhitespaceChild=function(a){for(a=a&&a.firstChild;a&&a.nodeType===Node.TEXT_NODE&&B.test(a.nodeValue);)a=a.nextSibling;return a};this.parseLength=x;this.parseNonNegativeLength=v;this.parseFoFontSize=function(a){var b;b=(b=x(a))&&(0>=b.value||"%"===b.unit)?null:b;return b||u(a)};this.parseFoLineHeight=function(a){return v(a)||u(a)};this.getImpactedParagraphs=function(a){var b,c,e;b=a.commonAncestorContainer;var d=[],f=[];for(b.nodeType===N [...]
- (d=L.getElementsByTagNameNS(b,H,"p").concat(L.getElementsByTagNameNS(b,H,"h")));b&&!p(b);)b=b.parentNode;b&&d.push(b);c=d.length;for(b=0;b<c;b+=1)e=d[b],L.rangeIntersectsNode(a,e)&&f.push(e);return f};this.getTextNodes=function(a,b){var c=a.startContainer.ownerDocument.createRange(),e;e=L.getNodesInRange(a,function(e){c.selectNodeContents(e);if(e.nodeType===Node.TEXT_NODE){if(b&&L.rangesIntersect(a,c)||L.containsRange(a,c))return Boolean(r(e)&&(!n(e.textContent)||w(e,0)))?NodeFilter.FIL [...]
- NodeFilter.FILTER_REJECT}else if(L.rangesIntersect(a,c)&&s(e))return NodeFilter.FILTER_SKIP;return NodeFilter.FILTER_REJECT});c.detach();return e};this.getTextElements=function(a,b,c){var e=a.startContainer.ownerDocument.createRange(),f;f=L.getNodesInRange(a,function(f){e.selectNodeContents(f);if(d(f.parentNode))return NodeFilter.FILTER_REJECT;if(f.nodeType===Node.TEXT_NODE){if(b&&L.rangesIntersect(a,e)||L.containsRange(a,e))if(c||Boolean(r(f)&&(!n(f.textContent)||w(f,0))))return NodeFi [...]
- L.rangesIntersect(a,e)||L.containsRange(a,e))return NodeFilter.FILTER_ACCEPT}else if(s(f)||h(f))return NodeFilter.FILTER_SKIP;return NodeFilter.FILTER_REJECT});e.detach();return f};this.getParagraphElements=function(a){var b=a.startContainer.ownerDocument.createRange(),c;c=L.getNodesInRange(a,function(c){b.selectNodeContents(c);if(p(c)){if(L.rangesIntersect(a,b))return NodeFilter.FILTER_ACCEPT}else if(s(c)||h(c))return NodeFilter.FILTER_SKIP;return NodeFilter.FILTER_REJECT});b.detach(); [...]
- this.getImageElements=function(a){var b=a.startContainer.ownerDocument.createRange(),c;c=L.getNodesInRange(a,function(c){b.selectNodeContents(c);return g(c)&&L.containsRange(a,b)?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_SKIP});b.detach();return c}};
- // Input 21
++odf.StyleInfo=function(){function m(a,c){var b,d,f,e,l,g=0;if(b=L[a.localName])if(f=b[a.namespaceURI])g=f.length;for(b=0;b<g;b+=1)d=f[b],e=d.ns,l=d.localname,(d=a.getAttributeNS(e,l))&&a.setAttributeNS(e,y[e]+l,c+d);for(f=a.firstElementChild;f;)m(f,c),f=f.nextElementSibling}function h(a,c){var b,d,f,e,l,g=0;if(b=L[a.localName])if(f=b[a.namespaceURI])g=f.length;for(b=0;b<g;b+=1)if(d=f[b],e=d.ns,l=d.localname,d=a.getAttributeNS(e,l))d=d.replace(c,""),a.setAttributeNS(e,y[e]+l,d);for(f=a.f [...]
++c),f=f.nextElementSibling}function b(a,c){var b,d,f,e,l,g=0;if(b=L[a.localName])if(f=b[a.namespaceURI])g=f.length;for(b=0;b<g;b+=1)if(e=f[b],d=e.ns,l=e.localname,d=a.getAttributeNS(d,l))c=c||{},e=e.keyname,c.hasOwnProperty(e)?c[e][d]=1:(l={},l[d]=1,c[e]=l);return c}function g(a,c){var d,f;b(a,c);for(d=a.firstChild;d;)d.nodeType===Node.ELEMENT_NODE&&(f=d,g(f,c)),d=d.nextSibling}function d(a,c,b){this.key=a;this.name=c;this.family=b;this.requires={}}function n(a,c,b){var f=a+'"'+c,e=b[f]; [...]
++new d(f,a,c));return e}function p(a,c,b){var d,f,e,l,g,k=0;d=a.getAttributeNS(t,"name");l=a.getAttributeNS(t,"family");d&&l&&(c=n(d,l,b));if(c){if(d=L[a.localName])if(e=d[a.namespaceURI])k=e.length;for(d=0;d<k;d+=1)if(l=e[d],f=l.ns,g=l.localname,f=a.getAttributeNS(f,g))l=l.keyname,l=n(f,l,b),c.requires[l.key]=l}for(a=a.firstElementChild;a;)p(a,c,b),a=a.nextElementSibling;return b}function k(a,c){var b=c[a.family];b||(b=c[a.family]={});b[a.name]=1;Object.keys(a.requires).forEach(function [...]
++c)})}function q(a,c){var b=p(a,null,{});Object.keys(b).forEach(function(a){a=b[a];var d=c[a.family];d&&d.hasOwnProperty(a.name)&&k(a,c)})}function e(a,c){function b(c){(c=l.getAttributeNS(t,c))&&(a[c]=!0)}var d=["font-name","font-name-asian","font-name-complex"],f,l;for(f=c&&c.firstElementChild;f;)l=f,d.forEach(b),e(a,l),f=f.nextElementSibling}function r(a,c){function b(a){var d=e.getAttributeNS(t,a);d&&c.hasOwnProperty(d)&&e.setAttributeNS(t,"style:"+a,c[d])}var d=["font-name","font-na [...]
++"font-name-complex"],f,e;for(f=a&&a.firstElementChild;f;)e=f,d.forEach(b),r(e,c),f=f.nextElementSibling}var a=odf.Namespaces.chartns,c=odf.Namespaces.dbns,l=odf.Namespaces.dr3dns,f=odf.Namespaces.drawns,v=odf.Namespaces.formns,w=odf.Namespaces.numberns,z=odf.Namespaces.officens,x=odf.Namespaces.presentationns,t=odf.Namespaces.stylens,u=odf.Namespaces.tablens,s=odf.Namespaces.textns,y={"urn:oasis:names:tc:opendocument:xmlns:chart:1.0":"chart:","urn:oasis:names:tc:opendocument:xmlns:datab [...]
++"urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0":"dr3d:","urn:oasis:names:tc:opendocument:xmlns:drawing:1.0":"draw:","urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0":"fo:","urn:oasis:names:tc:opendocument:xmlns:form:1.0":"form:","urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0":"number:","urn:oasis:names:tc:opendocument:xmlns:office:1.0":"office:","urn:oasis:names:tc:opendocument:xmlns:presentation:1.0":"presentation:","urn:oasis:names:tc:opendocument:xmlns:style:1.0":" [...]
++"urn:oasis:names:tc:opendocument:xmlns:table:1.0":"table:","urn:oasis:names:tc:opendocument:xmlns:text:1.0":"chart:","http://www.w3.org/XML/1998/namespace":"xml:"},F={text:[{ens:t,en:"tab-stop",ans:t,a:"leader-text-style"},{ens:t,en:"drop-cap",ans:t,a:"style-name"},{ens:s,en:"notes-configuration",ans:s,a:"citation-body-style-name"},{ens:s,en:"notes-configuration",ans:s,a:"citation-style-name"},{ens:s,en:"a",ans:s,a:"style-name"},{ens:s,en:"alphabetical-index",ans:s,a:"style-name"},{ens: [...]
++ans:s,a:"style-name"},{ens:s,en:"list-level-style-number",ans:s,a:"style-name"},{ens:s,en:"ruby-text",ans:s,a:"style-name"},{ens:s,en:"span",ans:s,a:"style-name"},{ens:s,en:"a",ans:s,a:"visited-style-name"},{ens:t,en:"text-properties",ans:t,a:"text-line-through-text-style"},{ens:s,en:"alphabetical-index-source",ans:s,a:"main-entry-style-name"},{ens:s,en:"index-entry-bibliography",ans:s,a:"style-name"},{ens:s,en:"index-entry-chapter",ans:s,a:"style-name"},{ens:s,en:"index-entry-link-end" [...]
++{ens:s,en:"index-entry-link-start",ans:s,a:"style-name"},{ens:s,en:"index-entry-page-number",ans:s,a:"style-name"},{ens:s,en:"index-entry-span",ans:s,a:"style-name"},{ens:s,en:"index-entry-tab-stop",ans:s,a:"style-name"},{ens:s,en:"index-entry-text",ans:s,a:"style-name"},{ens:s,en:"index-title-template",ans:s,a:"style-name"},{ens:s,en:"list-level-style-bullet",ans:s,a:"style-name"},{ens:s,en:"outline-level-style",ans:s,a:"style-name"}],paragraph:[{ens:f,en:"caption",ans:f,a:"text-style- [...]
++en:"circle",ans:f,a:"text-style-name"},{ens:f,en:"connector",ans:f,a:"text-style-name"},{ens:f,en:"control",ans:f,a:"text-style-name"},{ens:f,en:"custom-shape",ans:f,a:"text-style-name"},{ens:f,en:"ellipse",ans:f,a:"text-style-name"},{ens:f,en:"frame",ans:f,a:"text-style-name"},{ens:f,en:"line",ans:f,a:"text-style-name"},{ens:f,en:"measure",ans:f,a:"text-style-name"},{ens:f,en:"path",ans:f,a:"text-style-name"},{ens:f,en:"polygon",ans:f,a:"text-style-name"},{ens:f,en:"polyline",ans:f,a:" [...]
++{ens:f,en:"rect",ans:f,a:"text-style-name"},{ens:f,en:"regular-polygon",ans:f,a:"text-style-name"},{ens:z,en:"annotation",ans:f,a:"text-style-name"},{ens:v,en:"column",ans:v,a:"text-style-name"},{ens:t,en:"style",ans:t,a:"next-style-name"},{ens:u,en:"body",ans:u,a:"paragraph-style-name"},{ens:u,en:"even-columns",ans:u,a:"paragraph-style-name"},{ens:u,en:"even-rows",ans:u,a:"paragraph-style-name"},{ens:u,en:"first-column",ans:u,a:"paragraph-style-name"},{ens:u,en:"first-row",ans:u,a:"par [...]
++{ens:u,en:"last-column",ans:u,a:"paragraph-style-name"},{ens:u,en:"last-row",ans:u,a:"paragraph-style-name"},{ens:u,en:"odd-columns",ans:u,a:"paragraph-style-name"},{ens:u,en:"odd-rows",ans:u,a:"paragraph-style-name"},{ens:s,en:"notes-configuration",ans:s,a:"default-style-name"},{ens:s,en:"alphabetical-index-entry-template",ans:s,a:"style-name"},{ens:s,en:"bibliography-entry-template",ans:s,a:"style-name"},{ens:s,en:"h",ans:s,a:"style-name"},{ens:s,en:"illustration-index-entry-template" [...]
++{ens:s,en:"index-source-style",ans:s,a:"style-name"},{ens:s,en:"object-index-entry-template",ans:s,a:"style-name"},{ens:s,en:"p",ans:s,a:"style-name"},{ens:s,en:"table-index-entry-template",ans:s,a:"style-name"},{ens:s,en:"table-of-content-entry-template",ans:s,a:"style-name"},{ens:s,en:"table-index-entry-template",ans:s,a:"style-name"},{ens:s,en:"user-index-entry-template",ans:s,a:"style-name"},{ens:t,en:"page-layout-properties",ans:t,a:"register-truth-ref-style-name"}],chart:[{ens:a,e [...]
++a:"style-name"},{ens:a,en:"chart",ans:a,a:"style-name"},{ens:a,en:"data-label",ans:a,a:"style-name"},{ens:a,en:"data-point",ans:a,a:"style-name"},{ens:a,en:"equation",ans:a,a:"style-name"},{ens:a,en:"error-indicator",ans:a,a:"style-name"},{ens:a,en:"floor",ans:a,a:"style-name"},{ens:a,en:"footer",ans:a,a:"style-name"},{ens:a,en:"grid",ans:a,a:"style-name"},{ens:a,en:"legend",ans:a,a:"style-name"},{ens:a,en:"mean-value",ans:a,a:"style-name"},{ens:a,en:"plot-area",ans:a,a:"style-name"},{e [...]
++ans:a,a:"style-name"},{ens:a,en:"series",ans:a,a:"style-name"},{ens:a,en:"stock-gain-marker",ans:a,a:"style-name"},{ens:a,en:"stock-loss-marker",ans:a,a:"style-name"},{ens:a,en:"stock-range-line",ans:a,a:"style-name"},{ens:a,en:"subtitle",ans:a,a:"style-name"},{ens:a,en:"title",ans:a,a:"style-name"},{ens:a,en:"wall",ans:a,a:"style-name"}],section:[{ens:s,en:"alphabetical-index",ans:s,a:"style-name"},{ens:s,en:"bibliography",ans:s,a:"style-name"},{ens:s,en:"illustration-index",ans:s,a:"s [...]
++{ens:s,en:"index-title",ans:s,a:"style-name"},{ens:s,en:"object-index",ans:s,a:"style-name"},{ens:s,en:"section",ans:s,a:"style-name"},{ens:s,en:"table-of-content",ans:s,a:"style-name"},{ens:s,en:"table-index",ans:s,a:"style-name"},{ens:s,en:"user-index",ans:s,a:"style-name"}],ruby:[{ens:s,en:"ruby",ans:s,a:"style-name"}],table:[{ens:c,en:"query",ans:c,a:"style-name"},{ens:c,en:"table-representation",ans:c,a:"style-name"},{ens:u,en:"background",ans:u,a:"style-name"},{ens:u,en:"table",an [...]
++"table-column":[{ens:c,en:"column",ans:c,a:"style-name"},{ens:u,en:"table-column",ans:u,a:"style-name"}],"table-row":[{ens:c,en:"query",ans:c,a:"default-row-style-name"},{ens:c,en:"table-representation",ans:c,a:"default-row-style-name"},{ens:u,en:"table-row",ans:u,a:"style-name"}],"table-cell":[{ens:c,en:"column",ans:c,a:"default-cell-style-name"},{ens:u,en:"table-column",ans:u,a:"default-cell-style-name"},{ens:u,en:"table-row",ans:u,a:"default-cell-style-name"},{ens:u,en:"body",ans:u,a [...]
++{ens:u,en:"covered-table-cell",ans:u,a:"style-name"},{ens:u,en:"even-columns",ans:u,a:"style-name"},{ens:u,en:"covered-table-cell",ans:u,a:"style-name"},{ens:u,en:"even-columns",ans:u,a:"style-name"},{ens:u,en:"even-rows",ans:u,a:"style-name"},{ens:u,en:"first-column",ans:u,a:"style-name"},{ens:u,en:"first-row",ans:u,a:"style-name"},{ens:u,en:"last-column",ans:u,a:"style-name"},{ens:u,en:"last-row",ans:u,a:"style-name"},{ens:u,en:"odd-columns",ans:u,a:"style-name"},{ens:u,en:"odd-rows", [...]
++{ens:u,en:"table-cell",ans:u,a:"style-name"}],graphic:[{ens:l,en:"cube",ans:f,a:"style-name"},{ens:l,en:"extrude",ans:f,a:"style-name"},{ens:l,en:"rotate",ans:f,a:"style-name"},{ens:l,en:"scene",ans:f,a:"style-name"},{ens:l,en:"sphere",ans:f,a:"style-name"},{ens:f,en:"caption",ans:f,a:"style-name"},{ens:f,en:"circle",ans:f,a:"style-name"},{ens:f,en:"connector",ans:f,a:"style-name"},{ens:f,en:"control",ans:f,a:"style-name"},{ens:f,en:"custom-shape",ans:f,a:"style-name"},{ens:f,en:"ellips [...]
++{ens:f,en:"frame",ans:f,a:"style-name"},{ens:f,en:"g",ans:f,a:"style-name"},{ens:f,en:"line",ans:f,a:"style-name"},{ens:f,en:"measure",ans:f,a:"style-name"},{ens:f,en:"page-thumbnail",ans:f,a:"style-name"},{ens:f,en:"path",ans:f,a:"style-name"},{ens:f,en:"polygon",ans:f,a:"style-name"},{ens:f,en:"polyline",ans:f,a:"style-name"},{ens:f,en:"rect",ans:f,a:"style-name"},{ens:f,en:"regular-polygon",ans:f,a:"style-name"},{ens:z,en:"annotation",ans:f,a:"style-name"}],presentation:[{ens:l,en:"c [...]
++a:"style-name"},{ens:l,en:"extrude",ans:x,a:"style-name"},{ens:l,en:"rotate",ans:x,a:"style-name"},{ens:l,en:"scene",ans:x,a:"style-name"},{ens:l,en:"sphere",ans:x,a:"style-name"},{ens:f,en:"caption",ans:x,a:"style-name"},{ens:f,en:"circle",ans:x,a:"style-name"},{ens:f,en:"connector",ans:x,a:"style-name"},{ens:f,en:"control",ans:x,a:"style-name"},{ens:f,en:"custom-shape",ans:x,a:"style-name"},{ens:f,en:"ellipse",ans:x,a:"style-name"},{ens:f,en:"frame",ans:x,a:"style-name"},{ens:f,en:"g" [...]
++{ens:f,en:"line",ans:x,a:"style-name"},{ens:f,en:"measure",ans:x,a:"style-name"},{ens:f,en:"page-thumbnail",ans:x,a:"style-name"},{ens:f,en:"path",ans:x,a:"style-name"},{ens:f,en:"polygon",ans:x,a:"style-name"},{ens:f,en:"polyline",ans:x,a:"style-name"},{ens:f,en:"rect",ans:x,a:"style-name"},{ens:f,en:"regular-polygon",ans:x,a:"style-name"},{ens:z,en:"annotation",ans:x,a:"style-name"}],"drawing-page":[{ens:f,en:"page",ans:f,a:"style-name"},{ens:x,en:"notes",ans:f,a:"style-name"},{ens:t, [...]
++ans:f,a:"style-name"},{ens:t,en:"master-page",ans:f,a:"style-name"}],"list-style":[{ens:s,en:"list",ans:s,a:"style-name"},{ens:s,en:"numbered-paragraph",ans:s,a:"style-name"},{ens:s,en:"list-item",ans:s,a:"style-override"},{ens:t,en:"style",ans:t,a:"list-style-name"}],data:[{ens:t,en:"style",ans:t,a:"data-style-name"},{ens:t,en:"style",ans:t,a:"percentage-data-style-name"},{ens:x,en:"date-time-decl",ans:t,a:"data-style-name"},{ens:s,en:"creation-date",ans:t,a:"data-style-name"},{ens:s,e [...]
++ans:t,a:"data-style-name"},{ens:s,en:"database-display",ans:t,a:"data-style-name"},{ens:s,en:"date",ans:t,a:"data-style-name"},{ens:s,en:"editing-duration",ans:t,a:"data-style-name"},{ens:s,en:"expression",ans:t,a:"data-style-name"},{ens:s,en:"meta-field",ans:t,a:"data-style-name"},{ens:s,en:"modification-date",ans:t,a:"data-style-name"},{ens:s,en:"modification-time",ans:t,a:"data-style-name"},{ens:s,en:"print-date",ans:t,a:"data-style-name"},{ens:s,en:"print-time",ans:t,a:"data-style-n [...]
++en:"table-formula",ans:t,a:"data-style-name"},{ens:s,en:"time",ans:t,a:"data-style-name"},{ens:s,en:"user-defined",ans:t,a:"data-style-name"},{ens:s,en:"user-field-get",ans:t,a:"data-style-name"},{ens:s,en:"user-field-input",ans:t,a:"data-style-name"},{ens:s,en:"variable-get",ans:t,a:"data-style-name"},{ens:s,en:"variable-input",ans:t,a:"data-style-name"},{ens:s,en:"variable-set",ans:t,a:"data-style-name"}],"page-layout":[{ens:x,en:"notes",ans:t,a:"page-layout-name"},{ens:t,en:"handout- [...]
++a:"page-layout-name"},{ens:t,en:"master-page",ans:t,a:"page-layout-name"}]},L,O=xmldom.XPath;this.collectUsedFontFaces=e;this.changeFontFaceNames=r;this.UsedStyleList=function(a,c){var b={};this.uses=function(a){var c=a.localName,d=a.getAttributeNS(f,"name")||a.getAttributeNS(t,"name");a="style"===c?a.getAttributeNS(t,"family"):a.namespaceURI===w?"data":c;return(a=b[a])?0<a[d]:!1};g(a,b);c&&q(c,b)};this.hasDerivedStyles=function(a,c,b){var d=b.getAttributeNS(t,"name");b=b.getAttributeNS [...]
++return O.getODFElementsWithXPath(a,"//style:*[@style:parent-style-name='"+d+"'][@style:family='"+b+"']",c).length?!0:!1};this.prefixStyleNames=function(a,c,b){var d;if(a){for(d=a.firstChild;d;){if(d.nodeType===Node.ELEMENT_NODE){var e=d,l=c,g=e.getAttributeNS(f,"name"),k=void 0;g?k=f:(g=e.getAttributeNS(t,"name"))&&(k=t);k&&e.setAttributeNS(k,y[k]+"name",l+g)}d=d.nextSibling}m(a,c);b&&m(b,c)}};this.removePrefixFromStyleNames=function(a,c,b){var d=RegExp("^"+c);if(a){for(c=a.firstChild;c [...]
++Node.ELEMENT_NODE){var e=c,l=d,g=e.getAttributeNS(f,"name"),k=void 0;g?k=f:(g=e.getAttributeNS(t,"name"))&&(k=t);k&&(g=g.replace(l,""),e.setAttributeNS(k,y[k]+"name",g))}c=c.nextSibling}h(a,d);b&&h(b,d)}};this.determineStylesForNode=b;L=function(){var a,c,b,d,f,e={},l,g,k,n;for(b in F)if(F.hasOwnProperty(b))for(d=F[b],c=d.length,a=0;a<c;a+=1)f=d[a],k=f.en,n=f.ens,e.hasOwnProperty(k)?l=e[k]:e[k]=l={},l.hasOwnProperty(n)?g=l[n]:l[n]=g=[],g.push({ns:f.ans,localname:f.a,keyname:b});return e}()};
++// Input 26
++"function"!==typeof Object.create&&(Object.create=function(m){var h=function(){};h.prototype=m;return new h});
++xmldom.LSSerializer=function(){function m(b){var g=b||{},h=function(b){var a={},c;for(c in b)b.hasOwnProperty(c)&&(a[b[c]]=c);return a}(b),k=[g],m=[h],e=0;this.push=function(){e+=1;g=k[e]=Object.create(g);h=m[e]=Object.create(h)};this.pop=function(){k.pop();m.pop();e-=1;g=k[e];h=m[e]};this.getLocalNamespaceDefinitions=function(){return h};this.getQName=function(b){var a=b.namespaceURI,c=0,d;if(!a)return b.localName;if(d=h[a])return d+":"+b.localName;do{d||!b.prefix?(d="ns"+c,c+=1):d=b.p [...]
++a)break;if(!g[d]){g[d]=a;h[a]=d;break}d=null}while(null===d);return d+":"+b.localName}}function h(b){return b.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/'/g,"'").replace(/"/g,""")}function b(d,n){var p="",k=g.filter?g.filter.acceptNode(n):NodeFilter.FILTER_ACCEPT,m;if(k===NodeFilter.FILTER_ACCEPT&&n.nodeType===Node.ELEMENT_NODE){d.push();m=d.getQName(n);var e,r=n.attributes,a,c,l,f="",v;e="<"+m;a=r.length;for(c=0;c<a;c+=1)l=r.item(c),"http://www.w [...]
++l.namespaceURI&&(v=g.filter?g.filter.acceptNode(l):NodeFilter.FILTER_ACCEPT,v===NodeFilter.FILTER_ACCEPT&&(v=d.getQName(l),l="string"===typeof l.value?h(l.value):l.value,f+=" "+(v+'="'+l+'"')));a=d.getLocalNamespaceDefinitions();for(c in a)a.hasOwnProperty(c)&&((r=a[c])?"xmlns"!==r&&(e+=" xmlns:"+a[c]+'="'+c+'"'):e+=' xmlns="'+c+'"');p+=e+(f+">")}if(k===NodeFilter.FILTER_ACCEPT||k===NodeFilter.FILTER_SKIP){for(k=n.firstChild;k;)p+=b(d,k),k=k.nextSibling;n.nodeValue&&(p+=h(n.nodeValue))} [...]
++m+">",d.pop());return p}var g=this;this.filter=null;this.writeToString=function(d,g){if(!d)return"";var h=new m(g);return b(h,d)}};
++// Input 27
 +/*
 +
-  Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
++ Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- ops.Server=function(){};ops.Server.prototype.connect=function(g,l){};ops.Server.prototype.networkStatus=function(){};ops.Server.prototype.login=function(g,l,f,p){};ops.Server.prototype.joinSession=function(g,l,f,p){};ops.Server.prototype.leaveSession=function(g,l,f,p){};ops.Server.prototype.getGenesisUrl=function(g){};
- // Input 22
- xmldom.LSSerializerFilter=function(){};xmldom.LSSerializerFilter.prototype.acceptNode=function(g){};
- // Input 23
- xmldom.XPathIterator=function(){};xmldom.XPathIterator.prototype.next=function(){};xmldom.XPathIterator.prototype.reset=function(){};
- function createXPathSingleton(){function g(c,a,b){return-1!==c&&(c<a||-1===a)&&(c<b||-1===b)}function l(e){for(var a=[],b=0,d=e.length,f;b<d;){var h=e,m=d,l=a,n="",p=[],r=h.indexOf("[",b),s=h.indexOf("/",b),H=h.indexOf("=",b);g(s,r,H)?(n=h.substring(b,s),b=s+1):g(r,s,H)?(n=h.substring(b,r),b=c(h,r,p)):g(H,s,r)?(n=h.substring(b,H),b=H):(n=h.substring(b,m),b=m);l.push({location:n,predicates:p});if(b<d&&"="===e[b]){f=e.substring(b+1,d);if(2<f.length&&("'"===f[0]||'"'===f[0]))f=f.slice(1,f. [...]
- else try{f=parseInt(f,10)}catch(y){}b=d}}return{steps:a,value:f}}function f(){var c=null,a=!1;this.setNode=function(a){c=a};this.reset=function(){a=!1};this.next=function(){var b=a?null:c;a=!0;return b}}function p(c,a,b){this.reset=function(){c.reset()};this.next=function(){for(var d=c.next();d;){d.nodeType===Node.ELEMENT_NODE&&(d=d.getAttributeNodeNS(a,b));if(d)break;d=c.next()}return d}}function r(c,a){var b=c.next(),d=null;this.reset=function(){c.reset();b=c.next();d=null};this.next= [...]
- d.firstChild)d=d.firstChild;else{for(;!d.nextSibling&&d!==b;)d=d.parentNode;d===b?b=c.next():d=d.nextSibling}else{do(d=b.firstChild)||(b=c.next());while(b&&!d)}if(d&&d.nodeType===Node.ELEMENT_NODE)return d}return null}}function n(c,a){this.reset=function(){c.reset()};this.next=function(){for(var b=c.next();b&&!a(b);)b=c.next();return b}}function h(c,a,b){a=a.split(":",2);var d=b(a[0]),f=a[1];return new n(c,function(a){return a.localName===f&&a.namespaceURI===d})}function d(c,a,b){var d= [...]
- a,b),h=a.value;return void 0===h?new n(c,function(a){d.setNode(a);k.reset();return null!==k.next()}):new n(c,function(a){d.setNode(a);k.reset();return(a=k.next())?a.nodeValue===h:!1})}var m,c;c=function(c,a,b){for(var d=a,f=c.length,h=0;d<f;)"]"===c[d]?(h-=1,0>=h&&b.push(l(c.substring(a,d)))):"["===c[d]&&(0>=h&&(a=d+1),h+=1),d+=1;return d};m=function(c,a,b){var f,k,g,m;for(f=0;f<a.steps.length;f+=1){g=a.steps[f];k=g.location;if(""===k)c=new r(c,!1);else if("@"===k[0]){k=k.substr(1).spli [...]
- b(k[0]);if(!m)throw"No namespace associated with the prefix "+k[0];c=new p(c,m,k[1])}else"."!==k&&(c=new r(c,!1),-1!==k.indexOf(":")&&(c=h(c,k,b)));for(k=0;k<g.predicates.length;k+=1)m=g.predicates[k],c=d(c,m,b)}return c};return{getODFElementsWithXPath:function(c,a,b){var d=c.ownerDocument,k=[],h=null;if(d&&"function"===typeof d.evaluate)for(b=d.evaluate(a,c,b,XPathResult.UNORDERED_NODE_ITERATOR_TYPE,null),h=b.iterateNext();null!==h;)h.nodeType===Node.ELEMENT_NODE&&k.push(h),h=b.iterate [...]
- new f;k.setNode(c);c=l(a);k=m(k,c,b);c=[];for(b=k.next();b;)c.push(b),b=k.next();k=c}return k}}}xmldom.XPath=createXPathSingleton();
- // Input 24
- runtime.loadClass("core.DomUtils");
- core.Cursor=function(g,l){function f(a){a.parentNode&&(d.push(a.previousSibling),d.push(a.nextSibling),a.parentNode.removeChild(a))}function p(a,b,c){if(b.nodeType===Node.TEXT_NODE){runtime.assert(Boolean(b),"putCursorIntoTextNode: invalid container");var e=b.parentNode;runtime.assert(Boolean(e),"putCursorIntoTextNode: container without parent");runtime.assert(0<=c&&c<=b.length,"putCursorIntoTextNode: offset is out of bounds");0===c?e.insertBefore(a,b):(c!==b.length&&b.splitText(c),e.in [...]
- b.nextSibling))}else b.nodeType===Node.ELEMENT_NODE&&b.insertBefore(a,b.childNodes.item(c));d.push(a.previousSibling);d.push(a.nextSibling)}var r=g.createElementNS("urn:webodf:names:cursor","cursor"),n=g.createElementNS("urn:webodf:names:cursor","anchor"),h,d=[],m=g.createRange(),c,e=new core.DomUtils;this.getNode=function(){return r};this.getAnchorNode=function(){return n.parentNode?n:r};this.getSelectedRange=function(){c?(m.setStartBefore(r),m.collapse(!0)):(m.setStartAfter(h?n:r),m.s [...]
- r:n));return m};this.setSelectedRange=function(a,b){m&&m!==a&&m.detach();m=a;h=!1!==b;(c=a.collapsed)?(f(n),f(r),p(r,a.startContainer,a.startOffset)):(f(n),f(r),p(h?r:n,a.endContainer,a.endOffset),p(h?n:r,a.startContainer,a.startOffset));d.forEach(e.normalizeTextNodes);d.length=0};this.hasForwardSelection=function(){return h};this.remove=function(){f(r);d.forEach(e.normalizeTextNodes);d.length=0};r.setAttributeNS("urn:webodf:names:cursor","memberId",l);n.setAttributeNS("urn:webodf:names [...]
- l)};
- // Input 25
- runtime.loadClass("core.PositionIterator");core.PositionFilter=function(){};core.PositionFilter.FilterResult={FILTER_ACCEPT:1,FILTER_REJECT:2,FILTER_SKIP:3};core.PositionFilter.prototype.acceptPosition=function(g){};(function(){return core.PositionFilter})();
- // Input 26
- runtime.loadClass("core.PositionFilter");core.PositionFilterChain=function(){var g={},l=core.PositionFilter.FilterResult.FILTER_ACCEPT,f=core.PositionFilter.FilterResult.FILTER_REJECT;this.acceptPosition=function(p){for(var r in g)if(g.hasOwnProperty(r)&&g[r].acceptPosition(p)===f)return f;return l};this.addFilter=function(f,l){g[f]=l};this.removeFilter=function(f){delete g[f]}};
- // Input 27
++(function(){function m(b){var a,c=k.length;for(a=0;a<c;a+=1)if("urn:oasis:names:tc:opendocument:xmlns:office:1.0"===b.namespaceURI&&b.localName===k[a])return a;return-1}function h(b,a){var c=new d.UsedStyleList(b,a),e=new odf.OdfNodeFilter;this.acceptNode=function(b){var d=e.acceptNode(b);d===NodeFilter.FILTER_ACCEPT&&b.parentNode===a&&b.nodeType===Node.ELEMENT_NODE&&(d=c.uses(b)?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_REJECT);return d}}function b(b,a){var c=new h(b,a);this.acceptNod [...]
++c.acceptNode(a);b!==NodeFilter.FILTER_ACCEPT||!a.parentNode||a.parentNode.namespaceURI!==odf.Namespaces.textns||"s"!==a.parentNode.localName&&"tab"!==a.parentNode.localName||(b=NodeFilter.FILTER_REJECT);return b}}function g(b,a){if(a){var c=m(a),d,f=b.firstChild;if(-1!==c){for(;f;){d=m(f);if(-1!==d&&d>c)break;f=f.nextSibling}b.insertBefore(a,f)}}}var d=new odf.StyleInfo,n=new core.DomUtils,p=odf.Namespaces.stylens,k="meta settings scripts font-face-decls styles automatic-styles master-s [...]
++q=(new Date).getTime()+"_webodf_",e=new core.Base64;odf.ODFElement=function(){};odf.ODFDocumentElement=function(){};odf.ODFDocumentElement.prototype=new odf.ODFElement;odf.ODFDocumentElement.prototype.constructor=odf.ODFDocumentElement;odf.ODFDocumentElement.prototype.fontFaceDecls=null;odf.ODFDocumentElement.prototype.manifest=null;odf.ODFDocumentElement.prototype.settings=null;odf.ODFDocumentElement.namespaceURI="urn:oasis:names:tc:opendocument:xmlns:office:1.0";odf.ODFDocumentElement [...]
++"document";odf.AnnotationElement=function(){};odf.OdfPart=function(b,a,c,d){var f=this;this.size=0;this.type=null;this.name=b;this.container=c;this.url=null;this.mimetype=a;this.onstatereadychange=this.document=null;this.EMPTY=0;this.LOADING=1;this.DONE=2;this.state=this.EMPTY;this.data="";this.load=function(){null!==d&&(this.mimetype=a,d.loadAsDataURL(b,a,function(a,b){a&&runtime.log(a);f.url=b;if(f.onchange)f.onchange(f);if(f.onstatereadychange)f.onstatereadychange(f)}))}};odf.OdfPart [...]
++function(){};odf.OdfPart.prototype.getUrl=function(){return this.data?"data:;base64,"+e.toBase64(this.data):null};odf.OdfContainer=function a(c,l){function f(a){for(var b=a.firstChild,c;b;)c=b.nextSibling,b.nodeType===Node.ELEMENT_NODE?f(b):b.nodeType===Node.PROCESSING_INSTRUCTION_NODE&&a.removeChild(b),b=c}function k(a){var b={},c,d,f=a.ownerDocument.createNodeIterator(a,NodeFilter.SHOW_ELEMENT,null,!1);for(a=f.nextNode();a;)"urn:oasis:names:tc:opendocument:xmlns:office:1.0"===a.namesp [...]
++a.localName?(c=a.getAttributeNS("urn:oasis:names:tc:opendocument:xmlns:office:1.0","name"))&&(b.hasOwnProperty(c)?runtime.log("Warning: annotation name used more than once with <office:annotation/>: '"+c+"'"):b[c]=a):"annotation-end"===a.localName&&((c=a.getAttributeNS("urn:oasis:names:tc:opendocument:xmlns:office:1.0","name"))?b.hasOwnProperty(c)?(d=b[c],d.annotationEndElement?runtime.log("Warning: annotation name used more than once with <office:annotation-end/>: '"+c+"'"):d.annotatio [...]
++a):runtime.log("Warning: annotation end without an annotation start, name: '"+c+"'"):runtime.log("Warning: annotation end without a name found"))),a=f.nextNode()}function m(a,b){for(var c=a&&a.firstChild;c;)c.nodeType===Node.ELEMENT_NODE&&c.setAttributeNS("urn:webodf:names:scope","scope",b),c=c.nextSibling}function z(a){var b={},c;for(a=a.firstChild;a;)a.nodeType===Node.ELEMENT_NODE&&a.namespaceURI===p&&"font-face"===a.localName&&(c=a.getAttributeNS(p,"name"),b[c]=a),a=a.nextSibling;ret [...]
++b){var c=null,d,f,e;if(a)for(c=a.cloneNode(!0),d=c.firstElementChild;d;)f=d.nextElementSibling,(e=d.getAttributeNS("urn:webodf:names:scope","scope"))&&e!==b&&c.removeChild(d),d=f;return c}function t(a,b){var c,f,e,l=null,g={};if(a)for(b.forEach(function(a){d.collectUsedFontFaces(g,a)}),l=a.cloneNode(!0),c=l.firstElementChild;c;)f=c.nextElementSibling,e=c.getAttributeNS(p,"name"),g[e]||l.removeChild(c),c=f;return l}function u(a){var b=M.rootElement.ownerDocument,c;if(a){f(a.documentEleme [...]
++b.importNode(a.documentElement,!0)}catch(d){}}return c}function s(a){M.state=a;if(M.onchange)M.onchange(M);if(M.onstatereadychange)M.onstatereadychange(M)}function y(a){S=null;M.rootElement=a;a.fontFaceDecls=n.getDirectChild(a,"urn:oasis:names:tc:opendocument:xmlns:office:1.0","font-face-decls");a.styles=n.getDirectChild(a,"urn:oasis:names:tc:opendocument:xmlns:office:1.0","styles");a.automaticStyles=n.getDirectChild(a,"urn:oasis:names:tc:opendocument:xmlns:office:1.0","automatic-styles [...]
++n.getDirectChild(a,"urn:oasis:names:tc:opendocument:xmlns:office:1.0","master-styles");a.body=n.getDirectChild(a,"urn:oasis:names:tc:opendocument:xmlns:office:1.0","body");a.meta=n.getDirectChild(a,"urn:oasis:names:tc:opendocument:xmlns:office:1.0","meta");k(a)}function F(b){var c=u(b),f=M.rootElement,e;c&&"document-styles"===c.localName&&"urn:oasis:names:tc:opendocument:xmlns:office:1.0"===c.namespaceURI?(f.fontFaceDecls=n.getDirectChild(c,"urn:oasis:names:tc:opendocument:xmlns:office: [...]
++g(f,f.fontFaceDecls),e=n.getDirectChild(c,"urn:oasis:names:tc:opendocument:xmlns:office:1.0","styles"),f.styles=e||b.createElementNS("urn:oasis:names:tc:opendocument:xmlns:office:1.0","styles"),g(f,f.styles),e=n.getDirectChild(c,"urn:oasis:names:tc:opendocument:xmlns:office:1.0","automatic-styles"),f.automaticStyles=e||b.createElementNS("urn:oasis:names:tc:opendocument:xmlns:office:1.0","automatic-styles"),m(f.automaticStyles,"document-styles"),g(f,f.automaticStyles),c=n.getDirectChild( [...]
++"master-styles"),f.masterStyles=c||b.createElementNS("urn:oasis:names:tc:opendocument:xmlns:office:1.0","master-styles"),g(f,f.masterStyles),d.prefixStyleNames(f.automaticStyles,q,f.masterStyles)):s(a.INVALID)}function L(b){b=u(b);var c,f,e,l;if(b&&"document-content"===b.localName&&"urn:oasis:names:tc:opendocument:xmlns:office:1.0"===b.namespaceURI){c=M.rootElement;e=n.getDirectChild(b,"urn:oasis:names:tc:opendocument:xmlns:office:1.0","font-face-decls");if(c.fontFaceDecls&&e){l=c.fontF [...]
++h,y,L,q={};f=z(l);L=z(e);for(e=e.firstElementChild;e;){k=e.nextElementSibling;if(e.namespaceURI===p&&"font-face"===e.localName)if(h=e.getAttributeNS(p,"name"),f.hasOwnProperty(h)){if(!e.isEqualNode(f[h])){y=h;for(var H=f,G=L,F=0,v=void 0,v=y=y.replace(/\d+$/,"");H.hasOwnProperty(v)||G.hasOwnProperty(v);)F+=1,v=y+F;y=v;e.setAttributeNS(p,"style:name",y);l.appendChild(e);f[y]=e;delete L[h];q[h]=y}}else l.appendChild(e),f[h]=e,delete L[h];e=k}l=q}else e&&(c.fontFaceDecls=e,g(c,e));f=n.getD [...]
++"urn:oasis:names:tc:opendocument:xmlns:office:1.0","automatic-styles");m(f,"document-content");l&&d.changeFontFaceNames(f,l);if(c.automaticStyles&&f)for(l=f.firstChild;l;)c.automaticStyles.appendChild(l),l=f.firstChild;else f&&(c.automaticStyles=f,g(c,f));b=n.getDirectChild(b,"urn:oasis:names:tc:opendocument:xmlns:office:1.0","body");if(null===b)throw"<office:body/> tag is mising.";c.body=b;g(c,c.body)}else s(a.INVALID)}function O(a){a=u(a);var b;a&&"document-meta"===a.localName&&"urn:o [...]
++a.namespaceURI&&(b=M.rootElement,b.meta=n.getDirectChild(a,"urn:oasis:names:tc:opendocument:xmlns:office:1.0","meta"),g(b,b.meta))}function H(a){a=u(a);var b;a&&"document-settings"===a.localName&&"urn:oasis:names:tc:opendocument:xmlns:office:1.0"===a.namespaceURI&&(b=M.rootElement,b.settings=n.getDirectChild(a,"urn:oasis:names:tc:opendocument:xmlns:office:1.0","settings"),g(b,b.settings))}function U(a){a=u(a);var b;if(a&&"manifest"===a.localName&&"urn:oasis:names:tc:opendocument:xmlns:m [...]
++a.namespaceURI)for(b=M.rootElement,b.manifest=a,a=b.manifest.firstElementChild;a;)"file-entry"===a.localName&&"urn:oasis:names:tc:opendocument:xmlns:manifest:1.0"===a.namespaceURI&&(W[a.getAttributeNS("urn:oasis:names:tc:opendocument:xmlns:manifest:1.0","full-path")]=a.getAttributeNS("urn:oasis:names:tc:opendocument:xmlns:manifest:1.0","media-type")),a=a.nextElementSibling}function T(b){var c=b.shift();c?$.loadAsDOM(c.path,function(d,f){c.handler(f);d||M.state===a.INVALID||T(b)}):(k(M.r [...]
++s(a.DONE))}function X(a){var b="";odf.Namespaces.forEachPrefix(function(a,c){b+=" xmlns:"+a+'="'+c+'"'});return'<?xml version="1.0" encoding="UTF-8"?><office:'+a+" "+b+' office:version="1.2">'}function D(){var a=new xmldom.LSSerializer,b=X("document-meta");a.filter=new odf.OdfNodeFilter;b+=a.writeToString(M.rootElement.meta,odf.Namespaces.namespaceMap);return b+"</office:document-meta>"}function ba(a,b){var c=document.createElementNS("urn:oasis:names:tc:opendocument:xmlns:manifest:1.0", [...]
++c.setAttributeNS("urn:oasis:names:tc:opendocument:xmlns:manifest:1.0","manifest:full-path",a);c.setAttributeNS("urn:oasis:names:tc:opendocument:xmlns:manifest:1.0","manifest:media-type",b);return c}function G(){var a=runtime.parseXML('<manifest:manifest xmlns:manifest="urn:oasis:names:tc:opendocument:xmlns:manifest:1.0" manifest:version="1.2"></manifest:manifest>'),b=a.documentElement,c=new xmldom.LSSerializer,d;for(d in W)W.hasOwnProperty(d)&&b.appendChild(ba(d,W[d]));c.filter=new odf. [...]
++return'<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n'+c.writeToString(a,odf.Namespaces.namespaceMap)}function J(){var a=new xmldom.LSSerializer,b=X("document-settings");a.filter=new odf.OdfNodeFilter;M.rootElement.settings.firstElementChild&&(b+=a.writeToString(M.rootElement.settings,odf.Namespaces.namespaceMap));return b+"</office:document-settings>"}function Q(){var a,b,c,f=odf.Namespaces.namespaceMap,e=new xmldom.LSSerializer,l=X("document-styles");b=x(M.rootElement.autom [...]
++"document-styles");c=M.rootElement.masterStyles.cloneNode(!0);a=t(M.rootElement.fontFaceDecls,[c,M.rootElement.styles,b]);d.removePrefixFromStyleNames(b,q,c);e.filter=new h(c,b);l+=e.writeToString(a,f);l+=e.writeToString(M.rootElement.styles,f);l+=e.writeToString(b,f);l+=e.writeToString(c,f);return l+"</office:document-styles>"}function ea(){var a,c,d=odf.Namespaces.namespaceMap,f=new xmldom.LSSerializer,e=X("document-content");c=x(M.rootElement.automaticStyles,"document-content");a=t(M [...]
++[c]);f.filter=new b(M.rootElement.body,c);e+=f.writeToString(a,d);e+=f.writeToString(c,d);e+=f.writeToString(M.rootElement.body,d);return e+"</office:document-content>"}function P(b,c){runtime.loadXML(b,function(b,d){if(b)c(b);else{var f=u(d);f&&"document"===f.localName&&"urn:oasis:names:tc:opendocument:xmlns:office:1.0"===f.namespaceURI?(y(f),s(a.DONE)):s(a.INVALID)}})}function N(a,b){var c;c=M.rootElement;var d=c.meta;d||(c.meta=d=document.createElementNS("urn:oasis:names:tc:opendocum [...]
++"meta"),g(c,d));c=d;a&&n.mapKeyValObjOntoNode(c,a,odf.Namespaces.lookupNamespaceURI);b&&n.removeKeyElementsFromNode(c,b,odf.Namespaces.lookupNamespaceURI)}function I(){function b(a,c){var d;c||(c=a);d=document.createElementNS("urn:oasis:names:tc:opendocument:xmlns:office:1.0",c);f[a]=d;f.appendChild(d)}var c=new core.Zip("",null),d=runtime.byteArrayFromString("application/vnd.oasis.opendocument.text","utf8"),f=M.rootElement,e=document.createElementNS("urn:oasis:names:tc:opendocument:xml [...]
++"text");c.save("mimetype",d,!1,new Date);b("meta");b("settings");b("scripts");b("fontFaceDecls","font-face-decls");b("styles");b("automaticStyles","automatic-styles");b("masterStyles","master-styles");b("body");f.body.appendChild(e);W["/"]="application/vnd.oasis.opendocument.text";W["settings.xml"]="text/xml";W["meta.xml"]="text/xml";W["styles.xml"]="text/xml";W["content.xml"]="text/xml";s(a.DONE);return c}function B(){var a,b=new Date,c=runtime.getWindow();a="WebODF/"+("undefined"!==St [...]
++webodf_version:"FromSource");c&&(a=a+" "+c.navigator.userAgent);N({"meta:generator":a},null);a=runtime.byteArrayFromString(J(),"utf8");$.save("settings.xml",a,!0,b);a=runtime.byteArrayFromString(D(),"utf8");$.save("meta.xml",a,!0,b);a=runtime.byteArrayFromString(Q(),"utf8");$.save("styles.xml",a,!0,b);a=runtime.byteArrayFromString(ea(),"utf8");$.save("content.xml",a,!0,b);a=runtime.byteArrayFromString(G(),"utf8");$.save("META-INF/manifest.xml",a,!0,b)}function V(a,b){B();$.writeAs(a,fun [...]
++var M=this,$,W={},S;this.onstatereadychange=l;this.state=this.onchange=null;this.setRootElement=y;this.getContentElement=function(){var a;S||(a=M.rootElement.body,S=n.getDirectChild(a,"urn:oasis:names:tc:opendocument:xmlns:office:1.0","text")||n.getDirectChild(a,"urn:oasis:names:tc:opendocument:xmlns:office:1.0","presentation")||n.getDirectChild(a,"urn:oasis:names:tc:opendocument:xmlns:office:1.0","spreadsheet"));if(!S)throw"Could not find content element in <office:body/>.";return S};t [...]
++function(){var a=M.getContentElement();return a&&a.localName};this.getPart=function(a){return new odf.OdfPart(a,W[a],M,$)};this.getPartData=function(a,b){$.load(a,b)};this.setMetadata=N;this.incrementEditingCycles=function(){var a;for(a=(a=M.rootElement.meta)&&a.firstChild;a&&(a.namespaceURI!==odf.Namespaces.metans||"editing-cycles"!==a.localName);)a=a.nextSibling;for(a=a&&a.firstChild;a&&a.nodeType!==Node.TEXT_NODE;)a=a.nextSibling;a=a?a.data:null;a=a?parseInt(a,10):0;isNaN(a)&&(a=0);N [...]
++1},null)};this.createByteArray=function(a,b){B();$.createByteArray(a,b)};this.saveAs=V;this.save=function(a){V(c,a)};this.getUrl=function(){return c};this.setBlob=function(a,b,c){c=e.convertBase64ToByteArray(c);$.save(a,c,!1,new Date);W.hasOwnProperty(a)&&runtime.log(a+" has been overwritten.");W[a]=b};this.removeBlob=function(a){var b=$.remove(a);runtime.assert(b,"file is not found: "+a);delete W[a]};this.state=a.LOADING;this.rootElement=function(a){var b=document.createElementNS(a.nam [...]
++a.localName),c;a=new a.Type;for(c in a)a.hasOwnProperty(c)&&(b[c]=a[c]);return b}({Type:odf.ODFDocumentElement,namespaceURI:odf.ODFDocumentElement.namespaceURI,localName:odf.ODFDocumentElement.localName});$=c?new core.Zip(c,function(b,d){$=d;b?P(c,function(c){b&&($.error=b+"\n"+c,s(a.INVALID))}):T([{path:"styles.xml",handler:F},{path:"content.xml",handler:L},{path:"meta.xml",handler:O},{path:"settings.xml",handler:H},{path:"META-INF/manifest.xml",handler:U}])}):I()};odf.OdfContainer.EMP [...]
++1;odf.OdfContainer.DONE=2;odf.OdfContainer.INVALID=3;odf.OdfContainer.SAVING=4;odf.OdfContainer.MODIFIED=5;odf.OdfContainer.getContainer=function(a){return new odf.OdfContainer(a,null)};return odf.OdfContainer})();
++// Input 28
 +/*
 +
 + Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- gui.AnnotatableCanvas=function(){};gui.AnnotatableCanvas.prototype.refreshSize=function(){};gui.AnnotatableCanvas.prototype.getZoomLevel=function(){};gui.AnnotatableCanvas.prototype.getSizer=function(){};
- gui.AnnotationViewManager=function(g,l,f){function p(a){var b=a.node,d=a.end;a=m.createRange();d&&(a.setStart(b,b.childNodes.length),a.setEnd(d,0),d=c.getTextNodes(a,!1),d.forEach(function(a){var c=m.createElement("span"),d=b.getAttributeNS(odf.Namespaces.officens,"name");c.className="annotationHighlight";c.setAttribute("annotation",d);a.parentNode.insertBefore(c,a);c.appendChild(a)}));a.detach()}function r(a){var b=g.getSizer();a?(f.style.display="inline-block",b.style.paddingRight=e.g [...]
- (f.style.display="none",b.style.paddingRight=0);g.refreshSize()}function n(){d.sort(function(a,b){return a.node.compareDocumentPosition(b.node)===Node.DOCUMENT_POSITION_FOLLOWING?-1:1})}function h(){var a;for(a=0;a<d.length;a+=1){var b=d[a],c=b.node.parentElement,e=c.nextElementSibling,h=e.nextElementSibling,m=c.parentElement,l=0,l=d[d.indexOf(b)-1],n=void 0,b=g.getZoomLevel();c.style.left=(f.getBoundingClientRect().left-m.getBoundingClientRect().left)/b+"px";c.style.width=f.getBounding [...]
- b+"px";e.style.width=parseFloat(c.style.left)-30+"px";l&&(n=l.node.parentElement.getBoundingClientRect(),20>=(m.getBoundingClientRect().top-n.bottom)/b?c.style.top=Math.abs(m.getBoundingClientRect().top-n.bottom)/b+20+"px":c.style.top="0px");h.style.left=e.getBoundingClientRect().width/b+"px";var e=h.style,m=h.getBoundingClientRect().left/b,l=h.getBoundingClientRect().top/b,n=c.getBoundingClientRect().left/b,r=c.getBoundingClientRect().top/b,p=0,s=0,p=n-m,p=p*p,s=r-l,s=s*s,m=Math.sqrt(p [...]
- m+"px";l=Math.asin((c.getBoundingClientRect().top-h.getBoundingClientRect().top)/(b*parseFloat(h.style.width)));h.style.transform="rotate("+l+"rad)";h.style.MozTransform="rotate("+l+"rad)";h.style.WebkitTransform="rotate("+l+"rad)";h.style.msTransform="rotate("+l+"rad)"}}var d=[],m=l.ownerDocument,c=new odf.OdfUtils,e=runtime.getWindow();runtime.assert(Boolean(e),"Expected to be run in an environment which has a global window, like a browser.");this.rerenderAnnotations=h;this.addAnnotat [...]
- d.push({node:a.node,end:a.end});n();var b=m.createElement("div"),c=m.createElement("div"),e=m.createElement("div"),f=m.createElement("div"),g=m.createElement("div"),l=a.node;b.className="annotationWrapper";l.parentNode.insertBefore(b,l);c.className="annotationNote";c.appendChild(l);g.className="annotationRemoveButton";c.appendChild(g);e.className="annotationConnector horizontal";f.className="annotationConnector angular";b.appendChild(c);b.appendChild(e);b.appendChild(f);a.end&&p(a);h()} [...]
- function(){for(;d.length;){var a=d[0],b=d.indexOf(a),c=a.node,e=c.parentNode.parentNode;"div"===e.localName&&(e.parentNode.insertBefore(c,e),e.parentNode.removeChild(e));a=a.node.getAttributeNS(odf.Namespaces.officens,"name");a=m.querySelectorAll('span.annotationHighlight[annotation="'+a+'"]');e=c=void 0;for(c=0;c<a.length;c+=1){for(e=a.item(c);e.firstChild;)e.parentNode.insertBefore(e.firstChild,e);e.parentNode.removeChild(e)}-1!==b&&d.splice(b,1);0===d.length&&r(!1)}}};
- // Input 28
++odf.OdfUtils=function(){function m(a){return"image"===(a&&a.localName)&&a.namespaceURI===T}function h(a){return null!==a&&a.nodeType===Node.ELEMENT_NODE&&"frame"===a.localName&&a.namespaceURI===T&&"as-char"===a.getAttributeNS(U,"anchor-type")}function b(a){var b;(b="annotation"===(a&&a.localName)&&a.namespaceURI===odf.Namespaces.officens)||(b="div"===(a&&a.localName)&&"annotationWrapper"===a.className);return b}function g(a){return"a"===(a&&a.localName)&&a.namespaceURI===U}function d(a) [...]
++a.localName;return("p"===b||"h"===b)&&a.namespaceURI===U}function n(a){for(;a&&!d(a);)a=a.parentNode;return a}function p(a){return/^[ \t\r\n]+$/.test(a)}function k(a){if(null===a||a.nodeType!==Node.ELEMENT_NODE)return!1;var b=a.localName;return/^(span|p|h|a|meta)$/.test(b)&&a.namespaceURI===U||"span"===b&&"annotationHighlight"===a.className}function q(a){var b=a&&a.localName,c=!1;b&&(a=a.namespaceURI,a===U&&(c="s"===b||"tab"===b||"line-break"===b));return c}function e(a){return q(a)||h( [...]
++a&&a.localName,c=!1;b&&(a=a.namespaceURI,a===U&&(c="s"===b));return c}function a(a){for(;null!==a.firstChild&&k(a);)a=a.firstChild;return a}function c(a){for(;null!==a.lastChild&&k(a);)a=a.lastChild;return a}function l(a){for(;!d(a)&&null===a.previousSibling;)a=a.parentNode;return d(a)?null:c(a.previousSibling)}function f(b){for(;!d(b)&&null===b.nextSibling;)b=b.parentNode;return d(b)?null:a(b.nextSibling)}function v(a){for(var b=!1;a;)if(a.nodeType===Node.TEXT_NODE)if(0===a.length)a=l( [...]
++1,1));else e(a)?(b=!1===r(a),a=null):a=l(a);return b}function w(b){var c=!1,d;for(b=b&&a(b);b;){d=b.nodeType===Node.TEXT_NODE?b.length:0;if(0<d&&!p(b.data)){c=!0;break}if(e(b)){c=!0;break}b=f(b)}return c}function z(a,b){return p(a.data.substr(b))?!w(f(a)):!1}function x(a,b){var c=a.data,d;if(!p(c[b])||e(a.parentNode))return!1;0<b?p(c[b-1])||(d=!0):v(l(a))&&(d=!0);return!0===d?z(a,b)?!1:!0:!1}function t(a){return(a=/(-?[0-9]*[0-9][0-9]*(\.[0-9]*)?|0+\.[0-9]*[1-9][0-9]*|\.[0-9]*[1-9][0-9] [...]
++{value:parseFloat(a[1]),unit:a[3]}:null}function u(a){return(a=t(a))&&(0>a.value||"%"===a.unit)?null:a}function s(a){return(a=t(a))&&"%"!==a.unit?null:a}function y(a){switch(a.namespaceURI){case odf.Namespaces.drawns:case odf.Namespaces.svgns:case odf.Namespaces.dr3dns:return!1;case odf.Namespaces.textns:switch(a.localName){case "note-body":case "ruby-text":return!1}break;case odf.Namespaces.officens:switch(a.localName){case "annotation":case "binary-data":case "event-listeners":return! [...]
++function F(a,b){for(;0<b.length&&!ba.rangeContainsNode(a,b[0]);)b.shift();for(;0<b.length&&!ba.rangeContainsNode(a,b[b.length-1]);)b.pop()}function L(a,c,d){var f;f=ba.getNodesInRange(a,function(a){var c=NodeFilter.FILTER_REJECT;if(q(a.parentNode)||b(a))c=NodeFilter.FILTER_REJECT;else if(a.nodeType===Node.TEXT_NODE){if(d||Boolean(n(a)&&(!p(a.textContent)||x(a,0))))c=NodeFilter.FILTER_ACCEPT}else if(e(a))c=NodeFilter.FILTER_ACCEPT;else if(y(a)||k(a))c=NodeFilter.FILTER_SKIP;return c},Nod [...]
++NodeFilter.SHOW_TEXT);c||F(a,f);return f}function O(a,c,d){for(;a;){if(d(a)){c[0]!==a&&c.unshift(a);break}if(b(a))break;a=a.parentNode}}function H(a,b){var c=a;if(b<c.childNodes.length-1)c=c.childNodes[b+1];else{for(;!c.nextSibling;)c=c.parentNode;c=c.nextSibling}for(;c.firstChild;)c=c.firstChild;return c}var U=odf.Namespaces.textns,T=odf.Namespaces.drawns,X=odf.Namespaces.xlinkns,D=/^\s*$/,ba=new core.DomUtils;this.isImage=m;this.isCharacterFrame=h;this.isInlineRoot=b;this.isTextSpan=f [...]
++(a&&a.localName)&&a.namespaceURI===U};this.isHyperlink=g;this.getHyperlinkTarget=function(a){return a.getAttributeNS(X,"href")};this.isParagraph=d;this.getParagraphElement=n;this.isWithinTrackedChanges=function(a,b){for(;a&&a!==b;){if(a.namespaceURI===U&&"tracked-changes"===a.localName)return!0;a=a.parentNode}return!1};this.isListItem=function(a){return"list-item"===(a&&a.localName)&&a.namespaceURI===U};this.isLineBreak=function(a){return"line-break"===(a&&a.localName)&&a.namespaceURI== [...]
++p;this.isGroupingElement=k;this.isCharacterElement=q;this.isAnchoredAsCharacterElement=e;this.isSpaceElement=r;this.firstChild=a;this.lastChild=c;this.previousNode=l;this.nextNode=f;this.scanLeftForNonSpace=v;this.lookLeftForCharacter=function(a){var b,c=b=0;a.nodeType===Node.TEXT_NODE&&(c=a.length);0<c?(b=a.data,b=p(b.substr(c-1,1))?1===c?v(l(a))?2:0:p(b.substr(c-2,1))?0:2:1):e(a)&&(b=1);return b};this.lookRightForCharacter=function(a){var b=!1,c=0;a&&a.nodeType===Node.TEXT_NODE&&(c=a. [...]
++c?b=!p(a.data.substr(0,1)):e(a)&&(b=!0);return b};this.scanLeftForAnyCharacter=function(a){var b=!1,d;for(a=a&&c(a);a;){d=a.nodeType===Node.TEXT_NODE?a.length:0;if(0<d&&!p(a.data)){b=!0;break}if(e(a)){b=!0;break}a=l(a)}return b};this.scanRightForAnyCharacter=w;this.isTrailingWhitespace=z;this.isSignificantWhitespace=x;this.isDowngradableSpaceElement=function(a){return a.namespaceURI===U&&"s"===a.localName?v(l(a))&&w(f(a)):!1};this.getFirstNonWhitespaceChild=function(a){for(a=a&&a.firstC [...]
++Node.TEXT_NODE&&D.test(a.nodeValue);)a=a.nextSibling;return a};this.parseLength=t;this.parseNonNegativeLength=u;this.parseFoFontSize=function(a){var b;b=(b=t(a))&&(0>=b.value||"%"===b.unit)?null:b;return b||s(a)};this.parseFoLineHeight=function(a){return u(a)||s(a)};this.isTextContentContainingNode=y;this.getTextNodes=function(a,b){var c;c=ba.getNodesInRange(a,function(a){var b=NodeFilter.FILTER_REJECT;a.nodeType===Node.TEXT_NODE?Boolean(n(a)&&(!p(a.textContent)||x(a,0)))&&(b=NodeFilter [...]
++y(a)&&(b=NodeFilter.FILTER_SKIP);return b},NodeFilter.SHOW_ELEMENT|NodeFilter.SHOW_TEXT);b||F(a,c);return c};this.getTextElements=L;this.getParagraphElements=function(a){var b;b=ba.getNodesInRange(a,function(a){var b=NodeFilter.FILTER_REJECT;if(d(a))b=NodeFilter.FILTER_ACCEPT;else if(y(a)||k(a))b=NodeFilter.FILTER_SKIP;return b},NodeFilter.SHOW_ELEMENT);O(a.startContainer,b,d);return b};this.getImageElements=function(a){var b;b=ba.getNodesInRange(a,function(a){var b=NodeFilter.FILTER_SK [...]
++NodeFilter.FILTER_ACCEPT);return b},NodeFilter.SHOW_ELEMENT);O(a.startContainer,b,m);return b};this.getHyperlinkElements=function(a){var b=[],c=a.cloneRange();a.collapsed&&a.endContainer.nodeType===Node.ELEMENT_NODE&&(a=H(a.endContainer,a.endOffset),a.nodeType===Node.TEXT_NODE&&c.setEnd(a,1));L(c,!0,!1).forEach(function(a){for(a=a.parentNode;!d(a);){if(g(a)&&-1===b.indexOf(a)){b.push(a);break}a=a.parentNode}});c.detach();return b}};
++// Input 29
 +/*
 +
 + Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("core.Cursor");runtime.loadClass("core.DomUtils");runtime.loadClass("core.PositionIterator");runtime.loadClass("core.PositionFilter");runtime.loadClass("core.LoopWatchDog");runtime.loadClass("odf.OdfUtils");
- gui.SelectionMover=function(g,l){function f(){w.setUnfilteredPosition(g.getNode(),0);return w}function p(a,b){var c,d=null;a&&0<a.length&&(c=b?a.item(a.length-1):a.item(0));c&&(d={top:c.top,left:b?c.right:c.left,bottom:c.bottom});return d}function r(a,b,c,d){var e=a.nodeType;c.setStart(a,b);c.collapse(!d);d=p(c.getClientRects(),!0===d);!d&&0<b&&(c.setStart(a,b-1),c.setEnd(a,b),d=p(c.getClientRects(),!0));d||(e===Node.ELEMENT_NODE&&0<b&&a.childNodes.length>=b?d=r(a,b-1,c,!0):a.nodeType== [...]
- 0<b?d=r(a,b-1,c,!0):a.previousSibling?d=r(a.previousSibling,a.previousSibling.nodeType===Node.TEXT_NODE?a.previousSibling.textContent.length:a.previousSibling.childNodes.length,c,!0):a.parentNode&&a.parentNode!==l?d=r(a.parentNode,0,c,!1):(c.selectNode(l),d=p(c.getClientRects(),!1)));runtime.assert(Boolean(d),"No visible rectangle found");return d}function n(a,b,c){var d=a,e=f(),h,k=l.ownerDocument.createRange(),q=g.getSelectedRange().cloneRange(),m;for(h=r(e.container(),e.unfilteredDom [...]
- d&&c();)d-=1;b?(b=e.container(),e=e.unfilteredDomOffset(),-1===A.comparePoints(q.startContainer,q.startOffset,b,e)?(q.setStart(b,e),m=!1):q.setEnd(b,e)):(q.setStart(e.container(),e.unfilteredDomOffset()),q.collapse(!0));g.setSelectedRange(q,m);e=f();q=r(e.container(),e.unfilteredDomOffset(),k);if(q.top===h.top||void 0===x)x=q.left;runtime.clearTimeout(v);v=runtime.setTimeout(function(){x=void 0},2E3);k.detach();return a-d}function h(a){var b=f();return a.acceptPosition(b)===u&&(b.setUnf [...]
- 0),a.acceptPosition(b)===u)?!0:!1}function d(a,b,c){for(var d=new core.LoopWatchDog(1E4),e=0,f=0,h=0<=b?1:-1,k=0<=b?a.nextPosition:a.previousPosition;0!==b&&k();)d.check(),f+=h,c.acceptPosition(a)===u&&(b-=h,e+=f,f=0);return e}function m(a,b,c){for(var d=f(),e=new core.LoopWatchDog(1E4),h=0,k=0;0<a&&d.nextPosition();)e.check(),c.acceptPosition(d)===u&&(h+=1,b.acceptPosition(d)===u&&(k+=h,h=0,a-=1));return k}function c(a,b,c){for(var d=f(),e=new core.LoopWatchDog(1E4),h=0,k=0;0<a&&d.prev [...]
- c.acceptPosition(d)===u&&(h+=1,b.acceptPosition(d)===u&&(k+=h,h=0,a-=1));return k}function e(a,b){var c=f();return d(c,a,b)}function a(a,b,c){var e=f(),h=t.getParagraphElement(e.getCurrentNode()),k=0;e.setUnfilteredPosition(a,b);c.acceptPosition(e)!==u&&(k=d(e,-1,c),0===k||h&&h!==t.getParagraphElement(e.getCurrentNode()))&&(e.setUnfilteredPosition(a,b),k=d(e,1,c));return k}function b(a,b){var c=f(),d=0,e=0,h=0>a?-1:1;for(a=Math.abs(a);0<a;){for(var k=b,q=h,g=c,m=g.container(),n=0,p=null [...]
- t=10,w=void 0,A=0,F=void 0,C=void 0,Y=void 0,w=void 0,U=l.ownerDocument.createRange(),R=new core.LoopWatchDog(1E4),w=r(m,g.unfilteredDomOffset(),U),F=w.top,C=void 0===x?w.left:x,Y=F;!0===(0>q?g.previousPosition():g.nextPosition());)if(R.check(),k.acceptPosition(g)===u&&(n+=1,m=g.container(),w=r(m,g.unfilteredDomOffset(),U),w.top!==F)){if(w.top!==Y&&Y!==F)break;Y=w.top;w=Math.abs(C-w.left);if(null===p||w<t)p=m,v=g.unfilteredDomOffset(),t=w,A=n}null!==p?(g.setUnfilteredPosition(p,v),n=A): [...]
- d+=n;if(0===d)break;e+=d;a-=1}return e*h}function q(a,b){var c,d,e,h,k=f(),q=t.getParagraphElement(k.getCurrentNode()),g=0,m=l.ownerDocument.createRange();0>a?(c=k.previousPosition,d=-1):(c=k.nextPosition,d=1);for(e=r(k.container(),k.unfilteredDomOffset(),m);c.call(k);)if(b.acceptPosition(k)===u){if(t.getParagraphElement(k.getCurrentNode())!==q)break;h=r(k.container(),k.unfilteredDomOffset(),m);if(h.bottom!==e.bottom&&(e=h.top>=e.top&&h.bottom<e.bottom||h.top<=e.top&&h.bottom>e.bottom,! [...]
- d;e=h}m.detach();return g}function k(a,b,c){runtime.assert(null!==a,"SelectionMover.countStepsToPosition called with element===null");var d=f(),e=d.container(),h=d.unfilteredDomOffset(),k=0,q=new core.LoopWatchDog(1E4);for(d.setUnfilteredPosition(a,b);c.acceptPosition(d)!==u&&d.previousPosition();)q.check();a=d.container();runtime.assert(Boolean(a),"SelectionMover.countStepsToPosition: positionIterator.container() returned null");b=d.unfilteredDomOffset();for(d.setUnfilteredPosition(e,h [...]
- u&&d.previousPosition();)q.check();e=A.comparePoints(a,b,d.container(),d.unfilteredDomOffset());if(0>e)for(;d.nextPosition()&&(q.check(),c.acceptPosition(d)===u&&(k+=1),d.container()!==a||d.unfilteredDomOffset()!==b););else if(0<e)for(;d.previousPosition()&&(q.check(),c.acceptPosition(d)!==u||(k-=1,d.container()!==a||d.unfilteredDomOffset()!==b)););return k}var t=new odf.OdfUtils,A=new core.DomUtils,w,x,v,u=core.PositionFilter.FilterResult.FILTER_ACCEPT;this.movePointForward=function(a, [...]
- b||!1,w.nextPosition)};this.movePointBackward=function(a,b){return n(a,b||!1,w.previousPosition)};this.getStepCounter=function(){return{countSteps:e,convertForwardStepsBetweenFilters:m,convertBackwardStepsBetweenFilters:c,countLinesSteps:b,countStepsToLineBoundary:q,countStepsToPosition:k,isPositionWalkable:h,countPositionsToNearestStep:a}};(function(){w=gui.SelectionMover.createPositionIterator(l);var a=l.ownerDocument.createRange();a.setStart(w.container(),w.unfilteredDomOffset());a.c [...]
- g.setSelectedRange(a)})()};gui.SelectionMover.createPositionIterator=function(g){var l=new function(){this.acceptNode=function(f){return f&&"urn:webodf:names:cursor"!==f.namespaceURI&&"urn:webodf:names:editinfo"!==f.namespaceURI?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_REJECT}};return new core.PositionIterator(g,5,l,!1)};(function(){return gui.SelectionMover})();
- // Input 29
++gui.AnnotatableCanvas=function(){};gui.AnnotatableCanvas.prototype.refreshSize=function(){};gui.AnnotatableCanvas.prototype.getZoomLevel=function(){};gui.AnnotatableCanvas.prototype.getSizer=function(){};
++gui.AnnotationViewManager=function(m,h,b,g){function d(a){var b=a.annotationEndElement,d=e.createRange(),g=a.getAttributeNS(odf.Namespaces.officens,"name");b&&(d.setStart(a,a.childNodes.length),d.setEnd(b,0),a=r.getTextNodes(d,!1),a.forEach(function(a){var b=e.createElement("span");b.className="annotationHighlight";b.setAttribute("annotation",g);a.parentNode.insertBefore(b,a);b.appendChild(a)}));d.detach()}function n(c){var d=m.getSizer();c?(b.style.display="inline-block",d.style.paddin [...]
++(b.style.display="none",d.style.paddingRight=0);m.refreshSize()}function p(){q.sort(function(a,b){return 0!==(a.compareDocumentPosition(b)&Node.DOCUMENT_POSITION_FOLLOWING)?-1:1})}function k(){var a;for(a=0;a<q.length;a+=1){var d=q[a],f=d.parentNode,e=f.nextElementSibling,g=e.nextElementSibling,k=f.parentNode,h=0,h=q[q.indexOf(d)-1],n=void 0,d=m.getZoomLevel();f.style.left=(b.getBoundingClientRect().left-k.getBoundingClientRect().left)/d+"px";f.style.width=b.getBoundingClientRect().widt [...]
++parseFloat(f.style.left)-30+"px";h&&(n=h.parentNode.getBoundingClientRect(),20>=(k.getBoundingClientRect().top-n.bottom)/d?f.style.top=Math.abs(k.getBoundingClientRect().top-n.bottom)/d+20+"px":f.style.top="0px");g.style.left=e.getBoundingClientRect().width/d+"px";var e=g.style,k=g.getBoundingClientRect().left/d,h=g.getBoundingClientRect().top/d,n=f.getBoundingClientRect().left/d,p=f.getBoundingClientRect().top/d,r=0,y=0,r=n-k,r=r*r,y=p-h,y=y*y,k=Math.sqrt(r+y);e.width=k+"px";h=Math.asi [...]
++g.getBoundingClientRect().top)/(d*parseFloat(g.style.width)));g.style.transform="rotate("+h+"rad)";g.style.MozTransform="rotate("+h+"rad)";g.style.WebkitTransform="rotate("+h+"rad)";g.style.msTransform="rotate("+h+"rad)"}}var q=[],e=h.ownerDocument,r=new odf.OdfUtils,a=runtime.getWindow();runtime.assert(Boolean(a),"Expected to be run in an environment which has a global window, like a browser.");this.rerenderAnnotations=k;this.getMinimumHeightForAnnotationPane=function(){return"none"!== [...]
++0<q.length?(q[q.length-1].parentNode.getBoundingClientRect().bottom-b.getBoundingClientRect().top)/m.getZoomLevel()+"px":null};this.addAnnotation=function(a){n(!0);q.push(a);p();var b=e.createElement("div"),f=e.createElement("div"),h=e.createElement("div"),m=e.createElement("div"),r;b.className="annotationWrapper";a.parentNode.insertBefore(b,a);f.className="annotationNote";f.appendChild(a);g&&(r=e.createElement("div"),r.className="annotationRemoveButton",f.appendChild(r));h.className="a [...]
++m.className="annotationConnector angular";b.appendChild(f);b.appendChild(h);b.appendChild(m);a.annotationEndElement&&d(a);k()};this.forgetAnnotations=function(){for(;q.length;){var a=q[0],b=q.indexOf(a),d=a.parentNode.parentNode;"div"===d.localName&&(d.parentNode.insertBefore(a,d),d.parentNode.removeChild(d));for(var a=a.getAttributeNS(odf.Namespaces.officens,"name"),a=e.querySelectorAll('span.annotationHighlight[annotation="'+a+'"]'),g=d=void 0,d=0;d<a.length;d+=1){for(g=a.item(d);g.fi [...]
++g);g.parentNode.removeChild(g)}-1!==b&&q.splice(b,1);0===q.length&&n(!1)}}};
++// Input 30
 +/*
 +
-  Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
++ Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- odf.OdfNodeFilter=function(){this.acceptNode=function(g){return"http://www.w3.org/1999/xhtml"===g.namespaceURI?NodeFilter.FILTER_SKIP:g.namespaceURI&&g.namespaceURI.match(/^urn:webodf:/)?NodeFilter.FILTER_REJECT:NodeFilter.FILTER_ACCEPT}};
- // Input 30
++(function(){function m(g,d,h,p,k){var q,e=0,r;for(r in g)if(g.hasOwnProperty(r)){if(e===h){q=r;break}e+=1}q?d.getPartData(g[q].href,function(a,c){if(a)runtime.log(a);else if(c){var e="@font-face { font-family: '"+(g[q].family||q)+"'; src: url(data:application/x-font-ttf;charset=binary;base64,"+b.convertUTF8ArrayToBase64(c)+') format("truetype"); }';try{p.insertRule(e,p.cssRules.length)}catch(f){runtime.log("Problem inserting rule in CSS: "+runtime.toJson(f)+"\nRule: "+e)}}else runtime.l [...]
++g[q].href);m(g,d,h+1,p,k)}):k&&k()}var h=xmldom.XPath,b=new core.Base64;odf.FontLoader=function(){this.loadFonts=function(b,d){for(var n=b.rootElement.fontFaceDecls;d.cssRules.length;)d.deleteRule(d.cssRules.length-1);if(n){var p={},k,q,e,r;if(n)for(n=h.getODFElementsWithXPath(n,"style:font-face[svg:font-face-src]",odf.Namespaces.lookupNamespaceURI),k=0;k<n.length;k+=1)q=n[k],e=q.getAttributeNS(odf.Namespaces.stylens,"name"),r=q.getAttributeNS(odf.Namespaces.svgns,"font-family"),q=h.get [...]
++"svg:font-face-src/svg:font-face-uri",odf.Namespaces.lookupNamespaceURI),0<q.length&&(q=q[0].getAttributeNS(odf.Namespaces.xlinkns,"href"),p[e]={href:q,family:r});m(p,b,0,d)}}};return odf.FontLoader})();
++// Input 31
 +/*
 +
 + Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("odf.Namespaces");runtime.loadClass("odf.OdfUtils");runtime.loadClass("xmldom.XPath");runtime.loadClass("core.CSSUnits");odf.StyleTreeNode=function(g){this.derivedStyles={};this.element=g};
- odf.Style2CSS=function(){function g(a){var b,c,d,e={};if(!a)return e;for(a=a.firstElementChild;a;){if(c=a.namespaceURI!==k||"style"!==a.localName&&"default-style"!==a.localName?a.namespaceURI===w&&"list-style"===a.localName?"list":a.namespaceURI!==k||"page-layout"!==a.localName&&"default-page-layout"!==a.localName?void 0:"page":a.getAttributeNS(k,"family"))(b=a.getAttributeNS(k,"name"))||(b=""),e.hasOwnProperty(c)?d=e[c]:e[c]=d={},d[b]=a;a=a.nextElementSibling}return e}function l(a,b){i [...]
- var c,d=null;for(c in a)if(a.hasOwnProperty(c)&&(d=l(a[c].derivedStyles,b)))break;return d}function f(a,b,c){var d,e,h;if(!b.hasOwnProperty(a))return null;d=new odf.StyleTreeNode(b[a]);e=d.element.getAttributeNS(k,"parent-style-name");h=null;e&&(h=l(c,e)||f(e,b,c));h?h.derivedStyles[a]=d:c[a]=d;delete b[a];return d}function p(a,b){for(var c in a)a.hasOwnProperty(c)&&f(c,a,b)}function r(a,b,c){var d=[];c=c.derivedStyles;var e;var f=u[a],h;void 0===f?b=null:(h=b?"["+f+'|style-name="'+b+'" [...]
- f&&(f="draw",h=b?'[presentation|style-name="'+b+'"]':""),b=f+"|"+s[a].join(h+","+f+"|")+h);null!==b&&d.push(b);for(e in c)c.hasOwnProperty(e)&&(b=r(a,e,c[e]),d=d.concat(b));return d}function n(a,b,c){for(a=a&&a.firstElementChild;a&&(a.namespaceURI!==b||a.localName!==c);)a=a.nextElementSibling;return a}function h(a,b){var c="",d,e,f;for(d=0;d<b.length;d+=1)if(e=b[d],f=a.getAttributeNS(e[0],e[1])){f=f.trim();if(G.hasOwnProperty(e[1])){var h=f.indexOf(" "),k=void 0,q=void 0;-1!==h?(k=f.sub [...]
- q=f.substring(h)):(k=f,q="");(k=O.parseLength(k))&&"pt"===k.unit&&0.75>k.value&&(f="0.75pt"+q)}e[2]&&(c+=e[2]+":"+f+";")}return c}function d(a){return(a=n(a,k,"text-properties"))?O.parseFoFontSize(a.getAttributeNS(b,"font-size")):null}function m(a,b,c,d){return b+b+c+c+d+d}function c(a,c,d,e){c='text|list[text|style-name="'+c+'"]';var f=d.getAttributeNS(w,"level");d=n(d,k,"list-level-properties");d=n(d,k,"list-level-label-alignment");var h,q;d&&(h=d.getAttributeNS(b,"text-indent"),q=d.g [...]
- "margin-left"));h||(h="-0.6cm");d="-"===h.charAt(0)?h.substring(1):"-"+h;for(f=f&&parseInt(f,10);1<f;)c+=" > text|list-item > text|list",f-=1;if(q){f=c+" > text|list-item > *:not(text|list):first-child";f+="{";f=f+("margin-left:"+q+";")+"}";try{a.insertRule(f,a.cssRules.length)}catch(g){runtime.log("cannot load rule: "+f)}}e=c+" > text|list-item > *:not(text|list):first-child:before{"+e+";";e=e+"counter-increment:list;"+("margin-left:"+h+";");e+="width:"+d+";";e+="display:inline-block}" [...]
- a.cssRules.length)}catch(m){runtime.log("cannot load rule: "+e)}}function e(f,g,l,p){if("list"===g)for(var s=p.element.firstChild,t,u;s;){if(s.namespaceURI===w)if(t=s,"list-level-style-number"===s.localName){var G=t;u=G.getAttributeNS(k,"num-format");var T=G.getAttributeNS(k,"num-suffix")||"",G=G.getAttributeNS(k,"num-prefix")||"",$={1:"decimal",a:"lower-latin",A:"upper-latin",i:"lower-roman",I:"upper-roman"},X="";G&&(X+=' "'+G+'"');X=$.hasOwnProperty(u)?X+(" counter(list, "+$[u]+")"):u [...]
- '"'):X+" ''";u="content:"+X+' "'+T+'"';c(f,l,t,u)}else"list-level-style-image"===s.localName?(u="content: none;",c(f,l,t,u)):"list-level-style-bullet"===s.localName&&(u="content: '"+t.getAttributeNS(w,"bullet-char")+"';",c(f,l,t,u));s=s.nextSibling}else if("page"===g){if(u=p.element,G=T=l="",s=n(u,k,"page-layout-properties"))if(t=u.getAttributeNS(k,"name"),l+=h(s,ja),(T=n(s,k,"background-image"))&&(G=T.getAttributeNS(x,"href"))&&(l=l+("background-image: url('odfkit:"+G+"');")+h(T,y)),"p [...]
- aa)for(u=(u=n(u.parentNode.parentElement,q,"master-styles"))&&u.firstElementChild;u;){if(u.namespaceURI===k&&"master-page"===u.localName&&u.getAttributeNS(k,"page-layout-name")===t){G=u.getAttributeNS(k,"name");T="draw|page[draw|master-page-name="+G+"] {"+l+"}";G="office|body, draw|page[draw|master-page-name="+G+"] {"+h(s,ka)+" }";try{f.insertRule(T,f.cssRules.length),f.insertRule(G,f.cssRules.length)}catch(da){throw da;}}u=u.nextElementSibling}else if("text"===aa){T="office|text {"+l+" [...]
- s.getAttributeNS(b,"page-width")+";}";try{f.insertRule(T,f.cssRules.length),f.insertRule(G,f.cssRules.length)}catch(S){throw S;}}}else{l=r(g,l,p).join(",");s="";if(t=n(p.element,k,"text-properties")){G=t;u=X="";T=1;t=""+h(G,H);$=G.getAttributeNS(k,"text-underline-style");"solid"===$&&(X+=" underline");$=G.getAttributeNS(k,"text-line-through-style");"solid"===$&&(X+=" line-through");X.length&&(t+="text-decoration:"+X+";");if(X=G.getAttributeNS(k,"font-name")||G.getAttributeNS(b,"font-fam [...]
- t+="font-family: "+($||X)+";";$=G.parentElement;if(G=d($)){for(;$;){if(G=d($)){if("%"!==G.unit){u="font-size: "+G.value*T+G.unit+";";break}T*=G.value/100}G=$;X=$="";$=null;"default-style"===G.localName?$=null:($=G.getAttributeNS(k,"parent-style-name"),X=G.getAttributeNS(k,"family"),$=C.getODFElementsWithXPath(J,$?"//style:*[@style:name='"+$+"'][@style:family='"+X+"']":"//style:default-style[@style:family='"+X+"']",odf.Namespaces.lookupNamespaceURI)[0])}u||(u="font-size: "+parseFloat(F)* [...]
- ";");t+=u}s+=t}if(t=n(p.element,k,"paragraph-properties"))u=t,t=""+h(u,B),(T=n(u,k,"background-image"))&&(G=T.getAttributeNS(x,"href"))&&(t=t+("background-image: url('odfkit:"+G+"');")+h(T,y)),(u=u.getAttributeNS(b,"line-height"))&&"normal"!==u&&(u=O.parseFoLineHeight(u),t="%"!==u.unit?t+("line-height: "+u.value+u.unit+";"):t+("line-height: "+u.value/100+";")),s+=t;if(t=n(p.element,k,"graphic-properties"))G=t,t=""+h(G,L),u=G.getAttributeNS(a,"opacity"),T=G.getAttributeNS(a,"fill"),G=G.g [...]
- "fill-color"),"solid"===T||"hatch"===T?G&&"none"!==G?(u=isNaN(parseFloat(u))?1:parseFloat(u)/100,T=G.replace(/^#?([a-f\d])([a-f\d])([a-f\d])$/i,m),(G=(T=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(T))?{r:parseInt(T[1],16),g:parseInt(T[2],16),b:parseInt(T[3],16)}:null)&&(t+="background-color: rgba("+G.r+","+G.g+","+G.b+","+u+");")):t+="background: none;":"none"===T&&(t+="background: none;"),s+=t;if(t=n(p.element,k,"drawing-page-properties"))u=""+h(t,L),"true"===t.getAttributeNS(v,"b [...]
- (u+="background: none;"),s+=u;if(t=n(p.element,k,"table-cell-properties"))t=""+h(t,I),s+=t;if(t=n(p.element,k,"table-row-properties"))t=""+h(t,Q),s+=t;if(t=n(p.element,k,"table-column-properties"))t=""+h(t,W),s+=t;if(t=n(p.element,k,"table-properties"))u=t,t=""+h(u,z),u=u.getAttributeNS(A,"border-model"),"collapsing"===u?t+="border-collapse:collapse;":"separating"===u&&(t+="border-collapse:separate;"),s+=t;if(0!==s.length)try{f.insertRule(l+"{"+s+"}",f.cssRules.length)}catch(ga){throw g [...]
- e(f,g,E,p.derivedStyles[E])}var a=odf.Namespaces.drawns,b=odf.Namespaces.fons,q=odf.Namespaces.officens,k=odf.Namespaces.stylens,t=odf.Namespaces.svgns,A=odf.Namespaces.tablens,w=odf.Namespaces.textns,x=odf.Namespaces.xlinkns,v=odf.Namespaces.presentationns,u={graphic:"draw","drawing-page":"draw",paragraph:"text",presentation:"presentation",ruby:"text",section:"text",table:"table","table-cell":"table","table-column":"table","table-row":"table",text:"text",list:"text",page:"office"},s={g [...]
- paragraph:"alphabetical-index-entry-template h illustration-index-entry-template index-source-style object-index-entry-template p table-index-entry-template table-of-content-entry-template user-index-entry-template".split(" "),presentation:"caption circle connector control custom-shape ellipse frame g line measure page-thumbnail path polygon polyline rect regular-polygon".split(" "),"drawing-page":"caption circle connector control page custom-shape ellipse frame g line measure page-thum [...]
- ruby:["ruby","ruby-text"],section:"alphabetical-index bibliography illustration-index index-title object-index section table-of-content table-index user-index".split(" "),table:["background","table"],"table-cell":"body covered-table-cell even-columns even-rows first-column first-row last-column last-row odd-columns odd-rows table-cell".split(" "),"table-column":["table-column"],"table-row":["table-row"],text:"a index-entry-chapter index-entry-link-end index-entry-link-start index-entry- [...]
- list:["list-item"]},H=[[b,"color","color"],[b,"background-color","background-color"],[b,"font-weight","font-weight"],[b,"font-style","font-style"]],y=[[k,"repeat","background-repeat"]],B=[[b,"background-color","background-color"],[b,"text-align","text-align"],[b,"text-indent","text-indent"],[b,"padding","padding"],[b,"padding-left","padding-left"],[b,"padding-right","padding-right"],[b,"padding-top","padding-top"],[b,"padding-bottom","padding-bottom"],[b,"border-left","border-left"],[b, [...]
- "border-right"],[b,"border-top","border-top"],[b,"border-bottom","border-bottom"],[b,"margin","margin"],[b,"margin-left","margin-left"],[b,"margin-right","margin-right"],[b,"margin-top","margin-top"],[b,"margin-bottom","margin-bottom"],[b,"border","border"]],L=[[b,"background-color","background-color"],[b,"min-height","min-height"],[a,"stroke","border"],[t,"stroke-color","border-color"],[t,"stroke-width","border-width"],[b,"border","border"],[b,"border-left","border-left"],[b,"border-ri [...]
- [b,"border-top","border-top"],[b,"border-bottom","border-bottom"]],I=[[b,"background-color","background-color"],[b,"border-left","border-left"],[b,"border-right","border-right"],[b,"border-top","border-top"],[b,"border-bottom","border-bottom"],[b,"border","border"]],W=[[k,"column-width","width"]],Q=[[k,"row-height","height"],[b,"keep-together",null]],z=[[k,"width","width"],[b,"margin-left","margin-left"],[b,"margin-right","margin-right"],[b,"margin-top","margin-top"],[b,"margin-bottom", [...]
- ja=[[b,"background-color","background-color"],[b,"padding","padding"],[b,"padding-left","padding-left"],[b,"padding-right","padding-right"],[b,"padding-top","padding-top"],[b,"padding-bottom","padding-bottom"],[b,"border","border"],[b,"border-left","border-left"],[b,"border-right","border-right"],[b,"border-top","border-top"],[b,"border-bottom","border-bottom"],[b,"margin","margin"],[b,"margin-left","margin-left"],[b,"margin-right","margin-right"],[b,"margin-top","margin-top"],[b,"margi [...]
- "margin-bottom"]],ka=[[b,"page-width","width"],[b,"page-height","height"]],G={border:!0,"border-left":!0,"border-right":!0,"border-top":!0,"border-bottom":!0,"stroke-width":!0},Z={},O=new odf.OdfUtils,aa,J,F,C=xmldom.XPath,Y=new core.CSSUnits;this.style2css=function(a,b,c,d,f){for(var h,k,q,m;b.cssRules.length;)b.deleteRule(b.cssRules.length-1);h=null;d&&(h=d.ownerDocument,J=d.parentNode);f&&(h=f.ownerDocument,J=f.parentNode);if(h)for(m in odf.Namespaces.forEachPrefix(function(a,c){k="@ [...]
- a+" url("+c+");";try{b.insertRule(k,b.cssRules.length)}catch(d){}}),Z=c,aa=a,F=runtime.getWindow().getComputedStyle(document.body,null).getPropertyValue("font-size")||"12pt",a=g(d),d=g(f),f={},u)if(u.hasOwnProperty(m))for(q in c=f[m]={},p(a[m],c),p(d[m],c),c)c.hasOwnProperty(q)&&e(b,m,q,c[q])}};
- // Input 31
++odf.Formatting=function(){function m(a){return(a=u[a])?t.mergeObjects({},a):{}}function h(){for(var a=r.rootElement.fontFaceDecls,b={},d,f,a=a&&a.firstElementChild;a;){if(d=a.getAttributeNS(l,"name"))if((f=a.getAttributeNS(c,"font-family"))||0<a.getElementsByTagNameNS(c,"font-face-uri").length)b[d]=f;a=a.nextElementSibling}return b}function b(a){for(var b=r.rootElement.styles.firstElementChild;b;){if(b.namespaceURI===l&&"default-style"===b.localName&&b.getAttributeNS(l,"family")===a)ret [...]
++function g(a,b,c){var d,e,g;c=c||[r.rootElement.automaticStyles,r.rootElement.styles];for(g=0;g<c.length;g+=1)for(d=c[g],d=d.firstElementChild;d;){e=d.getAttributeNS(l,"name");if(d.namespaceURI===l&&"style"===d.localName&&d.getAttributeNS(l,"family")===b&&e===a||"list-style"===b&&d.namespaceURI===f&&"list-style"===d.localName&&e===a||"data"===b&&d.namespaceURI===v&&e===a)return d;d=d.nextElementSibling}return null}function d(a){for(var b,c,d,f,e={},g=a.firstElementChild;g;){if(g.namespa [...]
++e[g.nodeName]={},c=g.attributes,b=0;b<c.length;b+=1)f=c.item(b),d[f.name]=f.value;g=g.nextElementSibling}c=a.attributes;for(b=0;b<c.length;b+=1)f=c.item(b),e[f.name]=f.value;return e}function n(a,c){for(var f=r.rootElement.styles,e,k={},h=a.getAttributeNS(l,"family"),n=a;n;)e=d(n),k=t.mergeObjects(e,k),n=(e=n.getAttributeNS(l,"parent-style-name"))?g(e,h,[f]):null;if(n=b(h))e=d(n),k=t.mergeObjects(e,k);!1!==c&&(e=m(h),k=t.mergeObjects(e,k));return k}function p(b,c){function d(a){Object.k [...]
++"|"+b+":"+a+"|"})})}for(var f=b.nodeType===Node.TEXT_NODE?b.parentNode:b,e,l=[],g="",k=!1;f;)!k&&z.isGroupingElement(f)&&(k=!0),(e=a.determineStylesForNode(f))&&l.push(e),f=f.parentNode;k&&(l.forEach(d),c&&(c[g]=l));return k?l:void 0}function k(a){var b={orderedStyles:[]};a.forEach(function(a){Object.keys(a).forEach(function(c){var d=Object.keys(a[c])[0],f={name:d,family:c,displayName:void 0,isCommonStyle:!1},e;(e=g(d,c))?(c=n(e),b=t.mergeObjects(c,b),f.displayName=e.getAttributeNS(l,"d [...]
++f.isCommonStyle=e.parentNode===r.rootElement.styles):runtime.log("No style element found for '"+d+"' of family '"+c+"'");b.orderedStyles.push(f)})});return b}function q(a,b){var c={},d=[];b||(b={});a.forEach(function(a){p(a,c)});Object.keys(c).forEach(function(a){b[a]||(b[a]=k(c[a]));d.push(b[a])});return d}function e(a,b){var c=z.parseLength(a),d=b;if(c)switch(c.unit){case "cm":d=c.value;break;case "mm":d=0.1*c.value;break;case "in":d=2.54*c.value;break;case "pt":d=0.035277778*c.value; [...]
++default:runtime.log("Unit identifier: "+c.unit+" is not supported.")}return d}var r,a=new odf.StyleInfo,c=odf.Namespaces.svgns,l=odf.Namespaces.stylens,f=odf.Namespaces.textns,v=odf.Namespaces.numberns,w=odf.Namespaces.fons,z=new odf.OdfUtils,x=new core.DomUtils,t=new core.Utils,u={paragraph:{"style:paragraph-properties":{"fo:text-align":"left"}}};this.getSystemDefaultStyleAttributes=m;this.setOdfContainer=function(a){r=a};this.getFontMap=h;this.getAvailableParagraphStyles=function(){fo [...]
++b,c,d=[],a=a&&a.firstElementChild;a;)"style"===a.localName&&a.namespaceURI===l&&(b=a.getAttributeNS(l,"family"),"paragraph"===b&&(b=a.getAttributeNS(l,"name"),c=a.getAttributeNS(l,"display-name")||b,b&&c&&d.push({name:b,displayName:c}))),a=a.nextElementSibling;return d};this.isStyleUsed=function(b){var c,d=r.rootElement;c=a.hasDerivedStyles(d,odf.Namespaces.lookupNamespaceURI,b);b=(new a.UsedStyleList(d.styles)).uses(b)||(new a.UsedStyleList(d.automaticStyles)).uses(b)||(new a.UsedStyle [...]
++return c||b};this.getDefaultStyleElement=b;this.getStyleElement=g;this.getStyleAttributes=d;this.getInheritedStyleAttributes=n;this.getFirstCommonParentStyleNameOrSelf=function(a){var b=r.rootElement.automaticStyles,c=r.rootElement.styles,d;for(d=g(a,"paragraph",[b]);d;)a=d.getAttributeNS(l,"parent-style-name"),d=g(a,"paragraph",[b]);return(d=g(a,"paragraph",[c]))?a:null};this.hasParagraphStyle=function(a){return Boolean(g(a,"paragraph"))};this.getAppliedStyles=q;this.getAppliedStylesFo [...]
++b){return q([a],b)[0]};this.updateStyle=function(a,b){var d,f;x.mapObjOntoNode(a,b,odf.Namespaces.lookupNamespaceURI);(d=b["style:text-properties"]&&b["style:text-properties"]["style:font-name"])&&!h().hasOwnProperty(d)&&(f=a.ownerDocument.createElementNS(l,"style:font-face"),f.setAttributeNS(l,"style:name",d),f.setAttributeNS(c,"svg:font-family",d),r.rootElement.fontFaceDecls.appendChild(f))};this.createDerivedStyleObject=function(a,b,c){var f=g(a,b);runtime.assert(Boolean(f),"No style [...]
++a+"' of family '"+b+"'");a=f.parentNode===r.rootElement.styles?{"style:parent-style-name":a}:d(f);a["style:family"]=b;t.mergeObjects(a,c);return a};this.getDefaultTabStopDistance=function(){for(var a=b("paragraph"),a=a&&a.firstElementChild,c;a;)a.namespaceURI===l&&"paragraph-properties"===a.localName&&(c=a.getAttributeNS(l,"tab-stop-distance")),a=a.nextElementSibling;c||(c="1.25cm");return z.parseNonNegativeLength(c)};this.getContentSize=function(a,b){var c,d,f,k,h,n,p,m,q,v,t;a:{var u, [...]
++b);runtime.assert("paragraph"===b||"table"===b,"styleFamily has to be either paragraph or table");if(c){u=c.getAttributeNS(l,"master-page-name")||"Standard";for(c=r.rootElement.masterStyles.lastElementChild;c&&c.getAttributeNS(l,"name")!==u;)c=c.previousElementSibling;u=c.getAttributeNS(l,"page-layout-name");z=x.getElementsByTagNameNS(r.rootElement.automaticStyles,l,"page-layout");for(P=0;P<z.length;P+=1)if(c=z[P],c.getAttributeNS(l,"name")===u)break a}c=null}c||(c=x.getDirectChild(r.ro [...]
++l,"default-page-layout"));if(c=x.getDirectChild(c,l,"page-layout-properties"))d=c.getAttributeNS(l,"print-orientation")||"portrait","portrait"===d?(d=21.001,f=29.7):(d=29.7,f=21.001),d=e(c.getAttributeNS(w,"page-width"),d),f=e(c.getAttributeNS(w,"page-height"),f),k=e(c.getAttributeNS(w,"margin"),null),null===k?(k=e(c.getAttributeNS(w,"margin-left"),2),h=e(c.getAttributeNS(w,"margin-right"),2),n=e(c.getAttributeNS(w,"margin-top"),2),p=e(c.getAttributeNS(w,"margin-bottom"),2)):k=h=n=p=k,m [...]
++"padding"),null),null===m?(m=e(c.getAttributeNS(w,"padding-left"),0),q=e(c.getAttributeNS(w,"padding-right"),0),v=e(c.getAttributeNS(w,"padding-top"),0),t=e(c.getAttributeNS(w,"padding-bottom"),0)):m=q=v=t=m;return{width:d-k-h-m-q,height:f-n-p-v-t}}};
++// Input 32
 +/*
 +
 + Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("xmldom.XPath");runtime.loadClass("odf.Namespaces");
- odf.StyleInfo=function(){function g(a,b){var c,d,e,f,h,k=0;if(c=B[a.localName])if(e=c[a.namespaceURI])k=e.length;for(c=0;c<k;c+=1)d=e[c],f=d.ns,h=d.localname,(d=a.getAttributeNS(f,h))&&a.setAttributeNS(f,H[f]+h,b+d);for(e=a.firstElementChild;e;)g(e,b),e=e.nextElementSibling}function l(a,b){var c,d,e,f,h,k=0;if(c=B[a.localName])if(e=c[a.namespaceURI])k=e.length;for(c=0;c<k;c+=1)if(d=e[c],f=d.ns,h=d.localname,d=a.getAttributeNS(f,h))d=d.replace(b,""),a.setAttributeNS(f,H[f]+h,d);for(e=a.f [...]
- b),e=e.nextElementSibling}function f(a,b){var c,d,e,f,h,k=0;if(c=B[a.localName])if(e=c[a.namespaceURI])k=e.length;for(c=0;c<k;c+=1)if(f=e[c],d=f.ns,h=f.localname,d=a.getAttributeNS(d,h))b=b||{},f=f.keyname,b.hasOwnProperty(f)?b[f][d]=1:(h={},h[d]=1,b[f]=h);return b}function p(a,b){var c,d;f(a,b);for(c=a.firstChild;c;)c.nodeType===Node.ELEMENT_NODE&&(d=c,p(d,b)),c=c.nextSibling}function r(a,b,c){this.key=a;this.name=b;this.family=c;this.requires={}}function n(a,b,c){var d=a+'"'+b,e=c[d]; [...]
- new r(d,a,b));return e}function h(a,b,c){var d,e,f,k,q,g=0;d=a.getAttributeNS(v,"name");k=a.getAttributeNS(v,"family");d&&k&&(b=n(d,k,c));if(b){if(d=B[a.localName])if(f=d[a.namespaceURI])g=f.length;for(d=0;d<g;d+=1)if(k=f[d],e=k.ns,q=k.localname,e=a.getAttributeNS(e,q))k=k.keyname,k=n(e,k,c),b.requires[k.key]=k}for(a=a.firstElementChild;a;)h(a,b,c),a=a.nextElementSibling;return c}function d(a,b){var c=b[a.family];c||(c=b[a.family]={});c[a.name]=1;Object.keys(a.requires).forEach(function [...]
- b)})}function m(a,b){var c=h(a,null,{});Object.keys(c).forEach(function(a){a=c[a];var e=b[a.family];e&&e.hasOwnProperty(a.name)&&d(a,b)})}function c(a,b){function d(b){(b=h.getAttributeNS(v,b))&&(a[b]=!0)}var e=["font-name","font-name-asian","font-name-complex"],f,h;for(f=b&&b.firstElementChild;f;)h=f,e.forEach(d),c(a,h),f=f.nextElementSibling}function e(a,b){function c(a){var d=h.getAttributeNS(v,a);d&&b.hasOwnProperty(d)&&h.setAttributeNS(v,"style:"+a,b[d])}var d=["font-name","font-na [...]
- "font-name-complex"],f,h;for(f=a&&a.firstElementChild;f;)h=f,d.forEach(c),e(h,b),f=f.nextElementSibling}var a=odf.Namespaces.chartns,b=odf.Namespaces.dbns,q=odf.Namespaces.dr3dns,k=odf.Namespaces.drawns,t=odf.Namespaces.formns,A=odf.Namespaces.numberns,w=odf.Namespaces.officens,x=odf.Namespaces.presentationns,v=odf.Namespaces.stylens,u=odf.Namespaces.tablens,s=odf.Namespaces.textns,H={"urn:oasis:names:tc:opendocument:xmlns:chart:1.0":"chart:","urn:oasis:names:tc:opendocument:xmlns:datab [...]
- "urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0":"dr3d:","urn:oasis:names:tc:opendocument:xmlns:drawing:1.0":"draw:","urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0":"fo:","urn:oasis:names:tc:opendocument:xmlns:form:1.0":"form:","urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0":"number:","urn:oasis:names:tc:opendocument:xmlns:office:1.0":"office:","urn:oasis:names:tc:opendocument:xmlns:presentation:1.0":"presentation:","urn:oasis:names:tc:opendocument:xmlns:style:1.0":" [...]
- "urn:oasis:names:tc:opendocument:xmlns:table:1.0":"table:","urn:oasis:names:tc:opendocument:xmlns:text:1.0":"chart:","http://www.w3.org/XML/1998/namespace":"xml:"},y={text:[{ens:v,en:"tab-stop",ans:v,a:"leader-text-style"},{ens:v,en:"drop-cap",ans:v,a:"style-name"},{ens:s,en:"notes-configuration",ans:s,a:"citation-body-style-name"},{ens:s,en:"notes-configuration",ans:s,a:"citation-style-name"},{ens:s,en:"a",ans:s,a:"style-name"},{ens:s,en:"alphabetical-index",ans:s,a:"style-name"},{ens: [...]
- ans:s,a:"style-name"},{ens:s,en:"list-level-style-number",ans:s,a:"style-name"},{ens:s,en:"ruby-text",ans:s,a:"style-name"},{ens:s,en:"span",ans:s,a:"style-name"},{ens:s,en:"a",ans:s,a:"visited-style-name"},{ens:v,en:"text-properties",ans:v,a:"text-line-through-text-style"},{ens:s,en:"alphabetical-index-source",ans:s,a:"main-entry-style-name"},{ens:s,en:"index-entry-bibliography",ans:s,a:"style-name"},{ens:s,en:"index-entry-chapter",ans:s,a:"style-name"},{ens:s,en:"index-entry-link-end" [...]
- {ens:s,en:"index-entry-link-start",ans:s,a:"style-name"},{ens:s,en:"index-entry-page-number",ans:s,a:"style-name"},{ens:s,en:"index-entry-span",ans:s,a:"style-name"},{ens:s,en:"index-entry-tab-stop",ans:s,a:"style-name"},{ens:s,en:"index-entry-text",ans:s,a:"style-name"},{ens:s,en:"index-title-template",ans:s,a:"style-name"},{ens:s,en:"list-level-style-bullet",ans:s,a:"style-name"},{ens:s,en:"outline-level-style",ans:s,a:"style-name"}],paragraph:[{ens:k,en:"caption",ans:k,a:"text-style- [...]
- en:"circle",ans:k,a:"text-style-name"},{ens:k,en:"connector",ans:k,a:"text-style-name"},{ens:k,en:"control",ans:k,a:"text-style-name"},{ens:k,en:"custom-shape",ans:k,a:"text-style-name"},{ens:k,en:"ellipse",ans:k,a:"text-style-name"},{ens:k,en:"frame",ans:k,a:"text-style-name"},{ens:k,en:"line",ans:k,a:"text-style-name"},{ens:k,en:"measure",ans:k,a:"text-style-name"},{ens:k,en:"path",ans:k,a:"text-style-name"},{ens:k,en:"polygon",ans:k,a:"text-style-name"},{ens:k,en:"polyline",ans:k,a:" [...]
- {ens:k,en:"rect",ans:k,a:"text-style-name"},{ens:k,en:"regular-polygon",ans:k,a:"text-style-name"},{ens:w,en:"annotation",ans:k,a:"text-style-name"},{ens:t,en:"column",ans:t,a:"text-style-name"},{ens:v,en:"style",ans:v,a:"next-style-name"},{ens:u,en:"body",ans:u,a:"paragraph-style-name"},{ens:u,en:"even-columns",ans:u,a:"paragraph-style-name"},{ens:u,en:"even-rows",ans:u,a:"paragraph-style-name"},{ens:u,en:"first-column",ans:u,a:"paragraph-style-name"},{ens:u,en:"first-row",ans:u,a:"par [...]
- {ens:u,en:"last-column",ans:u,a:"paragraph-style-name"},{ens:u,en:"last-row",ans:u,a:"paragraph-style-name"},{ens:u,en:"odd-columns",ans:u,a:"paragraph-style-name"},{ens:u,en:"odd-rows",ans:u,a:"paragraph-style-name"},{ens:s,en:"notes-configuration",ans:s,a:"default-style-name"},{ens:s,en:"alphabetical-index-entry-template",ans:s,a:"style-name"},{ens:s,en:"bibliography-entry-template",ans:s,a:"style-name"},{ens:s,en:"h",ans:s,a:"style-name"},{ens:s,en:"illustration-index-entry-template" [...]
- {ens:s,en:"index-source-style",ans:s,a:"style-name"},{ens:s,en:"object-index-entry-template",ans:s,a:"style-name"},{ens:s,en:"p",ans:s,a:"style-name"},{ens:s,en:"table-index-entry-template",ans:s,a:"style-name"},{ens:s,en:"table-of-content-entry-template",ans:s,a:"style-name"},{ens:s,en:"table-index-entry-template",ans:s,a:"style-name"},{ens:s,en:"user-index-entry-template",ans:s,a:"style-name"},{ens:v,en:"page-layout-properties",ans:v,a:"register-truth-ref-style-name"}],chart:[{ens:a,e [...]
- a:"style-name"},{ens:a,en:"chart",ans:a,a:"style-name"},{ens:a,en:"data-label",ans:a,a:"style-name"},{ens:a,en:"data-point",ans:a,a:"style-name"},{ens:a,en:"equation",ans:a,a:"style-name"},{ens:a,en:"error-indicator",ans:a,a:"style-name"},{ens:a,en:"floor",ans:a,a:"style-name"},{ens:a,en:"footer",ans:a,a:"style-name"},{ens:a,en:"grid",ans:a,a:"style-name"},{ens:a,en:"legend",ans:a,a:"style-name"},{ens:a,en:"mean-value",ans:a,a:"style-name"},{ens:a,en:"plot-area",ans:a,a:"style-name"},{e [...]
- ans:a,a:"style-name"},{ens:a,en:"series",ans:a,a:"style-name"},{ens:a,en:"stock-gain-marker",ans:a,a:"style-name"},{ens:a,en:"stock-loss-marker",ans:a,a:"style-name"},{ens:a,en:"stock-range-line",ans:a,a:"style-name"},{ens:a,en:"subtitle",ans:a,a:"style-name"},{ens:a,en:"title",ans:a,a:"style-name"},{ens:a,en:"wall",ans:a,a:"style-name"}],section:[{ens:s,en:"alphabetical-index",ans:s,a:"style-name"},{ens:s,en:"bibliography",ans:s,a:"style-name"},{ens:s,en:"illustration-index",ans:s,a:"s [...]
- {ens:s,en:"index-title",ans:s,a:"style-name"},{ens:s,en:"object-index",ans:s,a:"style-name"},{ens:s,en:"section",ans:s,a:"style-name"},{ens:s,en:"table-of-content",ans:s,a:"style-name"},{ens:s,en:"table-index",ans:s,a:"style-name"},{ens:s,en:"user-index",ans:s,a:"style-name"}],ruby:[{ens:s,en:"ruby",ans:s,a:"style-name"}],table:[{ens:b,en:"query",ans:b,a:"style-name"},{ens:b,en:"table-representation",ans:b,a:"style-name"},{ens:u,en:"background",ans:u,a:"style-name"},{ens:u,en:"table",an [...]
- "table-column":[{ens:b,en:"column",ans:b,a:"style-name"},{ens:u,en:"table-column",ans:u,a:"style-name"}],"table-row":[{ens:b,en:"query",ans:b,a:"default-row-style-name"},{ens:b,en:"table-representation",ans:b,a:"default-row-style-name"},{ens:u,en:"table-row",ans:u,a:"style-name"}],"table-cell":[{ens:b,en:"column",ans:b,a:"default-cell-style-name"},{ens:u,en:"table-column",ans:u,a:"default-cell-style-name"},{ens:u,en:"table-row",ans:u,a:"default-cell-style-name"},{ens:u,en:"body",ans:u,a [...]
- {ens:u,en:"covered-table-cell",ans:u,a:"style-name"},{ens:u,en:"even-columns",ans:u,a:"style-name"},{ens:u,en:"covered-table-cell",ans:u,a:"style-name"},{ens:u,en:"even-columns",ans:u,a:"style-name"},{ens:u,en:"even-rows",ans:u,a:"style-name"},{ens:u,en:"first-column",ans:u,a:"style-name"},{ens:u,en:"first-row",ans:u,a:"style-name"},{ens:u,en:"last-column",ans:u,a:"style-name"},{ens:u,en:"last-row",ans:u,a:"style-name"},{ens:u,en:"odd-columns",ans:u,a:"style-name"},{ens:u,en:"odd-rows", [...]
- {ens:u,en:"table-cell",ans:u,a:"style-name"}],graphic:[{ens:q,en:"cube",ans:k,a:"style-name"},{ens:q,en:"extrude",ans:k,a:"style-name"},{ens:q,en:"rotate",ans:k,a:"style-name"},{ens:q,en:"scene",ans:k,a:"style-name"},{ens:q,en:"sphere",ans:k,a:"style-name"},{ens:k,en:"caption",ans:k,a:"style-name"},{ens:k,en:"circle",ans:k,a:"style-name"},{ens:k,en:"connector",ans:k,a:"style-name"},{ens:k,en:"control",ans:k,a:"style-name"},{ens:k,en:"custom-shape",ans:k,a:"style-name"},{ens:k,en:"ellips [...]
- {ens:k,en:"frame",ans:k,a:"style-name"},{ens:k,en:"g",ans:k,a:"style-name"},{ens:k,en:"line",ans:k,a:"style-name"},{ens:k,en:"measure",ans:k,a:"style-name"},{ens:k,en:"page-thumbnail",ans:k,a:"style-name"},{ens:k,en:"path",ans:k,a:"style-name"},{ens:k,en:"polygon",ans:k,a:"style-name"},{ens:k,en:"polyline",ans:k,a:"style-name"},{ens:k,en:"rect",ans:k,a:"style-name"},{ens:k,en:"regular-polygon",ans:k,a:"style-name"},{ens:w,en:"annotation",ans:k,a:"style-name"}],presentation:[{ens:q,en:"c [...]
- a:"style-name"},{ens:q,en:"extrude",ans:x,a:"style-name"},{ens:q,en:"rotate",ans:x,a:"style-name"},{ens:q,en:"scene",ans:x,a:"style-name"},{ens:q,en:"sphere",ans:x,a:"style-name"},{ens:k,en:"caption",ans:x,a:"style-name"},{ens:k,en:"circle",ans:x,a:"style-name"},{ens:k,en:"connector",ans:x,a:"style-name"},{ens:k,en:"control",ans:x,a:"style-name"},{ens:k,en:"custom-shape",ans:x,a:"style-name"},{ens:k,en:"ellipse",ans:x,a:"style-name"},{ens:k,en:"frame",ans:x,a:"style-name"},{ens:k,en:"g" [...]
- {ens:k,en:"line",ans:x,a:"style-name"},{ens:k,en:"measure",ans:x,a:"style-name"},{ens:k,en:"page-thumbnail",ans:x,a:"style-name"},{ens:k,en:"path",ans:x,a:"style-name"},{ens:k,en:"polygon",ans:x,a:"style-name"},{ens:k,en:"polyline",ans:x,a:"style-name"},{ens:k,en:"rect",ans:x,a:"style-name"},{ens:k,en:"regular-polygon",ans:x,a:"style-name"},{ens:w,en:"annotation",ans:x,a:"style-name"}],"drawing-page":[{ens:k,en:"page",ans:k,a:"style-name"},{ens:x,en:"notes",ans:k,a:"style-name"},{ens:v, [...]
- ans:k,a:"style-name"},{ens:v,en:"master-page",ans:k,a:"style-name"}],"list-style":[{ens:s,en:"list",ans:s,a:"style-name"},{ens:s,en:"numbered-paragraph",ans:s,a:"style-name"},{ens:s,en:"list-item",ans:s,a:"style-override"},{ens:v,en:"style",ans:v,a:"list-style-name"}],data:[{ens:v,en:"style",ans:v,a:"data-style-name"},{ens:v,en:"style",ans:v,a:"percentage-data-style-name"},{ens:x,en:"date-time-decl",ans:v,a:"data-style-name"},{ens:s,en:"creation-date",ans:v,a:"data-style-name"},{ens:s,e [...]
- ans:v,a:"data-style-name"},{ens:s,en:"database-display",ans:v,a:"data-style-name"},{ens:s,en:"date",ans:v,a:"data-style-name"},{ens:s,en:"editing-duration",ans:v,a:"data-style-name"},{ens:s,en:"expression",ans:v,a:"data-style-name"},{ens:s,en:"meta-field",ans:v,a:"data-style-name"},{ens:s,en:"modification-date",ans:v,a:"data-style-name"},{ens:s,en:"modification-time",ans:v,a:"data-style-name"},{ens:s,en:"print-date",ans:v,a:"data-style-name"},{ens:s,en:"print-time",ans:v,a:"data-style-n [...]
- en:"table-formula",ans:v,a:"data-style-name"},{ens:s,en:"time",ans:v,a:"data-style-name"},{ens:s,en:"user-defined",ans:v,a:"data-style-name"},{ens:s,en:"user-field-get",ans:v,a:"data-style-name"},{ens:s,en:"user-field-input",ans:v,a:"data-style-name"},{ens:s,en:"variable-get",ans:v,a:"data-style-name"},{ens:s,en:"variable-input",ans:v,a:"data-style-name"},{ens:s,en:"variable-set",ans:v,a:"data-style-name"}],"page-layout":[{ens:x,en:"notes",ans:v,a:"page-layout-name"},{ens:v,en:"handout- [...]
- a:"page-layout-name"},{ens:v,en:"master-page",ans:v,a:"page-layout-name"}]},B,L=xmldom.XPath;this.collectUsedFontFaces=c;this.changeFontFaceNames=e;this.UsedStyleList=function(a,b){var c={};this.uses=function(a){var b=a.localName,d=a.getAttributeNS(k,"name")||a.getAttributeNS(v,"name");a="style"===b?a.getAttributeNS(v,"family"):a.namespaceURI===A?"data":b;return(a=c[a])?0<a[d]:!1};p(a,c);b&&m(b,c)};this.hasDerivedStyles=function(a,b,c){var d=c.getAttributeNS(v,"name");c=c.getAttributeNS [...]
- return L.getODFElementsWithXPath(a,"//style:*[@style:parent-style-name='"+d+"'][@style:family='"+c+"']",b).length?!0:!1};this.prefixStyleNames=function(a,b,c){var d;if(a){for(d=a.firstChild;d;){if(d.nodeType===Node.ELEMENT_NODE){var e=d,f=b,h=e.getAttributeNS(k,"name"),q=void 0;h?q=k:(h=e.getAttributeNS(v,"name"))&&(q=v);q&&e.setAttributeNS(q,H[q]+"name",f+h)}d=d.nextSibling}g(a,b);c&&g(c,b)}};this.removePrefixFromStyleNames=function(a,b,c){var d=RegExp("^"+b);if(a){for(b=a.firstChild;b [...]
- Node.ELEMENT_NODE){var e=b,f=d,h=e.getAttributeNS(k,"name"),q=void 0;h?q=k:(h=e.getAttributeNS(v,"name"))&&(q=v);q&&(h=h.replace(f,""),e.setAttributeNS(q,H[q]+"name",h))}b=b.nextSibling}l(a,d);c&&l(c,d)}};this.determineStylesForNode=f;B=function(){var a,b,c,d,e,f={},h,k,q,g;for(c in y)if(y.hasOwnProperty(c))for(d=y[c],b=d.length,a=0;a<b;a+=1)e=d[a],q=e.en,g=e.ens,f.hasOwnProperty(q)?h=f[q]:f[q]=h={},h.hasOwnProperty(g)?k=h[g]:h[g]=k=[],k.push({ns:e.ans,localname:e.a,keyname:c});return f}()};
- // Input 32
++odf.StyleTreeNode=function(m){this.derivedStyles={};this.element=m};
++odf.Style2CSS=function(){function m(a){var b,c,d,f={};if(!a)return f;for(a=a.firstElementChild;a;){if(c=a.namespaceURI!==l||"style"!==a.localName&&"default-style"!==a.localName?a.namespaceURI===w&&"list-style"===a.localName?"list":a.namespaceURI!==l||"page-layout"!==a.localName&&"default-page-layout"!==a.localName?void 0:"page":a.getAttributeNS(l,"family"))(b=a.getAttributeNS(l,"name"))||(b=""),f.hasOwnProperty(c)?d=f[c]:f[c]=d={},d[b]=a;a=a.nextElementSibling}return f}function h(a,b){i [...]
++var c,d=null;for(c in a)if(a.hasOwnProperty(c)&&(d=h(a[c].derivedStyles,b)))break;return d}function b(a,c,d){var f,e,g;if(!c.hasOwnProperty(a))return null;f=new odf.StyleTreeNode(c[a]);e=f.element.getAttributeNS(l,"parent-style-name");g=null;e&&(g=h(d,e)||b(e,c,d));g?g.derivedStyles[a]=f:d[a]=f;delete c[a];return f}function g(a,c){for(var d in a)a.hasOwnProperty(d)&&b(d,a,c)}function d(a,b,c){var f=[];c=c.derivedStyles;var e;var l=u[a],g;void 0===l?b=null:(g=b?"["+l+'|style-name="'+b+'" [...]
++l&&(l="draw",g=b?'[presentation|style-name="'+b+'"]':""),b=l+"|"+s[a].join(g+","+l+"|")+g);null!==b&&f.push(b);for(e in c)c.hasOwnProperty(e)&&(b=d(a,e,c[e]),f=f.concat(b));return f}function n(a,b){var c="",d,f,e;for(d=0;d<b.length;d+=1)if(f=b[d],e=a.getAttributeNS(f[0],f[1])){e=e.trim();if(G.hasOwnProperty(f[1])){var l=e.indexOf(" "),g=void 0,k=void 0;-1!==l?(g=e.substring(0,l),k=e.substring(l)):(g=e,k="");(g=Q.parseLength(g))&&"pt"===g.unit&&0.75>g.value&&(e="0.75pt"+k)}f[2]&&(c+=f[2] [...]
++function p(b){return(b=t.getDirectChild(b,l,"text-properties"))?Q.parseFoFontSize(b.getAttributeNS(a,"font-size")):null}function k(a,b,c,d){return b+b+c+c+d+d}function q(b,c,d,f){c='text|list[text|style-name="'+c+'"]';var e=d.getAttributeNS(w,"level");d=t.getDirectChild(d,l,"list-level-properties");d=t.getDirectChild(d,l,"list-level-label-alignment");var g,k;d&&(g=d.getAttributeNS(a,"text-indent"),k=d.getAttributeNS(a,"margin-left"));g||(g="-0.6cm");d="-"===g.charAt(0)?g.substring(1):"- [...]
++e&&parseInt(e,10);1<e;)c+=" > text|list-item > text|list",e-=1;if(k){e=c+" > text|list-item > *:not(text|list):first-child";e+="{";e=e+("margin-left:"+k+";")+"}";try{b.insertRule(e,b.cssRules.length)}catch(h){runtime.log("cannot load rule: "+e)}}f=c+" > text|list-item > *:not(text|list):first-child:before{"+f+";";f=f+"counter-increment:list;"+("margin-left:"+g+";");f+="width:"+d+";";f+="display:inline-block}";try{b.insertRule(f,b.cssRules.length)}catch(n){runtime.log("cannot load rule:  [...]
++f,g,h){if("list"===f)for(var m=h.element.firstChild,s,u;m;){if(m.namespaceURI===w)if(s=m,"list-level-style-number"===m.localName){var G=s;u=G.getAttributeNS(l,"num-format");var A=G.getAttributeNS(l,"num-suffix")||"",G=G.getAttributeNS(l,"num-prefix")||"",Y={1:"decimal",a:"lower-latin",A:"upper-latin",i:"lower-roman",I:"upper-roman"},R="";G&&(R+=' "'+G+'"');R=Y.hasOwnProperty(u)?R+(" counter(list, "+Y[u]+")"):u?R+(' "'+u+'"'):R+" ''";u="content:"+R+' "'+A+'"';q(b,g,s,u)}else"list-level-s [...]
++m.localName?(u="content: none;",q(b,g,s,u)):"list-level-style-bullet"===m.localName&&(u="content: '"+s.getAttributeNS(w,"bullet-char")+"';",q(b,g,s,u));m=m.nextSibling}else if("page"===f){if(u=h.element,G=A=g="",m=t.getDirectChild(u,l,"page-layout-properties"))if(s=u.getAttributeNS(l,"name"),g+=n(m,D),(A=t.getDirectChild(m,l,"background-image"))&&(G=A.getAttributeNS(z,"href"))&&(g=g+("background-image: url('odfkit:"+G+"');")+n(A,F)),"presentation"===ea)for(u=(u=t.getDirectChild(u.parent [...]
++c,"master-styles"))&&u.firstElementChild;u;){if(u.namespaceURI===l&&"master-page"===u.localName&&u.getAttributeNS(l,"page-layout-name")===s){G=u.getAttributeNS(l,"name");A="draw|page[draw|master-page-name="+G+"] {"+g+"}";G="office|body, draw|page[draw|master-page-name="+G+"] {"+n(m,ba)+" }";try{b.insertRule(A,b.cssRules.length),b.insertRule(G,b.cssRules.length)}catch(aa){throw aa;}}u=u.nextElementSibling}else if("text"===ea){A="office|text {"+g+"}";G="office|body {width: "+m.getAttribut [...]
++";}";try{b.insertRule(A,b.cssRules.length),b.insertRule(G,b.cssRules.length)}catch(ia){throw ia;}}}else{g=d(f,g,h).join(",");m="";if(s=t.getDirectChild(h.element,l,"text-properties")){G=s;u=R="";A=1;s=""+n(G,y);Y=G.getAttributeNS(l,"text-underline-style");"solid"===Y&&(R+=" underline");Y=G.getAttributeNS(l,"text-line-through-style");"solid"===Y&&(R+=" line-through");R.length&&(s+="text-decoration:"+R+";");if(R=G.getAttributeNS(l,"font-name")||G.getAttributeNS(a,"font-family"))Y=J[R],s+= [...]
++(Y||R)+";";Y=G.parentNode;if(G=p(Y)){for(;Y;){if(G=p(Y)){if("%"!==G.unit){u="font-size: "+G.value*A+G.unit+";";break}A*=G.value/100}G=Y;R=Y="";Y=null;"default-style"===G.localName?Y=null:(Y=G.getAttributeNS(l,"parent-style-name"),R=G.getAttributeNS(l,"family"),Y=I.getODFElementsWithXPath(P,Y?"//style:*[@style:name='"+Y+"'][@style:family='"+R+"']":"//style:default-style[@style:family='"+R+"']",odf.Namespaces.lookupNamespaceURI)[0])}u||(u="font-size: "+parseFloat(N)*A+B.getUnits(N)+";");s [...]
++t.getDirectChild(h.element,l,"paragraph-properties"))u=s,s=""+n(u,L),(A=t.getDirectChild(u,l,"background-image"))&&(G=A.getAttributeNS(z,"href"))&&(s=s+("background-image: url('odfkit:"+G+"');")+n(A,F)),(u=u.getAttributeNS(a,"line-height"))&&"normal"!==u&&(u=Q.parseFoLineHeight(u),s="%"!==u.unit?s+("line-height: "+u.value+u.unit+";"):s+("line-height: "+u.value/100+";")),m+=s;if(s=t.getDirectChild(h.element,l,"graphic-properties"))G=s,s=""+n(G,O),u=G.getAttributeNS(r,"opacity"),A=G.getAt [...]
++"fill"),G=G.getAttributeNS(r,"fill-color"),"solid"===A||"hatch"===A?G&&"none"!==G?(u=isNaN(parseFloat(u))?1:parseFloat(u)/100,A=G.replace(/^#?([a-f\d])([a-f\d])([a-f\d])$/i,k),(G=(A=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(A))?{r:parseInt(A[1],16),g:parseInt(A[2],16),b:parseInt(A[3],16)}:null)&&(s+="background-color: rgba("+G.r+","+G.g+","+G.b+","+u+");")):s+="background: none;":"none"===A&&(s+="background: none;"),m+=s;if(s=t.getDirectChild(h.element,l,"drawing-page-properties" [...]
++O),"true"===s.getAttributeNS(x,"background-visible")&&(u+="background: none;"),m+=u;if(s=t.getDirectChild(h.element,l,"table-cell-properties"))s=""+n(s,H),m+=s;if(s=t.getDirectChild(h.element,l,"table-row-properties"))s=""+n(s,T),m+=s;if(s=t.getDirectChild(h.element,l,"table-column-properties"))s=""+n(s,U),m+=s;if(s=t.getDirectChild(h.element,l,"table-properties"))u=s,s=""+n(u,X),u=u.getAttributeNS(v,"border-model"),"collapsing"===u?s+="border-collapse:collapse;":"separating"===u&&(s+=" [...]
++m+=s;if(0!==m.length)try{b.insertRule(g+"{"+m+"}",b.cssRules.length)}catch(ga){throw ga;}}for(var da in h.derivedStyles)h.derivedStyles.hasOwnProperty(da)&&e(b,f,da,h.derivedStyles[da])}var r=odf.Namespaces.drawns,a=odf.Namespaces.fons,c=odf.Namespaces.officens,l=odf.Namespaces.stylens,f=odf.Namespaces.svgns,v=odf.Namespaces.tablens,w=odf.Namespaces.textns,z=odf.Namespaces.xlinkns,x=odf.Namespaces.presentationns,t=new core.DomUtils,u={graphic:"draw","drawing-page":"draw",paragraph:"text [...]
++ruby:"text",section:"text",table:"table","table-cell":"table","table-column":"table","table-row":"table",text:"text",list:"text",page:"office"},s={graphic:"circle connected control custom-shape ellipse frame g line measure page page-thumbnail path polygon polyline rect regular-polygon".split(" "),paragraph:"alphabetical-index-entry-template h illustration-index-entry-template index-source-style object-index-entry-template p table-index-entry-template table-of-content-entry-template user [...]
++presentation:"caption circle connector control custom-shape ellipse frame g line measure page-thumbnail path polygon polyline rect regular-polygon".split(" "),"drawing-page":"caption circle connector control page custom-shape ellipse frame g line measure page-thumbnail path polygon polyline rect regular-polygon".split(" "),ruby:["ruby","ruby-text"],section:"alphabetical-index bibliography illustration-index index-title object-index section table-of-content table-index user-index".split( [...]
++"table"],"table-cell":"body covered-table-cell even-columns even-rows first-column first-row last-column last-row odd-columns odd-rows table-cell".split(" "),"table-column":["table-column"],"table-row":["table-row"],text:"a index-entry-chapter index-entry-link-end index-entry-link-start index-entry-page-number index-entry-span index-entry-tab-stop index-entry-text index-title-template linenumbering-configuration list-level-style-number list-level-style-bullet outline-level-style span".s [...]
++list:["list-item"]},y=[[a,"color","color"],[a,"background-color","background-color"],[a,"font-weight","font-weight"],[a,"font-style","font-style"]],F=[[l,"repeat","background-repeat"]],L=[[a,"background-color","background-color"],[a,"text-align","text-align"],[a,"text-indent","text-indent"],[a,"padding","padding"],[a,"padding-left","padding-left"],[a,"padding-right","padding-right"],[a,"padding-top","padding-top"],[a,"padding-bottom","padding-bottom"],[a,"border-left","border-left"],[a, [...]
++"border-right"],[a,"border-top","border-top"],[a,"border-bottom","border-bottom"],[a,"margin","margin"],[a,"margin-left","margin-left"],[a,"margin-right","margin-right"],[a,"margin-top","margin-top"],[a,"margin-bottom","margin-bottom"],[a,"border","border"]],O=[[a,"background-color","background-color"],[a,"min-height","min-height"],[r,"stroke","border"],[f,"stroke-color","border-color"],[f,"stroke-width","border-width"],[a,"border","border"],[a,"border-left","border-left"],[a,"border-ri [...]
++[a,"border-top","border-top"],[a,"border-bottom","border-bottom"]],H=[[a,"background-color","background-color"],[a,"border-left","border-left"],[a,"border-right","border-right"],[a,"border-top","border-top"],[a,"border-bottom","border-bottom"],[a,"border","border"]],U=[[l,"column-width","width"]],T=[[l,"row-height","height"],[a,"keep-together",null]],X=[[l,"width","width"],[a,"margin-left","margin-left"],[a,"margin-right","margin-right"],[a,"margin-top","margin-top"],[a,"margin-bottom", [...]
++D=[[a,"background-color","background-color"],[a,"padding","padding"],[a,"padding-left","padding-left"],[a,"padding-right","padding-right"],[a,"padding-top","padding-top"],[a,"padding-bottom","padding-bottom"],[a,"border","border"],[a,"border-left","border-left"],[a,"border-right","border-right"],[a,"border-top","border-top"],[a,"border-bottom","border-bottom"],[a,"margin","margin"],[a,"margin-left","margin-left"],[a,"margin-right","margin-right"],[a,"margin-top","margin-top"],[a,"margin [...]
++ba=[[a,"page-width","width"],[a,"page-height","height"]],G={border:!0,"border-left":!0,"border-right":!0,"border-top":!0,"border-bottom":!0,"stroke-width":!0},J={},Q=new odf.OdfUtils,ea,P,N,I=xmldom.XPath,B=new core.CSSUnits;this.style2css=function(a,b,c,d,f){for(var l,k,h,n;b.cssRules.length;)b.deleteRule(b.cssRules.length-1);l=null;d&&(l=d.ownerDocument,P=d.parentNode);f&&(l=f.ownerDocument,P=f.parentNode);if(l)for(n in odf.Namespaces.forEachPrefix(function(a,c){k="@namespace "+a+" ur [...]
++try{b.insertRule(k,b.cssRules.length)}catch(d){}}),J=c,ea=a,N=runtime.getWindow().getComputedStyle(document.body,null).getPropertyValue("font-size")||"12pt",a=m(d),d=m(f),f={},u)if(u.hasOwnProperty(n))for(h in c=f[n]={},g(a[n],c),g(d[n],c),c)c.hasOwnProperty(h)&&e(b,n,h,c[h])}};
++// Input 33
 +/*
 +
-  Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
++ Copyright (C) 2014 KO GmbH <copyright at kogmbh.com>
++
++ @licstart
++ This file is part of WebODF.
++
++ WebODF is free software: you can redistribute it and/or modify it
++ under the terms of the GNU Affero General Public License (GNU AGPL)
++ as published by the Free Software Foundation, either version 3 of
++ the License, or (at your option) any later version.
++
++ WebODF is distributed in the hope that it will be useful, but
++ WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ GNU Affero General Public License for more details.
++
++ You should have received a copy of the GNU Affero General Public License
++ along with WebODF.  If not, see <http://www.gnu.org/licenses/>.
++ @licend
++
++ @source: http://www.webodf.org/
++ @source: https://github.com/kogmbh/WebODF/
++*/
++(function(){function m(h,b){var g=this;this.getDistance=function(b){var h=g.x-b.x;b=g.y-b.y;return Math.sqrt(h*h+b*b)};this.getCenter=function(b){return new m((g.x+b.x)/2,(g.y+b.y)/2)};g.x=h;g.y=b}gui.ZoomHelper=function(){function h(a,b,d,f){a=f?"translate3d("+a+"px, "+b+"px, 0) scale3d("+d+", "+d+", 1)":"translate("+a+"px, "+b+"px) scale("+d+")";c.style.WebkitTransform=a;c.style.MozTransform=a;c.style.msTransform=a;c.style.OTransform=a;c.style.transform=a}function b(a){a?h(-l.x,-l.y,w [...]
++0,w,!0),h(0,0,w,!1))}function g(a){if(t&&F){var b=t.style.overflow,c=t.classList.contains("customScrollbars");a&&c||!a&&!c||(a?(t.classList.add("customScrollbars"),t.style.overflow="hidden",runtime.requestAnimationFrame(function(){t.style.overflow=b})):t.classList.remove("customScrollbars"))}}function d(){h(-l.x,-l.y,w,!0);t.scrollLeft=0;t.scrollTop=0;g(!1)}function n(){h(0,0,w,!0);t.scrollLeft=l.x;t.scrollTop=l.y;g(!0)}function p(a){return new m(a.pageX-c.offsetLeft,a.pageY-c.offsetTop [...]
++(l.x-=a.x-f.x,l.y-=a.y-f.y,l=new m(Math.min(Math.max(l.x,c.offsetLeft),(c.offsetLeft+c.offsetWidth)*w-t.clientWidth),Math.min(Math.max(l.y,c.offsetTop),(c.offsetTop+c.offsetHeight)*w-t.clientHeight)));f=a}function q(a){var b=a.touches.length,c=0<b?p(a.touches[0]):null;a=1<b?p(a.touches[1]):null;c&&a?(v=c.getDistance(a),z=w,f=c.getCenter(a),d(),y=s.PINCH):c&&(f=c,y=s.SCROLL)}function e(a){var f=a.touches.length,e=0<f?p(a.touches[0]):null,f=1<f?p(a.touches[1]):null;if(e&&f)if(a.preventDef [...]
++s.SCROLL)y=s.PINCH,d(),v=e.getDistance(f);else{a=e.getCenter(f);e=e.getDistance(f)/v;k(a);var f=w,g=Math.min(x,c.offsetParent.clientWidth/c.offsetWidth);w=z*e;w=Math.min(Math.max(w,g),x);e=w/f;l.x+=(e-1)*(a.x+l.x);l.y+=(e-1)*(a.y+l.y);b(!0)}else e&&(y===s.PINCH?(y=s.SCROLL,n()):k(e))}function r(){y===s.PINCH&&(u.emit(gui.ZoomHelper.signalZoomChanged,w),n(),b(!1));y=s.NONE}function a(){t&&(t.removeEventListener("touchstart",q,!1),t.removeEventListener("touchmove",e,!1),t.removeEventListe [...]
++r,!1))}var c,l,f,v,w,z,x=4,t,u=new core.EventNotifier([gui.ZoomHelper.signalZoomChanged]),s={NONE:0,SCROLL:1,PINCH:2},y=s.NONE,F=runtime.getWindow().hasOwnProperty("ontouchstart");this.subscribe=function(a,b){u.subscribe(a,b)};this.unsubscribe=function(a,b){u.unsubscribe(a,b)};this.getZoomLevel=function(){return w};this.setZoomLevel=function(a){c&&(w=a,b(!1),u.emit(gui.ZoomHelper.signalZoomChanged,w))};this.destroy=function(b){a();g(!1);b()};this.setZoomableElement=function(d){a();c=d;t [...]
++b(!1);t&&(t.addEventListener("touchstart",q,!1),t.addEventListener("touchmove",e,!1),t.addEventListener("touchend",r,!1));g(!0)};z=w=1;l=new m(0,0)};gui.ZoomHelper.signalZoomChanged="zoomChanged"})();
++// Input 34
++/*
++
++ Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("odf.OdfUtils");
- odf.TextSerializer=function(){function g(p){var r="",n=l.filter?l.filter.acceptNode(p):NodeFilter.FILTER_ACCEPT,h=p.nodeType,d;if(n===NodeFilter.FILTER_ACCEPT||n===NodeFilter.FILTER_SKIP)for(d=p.firstChild;d;)r+=g(d),d=d.nextSibling;n===NodeFilter.FILTER_ACCEPT&&(h===Node.ELEMENT_NODE&&f.isParagraph(p)?r+="\n":h===Node.TEXT_NODE&&p.textContent&&(r+=p.textContent));return r}var l=this,f=new odf.OdfUtils;this.filter=null;this.writeToString=function(f){if(!f)return"";f=g(f);"\n"===f[f.leng [...]
- f.substr(0,f.length-1));return f}};
- // Input 33
++ops.Canvas=function(){};ops.Canvas.prototype.getZoomLevel=function(){};ops.Canvas.prototype.getElement=function(){};ops.Canvas.prototype.getZoomHelper=function(){};
++// Input 35
 +/*
 +
 + Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("core.PositionFilter");runtime.loadClass("odf.OdfUtils");
- ops.TextPositionFilter=function(g){function l(d,g,c){var e,a;if(g){if(f.isInlineRoot(g)&&f.isGroupingElement(c))return h;e=f.lookLeftForCharacter(g);if(1===e||2===e&&(f.scanRightForAnyCharacter(c)||f.scanRightForAnyCharacter(f.nextNode(d))))return n}e=null===g&&f.isParagraph(d);a=f.lookRightForCharacter(c);if(e)return a?n:f.scanRightForAnyCharacter(c)?h:n;if(!a)return h;g=g||f.previousNode(d);return f.scanLeftForAnyCharacter(g)?h:n}var f=new odf.OdfUtils,p=Node.ELEMENT_NODE,r=Node.TEXT_ [...]
- h=core.PositionFilter.FilterResult.FILTER_REJECT;this.acceptPosition=function(d){var m=d.container(),c=m.nodeType,e,a,b;if(c!==p&&c!==r)return h;if(c===r){if(!f.isGroupingElement(m.parentNode)||f.isWithinTrackedChanges(m.parentNode,g()))return h;c=d.unfilteredDomOffset();e=m.data;runtime.assert(c!==e.length,"Unexpected offset.");if(0<c){d=e[c-1];if(!f.isODFWhitespace(d))return n;if(1<c)if(d=e[c-2],!f.isODFWhitespace(d))a=n;else{if(!f.isODFWhitespace(e.substr(0,c)))return h}else b=f.prev [...]
- f.scanLeftForNonSpace(b)&&(a=n);if(a===n)return f.isTrailingWhitespace(m,c)?h:n;a=e[c];return f.isODFWhitespace(a)?h:f.scanLeftForAnyCharacter(f.previousNode(m))?h:n}b=d.leftNode();a=m;m=m.parentNode;a=l(m,b,a)}else!f.isGroupingElement(m)||f.isWithinTrackedChanges(m,g())?a=h:(b=d.leftNode(),a=d.rightNode(),a=l(m,b,a));return a}};
- // Input 34
- "function"!==typeof Object.create&&(Object.create=function(g){var l=function(){};l.prototype=g;return new l});
- xmldom.LSSerializer=function(){function g(f){var g=f||{},h=function(c){var a={},b;for(b in c)c.hasOwnProperty(b)&&(a[c[b]]=b);return a}(f),d=[g],m=[h],c=0;this.push=function(){c+=1;g=d[c]=Object.create(g);h=m[c]=Object.create(h)};this.pop=function(){d.pop();m.pop();c-=1;g=d[c];h=m[c]};this.getLocalNamespaceDefinitions=function(){return h};this.getQName=function(c){var a=c.namespaceURI,b=0,d;if(!a)return c.localName;if(d=h[a])return d+":"+c.localName;do{d||!c.prefix?(d="ns"+b,b+=1):d=c.p [...]
- a)break;if(!g[d]){g[d]=a;h[a]=d;break}d=null}while(null===d);return d+":"+c.localName}}function l(f){return f.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/'/g,"'").replace(/"/g,""")}function f(g,n){var h="",d=p.filter?p.filter.acceptNode(n):NodeFilter.FILTER_ACCEPT,m;if(d===NodeFilter.FILTER_ACCEPT&&n.nodeType===Node.ELEMENT_NODE){g.push();m=g.getQName(n);var c,e=n.attributes,a,b,q,k="",t;c="<"+m;a=e.length;for(b=0;b<a;b+=1)q=e.item(b),"http://www.w [...]
- q.namespaceURI&&(t=p.filter?p.filter.acceptNode(q):NodeFilter.FILTER_ACCEPT,t===NodeFilter.FILTER_ACCEPT&&(t=g.getQName(q),q="string"===typeof q.value?l(q.value):q.value,k+=" "+(t+'="'+q+'"')));a=g.getLocalNamespaceDefinitions();for(b in a)a.hasOwnProperty(b)&&((e=a[b])?"xmlns"!==e&&(c+=" xmlns:"+a[b]+'="'+b+'"'):c+=' xmlns="'+b+'"');h+=c+(k+">")}if(d===NodeFilter.FILTER_ACCEPT||d===NodeFilter.FILTER_SKIP){for(d=n.firstChild;d;)h+=f(g,d),d=d.nextSibling;n.nodeValue&&(h+=l(n.nodeValue))} [...]
- m+">",g.pop());return h}var p=this;this.filter=null;this.writeToString=function(l,n){if(!l)return"";var h=new g(n);return f(h,l)}};
- // Input 35
++(function(){function m(){function a(d){c=!0;runtime.setTimeout(function(){try{d()}catch(f){runtime.log(String(f))}c=!1;0<b.length&&a(b.pop())},10)}var b=[],c=!1;this.clearQueue=function(){b.length=0};this.addToQueue=function(d){if(0===b.length&&!c)return a(d);b.push(d)}}function h(a){function b(){for(;0<c.cssRules.length;)c.deleteRule(0);c.insertRule("#shadowContent draw|page {display:none;}",0);c.insertRule("office|presentation draw|page {display:none;}",1);c.insertRule("#shadowContent [...]
++d+") {display:block;}",2);c.insertRule("office|presentation draw|page:nth-of-type("+d+") {display:block;}",3)}var c=a.sheet,d=1;this.showFirstPage=function(){d=1;b()};this.showNextPage=function(){d+=1;b()};this.showPreviousPage=function(){1<d&&(d-=1,b())};this.showPage=function(a){0<a&&(d=a,b())};this.css=a;this.destroy=function(b){a.parentNode.removeChild(a);b()}}function b(a){for(;a.firstChild;)a.removeChild(a.firstChild)}function g(a){a=a.sheet;for(var b=a.cssRules;b.length;)a.delete [...]
++1)}function d(a,b,c){(new odf.Style2CSS).style2css(a.getDocumentType(),c.sheet,b.getFontMap(),a.rootElement.styles,a.rootElement.automaticStyles)}function n(a,b,c){var d=null;a=a.rootElement.body.getElementsByTagNameNS(H,c+"-decl");c=b.getAttributeNS(H,"use-"+c+"-name");var f;if(c&&0<a.length)for(b=0;b<a.length;b+=1)if(f=a[b],f.getAttributeNS(H,"name")===c){d=f.textContent;break}return d}function p(a,c,d,f){var e=a.ownerDocument;c=a.getElementsByTagNameNS(c,d);for(a=0;a<c.length;a+=1)b( [...]
++c[a],d.appendChild(e.createTextNode(f)))}function k(a,b,c){b.setAttributeNS("urn:webodf:names:helper","styleid",a);var d,f=b.getAttributeNS(F,"anchor-type"),e=b.getAttributeNS(s,"x"),l=b.getAttributeNS(s,"y"),g=b.getAttributeNS(s,"width"),k=b.getAttributeNS(s,"height"),h=b.getAttributeNS(x,"min-height"),n=b.getAttributeNS(x,"min-width");if("as-char"===f)d="display: inline-block;";else if(f||e||l)d="position: absolute;";else if(g||k||h||n)d="display: block;";e&&(d+="left: "+e+";");l&&(d+ [...]
++";");g&&(d+="width: "+g+";");k&&(d+="height: "+k+";");h&&(d+="min-height: "+h+";");n&&(d+="min-width: "+n+";");d&&(d="draw|"+b.localName+'[webodfhelper|styleid="'+a+'"] {'+d+"}",c.insertRule(d,c.cssRules.length))}function q(a){for(a=a.firstChild;a;){if(a.namespaceURI===t&&"binary-data"===a.localName)return"data:image/png;base64,"+a.textContent.replace(/[\r\n\s]/g,"");a=a.nextSibling}return""}function e(a,b,c,d){function f(b){b&&(b='draw|image[webodfhelper|styleid="'+a+'"] {'+("backgroun [...]
++b+");")+"}",d.insertRule(b,d.cssRules.length))}function e(a){f(a.url)}c.setAttributeNS("urn:webodf:names:helper","styleid",a);var l=c.getAttributeNS(L,"href"),g;if(l)try{g=b.getPart(l),g.onchange=e,g.load()}catch(k){runtime.log("slight problem: "+String(k))}else l=q(c),f(l)}function r(a){var b=a.ownerDocument;D.getElementsByTagNameNS(a,F,"line-break").forEach(function(a){a.hasChildNodes()||a.appendChild(b.createElement("br"))})}function a(a){var b=a.ownerDocument;D.getElementsByTagNameN [...]
++d;a.firstChild;)a.removeChild(a.firstChild);a.appendChild(b.createTextNode(" "));d=parseInt(a.getAttributeNS(F,"c"),10);if(1<d)for(a.removeAttributeNS(F,"c"),c=1;c<d;c+=1)a.parentNode.insertBefore(a.cloneNode(!0),a)})}function c(a){D.getElementsByTagNameNS(a,F,"tab").forEach(function(a){a.textContent="\t"})}function l(a,b){function c(a,d){var l=g.documentElement.namespaceURI;"video/"===d.substr(0,6)?(f=g.createElementNS(l,"video"),f.setAttribute("controls","controls"),e=g.createElementN [...]
++a&&e.setAttribute("src",a),e.setAttribute("type",d),f.appendChild(e),b.parentNode.appendChild(f)):b.innerHtml="Unrecognised Plugin"}function d(a){c(a.url,a.mimetype)}var f,e,l,g=b.ownerDocument,k;if(l=b.getAttributeNS(L,"href"))try{k=a.getPart(l),k.onchange=d,k.load()}catch(h){runtime.log("slight problem: "+String(h))}else runtime.log("using MP4 data fallback"),l=q(b),c(l,"video/mp4")}function f(a){var b=a.getElementsByTagName("head")[0],c,d;c=a.styleSheets.length;for(d=b.firstElementCh [...]
++d.localName||!d.hasAttribute("webodfcss"));)d=d.nextElementSibling;if(d)return c=parseInt(d.getAttribute("webodfcss"),10),d.setAttribute("webodfcss",c+1),d;"string"===String(typeof webodf_css)?c=webodf_css:(d="webodf.css",runtime.currentDirectory&&(d=runtime.currentDirectory(),0<d.length&&"/"!==d.substr(-1)&&(d+="/"),d+="../webodf.css"),c=runtime.readFileSync(d,"utf-8"));d=a.createElementNS(b.namespaceURI,"style");d.setAttribute("media","screen, print, handheld, projection");d.setAttrib [...]
++"text/css");d.setAttribute("webodfcss","1");d.appendChild(a.createTextNode(c));b.appendChild(d);return d}function v(a){var b=parseInt(a.getAttribute("webodfcss"),10);1===b?a.parentNode.removeChild(a):a.setAttribute("count",b-1)}function w(a){var b=a.getElementsByTagName("head")[0],c=a.createElementNS(b.namespaceURI,"style"),d="";c.setAttribute("type","text/css");c.setAttribute("media","screen, print, handheld, projection");odf.Namespaces.forEachPrefix(function(a,b){d+="@namespace "+a+"  [...]
++d+="@namespace webodfhelper url(urn:webodf:names:helper);\n";c.appendChild(a.createTextNode(d));b.appendChild(c);return c}var z=odf.Namespaces.drawns,x=odf.Namespaces.fons,t=odf.Namespaces.officens,u=odf.Namespaces.stylens,s=odf.Namespaces.svgns,y=odf.Namespaces.tablens,F=odf.Namespaces.textns,L=odf.Namespaces.xlinkns,O=odf.Namespaces.xmlns,H=odf.Namespaces.presentationns,U=runtime.getWindow(),T=xmldom.XPath,X=new odf.OdfUtils,D=new core.DomUtils;odf.OdfCanvas=function(q){function s(a,b [...]
++b,c,f){ka.addToQueue(function(){e(a,b,c,f)})}var f,l;f=b.getElementsByTagNameNS(z,"image");for(b=0;b<f.length;b+=1)l=f.item(b),d("image"+String(b),a,l,c)}function L(a,b){function c(a,b){ka.addToQueue(function(){l(a,b)})}var d,f,e;f=b.getElementsByTagNameNS(z,"plugin");for(d=0;d<f.length;d+=1)e=f.item(d),c(a,e)}function x(){var a;a=S.firstChild;var b=Z.getZoomLevel();a&&(S.style.WebkitTransformOrigin="0% 0%",S.style.MozTransformOrigin="0% 0%",S.style.msTransformOrigin="0% 0%",S.style.OTr [...]
++"0% 0%",S.style.transformOrigin="0% 0%",A&&((a=A.getMinimumHeightForAnnotationPane())?S.style.minHeight=a:S.style.removeProperty("min-height")),q.style.width=Math.round(b*S.offsetWidth)+"px",q.style.height=Math.round(b*S.offsetHeight)+"px")}function ea(a){ma?(fa.parentNode||S.appendChild(fa),A&&A.forgetAnnotations(),A=new gui.AnnotationViewManager(I,a.body,fa,ca),D.getElementsByTagNameNS(a.body,t,"annotation").forEach(A.addAnnotation),A.rerenderAnnotations(),x()):fa.parentNode&&(S.remov [...]
++A.forgetAnnotations(),x())}function P(f){function e(){g(R);g(aa);g(ia);b(q);q.style.display="inline-block";var l=M.rootElement;q.ownerDocument.importNode(l,!0);$.setOdfContainer(M);var h=M,m=R;(new odf.FontLoader).loadFonts(h,m.sheet);d(M,$,aa);m=M;h=ia.sheet;b(q);S=B.createElementNS(q.namespaceURI,"div");S.style.display="inline-block";S.style.background="white";S.style.setProperty("float","left","important");S.appendChild(l);q.appendChild(S);fa=B.createElementNS(q.namespaceURI,"div");f [...]
++ga=B.createElementNS(q.namespaceURI,"div");ga.id="shadowContent";ga.style.position="absolute";ga.style.top=0;ga.style.left=0;m.getContentElement().appendChild(ga);var v=l.body,w,x=[],D;for(w=v.firstElementChild;w&&w!==v;)if(w.namespaceURI===z&&(x[x.length]=w),w.firstElementChild)w=w.firstElementChild;else{for(;w&&w!==v&&!w.nextElementSibling;)w=w.parentNode;w&&w.nextElementSibling&&(w=w.nextElementSibling)}for(D=0;D<x.length;D+=1)w=x[D],k("frame"+String(D),w,h);x=T.getODFElementsWithXPa [...]
++odf.Namespaces.lookupNamespaceURI);for(w=0;w<x.length;w+=1)v=x[w],v.setAttributeNS&&v.setAttributeNS("urn:webodf:names:helper","containsparagraphanchor",!0);var v=ga,P,A,N;N=0;var I,K,x=m.rootElement.ownerDocument;if((w=l.body.firstElementChild)&&w.namespaceURI===t&&("presentation"===w.localName||"drawing"===w.localName))for(w=w.firstElementChild;w;){D=w.getAttributeNS(z,"master-page-name");if(D){for(P=m.rootElement.masterStyles.firstElementChild;P&&(P.getAttributeNS(u,"name")!==D||"mas [...]
++P.localName||P.namespaceURI!==u);)P=P.nextElementSibling;D=P}else D=null;if(D){P=w.getAttributeNS("urn:webodf:names:helper","styleid");A=x.createElementNS(z,"draw:page");K=D.firstElementChild;for(I=0;K;)"true"!==K.getAttributeNS(H,"placeholder")&&(N=K.cloneNode(!0),A.appendChild(N),k(P+"_"+I,N,h)),K=K.nextElementSibling,I+=1;K=I=N=void 0;var Q=A.getElementsByTagNameNS(z,"frame");for(N=0;N<Q.length;N+=1)I=Q[N],(K=I.getAttributeNS(H,"class"))&&!/^(date-time|footer|header|page-number)$/.te [...]
++v.appendChild(A);N=String(v.getElementsByTagNameNS(z,"page").length);p(A,F,"page-number",N);p(A,H,"header",n(m,w,"header"));p(A,H,"footer",n(m,w,"footer"));k(P,A,h);A.setAttributeNS(z,"draw:master-page-name",D.getAttributeNS(u,"name"))}w=w.nextElementSibling}v=q.namespaceURI;x=l.body.getElementsByTagNameNS(y,"table-cell");for(w=0;w<x.length;w+=1)D=x.item(w),D.hasAttributeNS(y,"number-columns-spanned")&&D.setAttributeNS(v,"colspan",D.getAttributeNS(y,"number-columns-spanned")),D.hasAttri [...]
++D.setAttributeNS(v,"rowspan",D.getAttributeNS(y,"number-rows-spanned"));r(l.body);a(l.body);c(l.body);s(m,l.body,h);L(m,l.body);D=l.body;m=q.namespaceURI;w={};var x={},V;P=U.document.getElementsByTagNameNS(F,"list-style");for(v=0;v<P.length;v+=1)I=P.item(v),(K=I.getAttributeNS(u,"name"))&&(x[K]=I);D=D.getElementsByTagNameNS(F,"list");for(v=0;v<D.length;v+=1)if(I=D.item(v),P=I.getAttributeNS(O,"id")){A=I.getAttributeNS(F,"continue-list");I.setAttributeNS(m,"id",P);N="text|list#"+P+" > te [...]
++if(K=I.getAttributeNS(F,"style-name")){I=x[K];V=X.getFirstNonWhitespaceChild(I);I=void 0;if(V)if("list-level-style-number"===V.localName){I=V.getAttributeNS(u,"num-format");K=V.getAttributeNS(u,"num-suffix")||"";var Q="",Q={1:"decimal",a:"lower-latin",A:"upper-latin",i:"lower-roman",I:"upper-roman"},W=void 0,W=V.getAttributeNS(u,"num-prefix")||"",W=Q.hasOwnProperty(I)?W+(" counter(list, "+Q[I]+")"):I?W+("'"+I+"';"):W+" ''";K&&(W+=" '"+K+"'");I=Q="content: "+W+";"}else"list-level-style-i [...]
++I="content: none;":"list-level-style-bullet"===V.localName&&(I="content: '"+V.getAttributeNS(F,"bullet-char")+"';");V=I}if(A){for(I=w[A];I;)I=w[I];N+="counter-increment:"+A+";";V?(V=V.replace("list",A),N+=V):N+="content:counter("+A+");"}else A="",V?(V=V.replace("list",P),N+=V):N+="content: counter("+P+");",N+="counter-increment:"+P+";",h.insertRule("text|list#"+P+" {counter-reset:"+P+"}",h.cssRules.length);N+="}";w[P]=A;N&&h.insertRule(N,h.cssRules.length)}S.insertBefore(ga,S.firstChild [...]
++ea(l);if(!f&&(l=[M],da.hasOwnProperty("statereadychange")))for(h=da.statereadychange,V=0;V<h.length;V+=1)h[V].apply(null,l)}M.state===odf.OdfContainer.DONE?e():(runtime.log("WARNING: refreshOdf called but ODF was not DONE."),la=runtime.setTimeout(function C(){M.state===odf.OdfContainer.DONE?e():(runtime.log("will be back later..."),la=runtime.setTimeout(C,500))},100))}function N(a){ka.clearQueue();q.innerHTML=runtime.tr("Loading")+" "+a+"...";q.removeAttribute("style");M=new odf.OdfCont [...]
++a;P(!1)})}runtime.assert(null!==q&&void 0!==q,"odf.OdfCanvas constructor needs DOM element");runtime.assert(null!==q.ownerDocument&&void 0!==q.ownerDocument,"odf.OdfCanvas constructor needs DOM");var I=this,B=q.ownerDocument,V=new core.Async,M,$=new odf.Formatting,W,S=null,fa=null,ma=!1,ca=!1,A=null,Y,R,aa,ia,ga,da={},la,ja,na=!1,ha=!1,ka=new m,Z=new gui.ZoomHelper;this.refreshCSS=function(){na=!0;ja.trigger()};this.refreshSize=function(){ja.trigger()};this.odfContainer=function(){retur [...]
++function(a,b){M=a;P(!0===b)};this.load=this.load=N;this.save=function(a){M.save(a)};this.addListener=function(a,b){switch(a){case "click":var c=q,d=a;c.addEventListener?c.addEventListener(d,b,!1):c.attachEvent?c.attachEvent("on"+d,b):c["on"+d]=b;break;default:c=da.hasOwnProperty(a)?da[a]:da[a]=[],b&&-1===c.indexOf(b)&&c.push(b)}};this.getFormatting=function(){return $};this.getAnnotationViewManager=function(){return A};this.refreshAnnotations=function(){ea(M.rootElement)};this.rerenderA [...]
++function(){A&&(ha=!0,ja.trigger())};this.getSizer=function(){return S};this.enableAnnotations=function(a,b){a!==ma&&(ma=a,ca=b,M&&ea(M.rootElement))};this.addAnnotation=function(a){A&&(A.addAnnotation(a),x())};this.forgetAnnotations=function(){A&&(A.forgetAnnotations(),x())};this.getZoomHelper=function(){return Z};this.setZoomLevel=function(a){Z.setZoomLevel(a)};this.getZoomLevel=function(){return Z.getZoomLevel()};this.fitToContainingElement=function(a,b){var c=Z.getZoomLevel(),d=q.off [...]
++c,c=a/(q.offsetWidth/c);b/d<c&&(c=b/d);Z.setZoomLevel(c)};this.fitToWidth=function(a){var b=q.offsetWidth/Z.getZoomLevel();Z.setZoomLevel(a/b)};this.fitSmart=function(a,b){var c,d;d=Z.getZoomLevel();c=q.offsetWidth/d;d=q.offsetHeight/d;c=a/c;void 0!==b&&b/d<c&&(c=b/d);Z.setZoomLevel(Math.min(1,c))};this.fitToHeight=function(a){var b=q.offsetHeight/Z.getZoomLevel();Z.setZoomLevel(a/b)};this.showFirstPage=function(){W.showFirstPage()};this.showNextPage=function(){W.showNextPage()};this.sh [...]
++function(){W.showPreviousPage()};this.showPage=function(a){W.showPage(a);x()};this.getElement=function(){return q};this.addCssForFrameWithImage=function(a){var b=a.getAttributeNS(z,"name"),c=a.firstElementChild;k(b,a,ia.sheet);c&&e(b+"img",M,c,ia.sheet)};this.destroy=function(a){var b=B.getElementsByTagName("head")[0],c=[W.destroy,ja.destroy];runtime.clearTimeout(la);fa&&fa.parentNode&&fa.parentNode.removeChild(fa);Z.destroy(function(){S&&(q.removeChild(S),S=null)});v(Y);b.removeChild(R [...]
++b.removeChild(ia);V.destroyAll(c,a)};Y=f(B);W=new h(w(B));R=w(B);aa=w(B);ia=w(B);ja=new core.ScheduledTask(function(){na&&(d(M,$,aa),na=!1);ha&&(A&&A.rerenderAnnotations(),ha=!1);x()},0);Z.subscribe(gui.ZoomHelper.signalZoomChanged,x)}})();
++// Input 36
 +/*
 +
 + Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
++ This file is part of WebODF.
++
++ WebODF is free software: you can redistribute it and/or modify it
++ under the terms of the GNU Affero General Public License (GNU AGPL)
++ as published by the Free Software Foundation, either version 3 of
++ the License, or (at your option) any later version.
++
++ WebODF is distributed in the hope that it will be useful, but
++ WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ GNU Affero General Public License for more details.
++
++ You should have received a copy of the GNU Affero General Public License
++ along with WebODF.  If not, see <http://www.gnu.org/licenses/>.
++ @licend
++
++ @source: http://www.webodf.org/
++ @source: https://github.com/kogmbh/WebODF/
++*/
++ops.MemberProperties=function(){};
++ops.Member=function(m,h){var b=new ops.MemberProperties;this.getMemberId=function(){return m};this.getProperties=function(){return b};this.setProperties=function(g){Object.keys(g).forEach(function(d){b[d]=g[d]})};this.removeProperties=function(g){Object.keys(g).forEach(function(d){"fullName"!==d&&"color"!==d&&"imageUrl"!==d&&b.hasOwnProperty(d)&&delete b[d]})};runtime.assert(Boolean(m),"No memberId was supplied!");h.fullName||(h.fullName=runtime.tr("Unknown Author"));h.color||(h.color=" [...]
++(h.imageUrl="avatar-joe.png");b=h};
++// Input 37
++/*
++
++ Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
++
++ @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("odf.Namespaces");runtime.loadClass("xmldom.LSSerializer");runtime.loadClass("odf.OdfNodeFilter");runtime.loadClass("odf.TextSerializer");
- gui.Clipboard=function(){var g,l,f;this.setDataFromRange=function(f,r){var n=!0,h,d=f.clipboardData;h=runtime.getWindow();var m=r.startContainer.ownerDocument;!d&&h&&(d=h.clipboardData);d?(m=m.createElement("span"),m.appendChild(r.cloneContents()),h=d.setData("text/plain",l.writeToString(m)),n=n&&h,h=d.setData("text/html",g.writeToString(m,odf.Namespaces.namespaceMap)),n=n&&h,f.preventDefault()):n=!1;return n};g=new xmldom.LSSerializer;l=new odf.TextSerializer;f=new odf.OdfNodeFilter;g. [...]
- f};
- // Input 36
++gui.SelectionMover=function(m,h){function b(){r.setUnfilteredPosition(m.getNode(),0);return r}function g(a,b){var d,e=null;a&&0<a.length&&(d=b?a.item(a.length-1):a.item(0));d&&(e={top:d.top,left:b?d.right:d.left,bottom:d.bottom});return e}function d(a,b,f,e){var k=a.nodeType;f.setStart(a,b);f.collapse(!e);e=g(f.getClientRects(),!0===e);!e&&0<b&&(f.setStart(a,b-1),f.setEnd(a,b),e=g(f.getClientRects(),!0));e||(k===Node.ELEMENT_NODE&&0<b&&a.childNodes.length>=b?e=d(a,b-1,f,!0):a.nodeType== [...]
++0<b?e=d(a,b-1,f,!0):a.previousSibling?e=d(a.previousSibling,a.previousSibling.nodeType===Node.TEXT_NODE?a.previousSibling.textContent.length:a.previousSibling.childNodes.length,f,!0):a.parentNode&&a.parentNode!==h?e=d(a.parentNode,0,f,!1):(f.selectNode(h),e=g(f.getClientRects(),!1)));runtime.assert(Boolean(e),"No visible rectangle found");return e}function n(c,d,f){for(var e=b(),g=new core.LoopWatchDog(1E4),k=0,h=0;0<c&&e.nextPosition();)g.check(),f.acceptPosition(e)===a&&(k+=1,d.accept [...]
++a&&(h+=k,k=0,c-=1));return h}function p(c,d,f){for(var e=b(),g=new core.LoopWatchDog(1E4),k=0,h=0;0<c&&e.previousPosition();)g.check(),f.acceptPosition(e)===a&&(k+=1,d.acceptPosition(e)===a&&(h+=k,k=0,c-=1));return h}function k(c,e){var f=b(),g=0,k=0,n=0>c?-1:1;for(c=Math.abs(c);0<c;){for(var m=e,p=n,r=f,q=r.container(),y=0,F=null,L=void 0,O=10,H=void 0,U=0,T=void 0,X=void 0,D=void 0,H=void 0,ba=h.ownerDocument.createRange(),G=new core.LoopWatchDog(1E4),H=d(q,r.unfilteredDomOffset(),ba) [...]
++H.left,D=T;!0===(0>p?r.previousPosition():r.nextPosition());)if(G.check(),m.acceptPosition(r)===a&&(y+=1,q=r.container(),H=d(q,r.unfilteredDomOffset(),ba),H.top!==T)){if(H.top!==D&&D!==T)break;D=H.top;H=Math.abs(X-H.left);if(null===F||H<O)F=q,L=r.unfilteredDomOffset(),O=H,U=y}null!==F?(r.setUnfilteredPosition(F,L),y=U):y=0;ba.detach();g+=y;if(0===g)break;k+=g;c-=1}return k*n}function q(c,l){var f,g,k,n,m=b(),p=e.getParagraphElement(m.getCurrentNode()),r=0,q=h.ownerDocument.createRange() [...]
++g=-1):(f=m.nextPosition,g=1);for(k=d(m.container(),m.unfilteredDomOffset(),q);f.call(m);)if(l.acceptPosition(m)===a){if(e.getParagraphElement(m.getCurrentNode())!==p)break;n=d(m.container(),m.unfilteredDomOffset(),q);if(n.bottom!==k.bottom&&(k=n.top>=k.top&&n.bottom<k.bottom||n.top<=k.top&&n.bottom>k.bottom,!k))break;r+=g;k=n}q.detach();return r}var e=new odf.OdfUtils,r,a=core.PositionFilter.FilterResult.FILTER_ACCEPT;this.getStepCounter=function(){return{convertForwardStepsBetweenFilte [...]
++countLinesSteps:k,countStepsToLineBoundary:q}};(function(){r=gui.SelectionMover.createPositionIterator(h);var a=h.ownerDocument.createRange();a.setStart(r.container(),r.unfilteredDomOffset());a.collapse(!0);m.setSelectedRange(a)})()};
++gui.SelectionMover.createPositionIterator=function(m){var h=new function(){this.acceptNode=function(b){return b&&"urn:webodf:names:cursor"!==b.namespaceURI&&"urn:webodf:names:editinfo"!==b.namespaceURI?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_REJECT}};return new core.PositionIterator(m,5,h,!1)};(function(){return gui.SelectionMover})();
++// Input 38
 +/*
 +
 + Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("core.Base64");runtime.loadClass("core.Zip");runtime.loadClass("core.DomUtils");runtime.loadClass("xmldom.LSSerializer");runtime.loadClass("odf.StyleInfo");runtime.loadClass("odf.Namespaces");runtime.loadClass("odf.OdfNodeFilter");
- (function(){function g(a,b,c){for(a=a?a.firstChild:null;a;){if(a.localName===c&&a.namespaceURI===b)return a;a=a.nextSibling}return null}function l(a){var b,c=m.length;for(b=0;b<c;b+=1)if("urn:oasis:names:tc:opendocument:xmlns:office:1.0"===a.namespaceURI&&a.localName===m[b])return b;return-1}function f(a,b){var c=new n.UsedStyleList(a,b),d=new odf.OdfNodeFilter;this.acceptNode=function(a){var e=d.acceptNode(a);e===NodeFilter.FILTER_ACCEPT&&a.parentNode===b&&a.nodeType===Node.ELEMENT_NOD [...]
- NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_REJECT);return e}}function p(a,b){var c=new f(a,b);this.acceptNode=function(a){var b=c.acceptNode(a);b!==NodeFilter.FILTER_ACCEPT||!a.parentNode||a.parentNode.namespaceURI!==odf.Namespaces.textns||"s"!==a.parentNode.localName&&"tab"!==a.parentNode.localName||(b=NodeFilter.FILTER_REJECT);return b}}function r(a,b){if(b){var c=l(b),d,e=a.firstChild;if(-1!==c){for(;e;){d=l(e);if(-1!==d&&d>c)break;e=e.nextSibling}a.insertBefore(b,e)}}}var n=new odf. [...]
- h=new core.DomUtils,d=odf.Namespaces.stylens,m="meta settings scripts font-face-decls styles automatic-styles master-styles body".split(" "),c=(new Date).getTime()+"_webodf_",e=new core.Base64;odf.ODFElement=function(){};odf.ODFDocumentElement=function(){};odf.ODFDocumentElement.prototype=new odf.ODFElement;odf.ODFDocumentElement.prototype.constructor=odf.ODFDocumentElement;odf.ODFDocumentElement.prototype.fontFaceDecls=null;odf.ODFDocumentElement.prototype.manifest=null;odf.ODFDocument [...]
- null;odf.ODFDocumentElement.namespaceURI="urn:oasis:names:tc:opendocument:xmlns:office:1.0";odf.ODFDocumentElement.localName="document";odf.OdfPart=function(a,b,c,d){var e=this;this.size=0;this.type=null;this.name=a;this.container=c;this.url=null;this.mimetype=b;this.onstatereadychange=this.document=null;this.EMPTY=0;this.LOADING=1;this.DONE=2;this.state=this.EMPTY;this.data="";this.load=function(){null!==d&&(this.mimetype=b,d.loadAsDataURL(a,b,function(a,b){a&&runtime.log(a);e.url=b;if [...]
- if(e.onstatereadychange)e.onstatereadychange(e)}))}};odf.OdfPart.prototype.load=function(){};odf.OdfPart.prototype.getUrl=function(){return this.data?"data:;base64,"+e.toBase64(this.data):null};odf.OdfContainer=function b(q,k){function m(b){for(var c=b.firstChild,d;c;)d=c.nextSibling,c.nodeType===Node.ELEMENT_NODE?m(c):c.nodeType===Node.PROCESSING_INSTRUCTION_NODE&&b.removeChild(c),c=d}function l(b,c){for(var d=b&&b.firstChild;d;)d.nodeType===Node.ELEMENT_NODE&&d.setAttributeNS("urn:web [...]
- "scope",c),d=d.nextSibling}function w(b){var c={},e;for(b=b.firstChild;b;)b.nodeType===Node.ELEMENT_NODE&&b.namespaceURI===d&&"font-face"===b.localName&&(e=b.getAttributeNS(d,"name"),c[e]=b),b=b.nextSibling;return c}function x(b,c){var d=null,e,f,h;if(b)for(d=b.cloneNode(!0),e=d.firstElementChild;e;)f=e.nextElementSibling,(h=e.getAttributeNS("urn:webodf:names:scope","scope"))&&h!==c&&d.removeChild(e),e=f;return d}function v(b,c){var e,f,h,k=null,g={};if(b)for(c.forEach(function(b){n.col [...]
- b)}),k=b.cloneNode(!0),e=k.firstElementChild;e;)f=e.nextElementSibling,h=e.getAttributeNS(d,"name"),g[h]||k.removeChild(e),e=f;return k}function u(b){var c=R.rootElement.ownerDocument,d;if(b){m(b.documentElement);try{d=c.importNode(b.documentElement,!0)}catch(e){}}return d}function s(b){R.state=b;if(R.onchange)R.onchange(R);if(R.onstatereadychange)R.onstatereadychange(R)}function H(b){ba=null;R.rootElement=b;b.fontFaceDecls=g(b,"urn:oasis:names:tc:opendocument:xmlns:office:1.0","font-fa [...]
- b.styles=g(b,"urn:oasis:names:tc:opendocument:xmlns:office:1.0","styles");b.automaticStyles=g(b,"urn:oasis:names:tc:opendocument:xmlns:office:1.0","automatic-styles");b.masterStyles=g(b,"urn:oasis:names:tc:opendocument:xmlns:office:1.0","master-styles");b.body=g(b,"urn:oasis:names:tc:opendocument:xmlns:office:1.0","body");b.meta=g(b,"urn:oasis:names:tc:opendocument:xmlns:office:1.0","meta")}function y(d){var e=u(d),f=R.rootElement,h;e&&"document-styles"===e.localName&&"urn:oasis:names:t [...]
- e.namespaceURI?(f.fontFaceDecls=g(e,"urn:oasis:names:tc:opendocument:xmlns:office:1.0","font-face-decls"),r(f,f.fontFaceDecls),h=g(e,"urn:oasis:names:tc:opendocument:xmlns:office:1.0","styles"),f.styles=h||d.createElementNS("urn:oasis:names:tc:opendocument:xmlns:office:1.0","styles"),r(f,f.styles),h=g(e,"urn:oasis:names:tc:opendocument:xmlns:office:1.0","automatic-styles"),f.automaticStyles=h||d.createElementNS("urn:oasis:names:tc:opendocument:xmlns:office:1.0","automatic-styles"),l(f.a [...]
- "document-styles"),r(f,f.automaticStyles),e=g(e,"urn:oasis:names:tc:opendocument:xmlns:office:1.0","master-styles"),f.masterStyles=e||d.createElementNS("urn:oasis:names:tc:opendocument:xmlns:office:1.0","master-styles"),r(f,f.masterStyles),n.prefixStyleNames(f.automaticStyles,c,f.masterStyles)):s(b.INVALID)}function B(c){c=u(c);var e,f,h,k;if(c&&"document-content"===c.localName&&"urn:oasis:names:tc:opendocument:xmlns:office:1.0"===c.namespaceURI){e=R.rootElement;h=g(c,"urn:oasis:names:t [...]
- "font-face-decls");if(e.fontFaceDecls&&h){k=e.fontFaceDecls;var q,m,p,t,v={};f=w(k);t=w(h);for(h=h.firstElementChild;h;){q=h.nextElementSibling;if(h.namespaceURI===d&&"font-face"===h.localName)if(m=h.getAttributeNS(d,"name"),f.hasOwnProperty(m)){if(!h.isEqualNode(f[m])){p=m;for(var y=f,I=t,z=0,B=void 0,B=p=p.replace(/\d+$/,"");y.hasOwnProperty(B)||I.hasOwnProperty(B);)z+=1,B=p+z;p=B;h.setAttributeNS(d,"style:name",p);k.appendChild(h);f[p]=h;delete t[m];v[m]=p}}else k.appendChild(h),f[m] [...]
- h=q}k=v}else h&&(e.fontFaceDecls=h,r(e,h));f=g(c,"urn:oasis:names:tc:opendocument:xmlns:office:1.0","automatic-styles");l(f,"document-content");k&&n.changeFontFaceNames(f,k);if(e.automaticStyles&&f)for(k=f.firstChild;k;)e.automaticStyles.appendChild(k),k=f.firstChild;else f&&(e.automaticStyles=f,r(e,f));c=g(c,"urn:oasis:names:tc:opendocument:xmlns:office:1.0","body");if(null===c)throw"<office:body/> tag is mising.";e.body=c;r(e,e.body)}else s(b.INVALID)}function L(b){b=u(b);var c;b&&"do [...]
- b.localName&&"urn:oasis:names:tc:opendocument:xmlns:office:1.0"===b.namespaceURI&&(c=R.rootElement,c.meta=g(b,"urn:oasis:names:tc:opendocument:xmlns:office:1.0","meta"),r(c,c.meta))}function I(b){b=u(b);var c;b&&"document-settings"===b.localName&&"urn:oasis:names:tc:opendocument:xmlns:office:1.0"===b.namespaceURI&&(c=R.rootElement,c.settings=g(b,"urn:oasis:names:tc:opendocument:xmlns:office:1.0","settings"),r(c,c.settings))}function W(b){b=u(b);var c;if(b&&"manifest"===b.localName&&"urn [...]
- b.namespaceURI)for(c=R.rootElement,c.manifest=b,b=c.manifest.firstElementChild;b;)"file-entry"===b.localName&&"urn:oasis:names:tc:opendocument:xmlns:manifest:1.0"===b.namespaceURI&&(M[b.getAttributeNS("urn:oasis:names:tc:opendocument:xmlns:manifest:1.0","full-path")]=b.getAttributeNS("urn:oasis:names:tc:opendocument:xmlns:manifest:1.0","media-type")),b=b.nextElementSibling}function Q(c){var d=c.shift();d?P.loadAsDOM(d.path,function(e,f){d.handler(f);e||R.state===b.INVALID||Q(c)}):s(b.DO [...]
- "";odf.Namespaces.forEachPrefix(function(b,d){c+=" xmlns:"+b+'="'+d+'"'});return'<?xml version="1.0" encoding="UTF-8"?><office:'+b+" "+c+' office:version="1.2">'}function ja(){var b=new xmldom.LSSerializer,c=z("document-meta");b.filter=new odf.OdfNodeFilter;c+=b.writeToString(R.rootElement.meta,odf.Namespaces.namespaceMap);return c+"</office:document-meta>"}function ka(b,c){var d=document.createElementNS("urn:oasis:names:tc:opendocument:xmlns:manifest:1.0","manifest:file-entry");d.setAt [...]
- "manifest:full-path",b);d.setAttributeNS("urn:oasis:names:tc:opendocument:xmlns:manifest:1.0","manifest:media-type",c);return d}function G(){var b=runtime.parseXML('<manifest:manifest xmlns:manifest="urn:oasis:names:tc:opendocument:xmlns:manifest:1.0" manifest:version="1.2"></manifest:manifest>'),c=g(b,"urn:oasis:names:tc:opendocument:xmlns:manifest:1.0","manifest"),d=new xmldom.LSSerializer,e;for(e in M)M.hasOwnProperty(e)&&c.appendChild(ka(e,M[e]));d.filter=new odf.OdfNodeFilter;retur [...]
- d.writeToString(b,odf.Namespaces.namespaceMap)}function Z(){var b=new xmldom.LSSerializer,c=z("document-settings");b.filter=new odf.OdfNodeFilter;c+=b.writeToString(R.rootElement.settings,odf.Namespaces.namespaceMap);return c+"</office:document-settings>"}function O(){var b,d,e,h=odf.Namespaces.namespaceMap,k=new xmldom.LSSerializer,g=z("document-styles");d=x(R.rootElement.automaticStyles,"document-styles");e=R.rootElement.masterStyles.cloneNode(!0);b=v(R.rootElement.fontFaceDecls,[e,R. [...]
- d]);n.removePrefixFromStyleNames(d,c,e);k.filter=new f(e,d);g+=k.writeToString(b,h);g+=k.writeToString(R.rootElement.styles,h);g+=k.writeToString(d,h);g+=k.writeToString(e,h);return g+"</office:document-styles>"}function aa(){var b,c,d=odf.Namespaces.namespaceMap,e=new xmldom.LSSerializer,f=z("document-content");c=x(R.rootElement.automaticStyles,"document-content");b=v(R.rootElement.fontFaceDecls,[c]);e.filter=new p(R.rootElement.body,c);f+=e.writeToString(b,d);f+=e.writeToString(c,d);f [...]
- d);return f+"</office:document-content>"}function J(c,d){runtime.loadXML(c,function(c,e){if(c)d(c);else{var f=u(e);f&&"document"===f.localName&&"urn:oasis:names:tc:opendocument:xmlns:office:1.0"===f.namespaceURI?(H(f),s(b.DONE)):s(b.INVALID)}})}function F(b,c){var d;d=R.rootElement;var e=d.meta;e||(d.meta=e=document.createElementNS("urn:oasis:names:tc:opendocument:xmlns:office:1.0","meta"),r(d,e));d=e;b&&h.mapKeyValObjOntoNode(d,b,odf.Namespaces.lookupNamespaceURI);c&&h.removeKeyElement [...]
- c,odf.Namespaces.lookupNamespaceURI)}function C(){function c(b,d){var e;d||(d=b);e=document.createElementNS("urn:oasis:names:tc:opendocument:xmlns:office:1.0",d);f[b]=e;f.appendChild(e)}var d=new core.Zip("",null),e=runtime.byteArrayFromString("application/vnd.oasis.opendocument.text","utf8"),f=R.rootElement,h=document.createElementNS("urn:oasis:names:tc:opendocument:xmlns:office:1.0","text");d.save("mimetype",e,!1,new Date);c("meta");c("settings");c("scripts");c("fontFaceDecls","font-f [...]
- c("styles");c("automaticStyles","automatic-styles");c("masterStyles","master-styles");c("body");f.body.appendChild(h);s(b.DONE);return d}function Y(){var b,c=new Date,d=runtime.getWindow();b="WebODF/"+("undefined"!==String(typeof webodf_version)?webodf_version:"FromSource");d&&(b=b+" "+d.navigator.userAgent);F({"meta:generator":b},null);b=runtime.byteArrayFromString(Z(),"utf8");P.save("settings.xml",b,!0,c);b=runtime.byteArrayFromString(ja(),"utf8");P.save("meta.xml",b,!0,c);b=runtime.b [...]
- "utf8");P.save("styles.xml",b,!0,c);b=runtime.byteArrayFromString(aa(),"utf8");P.save("content.xml",b,!0,c);b=runtime.byteArrayFromString(G(),"utf8");P.save("META-INF/manifest.xml",b,!0,c)}function U(b,c){Y();P.writeAs(b,function(b){c(b)})}var R=this,P,M={},ba;this.onstatereadychange=k;this.state=this.onchange=null;this.setRootElement=H;this.getContentElement=function(){var b;ba||(b=R.rootElement.body,ba=g(b,"urn:oasis:names:tc:opendocument:xmlns:office:1.0","text")||g(b,"urn:oasis:name [...]
- "presentation")||g(b,"urn:oasis:names:tc:opendocument:xmlns:office:1.0","spreadsheet"));if(!ba)throw"Could not find content element in <office:body/>.";return ba};this.getDocumentType=function(){var b=R.getContentElement();return b&&b.localName};this.getPart=function(b){return new odf.OdfPart(b,M[b],R,P)};this.getPartData=function(b,c){P.load(b,c)};this.setMetadata=F;this.incrementEditingCycles=function(){var b;for(b=(b=R.rootElement.meta)&&b.firstChild;b&&(b.namespaceURI!==odf.Namespac [...]
- "editing-cycles"!==b.localName);)b=b.nextSibling;for(b=b&&b.firstChild;b&&b.nodeType!==Node.TEXT_NODE;)b=b.nextSibling;b=b?b.data:null;b=b?parseInt(b,10):0;isNaN(b)&&(b=0);F({"meta:editing-cycles":b+1},null)};this.createByteArray=function(b,c){Y();P.createByteArray(b,c)};this.saveAs=U;this.save=function(b){U(q,b)};this.getUrl=function(){return q};this.setBlob=function(b,c,d){d=e.convertBase64ToByteArray(d);P.save(b,d,!1,new Date);M.hasOwnProperty(b)&&runtime.log(b+" has been overwritten [...]
- this.removeBlob=function(b){var c=P.remove(b);runtime.assert(c,"file is not found: "+b);delete M[b]};this.state=b.LOADING;this.rootElement=function(b){var c=document.createElementNS(b.namespaceURI,b.localName),d;b=new b.Type;for(d in b)b.hasOwnProperty(d)&&(c[d]=b[d]);return c}({Type:odf.ODFDocumentElement,namespaceURI:odf.ODFDocumentElement.namespaceURI,localName:odf.ODFDocumentElement.localName});P=q?new core.Zip(q,function(c,d){P=d;c?J(q,function(d){c&&(P.error=c+"\n"+d,s(b.INVALID)) [...]
- handler:y},{path:"content.xml",handler:B},{path:"meta.xml",handler:L},{path:"settings.xml",handler:I},{path:"META-INF/manifest.xml",handler:W}])}):C()};odf.OdfContainer.EMPTY=0;odf.OdfContainer.LOADING=1;odf.OdfContainer.DONE=2;odf.OdfContainer.INVALID=3;odf.OdfContainer.SAVING=4;odf.OdfContainer.MODIFIED=5;odf.OdfContainer.getContainer=function(b){return new odf.OdfContainer(b,null)};return odf.OdfContainer})();
- // Input 37
++ops.Document=function(){};ops.Document.prototype.getMemberIds=function(){};ops.Document.prototype.removeCursor=function(m){};ops.Document.prototype.getDocumentElement=function(){};ops.Document.prototype.getRootNode=function(){};ops.Document.prototype.getDOMDocument=function(){};ops.Document.prototype.cloneDocumentElement=function(){};ops.Document.prototype.setDocumentElement=function(m){};ops.Document.prototype.subscribe=function(m,h){};ops.Document.prototype.unsubscribe=function(m,h){};
++ops.Document.prototype.getCanvas=function(){};ops.Document.prototype.createRootFilter=function(m){};ops.Document.signalCursorAdded="cursor/added";ops.Document.signalCursorRemoved="cursor/removed";ops.Document.signalCursorMoved="cursor/moved";ops.Document.signalMemberAdded="member/added";ops.Document.signalMemberUpdated="member/updated";ops.Document.signalMemberRemoved="member/removed";
++// Input 39
++ops.OdtCursor=function(m,h){var b=this,g={},d,n,p,k=new core.EventNotifier([ops.OdtCursor.signalCursorUpdated]);this.removeFromDocument=function(){p.remove()};this.subscribe=function(b,d){k.subscribe(b,d)};this.unsubscribe=function(b,d){k.unsubscribe(b,d)};this.getStepCounter=function(){return n.getStepCounter()};this.getMemberId=function(){return m};this.getNode=function(){return p.getNode()};this.getAnchorNode=function(){return p.getAnchorNode()};this.getSelectedRange=function(){retur [...]
++this.setSelectedRange=function(d,e){p.setSelectedRange(d,e);k.emit(ops.OdtCursor.signalCursorUpdated,b)};this.hasForwardSelection=function(){return p.hasForwardSelection()};this.getDocument=function(){return h};this.getSelectionType=function(){return d};this.setSelectionType=function(b){g.hasOwnProperty(b)?d=b:runtime.log("Invalid selection type: "+b)};this.resetSelectionType=function(){b.setSelectionType(ops.OdtCursor.RangeSelection)};p=new core.Cursor(h.getDOMDocument(),m);n=new gui.S [...]
++h.getRootNode());g[ops.OdtCursor.RangeSelection]=!0;g[ops.OdtCursor.RegionSelection]=!0;b.resetSelectionType()};ops.OdtCursor.RangeSelection="Range";ops.OdtCursor.RegionSelection="Region";ops.OdtCursor.signalCursorUpdated="cursorUpdated";(function(){return ops.OdtCursor})();
++// Input 40
 +/*
 +
 + Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("core.Base64");runtime.loadClass("xmldom.XPath");runtime.loadClass("odf.OdfContainer");
- (function(){function g(l,r,n,h,d){var m,c=0,e;for(e in l)if(l.hasOwnProperty(e)){if(c===n){m=e;break}c+=1}m?r.getPartData(l[m].href,function(a,b){if(a)runtime.log(a);else if(b){var c="@font-face { font-family: '"+(l[m].family||m)+"'; src: url(data:application/x-font-ttf;charset=binary;base64,"+f.convertUTF8ArrayToBase64(b)+') format("truetype"); }';try{h.insertRule(c,h.cssRules.length)}catch(e){runtime.log("Problem inserting rule in CSS: "+runtime.toJson(e)+"\nRule: "+c)}}else runtime.l [...]
- l[m].href);g(l,r,n+1,h,d)}):d&&d()}var l=xmldom.XPath,f=new core.Base64;odf.FontLoader=function(){this.loadFonts=function(f,r){for(var n=f.rootElement.fontFaceDecls;r.cssRules.length;)r.deleteRule(r.cssRules.length-1);if(n){var h={},d,m,c,e;if(n)for(n=l.getODFElementsWithXPath(n,"style:font-face[svg:font-face-src]",odf.Namespaces.lookupNamespaceURI),d=0;d<n.length;d+=1)m=n[d],c=m.getAttributeNS(odf.Namespaces.stylens,"name"),e=m.getAttributeNS(odf.Namespaces.svgns,"font-family"),m=l.get [...]
- "svg:font-face-src/svg:font-face-uri",odf.Namespaces.lookupNamespaceURI),0<m.length&&(m=m[0].getAttributeNS(odf.Namespaces.xlinkns,"href"),h[c]={href:m,family:e});g(h,f,0,r)}}};return odf.FontLoader})();
- // Input 38
++ops.Operation=function(){};ops.Operation.prototype.init=function(m){};ops.Operation.prototype.execute=function(m){};ops.Operation.prototype.spec=function(){};
++// Input 41
++/*
++
++ Copyright (C) 2010-2014 KO GmbH <copyright at kogmbh.com>
++
++ @licstart
++ This file is part of WebODF.
++
++ WebODF is free software: you can redistribute it and/or modify it
++ under the terms of the GNU Affero General Public License (GNU AGPL)
++ as published by the Free Software Foundation, either version 3 of
++ the License, or (at your option) any later version.
++
++ WebODF is distributed in the hope that it will be useful, but
++ WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ GNU Affero General Public License for more details.
++
++ You should have received a copy of the GNU Affero General Public License
++ along with WebODF.  If not, see <http://www.gnu.org/licenses/>.
++ @licend
++
++ @source: http://www.webodf.org/
++ @source: https://github.com/kogmbh/WebODF/
++*/
++(function(){var m=0;ops.StepsCache=function(h,b,g){function d(a,c,d){this.nodeId=a;this.steps=c;this.node=d;this.previousBookmark=this.nextBookmark=null;this.setIteratorPosition=function(a){a.setPositionBeforeElement(d);do if(b.acceptPosition(a)===u)break;while(a.nextPosition())}}function n(a,c,d){this.nodeId=a;this.steps=c;this.node=d;this.previousBookmark=this.nextBookmark=null;this.setIteratorPosition=function(a){a.setUnfilteredPosition(d,0);do if(b.acceptPosition(a)===u)break;while( [...]
++function p(a,b){var c="["+a.nodeId;b&&(c+=" => "+b.nodeId);return c+"]"}function k(){for(var a=x,b,c,d,f=new core.LoopWatchDog(0,1E5);a;){f.check();(b=a.previousBookmark)?runtime.assert(b.nextBookmark===a,"Broken bookmark link to previous @"+p(b,a)):(runtime.assert(a===x,"Broken bookmark link @"+p(a)),runtime.assert(void 0===t||x.steps<=t,"Base point is damaged @"+p(a)));(c=a.nextBookmark)&&runtime.assert(c.previousBookmark===a,"Broken bookmark link to next @"+p(a,c));if(void 0===t||a.s [...]
++a.node),"Disconnected node is being reported as undamaged @"+p(a)),b&&(d=a.node.compareDocumentPosition(b.node),runtime.assert(0===d||0!==(d&Node.DOCUMENT_POSITION_PRECEDING),"Bookmark order with previous does not reflect DOM order @"+p(b,a))),c&&z.containsNode(h,c.node)&&(d=a.node.compareDocumentPosition(c.node),runtime.assert(0===d||0!==(d&Node.DOCUMENT_POSITION_FOLLOWING),"Bookmark order with next does not reflect DOM order @"+p(a,c)));a=a.nextBookmark}}function q(a){var b="";a.nodeT [...]
++(b=a.getAttributeNS(l,"nodeId"));return b}function e(a){var b=m.toString();a.setAttributeNS(l,"nodeId",b);m+=1;return b}function r(a){var b,c,d=new core.LoopWatchDog(0,1E4);void 0!==t&&a>t&&(a=t);for(b=Math.floor(a/g)*g;!c&&0!==b;)c=f[b],b-=g;for(c=c||x;c.nextBookmark&&c.nextBookmark.steps<=a;)d.check(),c=c.nextBookmark;return c}function a(a){a.previousBookmark&&(a.previousBookmark.nextBookmark=a.nextBookmark);a.nextBookmark&&(a.nextBookmark.previousBookmark=a.previousBookmark)}function [...]
++c=null;!c&&a&&a!==h;)(b=q(a))&&(c=v[b])&&c.node!==a&&(runtime.log("Cloned node detected. Creating new bookmark"),c=null,a.removeAttributeNS(l,"nodeId")),a=a.parentNode;return c}var l="urn:webodf:names:steps",f={},v={},w=new odf.OdfUtils,z=new core.DomUtils,x,t,u=core.PositionFilter.FilterResult.FILTER_ACCEPT,s;this.updateCache=function(b,c,l){var k;k=c.getCurrentNode();if(c.isBeforeNode()&&w.isParagraph(k)){l||(b+=1);c=b;var n,m,p;if(void 0!==t&&t<c){n=r(t);for(l=n.nextBookmark;l&&l.ste [...]
++p=Math.ceil(l.steps/g)*g,f[p]===l&&delete f[p],z.containsNode(h,l.node)?l.steps=c+1:(a(l),delete v[l.nodeId]),l=m;t=c}else n=r(c);c=n;l=q(k)||e(k);(n=v[l])?n.node===k?n.steps=b:(runtime.log("Cloned node detected. Creating new bookmark"),l=e(k),n=v[l]=new d(l,b,k)):n=v[l]=new d(l,b,k);k=n;c!==k&&c.nextBookmark!==k&&(a(k),b=c.nextBookmark,k.nextBookmark=c.nextBookmark,k.previousBookmark=c,c.nextBookmark=k,b&&(b.previousBookmark=k));b=Math.ceil(k.steps/g)*g;c=f[b];if(!c||k.steps>c.steps)f[ [...]
++this.setToClosestStep=function(a,b){var c;s();c=r(a);c.setIteratorPosition(b);return c.steps};this.setToClosestDomPoint=function(a,b,d){var e,l;s();if(a===h&&0===b)e=x;else if(a===h&&b===h.childNodes.length)for(l in e=x,f)f.hasOwnProperty(l)&&(a=f[l],a.steps>e.steps&&(e=a));else if(e=c(a.childNodes.item(b)||a),!e)for(d.setUnfilteredPosition(a,b);!e&&d.previousNode();)e=c(d.getCurrentNode());e=e||x;void 0!==t&&e.steps>t&&(e=r(t));e.setIteratorPosition(d);return e.steps};this.damageCacheA [...]
++a&&(a=0);void 0===t?t=a:a<t&&(t=a);s()};(function(){var a=q(h)||e(h);x=new n(a,0,h);s=ops.StepsCache.ENABLE_CACHE_VERIFICATION?k:function(){}})()};ops.StepsCache.ENABLE_CACHE_VERIFICATION=!1;ops.StepsCache.Bookmark=function(){};ops.StepsCache.Bookmark.prototype.setIteratorPosition=function(h){}})();
++// Input 42
 +/*
 +
 + Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("core.DomUtils");runtime.loadClass("core.Utils");
- odf.ObjectNameGenerator=function(g,l){function f(a,b){var c={};this.generateName=function(){var d=b(),e=0,f;do f=a+e,e+=1;while(c[f]||d[f]);c[f]=!0;return f}}function p(){var a={};[g.rootElement.automaticStyles,g.rootElement.styles].forEach(function(b){for(b=b.firstElementChild;b;)b.namespaceURI===r&&"style"===b.localName&&(a[b.getAttributeNS(r,"name")]=!0),b=b.nextElementSibling});return a}var r=odf.Namespaces.stylens,n=odf.Namespaces.drawns,h=odf.Namespaces.xlinkns,d=new core.DomUtils [...]
- c=null,e=null,a=null,b={},q={};this.generateStyleName=function(){null===c&&(c=new f("auto"+m+"_",function(){return p()}));return c.generateName()};this.generateFrameName=function(){null===e&&(d.getElementsByTagNameNS(g.rootElement.body,n,"frame").forEach(function(a){b[a.getAttributeNS(n,"name")]=!0}),e=new f("fr"+m+"_",function(){return b}));return e.generateName()};this.generateImageName=function(){null===a&&(d.getElementsByTagNameNS(g.rootElement.body,n,"image").forEach(function(a){a= [...]
- "href");a=a.substring(9,a.lastIndexOf("."));q[a]=!0}),a=new f("img"+m+"_",function(){return q}));return a.generateName()}};
- // Input 39
++(function(){ops.StepsTranslator=function(m,h,b,g){function d(){var a=m();a!==p&&(runtime.log("Undo detected. Resetting steps cache"),p=a,k=new ops.StepsCache(p,b,g),e=h(p))}function n(a,c){if(!c||b.acceptPosition(a)===r)return!0;for(;a.previousPosition();)if(b.acceptPosition(a)===r){if(c(0,a.container(),a.unfilteredDomOffset()))return!0;break}for(;a.nextPosition();)if(b.acceptPosition(a)===r){if(c(1,a.container(),a.unfilteredDomOffset()))return!0;break}return!1}var p=m(),k=new ops.Steps [...]
++g),q=new core.DomUtils,e=h(m()),r=core.PositionFilter.FilterResult.FILTER_ACCEPT;this.convertStepsToDomPoint=function(a){var c,l;if(isNaN(a))throw new TypeError("Requested steps is not numeric ("+a+")");if(0>a)throw new RangeError("Requested steps is negative ("+a+")");d();for(c=k.setToClosestStep(a,e);c<a&&e.nextPosition();)(l=b.acceptPosition(e)===r)&&(c+=1),k.updateCache(c,e,l);if(c!==a)throw new RangeError("Requested steps ("+a+") exceeds available steps ("+c+")");return{node:e.cont [...]
++this.convertDomPointToSteps=function(a,c,l){var f;d();q.containsNode(p,a)||(c=0>q.comparePoints(p,0,a,c),a=p,c=c?0:p.childNodes.length);e.setUnfilteredPosition(a,c);n(e,l)||e.setUnfilteredPosition(a,c);l=e.container();c=e.unfilteredDomOffset();a=k.setToClosestDomPoint(l,c,e);if(0>q.comparePoints(e.container(),e.unfilteredDomOffset(),l,c))return 0<a?a-1:a;for(;(e.container()!==l||e.unfilteredDomOffset()!==c)&&e.nextPosition();)(f=b.acceptPosition(e)===r)&&(a+=1),k.updateCache(a,e,f);retu [...]
++function(){var a,c;d();for(a=k.setToClosestStep(0,e);e.nextPosition();)(c=b.acceptPosition(e)===r)&&(a+=1),k.updateCache(a,e,c)};this.handleStepsInserted=function(a){d();k.damageCacheAfterStep(a.position)};this.handleStepsRemoved=function(a){d();k.damageCacheAfterStep(a.position-1)}};ops.StepsTranslator.PREVIOUS_STEP=0;ops.StepsTranslator.NEXT_STEP=1;return ops.StepsTranslator})();
++// Input 43
 +/*
 +
 + Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("core.Utils");runtime.loadClass("odf.ObjectNameGenerator");runtime.loadClass("odf.Namespaces");runtime.loadClass("odf.OdfContainer");runtime.loadClass("odf.StyleInfo");runtime.loadClass("odf.OdfUtils");
- odf.Formatting=function(){function g(a){return(a=u[a])?v.mergeObjects({},a):{}}function l(a,b,c){for(a=a&&a.firstElementChild;a&&(a.namespaceURI!==b||a.localName!==c);)a=a.nextElementSibling;return a}function f(){for(var a=e.rootElement.fontFaceDecls,c={},d,f,a=a&&a.firstElementChild;a;){if(d=a.getAttributeNS(q,"name"))if((f=a.getAttributeNS(b,"font-family"))||0<a.getElementsByTagNameNS(b,"font-face-uri").length)c[d]=f;a=a.nextElementSibling}return c}function p(a){for(var b=e.rootElemen [...]
- q&&"default-style"===b.localName&&b.getAttributeNS(q,"family")===a)return b;b=b.nextElementSibling}return null}function r(a,b,c){var d,f,h;c=c||[e.rootElement.automaticStyles,e.rootElement.styles];for(h=0;h<c.length;h+=1)for(d=c[h],d=d.firstElementChild;d;){f=d.getAttributeNS(q,"name");if(d.namespaceURI===q&&"style"===d.localName&&d.getAttributeNS(q,"family")===b&&f===a||"list-style"===b&&d.namespaceURI===k&&"list-style"===d.localName&&f===a||"data"===b&&d.namespaceURI===t&&f===a)return [...]
- function n(a){for(var b,c,d,e,f={},h=a.firstElementChild;h;){if(h.namespaceURI===q)for(d=f[h.nodeName]={},c=h.attributes,b=0;b<c.length;b+=1)e=c.item(b),d[e.name]=e.value;h=h.nextElementSibling}c=a.attributes;for(b=0;b<c.length;b+=1)e=c.item(b),f[e.name]=e.value;return f}function h(a,b){for(var c=e.rootElement.styles,d,f={},h=a.getAttributeNS(q,"family"),k=a;k;)d=n(k),f=v.mergeObjects(d,f),k=(d=k.getAttributeNS(q,"parent-style-name"))?r(d,h,[c]):null;if(k=p(h))d=n(k),f=v.mergeObjects(d, [...]
- (f=v.mergeObjects(d,f));return f}function d(b,c){function d(a){Object.keys(a).forEach(function(b){Object.keys(a[b]).forEach(function(a){k+="|"+b+":"+a+"|"})})}for(var e=b.nodeType===Node.TEXT_NODE?b.parentNode:b,f,h=[],k="",g=!1;e;)!g&&w.isGroupingElement(e)&&(g=!0),(f=a.determineStylesForNode(e))&&h.push(f),e=e.parentElement;g&&(h.forEach(d),c&&(c[k]=h));return g?h:void 0}function m(a){var b={orderedStyles:[]};a.forEach(function(a){Object.keys(a).forEach(function(c){var d=Object.keys(a [...]
- f;(e=r(d,c))?(f=h(e),b=v.mergeObjects(f,b),f=e.getAttributeNS(q,"display-name")):runtime.log("No style element found for '"+d+"' of family '"+c+"'");b.orderedStyles.push({name:d,family:c,displayName:f})})});return b}function c(a,b){var c=w.parseLength(a),d=b;if(c)switch(c.unit){case "cm":d=c.value;break;case "mm":d=0.1*c.value;break;case "in":d=2.54*c.value;break;case "pt":d=0.035277778*c.value;break;case "pc":case "px":case "em":break;default:runtime.log("Unit identifier: "+c.unit+" is [...]
- var e,a=new odf.StyleInfo,b=odf.Namespaces.svgns,q=odf.Namespaces.stylens,k=odf.Namespaces.textns,t=odf.Namespaces.numberns,A=odf.Namespaces.fons,w=new odf.OdfUtils,x=new core.DomUtils,v=new core.Utils,u={paragraph:{"style:paragraph-properties":{"fo:text-align":"left"}}};this.getSystemDefaultStyleAttributes=g;this.setOdfContainer=function(a){e=a};this.getFontMap=f;this.getAvailableParagraphStyles=function(){for(var a=e.rootElement.styles,b,c,d=[],a=a&&a.firstElementChild;a;)"style"===a. [...]
- a.namespaceURI===q&&(b=a.getAttributeNS(q,"family"),"paragraph"===b&&(b=a.getAttributeNS(q,"name"),c=a.getAttributeNS(q,"display-name")||b,b&&c&&d.push({name:b,displayName:c}))),a=a.nextElementSibling;return d};this.isStyleUsed=function(b){var c,d=e.rootElement;c=a.hasDerivedStyles(d,odf.Namespaces.lookupNamespaceURI,b);b=(new a.UsedStyleList(d.styles)).uses(b)||(new a.UsedStyleList(d.automaticStyles)).uses(b)||(new a.UsedStyleList(d.body)).uses(b);return c||b};this.getDefaultStyleEleme [...]
- r;this.getStyleAttributes=n;this.getInheritedStyleAttributes=h;this.getFirstCommonParentStyleNameOrSelf=function(a){var b=e.rootElement.automaticStyles,c=e.rootElement.styles,d;for(d=r(a,"paragraph",[b]);d;)a=d.getAttributeNS(q,"parent-style-name"),d=r(a,"paragraph",[b]);return(d=r(a,"paragraph",[c]))?a:null};this.hasParagraphStyle=function(a){return Boolean(r(a,"paragraph"))};this.getAppliedStyles=function(a){var b={},c=[];a.forEach(function(a){d(a,b)});Object.keys(b).forEach(function( [...]
- return c};this.getAppliedStylesForElement=function(a){return(a=d(a))?m(a):void 0};this.updateStyle=function(a,c){var d,h;x.mapObjOntoNode(a,c,odf.Namespaces.lookupNamespaceURI);(d=c["style:text-properties"]&&c["style:text-properties"]["style:font-name"])&&!f().hasOwnProperty(d)&&(h=a.ownerDocument.createElementNS(q,"style:font-face"),h.setAttributeNS(q,"style:name",d),h.setAttributeNS(b,"svg:font-family",d),e.rootElement.fontFaceDecls.appendChild(h))};this.createDerivedStyleObject=funct [...]
- r(a,b);runtime.assert(Boolean(d),"No style element found for '"+a+"' of family '"+b+"'");a=d.parentNode===e.rootElement.automaticStyles?n(d):{"style:parent-style-name":a};a["style:family"]=b;v.mergeObjects(a,c);return a};this.getDefaultTabStopDistance=function(){for(var a=p("paragraph"),a=a&&a.firstElementChild,b;a;)a.namespaceURI===q&&"paragraph-properties"===a.localName&&(b=a.getAttributeNS(q,"tab-stop-distance")),a=a.nextElementSibling;b||(b="1.25cm");return w.parseNonNegativeLength( [...]
- function(a,b){var d,f,h,k,g,m,n,p,t,v,u;a:{var w,aa,J;d=r(a,b);runtime.assert("paragraph"===b||"table"===b,"styleFamily has to be either paragraph or table");if(d){w=d.getAttributeNS(q,"master-page-name")||"Standard";for(d=e.rootElement.masterStyles.lastElementChild;d&&d.getAttributeNS(q,"name")!==w;)d=d.previousElementSibling;w=d.getAttributeNS(q,"page-layout-name");aa=x.getElementsByTagNameNS(e.rootElement.automaticStyles,q,"page-layout");for(J=0;J<aa.length;J+=1)if(d=aa[J],d.getAttri [...]
- w)break a}d=null}d||(d=l(e.rootElement.styles,q,"default-page-layout"));if(d=l(d,q,"page-layout-properties"))f=d.getAttributeNS(q,"print-orientation")||"portrait","portrait"===f?(f=21.001,h=29.7):(f=29.7,h=21.001),f=c(d.getAttributeNS(A,"page-width"),f),h=c(d.getAttributeNS(A,"page-height"),h),k=c(d.getAttributeNS(A,"margin"),null),null===k?(k=c(d.getAttributeNS(A,"margin-left"),2),g=c(d.getAttributeNS(A,"margin-right"),2),m=c(d.getAttributeNS(A,"margin-top"),2),n=c(d.getAttributeNS(A," [...]
- 2)):k=g=m=n=k,p=c(d.getAttributeNS(A,"padding"),null),null===p?(p=c(d.getAttributeNS(A,"padding-left"),0),t=c(d.getAttributeNS(A,"padding-right"),0),v=c(d.getAttributeNS(A,"padding-top"),0),u=c(d.getAttributeNS(A,"padding-bottom"),0)):p=t=v=u=p;return{width:f-k-g-p-t,height:h-m-n-v-u}}};
- // Input 40
++ops.TextPositionFilter=function(m){function h(d,g,e){var h,a;if(g){if(b.isInlineRoot(g)&&b.isGroupingElement(e))return p;h=b.lookLeftForCharacter(g);if(1===h||2===h&&(b.scanRightForAnyCharacter(e)||b.scanRightForAnyCharacter(b.nextNode(d))))return n}h=null===g&&b.isParagraph(d);a=b.lookRightForCharacter(e);if(h)return a?n:b.scanRightForAnyCharacter(e)?p:n;if(!a)return p;g=g||b.previousNode(d);return b.scanLeftForAnyCharacter(g)?p:n}var b=new odf.OdfUtils,g=Node.ELEMENT_NODE,d=Node.TEXT_ [...]
++p=core.PositionFilter.FilterResult.FILTER_REJECT;this.acceptPosition=function(k){var q=k.container(),e=q.nodeType,r,a,c;if(e!==g&&e!==d)return p;if(e===d){if(!b.isGroupingElement(q.parentNode)||b.isWithinTrackedChanges(q.parentNode,m()))return p;e=k.unfilteredDomOffset();r=q.data;runtime.assert(e!==r.length,"Unexpected offset.");if(0<e){k=r[e-1];if(!b.isODFWhitespace(k))return n;if(1<e)if(k=r[e-2],!b.isODFWhitespace(k))a=n;else{if(!b.isODFWhitespace(r.substr(0,e)))return p}else c=b.prev [...]
++b.scanLeftForNonSpace(c)&&(a=n);if(a===n)return b.isTrailingWhitespace(q,e)?p:n;a=r[e];return b.isODFWhitespace(a)?p:b.scanLeftForAnyCharacter(b.previousNode(q))?p:n}c=k.leftNode();a=q;q=q.parentNode;a=h(q,c,a)}else!b.isGroupingElement(q)||b.isWithinTrackedChanges(q,m())?a=p:(c=k.leftNode(),a=k.rightNode(),a=h(q,c,a));return a}};
++// Input 44
 +/*
 +
 + Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("core.DomUtils");runtime.loadClass("odf.OdfContainer");runtime.loadClass("odf.Formatting");runtime.loadClass("xmldom.XPath");runtime.loadClass("odf.FontLoader");runtime.loadClass("odf.Style2CSS");runtime.loadClass("odf.OdfUtils");runtime.loadClass("gui.AnnotationViewManager");
- (function(){function g(){function a(d){c=!0;runtime.setTimeout(function(){try{d()}catch(e){runtime.log(String(e))}c=!1;0<b.length&&a(b.pop())},10)}var b=[],c=!1;this.clearQueue=function(){b.length=0};this.addToQueue=function(d){if(0===b.length&&!c)return a(d);b.push(d)}}function l(a){function b(){for(;0<c.cssRules.length;)c.deleteRule(0);c.insertRule("#shadowContent draw|page {display:none;}",0);c.insertRule("office|presentation draw|page {display:none;}",1);c.insertRule("#shadowContent [...]
- d+") {display:block;}",2);c.insertRule("office|presentation draw|page:nth-of-type("+d+") {display:block;}",3)}var c=a.sheet,d=1;this.showFirstPage=function(){d=1;b()};this.showNextPage=function(){d+=1;b()};this.showPreviousPage=function(){1<d&&(d-=1,b())};this.showPage=function(a){0<a&&(d=a,b())};this.css=a;this.destroy=function(b){a.parentNode.removeChild(a);b()}}function f(a){for(;a.firstChild;)a.removeChild(a.firstChild)}function p(a,b,c){(new odf.Style2CSS).style2css(a.getDocumentTy [...]
- b.getFontMap(),a.rootElement.styles,a.rootElement.automaticStyles)}function r(a,b,c){var d=null;a=a.rootElement.body.getElementsByTagNameNS(L,c+"-decl");c=b.getAttributeNS(L,"use-"+c+"-name");var e;if(c&&0<a.length)for(b=0;b<a.length;b+=1)if(e=a[b],e.getAttributeNS(L,"name")===c){d=e.textContent;break}return d}function n(a,b,c,d){var e=a.ownerDocument;b=a.getElementsByTagNameNS(b,c);for(a=0;a<b.length;a+=1)f(b[a]),d&&(c=b[a],c.appendChild(e.createTextNode(d)))}function h(a,b,c){b.setAtt [...]
- "styleid",a);var d,e=b.getAttributeNS(H,"anchor-type"),f=b.getAttributeNS(u,"x"),h=b.getAttributeNS(u,"y"),k=b.getAttributeNS(u,"width"),g=b.getAttributeNS(u,"height"),q=b.getAttributeNS(w,"min-height"),m=b.getAttributeNS(w,"min-width");if("as-char"===e)d="display: inline-block;";else if(e||f||h)d="position: absolute;";else if(k||g||q||m)d="display: block;";f&&(d+="left: "+f+";");h&&(d+="top: "+h+";");k&&(d+="width: "+k+";");g&&(d+="height: "+g+";");q&&(d+="min-height: "+q+";");m&&(d+=" [...]
- m+";");d&&(d="draw|"+b.localName+'[webodfhelper|styleid="'+a+'"] {'+d+"}",c.insertRule(d,c.cssRules.length))}function d(a){for(a=a.firstChild;a;){if(a.namespaceURI===x&&"binary-data"===a.localName)return"data:image/png;base64,"+a.textContent.replace(/[\r\n\s]/g,"");a=a.nextSibling}return""}function m(a,b,c,e){function f(b){b&&(b='draw|image[webodfhelper|styleid="'+a+'"] {'+("background-image: url("+b+");")+"}",e.insertRule(b,e.cssRules.length))}function h(a){f(a.url)}c.setAttributeNS("u [...]
- "styleid",a);var k=c.getAttributeNS(y,"href"),g;if(k)try{g=b.getPart(k),g.onchange=h,g.load()}catch(q){runtime.log("slight problem: "+String(q))}else k=d(c),f(k)}function c(a){function b(c){var d,e;c.hasAttributeNS(y,"href")&&(d=c.getAttributeNS(y,"href"),"#"===d[0]?(d=d.substring(1),e=function(){var b=W.getODFElementsWithXPath(a,"//text:bookmark-start[@text:name='"+d+"']",odf.Namespaces.lookupNamespaceURI);0===b.length&&(b=W.getODFElementsWithXPath(a,"//text:bookmark[@text:name='"+d+"' [...]
- 0<b.length&&b[0].scrollIntoView(!0);return!1}):e=function(){I.open(d)},c.onclick=e)}var c,d,e;d=a.getElementsByTagNameNS(H,"a");for(c=0;c<d.length;c+=1)e=d.item(c),b(e)}function e(a){var b=a.ownerDocument;z.getElementsByTagNameNS(a,H,"line-break").forEach(function(a){a.hasChildNodes()||a.appendChild(b.createElement("br"))})}function a(a){var b=a.ownerDocument;z.getElementsByTagNameNS(a,H,"s").forEach(function(a){for(var c,d;a.firstChild;)a.removeChild(a.firstChild);a.appendChild(b.creat [...]
- d=parseInt(a.getAttributeNS(H,"c"),10);if(1<d)for(a.removeAttributeNS(H,"c"),c=1;c<d;c+=1)a.parentNode.insertBefore(a.cloneNode(!0),a)})}function b(a){z.getElementsByTagNameNS(a,H,"tab").forEach(function(a){a.textContent="\t"})}function q(a,b){function c(a,d){var e=g.documentElement.namespaceURI;"video/"===d.substr(0,6)?(f=g.createElementNS(e,"video"),f.setAttribute("controls","controls"),h=g.createElementNS(e,"source"),a&&h.setAttribute("src",a),h.setAttribute("type",d),f.appendChild(h [...]
- b.innerHtml="Unrecognised Plugin"}function e(a){c(a.url,a.mimetype)}var f,h,k,g=b.ownerDocument,q;if(k=b.getAttributeNS(y,"href"))try{q=a.getPart(k),q.onchange=e,q.load()}catch(m){runtime.log("slight problem: "+String(m))}else runtime.log("using MP4 data fallback"),k=d(b),c(k,"video/mp4")}function k(a){var b=a.getElementsByTagName("head")[0],c;"undefined"!==String(typeof webodf_css)?(c=a.createElementNS(b.namespaceURI,"style"),c.setAttribute("media","screen, print, handheld, projection" [...]
- (c=a.createElementNS(b.namespaceURI,"link"),a="webodf.css",runtime.currentDirectory&&(a=runtime.currentDirectory()+"/../"+a),c.setAttribute("href",a),c.setAttribute("rel","stylesheet"));c.setAttribute("type","text/css");b.appendChild(c);return c}function t(a){var b=a.getElementsByTagName("head")[0],c=a.createElementNS(b.namespaceURI,"style"),d="";c.setAttribute("type","text/css");c.setAttribute("media","screen, print, handheld, projection");odf.Namespaces.forEachPrefix(function(a,b){d+= [...]
- a+" url("+b+");\n"});d+="@namespace webodfhelper url(urn:webodf:names:helper);\n";c.appendChild(a.createTextNode(d));b.appendChild(c);return c}var A=odf.Namespaces.drawns,w=odf.Namespaces.fons,x=odf.Namespaces.officens,v=odf.Namespaces.stylens,u=odf.Namespaces.svgns,s=odf.Namespaces.tablens,H=odf.Namespaces.textns,y=odf.Namespaces.xlinkns,B=odf.Namespaces.xmlns,L=odf.Namespaces.presentationns,I=runtime.getWindow(),W=xmldom.XPath,Q=new odf.OdfUtils,z=new core.DomUtils;odf.OdfCanvas=funct [...]
- b,c){function d(a,b,c,e){E.addToQueue(function(){m(a,b,c,e)})}var e,f;e=b.getElementsByTagNameNS(A,"image");for(b=0;b<e.length;b+=1)f=e.item(b),d("image"+String(b),a,f,c)}function w(a,b){function c(a,b){E.addToQueue(function(){q(a,b)})}var d,e,f;e=b.getElementsByTagNameNS(A,"plugin");for(d=0;d<e.length;d+=1)f=e.item(d),c(a,f)}function y(){M.firstChild&&(1<S?(M.style.MozTransformOrigin="center top",M.style.WebkitTransformOrigin="center top",M.style.OTransformOrigin="center top",M.style.m [...]
- "center top"):(M.style.MozTransformOrigin="left top",M.style.WebkitTransformOrigin="left top",M.style.OTransformOrigin="left top",M.style.msTransformOrigin="left top"),M.style.WebkitTransform="scale("+S+")",M.style.MozTransform="scale("+S+")",M.style.OTransform="scale("+S+")",M.style.msTransform="scale("+S+")",d.style.width=Math.round(S*M.offsetWidth)+"px",d.style.height=Math.round(S*M.offsetHeight)+"px")}function O(a){function b(a){return d===a.getAttributeNS(x,"name")}var c=z.getEleme [...]
- x,"annotation");a=z.getElementsByTagNameNS(a,x,"annotation-end");var d,e;for(e=0;e<c.length;e+=1)d=c[e].getAttributeNS(x,"name"),ca.addAnnotation({node:c[e],end:a.filter(b)[0]||null});ca.rerenderAnnotations()}function aa(a){la?(ba.parentNode||(M.appendChild(ba),y()),ca&&ca.forgetAnnotations(),ca=new gui.AnnotationViewManager(C,a.body,ba),O(a.body)):ba.parentNode&&(M.removeChild(ba),ca.forgetAnnotations(),y())}function J(k){function g(){f(d);d.style.display="inline-block";var q=U.rootEle [...]
- !0);R.setOdfContainer(U);var m=U,l=T;(new odf.FontLoader).loadFonts(m,l.sheet);p(U,R,$);l=U;m=X.sheet;f(d);M=Y.createElementNS(d.namespaceURI,"div");M.style.display="inline-block";M.style.background="white";M.appendChild(q);d.appendChild(M);ba=Y.createElementNS(d.namespaceURI,"div");ba.id="annotationsPane";da=Y.createElementNS(d.namespaceURI,"div");da.id="shadowContent";da.style.position="absolute";da.style.top=0;da.style.left=0;l.getContentElement().appendChild(da);var t=q.body,z,D=[], [...]
- z!==t;)if(z.namespaceURI===A&&(D[D.length]=z),z.firstElementChild)z=z.firstElementChild;else{for(;z&&z!==t&&!z.nextElementSibling;)z=z.parentElement;z&&z.nextElementSibling&&(z=z.nextElementSibling)}for(C=0;C<D.length;C+=1)z=D[C],h("frame"+String(C),z,m);D=W.getODFElementsWithXPath(t,".//*[*[@text:anchor-type='paragraph']]",odf.Namespaces.lookupNamespaceURI);for(z=0;z<D.length;z+=1)t=D[z],t.setAttributeNS&&t.setAttributeNS("urn:webodf:names:helper","containsparagraphanchor",!0);var t=da [...]
- var J,P,D=l.rootElement.ownerDocument;if((z=q.body.firstElementChild)&&z.namespaceURI===x&&("presentation"===z.localName||"drawing"===z.localName))for(z=z.firstElementChild;z;){C=z.getAttributeNS(A,"master-page-name");if(C){for(O=l.rootElement.masterStyles.firstElementChild;O&&(O.getAttributeNS(v,"name")!==C||"master-page"!==O.localName||O.namespaceURI!==v););C=O}else C=null;if(C){O=z.getAttributeNS("urn:webodf:names:helper","styleid");E=D.createElementNS(A,"draw:page");P=C.firstElement [...]
- 0;P;)"true"!==P.getAttributeNS(L,"placeholder")&&(F=P.cloneNode(!0),E.appendChild(F),h(O+"_"+J,F,m)),P=P.nextElementSibling,J+=1;P=J=F=void 0;var V=E.getElementsByTagNameNS(A,"frame");for(F=0;F<V.length;F+=1)J=V[F],(P=J.getAttributeNS(L,"class"))&&!/^(date-time|footer|header|page-number')$/.test(P)&&J.parentNode.removeChild(J);t.appendChild(E);F=String(t.getElementsByTagNameNS(A,"page").length);n(E,H,"page-number",F);n(E,L,"header",r(l,z,"header"));n(E,L,"footer",r(l,z,"footer"));h(O,E, [...]
- "draw:master-page-name",C.getAttributeNS(v,"name"))}z=z.nextElementSibling}t=d.namespaceURI;D=q.body.getElementsByTagNameNS(s,"table-cell");for(z=0;z<D.length;z+=1)C=D.item(z),C.hasAttributeNS(s,"number-columns-spanned")&&C.setAttributeNS(t,"colspan",C.getAttributeNS(s,"number-columns-spanned")),C.hasAttributeNS(s,"number-rows-spanned")&&C.setAttributeNS(t,"rowspan",C.getAttributeNS(s,"number-rows-spanned"));c(q.body);e(q.body);a(q.body);b(q.body);u(l,q.body,m);w(l,q.body);C=q.body;l=d. [...]
- z={};var D={},K;O=I.document.getElementsByTagNameNS(H,"list-style");for(t=0;t<O.length;t+=1)J=O.item(t),(P=J.getAttributeNS(v,"name"))&&(D[P]=J);C=C.getElementsByTagNameNS(H,"list");for(t=0;t<C.length;t+=1)if(J=C.item(t),O=J.getAttributeNS(B,"id")){E=J.getAttributeNS(H,"continue-list");J.setAttributeNS(l,"id",O);F="text|list#"+O+" > text|list-item > *:first-child:before {";if(P=J.getAttributeNS(H,"style-name")){J=D[P];K=Q.getFirstNonWhitespaceChild(J);J=void 0;if(K)if("list-level-style- [...]
- K.localName){J=K.getAttributeNS(v,"num-format");P=K.getAttributeNS(v,"num-suffix")||"";var V="",V={1:"decimal",a:"lower-latin",A:"upper-latin",i:"lower-roman",I:"upper-roman"},S=void 0,S=K.getAttributeNS(v,"num-prefix")||"",S=V.hasOwnProperty(J)?S+(" counter(list, "+V[J]+")"):J?S+("'"+J+"';"):S+" ''";P&&(S+=" '"+P+"'");J=V="content: "+S+";"}else"list-level-style-image"===K.localName?J="content: none;":"list-level-style-bullet"===K.localName&&(J="content: '"+K.getAttributeNS(H,"bullet-ch [...]
- K=J}if(E){for(J=z[E];J;)J=z[J];F+="counter-increment:"+E+";";K?(K=K.replace("list",E),F+=K):F+="content:counter("+E+");"}else E="",K?(K=K.replace("list",O),F+=K):F+="content: counter("+O+");",F+="counter-increment:"+O+";",m.insertRule("text|list#"+O+" {counter-reset:"+O+"}",m.cssRules.length);F+="}";z[O]=E;F&&m.insertRule(F,m.cssRules.length)}M.insertBefore(da,M.firstChild);y();aa(q);if(!k&&(q=[U],ga.hasOwnProperty("statereadychange")))for(m=ga.statereadychange,K=0;K<m.length;K+=1)m[K]. [...]
- q)}U.state===odf.OdfContainer.DONE?g():(runtime.log("WARNING: refreshOdf called but ODF was not DONE."),runtime.setTimeout(function ha(){U.state===odf.OdfContainer.DONE?g():(runtime.log("will be back later..."),runtime.setTimeout(ha,500))},100))}function F(a){E.clearQueue();d.innerHTML=runtime.tr("Loading")+" "+a+"...";d.removeAttribute("style");U=new odf.OdfContainer(a,function(a){U=a;J(!1)})}runtime.assert(null!==d&&void 0!==d,"odf.OdfCanvas constructor needs DOM element");runtime.ass [...]
- d.ownerDocument&&void 0!==d.ownerDocument,"odf.OdfCanvas constructor needs DOM");var C=this,Y=d.ownerDocument,U,R=new odf.Formatting,P,M=null,ba=null,la=!1,ca=null,ma,T,$,X,da,S=1,ga={},E=new g;this.refreshCSS=function(){p(U,R,$);y()};this.refreshSize=function(){y()};this.odfContainer=function(){return U};this.setOdfContainer=function(a,b){U=a;J(!0===b)};this.load=this.load=F;this.save=function(a){U.save(a)};this.addListener=function(a,b){switch(a){case "click":var c=d,e=a;c.addEventLis [...]
- b,!1):c.attachEvent?c.attachEvent("on"+e,b):c["on"+e]=b;break;default:c=ga.hasOwnProperty(a)?ga[a]:ga[a]=[],b&&-1===c.indexOf(b)&&c.push(b)}};this.getFormatting=function(){return R};this.getAnnotationViewManager=function(){return ca};this.refreshAnnotations=function(){aa(U.rootElement)};this.rerenderAnnotations=function(){ca&&ca.rerenderAnnotations()};this.getSizer=function(){return M};this.enableAnnotations=function(a){a!==la&&(la=a,U&&aa(U.rootElement))};this.addAnnotation=function(a) [...]
- this.forgetAnnotations=function(){ca&&ca.forgetAnnotations()};this.setZoomLevel=function(a){S=a;y()};this.getZoomLevel=function(){return S};this.fitToContainingElement=function(a,b){var c=d.offsetHeight/S;S=a/(d.offsetWidth/S);b/c<S&&(S=b/c);y()};this.fitToWidth=function(a){S=a/(d.offsetWidth/S);y()};this.fitSmart=function(a,b){var c,e;c=d.offsetWidth/S;e=d.offsetHeight/S;c=a/c;void 0!==b&&b/e<c&&(c=b/e);S=Math.min(1,c);y()};this.fitToHeight=function(a){S=a/(d.offsetHeight/S);y()};this. [...]
- function(){P.showFirstPage()};this.showNextPage=function(){P.showNextPage()};this.showPreviousPage=function(){P.showPreviousPage()};this.showPage=function(a){P.showPage(a);y()};this.getElement=function(){return d};this.addCssForFrameWithImage=function(a){var b=a.getAttributeNS(A,"name"),c=a.firstElementChild;h(b,a,X.sheet);c&&m(b+"img",U,c,X.sheet)};this.destroy=function(a){var b=Y.getElementsByTagName("head")[0];ba&&ba.parentNode&&ba.parentNode.removeChild(ba);M&&(d.removeChild(M),M=nu [...]
- b.removeChild(T);b.removeChild($);b.removeChild(X);P.destroy(a)};ma=k(Y);P=new l(t(Y));T=t(Y);$=t(Y);X=t(Y)}})();
- // Input 41
++ops.OdtDocument=function(m){function h(){var a=m.odfContainer().getContentElement(),b=a&&a.localName;runtime.assert("text"===b,"Unsupported content element type '"+b+"' for OdtDocument");return a}function b(){return a.getDocumentElement().ownerDocument}function g(a){for(;a&&!(a.namespaceURI===odf.Namespaces.officens&&"text"===a.localName||a.namespaceURI===odf.Namespaces.officens&&"annotation"===a.localName);)a=a.parentNode;return a}function d(a){this.acceptPosition=function(b){b=b.conta [...]
++c="string"===typeof a?f[a].getNode():a;return g(b)===g(c)?z:x}}function n(a,b,c,d){d=gui.SelectionMover.createPositionIterator(d);var f;1===c.length?f=c[0]:(f=new core.PositionFilterChain,c.forEach(f.addFilter));c=new core.StepIterator(f,d);c.setPosition(a,b);return c}function p(a){var b=gui.SelectionMover.createPositionIterator(h());a=u.convertStepsToDomPoint(a);b.setUnfilteredPosition(a.node,a.offset);return b}function k(a){return c.getParagraphElement(a)}function q(a,b){return m.getF [...]
++b)}function e(a){return q(a,"paragraph")}function r(a,b,c){a=a.childNodes.item(b)||a;return(a=k(a))&&l.containsNode(c,a)?a:c}var a=this,c,l,f={},v={},w=new core.EventNotifier([ops.Document.signalMemberAdded,ops.Document.signalMemberUpdated,ops.Document.signalMemberRemoved,ops.Document.signalCursorAdded,ops.Document.signalCursorRemoved,ops.Document.signalCursorMoved,ops.OdtDocument.signalParagraphChanged,ops.OdtDocument.signalParagraphStyleModified,ops.OdtDocument.signalCommonStyleCreate [...]
++ops.OdtDocument.signalTableAdded,ops.OdtDocument.signalOperationStart,ops.OdtDocument.signalOperationEnd,ops.OdtDocument.signalProcessingBatchStart,ops.OdtDocument.signalProcessingBatchEnd,ops.OdtDocument.signalUndoStackChanged,ops.OdtDocument.signalStepsInserted,ops.OdtDocument.signalStepsRemoved]),z=core.PositionFilter.FilterResult.FILTER_ACCEPT,x=core.PositionFilter.FilterResult.FILTER_REJECT,t,u,s;this.getDocumentElement=function(){return m.odfContainer().rootElement};this.getDOMDoc [...]
++this.cloneDocumentElement=function(){var b=a.getDocumentElement(),c=m.getAnnotationViewManager();c&&c.forgetAnnotations();b=b.cloneNode(!0);m.refreshAnnotations();return b};this.setDocumentElement=function(a){var b=m.odfContainer();b.setRootElement(a);m.setOdfContainer(b,!0);m.refreshCSS()};this.getDOMDocument=b;this.getRootElement=g;this.createStepIterator=n;this.getIteratorAtPosition=p;this.convertDomPointToCursorStep=function(a,b,c){return u.convertDomPointToSteps(a,b,c)};this.conver [...]
++function(a,b){var c,d;c=b&&b(a.anchorNode,a.anchorOffset);c=u.convertDomPointToSteps(a.anchorNode,a.anchorOffset,c);b||a.anchorNode!==a.focusNode||a.anchorOffset!==a.focusOffset?(d=b&&b(a.focusNode,a.focusOffset),d=u.convertDomPointToSteps(a.focusNode,a.focusOffset,d)):d=c;return{position:c,length:d-c}};this.convertCursorToDomRange=function(a,c){var d=b().createRange(),f,e;f=u.convertStepsToDomPoint(a);c?(e=u.convertStepsToDomPoint(a+c),0<c?(d.setStart(f.node,f.offset),d.setEnd(e.node,e [...]
++(d.setStart(e.node,e.offset),d.setEnd(f.node,f.offset))):d.setStart(f.node,f.offset);return d};this.getStyleElement=q;this.upgradeWhitespacesAtPosition=function(a){a=p(a);var b,d,f;a.previousPosition();a.previousPosition();for(f=-1;1>=f;f+=1){b=a.container();d=a.unfilteredDomOffset();if(b.nodeType===Node.TEXT_NODE&&" "===b.data[d]&&c.isSignificantWhitespace(b,d)){runtime.assert(" "===b.data[d],"upgradeWhitespaceToElement: textNode.data[offset] should be a literal space");var e=b.ownerDo [...]
++"text:s"),l=b.parentNode,g=b;e.appendChild(b.ownerDocument.createTextNode(" "));1===b.length?l.replaceChild(e,b):(b.deleteData(d,1),0<d&&(d<b.length&&b.splitText(d),g=b.nextSibling),l.insertBefore(e,g));b=e;a.moveToEndOfNode(b)}a.nextPosition()}};this.downgradeWhitespacesAtPosition=function(a){var b=p(a),d;a=b.container();for(b=b.unfilteredDomOffset();!c.isSpaceElement(a)&&a.childNodes.item(b);)a=a.childNodes.item(b),b=0;a.nodeType===Node.TEXT_NODE&&(a=a.parentNode);c.isDowngradableSpac [...]
++(b=a.firstChild,d=a.lastChild,l.mergeIntoParent(a),d!==b&&l.normalizeTextNodes(d),l.normalizeTextNodes(b))};this.getParagraphStyleElement=e;this.getParagraphElement=k;this.getParagraphStyleAttributes=function(a){return(a=e(a))?m.getFormatting().getInheritedStyleAttributes(a,!1):null};this.getTextNodeAtStep=function(c,d){var e=p(c),l=e.container(),g,k=0,h=null;l.nodeType===Node.TEXT_NODE?(g=l,k=e.unfilteredDomOffset(),0<g.length&&(0<k&&(g=g.splitText(k)),g.parentNode.insertBefore(b().cre [...]
++g),g=g.previousSibling,k=0)):(g=b().createTextNode(""),k=0,l.insertBefore(g,e.rightNode()));if(d){if(f[d]&&a.getCursorPosition(d)===c){for(h=f[d].getNode();h.nextSibling&&"cursor"===h.nextSibling.localName;)h.parentNode.insertBefore(h.nextSibling,h);0<g.length&&g.nextSibling!==h&&(g=b().createTextNode(""),k=0);h.parentNode.insertBefore(g,h)}}else for(;g.nextSibling&&"cursor"===g.nextSibling.localName;)g.parentNode.insertBefore(g.nextSibling,g);for(;g.previousSibling&&g.previousSibling.n [...]
++Node.TEXT_NODE;)e=g.previousSibling,e.appendData(g.data),k=e.length,g=e,g.parentNode.removeChild(g.nextSibling);for(;g.nextSibling&&g.nextSibling.nodeType===Node.TEXT_NODE;)e=g.nextSibling,g.appendData(e.data),g.parentNode.removeChild(e);return{textNode:g,offset:k}};this.fixCursorPositions=function(){Object.keys(f).forEach(function(b){var c=f[b],d=g(c.getNode()),e=a.createRootFilter(d),l,k,h,m=!1;h=c.getSelectedRange();l=r(h.startContainer,h.startOffset,d);k=n(h.startContainer,h.startOf [...]
++l);h.collapsed?d=k:(l=r(h.endContainer,h.endOffset,d),d=n(h.endContainer,h.endOffset,[t,e],l));k.isStep()&&d.isStep()?k.container()!==d.container()||k.offset()!==d.offset()||h.collapsed&&c.getAnchorNode()===c.getNode()||(m=!0,h.setStart(k.container(),k.offset()),h.collapse(!0)):(m=!0,runtime.assert(k.roundToClosestStep(),"No walkable step found for cursor owned by "+b),h.setStart(k.container(),k.offset()),runtime.assert(d.roundToClosestStep(),"No walkable step found for cursor owned by  [...]
++d.offset()));m&&(c.setSelectedRange(h,c.hasForwardSelection()),a.emit(ops.Document.signalCursorMoved,c))})};this.getCursorPosition=function(a){return(a=f[a])?u.convertDomPointToSteps(a.getNode(),0):0};this.getCursorSelection=function(a){a=f[a];var b=0,c=0;a&&(b=u.convertDomPointToSteps(a.getNode(),0),c=u.convertDomPointToSteps(a.getAnchorNode(),0));return{position:c,length:b-c}};this.getPositionFilter=function(){return t};this.getOdfCanvas=function(){return m};this.getCanvas=function(){ [...]
++this.getRootNode=h;this.addMember=function(a){runtime.assert(void 0===v[a.getMemberId()],"This member already exists");v[a.getMemberId()]=a};this.getMember=function(a){return v.hasOwnProperty(a)?v[a]:null};this.removeMember=function(a){delete v[a]};this.getCursor=function(a){return f[a]};this.getMemberIds=function(){var a=[],b;for(b in f)f.hasOwnProperty(b)&&a.push(f[b].getMemberId());return a};this.addCursor=function(b){runtime.assert(Boolean(b),"OdtDocument::addCursor without cursor") [...]
++d=a.convertCursorToDomRange(0,0);runtime.assert("string"===typeof c,"OdtDocument::addCursor has cursor without memberid");runtime.assert(!f[c],"OdtDocument::addCursor is adding a duplicate cursor with memberid "+c);b.setSelectedRange(d,!0);f[c]=b};this.removeCursor=function(b){var c=f[b];return c?(c.removeFromDocument(),delete f[b],a.emit(ops.Document.signalCursorRemoved,b),!0):!1};this.moveCursor=function(b,c,d,e){b=f[b];c=a.convertCursorToDomRange(c,d);b&&(b.setSelectedRange(c,0<=d),b [...]
++ops.OdtCursor.RangeSelection))};this.getFormatting=function(){return m.getFormatting()};this.emit=function(a,b){w.emit(a,b)};this.subscribe=function(a,b){w.subscribe(a,b)};this.unsubscribe=function(a,b){w.unsubscribe(a,b)};this.createRootFilter=function(a){return new d(a)};this.close=function(a){a()};this.destroy=function(a){a()};t=new ops.TextPositionFilter(h);c=new odf.OdfUtils;l=new core.DomUtils;u=new ops.StepsTranslator(h,gui.SelectionMover.createPositionIterator,t,500);w.subscribe [...]
++u.handleStepsInserted);w.subscribe(ops.OdtDocument.signalStepsRemoved,u.handleStepsRemoved);w.subscribe(ops.OdtDocument.signalOperationEnd,function(b){var c=b.spec(),d=c.memberid,c=(new Date(c.timestamp)).toISOString(),f=m.odfContainer();b.isEdit&&(d=a.getMember(d).getProperties().fullName,f.setMetadata({"dc:creator":d,"dc:date":c},null),s||(f.incrementEditingCycles(),f.setMetadata(null,["meta:editing-duration","meta:document-statistic"])),s=b)})};ops.OdtDocument.signalParagraphChanged= [...]
++ops.OdtDocument.signalTableAdded="table/added";ops.OdtDocument.signalCommonStyleCreated="style/created";ops.OdtDocument.signalCommonStyleDeleted="style/deleted";ops.OdtDocument.signalParagraphStyleModified="paragraphstyle/modified";ops.OdtDocument.signalOperationStart="operation/start";ops.OdtDocument.signalOperationEnd="operation/end";ops.OdtDocument.signalProcessingBatchStart="router/batchstart";ops.OdtDocument.signalProcessingBatchEnd="router/batchend";ops.OdtDocument.signalUndoStack [...]
++ops.OdtDocument.signalStepsInserted="steps/inserted";ops.OdtDocument.signalStepsRemoved="steps/removed";(function(){return ops.OdtDocument})();
++// Input 45
 +/*
 +
 + Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("core.DomUtils");runtime.loadClass("core.LoopWatchDog");runtime.loadClass("odf.Namespaces");
- odf.TextStyleApplicator=function(g,l,f){function p(c){function d(a,b){return"object"===typeof a&&"object"===typeof b?Object.keys(a).every(function(c){return d(a[c],b[c])}):a===b}this.isStyleApplied=function(a){a=l.getAppliedStylesForElement(a);return d(c,a)}}function r(c){var e={};this.applyStyleToContainer=function(a){var b;b=a.getAttributeNS(d,"style-name");var h=a.ownerDocument;b=b||"";if(!e.hasOwnProperty(b)){var k=b,n;n=b?l.createDerivedStyleObject(b,"text",c):c;h=h.createElementNS [...]
- l.updateStyle(h,n);h.setAttributeNS(m,"style:name",g.generateStyleName());h.setAttributeNS(m,"style:family","text");h.setAttributeNS("urn:webodf:names:scope","scope","document-content");f.appendChild(h);e[k]=h}b=e[b].getAttributeNS(m,"name");a.setAttributeNS(d,"text:style-name",b)}}function n(c,e){var a=c.ownerDocument,b=c.parentNode,f,k,g=new core.LoopWatchDog(1E4);k=[];"span"!==b.localName||b.namespaceURI!==d?(f=a.createElementNS(d,"text:span"),b.insertBefore(f,c),b=!1):(c.previousSib [...]
- b.firstChild)?(f=b.cloneNode(!1),b.parentNode.insertBefore(f,b.nextSibling)):f=b,b=!0);k.push(c);for(a=c.nextSibling;a&&h.rangeContainsNode(e,a);)g.check(),k.push(a),a=a.nextSibling;k.forEach(function(a){a.parentNode!==f&&f.appendChild(a)});if(a&&b)for(k=f.cloneNode(!1),f.parentNode.insertBefore(k,f.nextSibling);a;)g.check(),b=a.nextSibling,k.appendChild(a),a=b;return f}var h=new core.DomUtils,d=odf.Namespaces.textns,m=odf.Namespaces.stylens;this.applyStyle=function(c,d,a){var b={},f,h, [...]
- a.hasOwnProperty("style:text-properties"),"applyStyle without any text properties");b["style:text-properties"]=a["style:text-properties"];g=new r(b);m=new p(b);c.forEach(function(a){f=m.isStyleApplied(a);!1===f&&(h=n(a,d),g.applyStyleToContainer(h))})}};
- // Input 42
++ops.OpAddAnnotation=function(){function m(b,d,e){var g=b.getTextNodeAtStep(e,h);g&&(b=g.textNode,e=b.parentNode,g.offset!==b.length&&b.splitText(g.offset),e.insertBefore(d,b.nextSibling),0===b.length&&e.removeChild(b))}var h,b,g,d,n,p;this.init=function(k){h=k.memberid;b=parseInt(k.timestamp,10);g=parseInt(k.position,10);d=parseInt(k.length,10)||0;n=k.name};this.isEdit=!0;this.group=void 0;this.execute=function(k){var q=k.getCursor(h),e,r;r=new core.DomUtils;p=k.getDOMDocument();var a=n [...]
++c,l,f,v;c=p.createElementNS(odf.Namespaces.officens,"office:annotation");c.setAttributeNS(odf.Namespaces.officens,"office:name",n);e=p.createElementNS(odf.Namespaces.dcns,"dc:creator");e.setAttributeNS("urn:webodf:names:editinfo","editinfo:memberid",h);e.textContent=k.getMember(h).getProperties().fullName;l=p.createElementNS(odf.Namespaces.dcns,"dc:date");l.appendChild(p.createTextNode(a.toISOString()));a=p.createElementNS(odf.Namespaces.textns,"text:list");f=p.createElementNS(odf.Names [...]
++"text:list-item");v=p.createElementNS(odf.Namespaces.textns,"text:p");f.appendChild(v);a.appendChild(f);c.appendChild(e);c.appendChild(l);c.appendChild(a);d&&(e=p.createElementNS(odf.Namespaces.officens,"office:annotation-end"),e.setAttributeNS(odf.Namespaces.officens,"office:name",n),c.annotationEndElement=e,m(k,e,g+d));m(k,c,g);k.emit(ops.OdtDocument.signalStepsInserted,{position:g,length:d});q&&(e=p.createRange(),r=r.getElementsByTagNameNS(c,odf.Namespaces.textns,"p")[0],e.selectNode [...]
++q.setSelectedRange(e,!1),k.emit(ops.Document.signalCursorMoved,q));k.getOdfCanvas().addAnnotation(c);k.fixCursorPositions();return!0};this.spec=function(){return{optype:"AddAnnotation",memberid:h,timestamp:b,position:g,length:d,name:n}}};
++// Input 46
 +/*
 +
 + Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("odf.Namespaces");runtime.loadClass("odf.OdfUtils");
- gui.StyleHelper=function(g){function l(f,h,d){var g=!0,c;for(c=0;c<f.length&&!(g=f[c]["style:text-properties"],g=!g||g[h]!==d);c+=1);return!g}function f(f,h,d){function m(){b=!0;(e=g.getDefaultStyleElement("paragraph"))||(e=null)}var c,e;f=p.getParagraphElements(f);for(var a={},b=!1;0<f.length;){(c=f[0].getAttributeNS(r,"style-name"))?a[c]||(e=g.getStyleElement(c,"paragraph"),a[c]=!0,e||b||m()):b?e=void 0:m();if(void 0!==e&&(c=null===e?g.getSystemDefaultStyleAttributes("paragraph"):g.ge [...]
- !0),(c=c["style:paragraph-properties"])&&-1===d.indexOf(c[h])))return!1;f.pop()}return!0}var p=new odf.OdfUtils,r=odf.Namespaces.textns;this.getAppliedStyles=function(f){var h;f.collapsed?(h=f.startContainer,h.hasChildNodes()&&f.startOffset<h.childNodes.length&&(h=h.childNodes.item(f.startOffset)),f=[h]):f=p.getTextNodes(f,!0);return g.getAppliedStyles(f)};this.isBold=function(f){return l(f,"fo:font-weight","bold")};this.isItalic=function(f){return l(f,"fo:font-style","italic")};this.ha [...]
- function(f){return l(f,"style:text-underline-style","solid")};this.hasStrikeThrough=function(f){return l(f,"style:text-line-through-style","solid")};this.isAlignedLeft=function(g){return f(g,"fo:text-align",["left","start"])};this.isAlignedCenter=function(g){return f(g,"fo:text-align",["center"])};this.isAlignedRight=function(g){return f(g,"fo:text-align",["right","end"])};this.isAlignedJustified=function(g){return f(g,"fo:text-align",["justify"])}};
- // Input 43
- core.RawDeflate=function(){function g(){this.dl=this.fc=0}function l(){this.extra_bits=this.static_tree=this.dyn_tree=null;this.max_code=this.max_length=this.elems=this.extra_base=0}function f(a,b,c,d){this.good_length=a;this.max_lazy=b;this.nice_length=c;this.max_chain=d}function p(){this.next=null;this.len=0;this.ptr=[];this.ptr.length=r;this.off=0}var r=8192,n,h,d,m,c=null,e,a,b,q,k,t,A,w,x,v,u,s,H,y,B,L,I,W,Q,z,ja,ka,G,Z,O,aa,J,F,C,Y,U,R,P,M,ba,la,ca,ma,T,$,X,da,S,ga,E,fa,D,pa,ha,ia [...]
- 0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0],qa=[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13],sa=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7],xa=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],ra;ra=[new f(0,0,0,0),new f(4,4,8,4),new f(4,5,16,8),new f(4,6,32,32),new f(4,4,16,16),new f(8,16,32,32),new f(8,16,128,128),new f(8,32,128,256),new f(32,128,258,1024),new f(32,258,258,4096)];var Aa=function(b){c[a+e++]=b;if(a+e===r){var f;if(0!==e){null!==n?(b=n,n=n. [...]
- b.next=null;b.len=b.off=0;null===h?h=d=b:d=d.next=b;b.len=e-a;for(f=0;f<b.len;f++)b.ptr[f]=c[a+f];e=a=0}}},ta=function(b){b&=65535;a+e<r-2?(c[a+e++]=b&255,c[a+e++]=b>>>8):(Aa(b&255),Aa(b>>>8))},Ba=function(){u=(u<<5^q[I+3-1]&255)&8191;s=A[32768+u];A[I&32767]=s;A[32768+u]=I},V=function(a,b){x>16-b?(w|=a<<x,ta(w),w=a>>16-x,x+=b-16):(w|=a<<x,x+=b)},K=function(a,b){V(b[a].fc,b[a].dl)},ua=function(a,b,c){return a[b].fc<a[c].fc||a[b].fc===a[c].fc&&ca[b]<=ca[c]},na=function(a,b,c){var d;for(d= [...]
- ia.length;d++)a[b+d]=ia.charCodeAt(Da++)&255;return d},ea=function(){var a,b,c=65536-z-I;if(-1===c)c--;else if(65274<=I){for(a=0;32768>a;a++)q[a]=q[a+32768];W-=32768;I-=32768;v-=32768;for(a=0;8192>a;a++)b=A[32768+a],A[32768+a]=32768<=b?b-32768:0;for(a=0;32768>a;a++)b=A[a],A[a]=32768<=b?b-32768:0;c+=32768}Q||(a=na(q,I+z,c),0>=a?Q=!0:z+=a)},oa=function(a){var b=ja,c=I,d,e=L,f=32506<I?I-32506:0,h=I+258,k=q[c+e-1],g=q[c+e];L>=Z&&(b>>=2);do if(d=a,q[d+e]===g&&q[d+e-1]===k&&q[d]===q[c]&&q[++d [...]
- 2;d++;do++c;while(q[c]===q[++d]&&q[++c]===q[++d]&&q[++c]===q[++d]&&q[++c]===q[++d]&&q[++c]===q[++d]&&q[++c]===q[++d]&&q[++c]===q[++d]&&q[++c]===q[++d]&&c<h);d=258-(h-c);c=h-258;if(d>e){W=a;e=d;if(258<=d)break;k=q[c+e-1];g=q[c+e]}a=A[a&32767]}while(a>f&&0!==--b);return e},Ca=function(a,b){t[S++]=b;0===a?O[b].fc++:(a--,O[ma[b]+256+1].fc++,aa[(256>a?T[a]:T[256+(a>>7)])&255].fc++,k[ga++]=a,fa|=D);D<<=1;0===(S&7)&&(da[E++]=fa,fa=0,D=1);if(2<G&&0===(S&4095)){var c=8*S,d=I-v,e;for(e=0;30>e;e++ [...]
- (5+qa[e]);c>>=3;if(ga<parseInt(S/2,10)&&c<parseInt(d/2,10))return!0}return 8191===S||8192===ga},ya=function(a,b){for(var c=M[b],d=b<<1;d<=ba;){d<ba&&ua(a,M[d+1],M[d])&&d++;if(ua(a,c,M[d]))break;M[b]=M[d];b=d;d<<=1}M[b]=c},Ea=function(a,b){var c=0;do c|=a&1,a>>=1,c<<=1;while(0<--b);return c>>1},za=function(a,b){var c=[];c.length=16;var d=0,e;for(e=1;15>=e;e++)d=d+P[e-1]<<1,c[e]=d;for(d=0;d<=b;d++)e=a[d].dl,0!==e&&(a[d].fc=Ea(c[e]++,e))},va=function(a){var b=a.dyn_tree,c=a.static_tree,d=a [...]
- -1,h=d;ba=0;la=573;for(e=0;e<d;e++)0!==b[e].fc?(M[++ba]=f=e,ca[e]=0):b[e].dl=0;for(;2>ba;)e=M[++ba]=2>f?++f:0,b[e].fc=1,ca[e]=0,pa--,null!==c&&(ha-=c[e].dl);a.max_code=f;for(e=ba>>1;1<=e;e--)ya(b,e);do e=M[1],M[1]=M[ba--],ya(b,1),c=M[1],M[--la]=e,M[--la]=c,b[h].fc=b[e].fc+b[c].fc,ca[h]=ca[e]>ca[c]+1?ca[e]:ca[c]+1,b[e].dl=b[c].dl=h,M[1]=h++,ya(b,1);while(2<=ba);M[--la]=M[1];h=a.dyn_tree;e=a.extra_bits;var d=a.extra_base,c=a.max_code,k=a.max_length,g=a.static_tree,q,m,l,p,n=0;for(m=0;15>= [...]
- 0;h[M[la]].dl=0;for(a=la+1;573>a;a++)q=M[a],m=h[h[q].dl].dl+1,m>k&&(m=k,n++),h[q].dl=m,q>c||(P[m]++,l=0,q>=d&&(l=e[q-d]),p=h[q].fc,pa+=p*(m+l),null!==g&&(ha+=p*(g[q].dl+l)));if(0!==n){do{for(m=k-1;0===P[m];)m--;P[m]--;P[m+1]+=2;P[k]--;n-=2}while(0<n);for(m=k;0!==m;m--)for(q=P[m];0!==q;)e=M[--a],e>c||(h[e].dl!==m&&(pa+=(m-h[e].dl)*h[e].fc,h[e].fc=m),q--)}za(b,f)},Fa=function(a,b){var c,d=-1,e,f=a[0].dl,h=0,k=7,g=4;0===f&&(k=138,g=3);a[b+1].dl=65535;for(c=0;c<=b;c++)e=f,f=a[c+1].dl,++h<k& [...]
- g?C[e].fc+=h:0!==e?(e!==d&&C[e].fc++,C[16].fc++):10>=h?C[17].fc++:C[18].fc++,h=0,d=e,0===f?(k=138,g=3):e===f?(k=6,g=3):(k=7,g=4))},wa=function(){8<x?ta(w):0<x&&Aa(w);x=w=0},Ha=function(a,b){var c,d=0,e=0,f=0,h=0,g,q;if(0!==S){do 0===(d&7)&&(h=da[f++]),c=t[d++]&255,0===(h&1)?K(c,a):(g=ma[c],K(g+256+1,a),q=N[g],0!==q&&(c-=$[g],V(c,q)),c=k[e++],g=(256>c?T[c]:T[256+(c>>7)])&255,K(g,b),q=qa[g],0!==q&&(c-=X[g],V(c,q))),h>>=1;while(d<S)}K(256,a)},Ia=function(a,b){var c,d=-1,e,f=a[0].dl,h=0,k=7 [...]
- (k=138,g=3);for(c=0;c<=b;c++)if(e=f,f=a[c+1].dl,!(++h<k&&e===f)){if(h<g){do K(e,C);while(0!==--h)}else 0!==e?(e!==d&&(K(e,C),h--),K(16,C),V(h-3,2)):10>=h?(K(17,C),V(h-3,3)):(K(18,C),V(h-11,7));h=0;d=e;0===f?(k=138,g=3):e===f?(k=6,g=3):(k=7,g=4)}},Ja=function(){var a;for(a=0;286>a;a++)O[a].fc=0;for(a=0;30>a;a++)aa[a].fc=0;for(a=0;19>a;a++)C[a].fc=0;O[256].fc=1;fa=S=ga=E=pa=ha=0;D=1},Ga=function(a){var b,c,d,e;e=I-v;da[E]=fa;va(Y);va(U);Fa(O,Y.max_code);Fa(aa,U.max_code);va(R);for(d=18;3< [...]
- pa+=3*(d+1)+14;b=pa+3+7>>3;c=ha+3+7>>3;c<=b&&(b=c);if(e+4<=b&&0<=v)for(V(0+a,3),wa(),ta(e),ta(~e),d=0;d<e;d++)Aa(q[v+d]);else if(c===b)V(2+a,3),Ha(J,F);else{V(4+a,3);e=Y.max_code+1;b=U.max_code+1;d+=1;V(e-257,5);V(b-1,5);V(d-4,4);for(c=0;c<d;c++)V(C[xa[c]].dl,3);Ia(O,e-1);Ia(aa,b-1);Ha(O,aa)}Ja();0!==a&&wa()},Ka=function(b,d,f){var k,g,q;for(k=0;null!==h&&k<f;){g=f-k;g>h.len&&(g=h.len);for(q=0;q<g;q++)b[d+k+q]=h.ptr[h.off+q];h.off+=g;h.len-=g;k+=g;0===h.len&&(g=h,h=h.next,g.next=n,n=g)} [...]
- if(a<e){g=f-k;g>e-a&&(g=e-a);for(q=0;q<g;q++)b[d+k+q]=c[a+q];a+=g;k+=g;e===a&&(e=a=0)}return k},La=function(c,d,f){var k;if(!m){if(!Q){x=w=0;var g,l;if(0===F[0].dl){Y.dyn_tree=O;Y.static_tree=J;Y.extra_bits=N;Y.extra_base=257;Y.elems=286;Y.max_length=15;Y.max_code=0;U.dyn_tree=aa;U.static_tree=F;U.extra_bits=qa;U.extra_base=0;U.elems=30;U.max_length=15;U.max_code=0;R.dyn_tree=C;R.static_tree=null;R.extra_bits=sa;R.extra_base=0;R.elems=19;R.max_length=7;for(l=g=R.max_code=0;28>l;l++)for( [...]
- 1<<N[l];k++)ma[g++]=l;ma[g-1]=l;for(l=g=0;16>l;l++)for(X[l]=g,k=0;k<1<<qa[l];k++)T[g++]=l;for(g>>=7;30>l;l++)for(X[l]=g<<7,k=0;k<1<<qa[l]-7;k++)T[256+g++]=l;for(k=0;15>=k;k++)P[k]=0;for(k=0;143>=k;)J[k++].dl=8,P[8]++;for(;255>=k;)J[k++].dl=9,P[9]++;for(;279>=k;)J[k++].dl=7,P[7]++;for(;287>=k;)J[k++].dl=8,P[8]++;za(J,287);for(k=0;30>k;k++)F[k].dl=5,F[k].fc=Ea(k,5);Ja()}for(k=0;8192>k;k++)A[32768+k]=0;ka=ra[G].max_lazy;Z=ra[G].good_length;ja=ra[G].max_chain;v=I=0;z=na(q,0,65536);if(0>=z)Q [...]
- !1;262>z&&!Q;)ea();for(k=u=0;2>k;k++)u=(u<<5^q[k]&255)&8191}h=null;a=e=0;3>=G?(L=2,B=0):(B=2,y=0);b=!1}m=!0;if(0===z)return b=!0,0}k=Ka(c,d,f);if(k===f)return f;if(b)return k;if(3>=G)for(;0!==z&&null===h;){Ba();0!==s&&32506>=I-s&&(B=oa(s),B>z&&(B=z));if(3<=B)if(l=Ca(I-W,B-3),z-=B,B<=ka){B--;do I++,Ba();while(0!==--B);I++}else I+=B,B=0,u=q[I]&255,u=(u<<5^q[I+1]&255)&8191;else l=Ca(0,q[I]&255),z--,I++;l&&(Ga(0),v=I);for(;262>z&&!Q;)ea()}else for(;0!==z&&null===h;){Ba();L=B;H=W;B=2;0!==s&& [...]
- I-s&&(B=oa(s),B>z&&(B=z),3===B&&4096<I-W&&B--);if(3<=L&&B<=L){l=Ca(I-1-H,L-3);z-=L-1;L-=2;do I++,Ba();while(0!==--L);y=0;B=2;I++;l&&(Ga(0),v=I)}else 0!==y?Ca(0,q[I-1]&255)&&(Ga(0),v=I):y=1,I++,z--;for(;262>z&&!Q;)ea()}0===z&&(0!==y&&Ca(0,q[I-1]&255),Ga(1),b=!0);return k+Ka(c,k+d,f-k)};this.deflate=function(a,b){var e,f;ia=a;Da=0;"undefined"===String(typeof b)&&(b=6);(e=b)?1>e?e=1:9<e&&(e=9):e=6;G=e;Q=m=!1;if(null===c){n=h=d=null;c=[];c.length=r;q=[];q.length=65536;k=[];k.length=8192;t=[ [...]
- 32832;A=[];A.length=65536;O=[];O.length=573;for(e=0;573>e;e++)O[e]=new g;aa=[];aa.length=61;for(e=0;61>e;e++)aa[e]=new g;J=[];J.length=288;for(e=0;288>e;e++)J[e]=new g;F=[];F.length=30;for(e=0;30>e;e++)F[e]=new g;C=[];C.length=39;for(e=0;39>e;e++)C[e]=new g;Y=new l;U=new l;R=new l;P=[];P.length=16;M=[];M.length=573;ca=[];ca.length=573;ma=[];ma.length=256;T=[];T.length=512;$=[];$.length=29;X=[];X.length=30;da=[];da.length=1024}var p=Array(1024),v=[],s=[];for(e=La(p,0,p.length);0<e;){s.le [...]
- 0;f<e;f++)s[f]=String.fromCharCode(p[f]);v[v.length]=s.join("");e=La(p,0,p.length)}ia="";return v.join("")}};
- // Input 44
- runtime.loadClass("odf.Namespaces");
- gui.ImageSelector=function(g){function l(){var f=g.getSizer(),d,m;d=r.createElement("div");d.id="imageSelector";d.style.borderWidth="1px";f.appendChild(d);p.forEach(function(c){m=r.createElement("div");m.className=c;d.appendChild(m)});return d}var f=odf.Namespaces.svgns,p="topLeft topRight bottomRight bottomLeft topMiddle rightMiddle bottomMiddle leftMiddle".split(" "),r=g.getElement().ownerDocument,n=!1;this.select=function(h){var d,m,c=r.getElementById("imageSelector");c||(c=l());n=!0 [...]
- m=h.getBoundingClientRect();var e=d.getBoundingClientRect(),a=g.getZoomLevel();d=(m.left-e.left)/a-1;m=(m.top-e.top)/a-1;c.style.display="block";c.style.left=d+"px";c.style.top=m+"px";c.style.width=h.getAttributeNS(f,"width");c.style.height=h.getAttributeNS(f,"height")};this.clearSelection=function(){var f;n&&(f=r.getElementById("imageSelector"))&&(f.style.display="none");n=!1};this.isSelectorElement=function(f){var d=r.getElementById("imageSelector");return d?f===d||f.parentNode===d:!1}};
- // Input 45
- runtime.loadClass("odf.OdfCanvas");
- odf.CommandLineTools=function(){this.roundTrip=function(g,l,f){return new odf.OdfContainer(g,function(p){if(p.state===odf.OdfContainer.INVALID)return f("Document "+g+" is invalid.");p.state===odf.OdfContainer.DONE?p.saveAs(l,function(g){f(g)}):f("Document was not completely loaded.")})};this.render=function(g,l,f){for(l=l.getElementsByTagName("body")[0];l.firstChild;)l.removeChild(l.firstChild);l=new odf.OdfCanvas(l);l.addListener("statereadychange",function(g){f(g)});l.load(g)}};
- // Input 46
++ops.OpAddCursor=function(){var m,h;this.init=function(b){m=b.memberid;h=b.timestamp};this.isEdit=!1;this.group=void 0;this.execute=function(b){var g=b.getCursor(m);if(g)return!1;g=new ops.OdtCursor(m,b);b.addCursor(g);b.emit(ops.Document.signalCursorAdded,g);return!0};this.spec=function(){return{optype:"AddCursor",memberid:m,timestamp:h}}};
++// Input 47
 +/*
 +
 + Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + This file is part of WebODF.
 +
 + WebODF is free software: you can redistribute it and/or modify it
 + under the terms of the GNU Affero General Public License (GNU AGPL)
 + as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.
 +
 + WebODF is distributed in the hope that it will be useful, but
 + WITHOUT ANY WARRANTY; without even the implied warranty of
 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + GNU Affero General Public License for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with WebODF.  If not, see <http://www.gnu.org/licenses/>.
 + @licend
 +
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- ops.Member=function(g,l){var f={};this.getMemberId=function(){return g};this.getProperties=function(){return f};this.setProperties=function(g){Object.keys(g).forEach(function(l){f[l]=g[l]})};this.removeProperties=function(g){delete g.fullName;delete g.color;delete g.imageUrl;Object.keys(g).forEach(function(g){f.hasOwnProperty(g)&&delete f[g]})};runtime.assert(Boolean(g),"No memberId was supplied!");l.fullName||(l.fullName=runtime.tr("Unknown Author"));l.color||(l.color="black");l.imageU [...]
- "avatar-joe.png");f=l};
- // Input 47
++ops.OpAddMember=function(){var m,h,b;this.init=function(g){m=g.memberid;h=parseInt(g.timestamp,10);b=g.setProperties};this.isEdit=!1;this.group=void 0;this.execute=function(g){var d;if(g.getMember(m))return!1;d=new ops.Member(m,b);g.addMember(d);g.emit(ops.Document.signalMemberAdded,d);return!0};this.spec=function(){return{optype:"AddMember",memberid:m,timestamp:h,setProperties:b}}};
++// Input 48
 +/*
 +
 + Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("core.DomUtils");runtime.loadClass("core.PositionFilter");runtime.loadClass("odf.OdfUtils");
- (function(){function g(f,g,r){function n(a,b){function c(a){for(var b=0;a&&a.previousSibling;)b+=1,a=a.previousSibling;return b}this.steps=a;this.node=b;this.setIteratorPosition=function(a){a.setUnfilteredPosition(b.parentNode,c(b));do if(g.acceptPosition(a)===t)break;while(a.nextPosition())}}function h(a){return a.nodeType===Node.ELEMENT_NODE&&a.getAttributeNS(c,"nodeId")}function d(a){var b=l;a.setAttributeNS(c,"nodeId",b.toString());l+=1;return b}function m(b,d){var e,k=null;for(b=b. [...]
- b;!k&&b&&b!==f;)(e=h(b))&&(k=a[e])&&k.node!==b&&(runtime.log("Cloned node detected. Creating new bookmark"),k=null,b.removeAttributeNS(c,"nodeId")),b=b.parentNode;return k}var c="urn:webodf:names:steps",e={},a={},b=new odf.OdfUtils,q=new core.DomUtils,k,t=core.PositionFilter.FilterResult.FILTER_ACCEPT;this.updateCache=function(c,f,k,g){var q;0===k&&b.isParagraph(f)?(q=!0,g||(c+=1)):f.hasChildNodes()&&f.childNodes[k]&&(f=f.childNodes[k],(q=b.isParagraph(f))&&(c+=1));q&&(k=h(f)||d(f),(g=a [...]
- f?g.steps=c:(runtime.log("Cloned node detected. Creating new bookmark"),k=d(f),g=a[k]=new n(c,f)):g=a[k]=new n(c,f),k=g,c=Math.ceil(k.steps/r)*r,f=e[c],!f||k.steps>f.steps)&&(e[c]=k)};this.setToClosestStep=function(a,b){for(var c=Math.floor(a/r)*r,d;!d&&0!==c;)d=e[c],c-=r;d=d||k;d.setIteratorPosition(b);return d.steps};this.setToClosestDomPoint=function(a,b,c){var d;if(a===f&&0===b)d=k;else if(a===f&&b===f.childNodes.length)d=Object.keys(e).map(function(a){return e[a]}).reduce(function( [...]
- a.steps?b:a},k);else if(d=m(a,b),!d)for(c.setUnfilteredPosition(a,b);!d&&c.previousNode();)d=m(c.container(),c.unfilteredDomOffset());d=d||k;d.setIteratorPosition(c);return d.steps};this.updateCacheAtPoint=function(b,c){var d={};Object.keys(a).map(function(b){return a[b]}).filter(function(a){return a.steps>b}).forEach(function(b){var k=Math.ceil(b.steps/r)*r,g,m;if(q.containsNode(f,b.node)){if(c(b),g=Math.ceil(b.steps/r)*r,m=d[g],!m||b.steps>m.steps)d[g]=b}else delete a[h(b.node)];e[k]= [...]
- Object.keys(d).forEach(function(a){e[a]=d[a]})};k=new function(a,b){this.steps=a;this.node=b;this.setIteratorPosition=function(a){a.setUnfilteredPosition(b,0);do if(g.acceptPosition(a)===t)break;while(a.nextPosition())}}(0,f)}var l=0;ops.StepsTranslator=function(f,l,r,n){function h(){var b=f();b!==m&&(runtime.log("Undo detected. Resetting steps cache"),m=b,c=new g(m,r,n),a=l(m))}function d(a,c){if(!c||r.acceptPosition(a)===b)return!0;for(;a.previousPosition();)if(r.acceptPosition(a)===b [...]
- a.unfilteredDomOffset()))return!0;break}for(;a.nextPosition();)if(r.acceptPosition(a)===b){if(c(1,a.container(),a.unfilteredDomOffset()))return!0;break}return!1}var m=f(),c=new g(m,r,n),e=new core.DomUtils,a=l(f()),b=core.PositionFilter.FilterResult.FILTER_ACCEPT;this.convertStepsToDomPoint=function(d){var e,f;0>d&&(runtime.log("warn","Requested steps were negative ("+d+")"),d=0);h();for(e=c.setToClosestStep(d,a);e<d&&a.nextPosition();)(f=r.acceptPosition(a)===b)&&(e+=1),c.updateCache(e [...]
- a.unfilteredDomOffset(),f);e!==d&&runtime.log("warn","Requested "+d+" steps but only "+e+" are available");return{node:a.container(),offset:a.unfilteredDomOffset()}};this.convertDomPointToSteps=function(f,k,g){var l;h();e.containsNode(m,f)||(k=0>e.comparePoints(m,0,f,k),f=m,k=k?0:m.childNodes.length);a.setUnfilteredPosition(f,k);d(a,g)||a.setUnfilteredPosition(f,k);g=a.container();k=a.unfilteredDomOffset();f=c.setToClosestDomPoint(g,k,a);if(0>e.comparePoints(a.container(),a.unfilteredDo [...]
- g,k))return 0<f?f-1:f;for(;(a.container()!==g||a.unfilteredDomOffset()!==k)&&a.nextPosition();)(l=r.acceptPosition(a)===b)&&(f+=1),c.updateCache(f,a.container(),a.unfilteredDomOffset(),l);return f+0};this.prime=function(){var d,e;h();for(d=c.setToClosestStep(0,a);a.nextPosition();)(e=r.acceptPosition(a)===b)&&(d+=1),c.updateCache(d,a.container(),a.unfilteredDomOffset(),e)};this.handleStepsInserted=function(a){h();c.updateCacheAtPoint(a.position,function(b){b.steps+=a.length})};this.hand [...]
- function(a){h();c.updateCacheAtPoint(a.position,function(b){b.steps-=a.length;0>b.steps&&(b.steps=0)})}};ops.StepsTranslator.PREVIOUS_STEP=0;ops.StepsTranslator.NEXT_STEP=1;return ops.StepsTranslator})();
- // Input 48
- xmldom.RNG={};
- xmldom.RelaxNGParser=function(){function g(c,d){this.message=function(){d&&(c+=1===d.nodeType?" Element ":" Node ",c+=d.nodeName,d.nodeValue&&(c+=" with value '"+d.nodeValue+"'"),c+=".");return c}}function l(c){if(2>=c.e.length)return c;var d={name:c.name,e:c.e.slice(0,2)};return l({name:c.name,e:[d].concat(c.e.slice(2))})}function f(c){c=c.split(":",2);var e="",a;1===c.length?c=["",c[0]]:e=c[0];for(a in d)d[a]===e&&(c[0]=a);return c}function p(c,d){for(var a=0,b,h,k=c.name;c.e&&a<c.e.l [...]
- "ref"===b.name){h=d[b.a.name];if(!h)throw b.a.name+" was not defined.";b=c.e.slice(a+1);c.e=c.e.slice(0,a);c.e=c.e.concat(h.e);c.e=c.e.concat(b)}else a+=1,p(b,d);b=c.e;"choice"!==k||b&&b[1]&&"empty"!==b[1].name||(b&&b[0]&&"empty"!==b[0].name?(b[1]=b[0],b[0]={name:"empty"}):(delete c.e,c.name="empty"));if("group"===k||"interleave"===k)"empty"===b[0].name?"empty"===b[1].name?(delete c.e,c.name="empty"):(k=c.name=b[1].name,c.names=b[1].names,b=c.e=b[1].e):"empty"===b[1].name&&(k=c.name=b[0 [...]
- b[0].names,b=c.e=b[0].e);"oneOrMore"===k&&"empty"===b[0].name&&(delete c.e,c.name="empty");if("attribute"===k){h=c.names?c.names.length:0;for(var g,m=[],l=[],a=0;a<h;a+=1)g=f(c.names[a]),l[a]=g[0],m[a]=g[1];c.localnames=m;c.namespaces=l}"interleave"===k&&("interleave"===b[0].name?c.e="interleave"===b[1].name?b[0].e.concat(b[1].e):[b[1]].concat(b[0].e):"interleave"===b[1].name&&(c.e=[b[0]].concat(b[1].e)))}function r(c,d){for(var a=0,b;c.e&&a<c.e.length;)b=c.e[a],"elementref"===b.name?(b [...]
- 0,c.e[a]=d[b.id]):"element"!==b.name&&r(b,d),a+=1}var n=this,h,d={"http://www.w3.org/XML/1998/namespace":"xml"},m;m=function(c,e,a){var b=[],h,g,n=c.localName,p=[];h=c.attributes;var r=n,x=p,v={},u,s;for(u=0;h&&u<h.length;u+=1)if(s=h.item(u),s.namespaceURI)"http://www.w3.org/2000/xmlns/"===s.namespaceURI&&(d[s.value]=s.localName);else{"name"!==s.localName||"element"!==r&&"attribute"!==r||x.push(s.value);if("name"===s.localName||"combine"===s.localName||"type"===s.localName){var H=s,y;y= [...]
- y.replace(/^\s\s*/,"");for(var B=/\s/,L=y.length-1;B.test(y.charAt(L));)L-=1;y=y.slice(0,L+1);H.value=y}v[s.localName]=s.value}h=v;h.combine=h.combine||void 0;c=c.firstChild;r=b;x=p;for(v="";c;){if(c.nodeType===Node.ELEMENT_NODE&&"http://relaxng.org/ns/structure/1.0"===c.namespaceURI){if(u=m(c,e,r))"name"===u.name?x.push(d[u.a.ns]+":"+u.text):"choice"===u.name&&u.names&&u.names.length&&(x=x.concat(u.names),delete u.names),r.push(u)}else c.nodeType===Node.TEXT_NODE&&(v+=c.nodeValue);c=c. [...]
- v;"value"!==n&&"param"!==n&&(c=/^\s*([\s\S]*\S)?\s*$/.exec(c)[1]);"value"===n&&void 0===h.type&&(h.type="token",h.datatypeLibrary="");"attribute"!==n&&"element"!==n||void 0===h.name||(g=f(h.name),b=[{name:"name",text:g[1],a:{ns:g[0]}}].concat(b),delete h.name);"name"===n||"nsName"===n||"value"===n?void 0===h.ns&&(h.ns=""):delete h.ns;"name"===n&&(g=f(c),h.ns=g[0],c=g[1]);1<b.length&&("define"===n||"oneOrMore"===n||"zeroOrMore"===n||"optional"===n||"list"===n||"mixed"===n)&&(b=[{name:"gr [...]
- e:b}).e}]);2<b.length&&"element"===n&&(b=[b[0]].concat({name:"group",e:l({name:"group",e:b.slice(1)}).e}));1===b.length&&"attribute"===n&&b.push({name:"text",text:c});1!==b.length||"choice"!==n&&"group"!==n&&"interleave"!==n?2<b.length&&("choice"===n||"group"===n||"interleave"===n)&&(b=l({name:n,e:b}).e):(n=b[0].name,p=b[0].names,h=b[0].a,c=b[0].text,b=b[0].e);"mixed"===n&&(n="interleave",b=[b[0],{name:"text"}]);"optional"===n&&(n="choice",b=[b[0],{name:"empty"}]);"zeroOrMore"===n&&(n=" [...]
- [{name:"oneOrMore",e:[b[0]]},{name:"empty"}]);if("define"===n&&h.combine){a:{r=h.combine;x=h.name;v=b;for(u=0;a&&u<a.length;u+=1)if(s=a[u],"define"===s.name&&s.a&&s.a.name===x){s.e=[{name:r,e:s.e.concat(v)}];a=s;break a}a=null}if(a)return null}a={name:n};b&&0<b.length&&(a.e=b);for(g in h)if(h.hasOwnProperty(g)){a.a=h;break}void 0!==c&&(a.text=c);p&&0<p.length&&(a.names=p);"element"===n&&(a.id=e.length,e.push(a),a={name:"elementref",id:a.id});return a};this.parseRelaxNGDOM=function(c,e){ [...]
- m(c&&c.documentElement,a,void 0),f,k,l={};for(f=0;f<b.e.length;f+=1)k=b.e[f],"define"===k.name?l[k.a.name]=k:"start"===k.name&&(h=k);if(!h)return[new g("No Relax NG start element was found.")];p(h,l);for(f in l)l.hasOwnProperty(f)&&p(l[f],l);for(f=0;f<a.length;f+=1)p(a[f],l);e&&(n.rootPattern=e(h.e[0],a));r(h,a);for(f=0;f<a.length;f+=1)r(a[f],a);n.start=h;n.elements=a;n.nsmap=d;return null}};
++ops.OpAddStyle=function(){var m,h,b,g,d,n,p=odf.Namespaces.stylens;this.init=function(k){m=k.memberid;h=k.timestamp;b=k.styleName;g=k.styleFamily;d="true"===k.isAutomaticStyle||!0===k.isAutomaticStyle;n=k.setProperties};this.isEdit=!0;this.group=void 0;this.execute=function(k){var h=k.getOdfCanvas().odfContainer(),e=k.getFormatting(),m=k.getDOMDocument().createElementNS(p,"style:style");if(!m)return!1;n&&e.updateStyle(m,n);m.setAttributeNS(p,"style:family",g);m.setAttributeNS(p,"style:n [...]
++h.rootElement.automaticStyles.appendChild(m):h.rootElement.styles.appendChild(m);k.getOdfCanvas().refreshCSS();d||k.emit(ops.OdtDocument.signalCommonStyleCreated,{name:b,family:g});return!0};this.spec=function(){return{optype:"AddStyle",memberid:m,timestamp:h,styleName:b,styleFamily:g,isAutomaticStyle:d,setProperties:n}}};
 +// Input 49
- runtime.loadClass("core.Cursor");runtime.loadClass("gui.SelectionMover");
- ops.OdtCursor=function(g,l){var f=this,p={},r,n,h;this.removeFromOdtDocument=function(){h.remove()};this.move=function(d,h){var c=0;0<d?c=n.movePointForward(d,h):0>=d&&(c=-n.movePointBackward(-d,h));f.handleUpdate();return c};this.handleUpdate=function(){};this.getStepCounter=function(){return n.getStepCounter()};this.getMemberId=function(){return g};this.getNode=function(){return h.getNode()};this.getAnchorNode=function(){return h.getAnchorNode()};this.getSelectedRange=function(){retur [...]
- this.setSelectedRange=function(d,g){h.setSelectedRange(d,g);f.handleUpdate()};this.hasForwardSelection=function(){return h.hasForwardSelection()};this.getOdtDocument=function(){return l};this.getSelectionType=function(){return r};this.setSelectionType=function(d){p.hasOwnProperty(d)?r=d:runtime.log("Invalid selection type: "+d)};this.resetSelectionType=function(){f.setSelectionType(ops.OdtCursor.RangeSelection)};h=new core.Cursor(l.getDOM(),g);n=new gui.SelectionMover(h,l.getRootNode()) [...]
- !0;p[ops.OdtCursor.RegionSelection]=!0;f.resetSelectionType()};ops.OdtCursor.RangeSelection="Range";ops.OdtCursor.RegionSelection="Region";(function(){return ops.OdtCursor})();
- // Input 50
 +/*
 +
 + Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("core.EventNotifier");runtime.loadClass("core.DomUtils");runtime.loadClass("odf.OdfUtils");runtime.loadClass("odf.Namespaces");runtime.loadClass("gui.SelectionMover");runtime.loadClass("core.PositionFilterChain");runtime.loadClass("ops.StepsTranslator");runtime.loadClass("ops.TextPositionFilter");runtime.loadClass("ops.Member");
- ops.OdtDocument=function(g){function l(){var a=g.odfContainer().getContentElement(),b=a&&a.localName;runtime.assert("text"===b,"Unsupported content element type '"+b+"' for OdtDocument");return a}function f(){return l().ownerDocument}function p(a){for(;a&&!(a.namespaceURI===odf.Namespaces.officens&&"text"===a.localName||a.namespaceURI===odf.Namespaces.officens&&"annotation"===a.localName);)a=a.parentNode;return a}function r(b){this.acceptPosition=function(c){c=c.container();var d;d="str [...]
- a[b].getNode():b;return p(c)===p(d)?k:t}}function n(a){var b=gui.SelectionMover.createPositionIterator(l());a=w.convertStepsToDomPoint(a);b.setUnfilteredPosition(a.node,a.offset);return b}function h(a,b){return g.getFormatting().getStyleElement(a,b)}function d(a){return h(a,"paragraph")}var m=this,c,e,a={},b={},q=new core.EventNotifier([ops.OdtDocument.signalMemberAdded,ops.OdtDocument.signalMemberUpdated,ops.OdtDocument.signalMemberRemoved,ops.OdtDocument.signalCursorAdded,ops.OdtDocum [...]
- ops.OdtDocument.signalCursorMoved,ops.OdtDocument.signalParagraphChanged,ops.OdtDocument.signalParagraphStyleModified,ops.OdtDocument.signalCommonStyleCreated,ops.OdtDocument.signalCommonStyleDeleted,ops.OdtDocument.signalTableAdded,ops.OdtDocument.signalOperationExecuted,ops.OdtDocument.signalUndoStackChanged,ops.OdtDocument.signalStepsInserted,ops.OdtDocument.signalStepsRemoved]),k=core.PositionFilter.FilterResult.FILTER_ACCEPT,t=core.PositionFilter.FilterResult.FILTER_REJECT,A,w,x;th [...]
- f;this.getRootElement=p;this.getIteratorAtPosition=n;this.convertDomPointToCursorStep=function(a,b,c){return w.convertDomPointToSteps(a,b,c)};this.convertDomToCursorRange=function(a,b){var c,d;c=b(a.anchorNode,a.anchorOffset);c=w.convertDomPointToSteps(a.anchorNode,a.anchorOffset,c);b||a.anchorNode!==a.focusNode||a.anchorOffset!==a.focusOffset?(d=b(a.focusNode,a.focusOffset),d=w.convertDomPointToSteps(a.focusNode,a.focusOffset,d)):d=c;return{position:c,length:d-c}};this.convertCursorToD [...]
- b){var c=f().createRange(),d,e;d=w.convertStepsToDomPoint(a);b?(e=w.convertStepsToDomPoint(a+b),0<b?(c.setStart(d.node,d.offset),c.setEnd(e.node,e.offset)):(c.setStart(e.node,e.offset),c.setEnd(d.node,d.offset))):c.setStart(d.node,d.offset);return c};this.getStyleElement=h;this.upgradeWhitespacesAtPosition=function(a){a=n(a);var b,d,e;a.previousPosition();a.previousPosition();for(e=-1;1>=e;e+=1){b=a.container();d=a.unfilteredDomOffset();if(b.nodeType===Node.TEXT_NODE&&" "===b.data[d]&&c [...]
- d)){runtime.assert(" "===b.data[d],"upgradeWhitespaceToElement: textNode.data[offset] should be a literal space");var f=b.ownerDocument.createElementNS(odf.Namespaces.textns,"text:s");f.appendChild(b.ownerDocument.createTextNode(" "));b.deleteData(d,1);0<d&&(b=b.splitText(d));b.parentNode.insertBefore(f,b);b=f;a.moveToEndOfNode(b)}a.nextPosition()}};this.downgradeWhitespacesAtPosition=function(a){var b=n(a),d;a=b.container();for(b=b.unfilteredDomOffset();!c.isSpaceElement(a)&&a.childNod [...]
- b=0;a.nodeType===Node.TEXT_NODE&&(a=a.parentNode);c.isDowngradableSpaceElement(a)&&(b=a.firstChild,d=a.lastChild,e.mergeIntoParent(a),d!==b&&e.normalizeTextNodes(d),e.normalizeTextNodes(b))};this.getParagraphStyleElement=d;this.getParagraphElement=function(a){return c.getParagraphElement(a)};this.getParagraphStyleAttributes=function(a){return(a=d(a))?g.getFormatting().getInheritedStyleAttributes(a):null};this.getTextNodeAtStep=function(b,c){var d=n(b),e=d.container(),h,g=0,k=null;e.node [...]
- (h=e,g=d.unfilteredDomOffset(),0<h.length&&(0<g&&(h=h.splitText(g)),h.parentNode.insertBefore(f().createTextNode(""),h),h=h.previousSibling,g=0)):(h=f().createTextNode(""),g=0,e.insertBefore(h,d.rightNode()));if(c){if(a[c]&&m.getCursorPosition(c)===b){for(k=a[c].getNode();k.nextSibling&&"cursor"===k.nextSibling.localName;)k.parentNode.insertBefore(k.nextSibling,k);0<h.length&&h.nextSibling!==k&&(h=f().createTextNode(""),g=0);k.parentNode.insertBefore(h,k)}}else for(;h.nextSibling&&"curs [...]
- h);for(;h.previousSibling&&h.previousSibling.nodeType===Node.TEXT_NODE;)h.previousSibling.appendData(h.data),g=h.previousSibling.length,h=h.previousSibling,h.parentNode.removeChild(h.nextSibling);for(;h.nextSibling&&h.nextSibling.nodeType===Node.TEXT_NODE;)h.appendData(h.nextSibling.data),h.parentNode.removeChild(h.nextSibling);return{textNode:h,offset:g}};this.fixCursorPositions=function(){var b=new core.PositionFilterChain;b.addFilter("BaseFilter",A);Object.keys(a).forEach(function(c) [...]
- e=d.getStepCounter(),f,h,g=!1;b.addFilter("RootFilter",m.createRootFilter(c));c=e.countStepsToPosition(d.getAnchorNode(),0,b);e.isPositionWalkable(b)?0===c&&(g=!0,d.move(0)):(g=!0,f=e.countPositionsToNearestStep(d.getNode(),0,b),h=e.countPositionsToNearestStep(d.getAnchorNode(),0,b),d.move(f),0!==c&&(0<h&&(c+=1),0<f&&(c-=1),e=e.countSteps(c,b),d.move(e),d.move(-e,!0)));g&&m.emit(ops.OdtDocument.signalCursorMoved,d);b.removeFilter("RootFilter")})};this.getDistanceFromCursor=function(b,c, [...]
- var e,f;runtime.assert(null!==c&&void 0!==c,"OdtDocument.getDistanceFromCursor called without node");b&&(e=w.convertDomPointToSteps(b.getNode(),0),f=w.convertDomPointToSteps(c,d));return f-e};this.getCursorPosition=function(b){return(b=a[b])?w.convertDomPointToSteps(b.getNode(),0):0};this.getCursorSelection=function(b){b=a[b];var c=0,d=0;b&&(c=w.convertDomPointToSteps(b.getNode(),0),d=w.convertDomPointToSteps(b.getAnchorNode(),0));return{position:d,length:c-d}};this.getPositionFilter=fu [...]
- this.getOdfCanvas=function(){return g};this.getRootNode=l;this.addMember=function(a){runtime.assert(void 0===b[a.getMemberId()],"This member already exists");b[a.getMemberId()]=a};this.getMember=function(a){return b.hasOwnProperty(a)?b[a]:null};this.removeMember=function(a){delete b[a]};this.getCursor=function(b){return a[b]};this.getCursors=function(){var b=[],c;for(c in a)a.hasOwnProperty(c)&&b.push(a[c]);return b};this.addCursor=function(b){runtime.assert(Boolean(b),"OdtDocument::add [...]
- var c=b.getStepCounter().countSteps(1,A),d=b.getMemberId();runtime.assert("string"===typeof d,"OdtDocument::addCursor has cursor without memberid");runtime.assert(!a[d],"OdtDocument::addCursor is adding a duplicate cursor with memberid "+d);b.move(c);a[d]=b};this.removeCursor=function(b){var c=a[b];return c?(c.removeFromOdtDocument(),delete a[b],m.emit(ops.OdtDocument.signalCursorRemoved,b),!0):!1};this.moveCursor=function(b,c,d,e){b=a[b];c=m.convertCursorToDomRange(c,d);b&&c&&(b.setSel [...]
- 0<=d),b.setSelectionType(e||ops.OdtCursor.RangeSelection))};this.getFormatting=function(){return g.getFormatting()};this.emit=function(a,b){q.emit(a,b)};this.subscribe=function(a,b){q.subscribe(a,b)};this.unsubscribe=function(a,b){q.unsubscribe(a,b)};this.createRootFilter=function(a){return new r(a)};this.close=function(a){a()};this.destroy=function(a){a()};A=new ops.TextPositionFilter(l);c=new odf.OdfUtils;e=new core.DomUtils;w=new ops.StepsTranslator(l,gui.SelectionMover.createPositio [...]
- A,500);q.subscribe(ops.OdtDocument.signalStepsInserted,w.handleStepsInserted);q.subscribe(ops.OdtDocument.signalStepsRemoved,w.handleStepsRemoved);q.subscribe(ops.OdtDocument.signalOperationExecuted,function(a){var b=a.spec(),c=b.memberid,b=(new Date(b.timestamp)).toISOString(),d=g.odfContainer();a.isEdit&&(c=m.getMember(c).getProperties().fullName,d.setMetadata({"dc:creator":c,"dc:date":b},null),x||(d.incrementEditingCycles(),d.setMetadata(null,["meta:editing-duration","meta:document-s [...]
- x=a)})};ops.OdtDocument.signalMemberAdded="member/added";ops.OdtDocument.signalMemberUpdated="member/updated";ops.OdtDocument.signalMemberRemoved="member/removed";ops.OdtDocument.signalCursorAdded="cursor/added";ops.OdtDocument.signalCursorRemoved="cursor/removed";ops.OdtDocument.signalCursorMoved="cursor/moved";ops.OdtDocument.signalParagraphChanged="paragraph/changed";ops.OdtDocument.signalTableAdded="table/added";ops.OdtDocument.signalCommonStyleCreated="style/created";
- ops.OdtDocument.signalCommonStyleDeleted="style/deleted";ops.OdtDocument.signalParagraphStyleModified="paragraphstyle/modified";ops.OdtDocument.signalOperationExecuted="operation/executed";ops.OdtDocument.signalUndoStackChanged="undo/changed";ops.OdtDocument.signalStepsInserted="steps/inserted";ops.OdtDocument.signalStepsRemoved="steps/removed";(function(){return ops.OdtDocument})();
- // Input 51
++odf.ObjectNameGenerator=function(m,h){function b(a,b){var c={};this.generateName=function(){var d=b(),e=0,g;do g=a+e,e+=1;while(c[g]||d[g]);c[g]=!0;return g}}function g(){var a={};[m.rootElement.automaticStyles,m.rootElement.styles].forEach(function(b){for(b=b.firstElementChild;b;)b.namespaceURI===d&&"style"===b.localName&&(a[b.getAttributeNS(d,"name")]=!0),b=b.nextElementSibling});return a}var d=odf.Namespaces.stylens,n=odf.Namespaces.drawns,p=odf.Namespaces.xlinkns,k=new core.DomUtils [...]
++e=null,r=null,a=null,c={},l={};this.generateStyleName=function(){null===e&&(e=new b("auto"+q+"_",function(){return g()}));return e.generateName()};this.generateFrameName=function(){null===r&&(k.getElementsByTagNameNS(m.rootElement.body,n,"frame").forEach(function(a){c[a.getAttributeNS(n,"name")]=!0}),r=new b("fr"+q+"_",function(){return c}));return r.generateName()};this.generateImageName=function(){null===a&&(k.getElementsByTagNameNS(m.rootElement.body,n,"image").forEach(function(a){a= [...]
++"href");a=a.substring(9,a.lastIndexOf("."));l[a]=!0}),a=new b("img"+q+"_",function(){return l}));return a.generateName()}};
++// Input 50
 +/*
 +
 + Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- ops.Operation=function(){};ops.Operation.prototype.init=function(g){};ops.Operation.prototype.execute=function(g){};ops.Operation.prototype.spec=function(){};
- // Input 52
- runtime.loadClass("xmldom.RelaxNGParser");
- xmldom.RelaxNG=function(){function g(a){return function(){var b;return function(){void 0===b&&(b=a());return b}}()}function l(a,b){return function(){var c={},d=0;return function(e){var f=e.hash||e.toString();if(c.hasOwnProperty(f))return c[f];c[f]=e=b(e);e.hash=a+d.toString();d+=1;return e}}()}function f(a){return function(){var b={};return function(c){var d,e;if(b.hasOwnProperty(c.localName)){if(e=b[c.localName],d=e[c.namespaceURI],void 0!==d)return d}else b[c.localName]=e={};return e[ [...]
- d=a(c)}}()}function p(a,b,c){return function(){var d={},e=0;return function(f,h){var g=b&&b(f,h),k;if(void 0!==g)return g;k=f.hash||f.toString();g=h.hash||h.toString();if(d.hasOwnProperty(k)){if(k=d[k],k.hasOwnProperty(g))return k[g]}else d[k]=k={};k[g]=g=c(f,h);g.hash=a+e.toString();e+=1;return g}}()}function r(a,b){"choice"===b.p1.type?r(a,b.p1):a[b.p1.hash]=b.p1;"choice"===b.p2.type?r(a,b.p2):a[b.p2.hash]=b.p2}function n(a,b){return{type:"element",nc:a,nullable:!1,textDeriv:function( [...]
- startTagOpenDeriv:function(c){return a.contains(c)?q(b,B):y},attDeriv:function(){return y},startTagCloseDeriv:function(){return this}}}function h(){return{type:"list",nullable:!1,hash:"list",textDeriv:function(){return B}}}function d(a,b,e,f){if(b===y)return y;if(f>=e.length)return b;0===f&&(f=0);for(var h=e.item(f);h.namespaceURI===c;){f+=1;if(f>=e.length)return b;h=e.item(f)}return h=d(a,b.attDeriv(a,e.item(f)),e,f+1)}function m(a,b,c){c.e[0].a?(a.push(c.e[0].text),b.push(c.e[0].a.ns) [...]
- c.e[1].a?(a.push(c.e[1].text),b.push(c.e[1].a.ns)):m(a,b,c.e[1])}var c="http://www.w3.org/2000/xmlns/",e,a,b,q,k,t,A,w,x,v,u,s,H,y={type:"notAllowed",nullable:!1,hash:"notAllowed",nc:void 0,p:void 0,p1:void 0,p2:void 0,textDeriv:function(){return y},startTagOpenDeriv:function(){return y},attDeriv:function(){return y},startTagCloseDeriv:function(){return y},endTagDeriv:function(){return y}},B={type:"empty",nullable:!0,hash:"empty",nc:void 0,p:void 0,p1:void 0,p2:void 0,textDeriv:function [...]
- startTagOpenDeriv:function(){return y},attDeriv:function(){return y},startTagCloseDeriv:function(){return B},endTagDeriv:function(){return y}},L={type:"text",nullable:!0,hash:"text",nc:void 0,p:void 0,p1:void 0,p2:void 0,textDeriv:function(){return L},startTagOpenDeriv:function(){return y},attDeriv:function(){return y},startTagCloseDeriv:function(){return L},endTagDeriv:function(){return y}};e=p("choice",function(a,b){if(a===y)return b;if(b===y||a===b)return a},function(a,b){var c={},d; [...]
- p2:b});b=a=void 0;for(d in c)c.hasOwnProperty(d)&&(void 0===a?a=c[d]:b=void 0===b?c[d]:e(b,c[d]));return function(a,b){return{type:"choice",nullable:a.nullable||b.nullable,hash:void 0,nc:void 0,p:void 0,p1:a,p2:b,textDeriv:function(c,d){return e(a.textDeriv(c,d),b.textDeriv(c,d))},startTagOpenDeriv:f(function(c){return e(a.startTagOpenDeriv(c),b.startTagOpenDeriv(c))}),attDeriv:function(c,d){return e(a.attDeriv(c,d),b.attDeriv(c,d))},startTagCloseDeriv:g(function(){return e(a.startTagCl [...]
- b.startTagCloseDeriv())}),endTagDeriv:g(function(){return e(a.endTagDeriv(),b.endTagDeriv())})}}(a,b)});a=function(a,b,c){return function(){var d={},e=0;return function(f,h){var g=b&&b(f,h),k,m;if(void 0!==g)return g;k=f.hash||f.toString();g=h.hash||h.toString();k<g&&(m=k,k=g,g=m,m=f,f=h,h=m);if(d.hasOwnProperty(k)){if(k=d[k],k.hasOwnProperty(g))return k[g]}else d[k]=k={};k[g]=g=c(f,h);g.hash=a+e.toString();e+=1;return g}}()}("interleave",function(a,b){if(a===y||b===y)return y;if(a===B) [...]
- B)return a},function(b,c){return{type:"interleave",nullable:b.nullable&&c.nullable,hash:void 0,p1:b,p2:c,textDeriv:function(d,f){return e(a(b.textDeriv(d,f),c),a(b,c.textDeriv(d,f)))},startTagOpenDeriv:f(function(d){return e(u(function(b){return a(b,c)},b.startTagOpenDeriv(d)),u(function(c){return a(b,c)},c.startTagOpenDeriv(d)))}),attDeriv:function(d,f){return e(a(b.attDeriv(d,f),c),a(b,c.attDeriv(d,f)))},startTagCloseDeriv:g(function(){return a(b.startTagCloseDeriv(),c.startTagCloseDe [...]
- b=p("group",function(a,b){if(a===y||b===y)return y;if(a===B)return b;if(b===B)return a},function(a,c){return{type:"group",p1:a,p2:c,nullable:a.nullable&&c.nullable,textDeriv:function(d,f){var h=b(a.textDeriv(d,f),c);return a.nullable?e(h,c.textDeriv(d,f)):h},startTagOpenDeriv:function(d){var f=u(function(a){return b(a,c)},a.startTagOpenDeriv(d));return a.nullable?e(f,c.startTagOpenDeriv(d)):f},attDeriv:function(d,f){return e(b(a.attDeriv(d,f),c),b(a,c.attDeriv(d,f)))},startTagCloseDeriv [...]
- c.startTagCloseDeriv())})}});q=p("after",function(a,b){if(a===y||b===y)return y},function(a,b){return{type:"after",p1:a,p2:b,nullable:!1,textDeriv:function(c,d){return q(a.textDeriv(c,d),b)},startTagOpenDeriv:f(function(c){return u(function(a){return q(a,b)},a.startTagOpenDeriv(c))}),attDeriv:function(c,d){return q(a.attDeriv(c,d),b)},startTagCloseDeriv:g(function(){return q(a.startTagCloseDeriv(),b)}),endTagDeriv:g(function(){return a.nullable?b:y})}});k=l("oneormore",function(a){retur [...]
- {type:"oneOrMore",p:a,nullable:a.nullable,textDeriv:function(c,d){return b(a.textDeriv(c,d),e(this,B))},startTagOpenDeriv:function(c){var d=this;return u(function(a){return b(a,e(d,B))},a.startTagOpenDeriv(c))},attDeriv:function(c,d){return b(a.attDeriv(c,d),e(this,B))},startTagCloseDeriv:g(function(){return k(a.startTagCloseDeriv())})}});A=p("attribute",void 0,function(a,b){return{type:"attribute",nullable:!1,hash:void 0,nc:a,p:b,p1:void 0,p2:void 0,textDeriv:void 0,startTagOpenDeriv:v [...]
- d){return a.contains(d)&&(b.nullable&&/^\s+$/.test(d.nodeValue)||b.textDeriv(c,d.nodeValue).nullable)?B:y},startTagCloseDeriv:function(){return y},endTagDeriv:void 0}});t=l("value",function(a){return{type:"value",nullable:!1,value:a,textDeriv:function(b,c){return c===a?B:y},attDeriv:function(){return y},startTagCloseDeriv:function(){return this}}});x=l("data",function(a){return{type:"data",nullable:!1,dataType:a,textDeriv:function(){return B},attDeriv:function(){return y},startTagCloseD [...]
- u=function W(a,b){return"after"===b.type?q(b.p1,a(b.p2)):"choice"===b.type?e(W(a,b.p1),W(a,b.p2)):b};s=function(a,b,c){var f=c.currentNode;b=b.startTagOpenDeriv(f);b=d(a,b,f.attributes,0);var h=b=b.startTagCloseDeriv(),f=c.currentNode;b=c.firstChild();for(var g=[],k;b;)b.nodeType===Node.ELEMENT_NODE?g.push(b):b.nodeType!==Node.TEXT_NODE||/^\s*$/.test(b.nodeValue)||g.push(b.nodeValue),b=c.nextSibling();0===g.length&&(g=[""]);k=h;for(h=0;k!==y&&h<g.length;h+=1)b=g[h],"string"===typeof b?k [...]
- e(k,k.textDeriv(a,b)):k.textDeriv(a,b):(c.currentNode=b,k=s(a,k,c));c.currentNode=f;return b=k.endTagDeriv()};w=function(a){var b,c,d;if("name"===a.name)b=a.text,c=a.a.ns,a={name:b,ns:c,hash:"{"+c+"}"+b,contains:function(a){return a.namespaceURI===c&&a.localName===b}};else if("choice"===a.name){b=[];c=[];m(b,c,a);a="";for(d=0;d<b.length;d+=1)a+="{"+c[d]+"}"+b[d]+",";a={hash:a,contains:function(a){var d;for(d=0;d<b.length;d+=1)if(b[d]===a.localName&&c[d]===a.namespaceURI)return!0;return! [...]
- {hash:"anyName",contains:function(){return!0}};return a};v=function Q(c,d){var f,g;if("elementref"===c.name){f=c.id||0;c=d[f];if(void 0!==c.name){var m=c;f=d[m.id]={hash:"element"+m.id.toString()};m=n(w(m.e[0]),v(m.e[1],d));for(g in m)m.hasOwnProperty(g)&&(f[g]=m[g]);return f}return c}switch(c.name){case "empty":return B;case "notAllowed":return y;case "text":return L;case "choice":return e(Q(c.e[0],d),Q(c.e[1],d));case "interleave":f=Q(c.e[0],d);for(g=1;g<c.e.length;g+=1)f=a(f,Q(c.e[g] [...]
- case "group":return b(Q(c.e[0],d),Q(c.e[1],d));case "oneOrMore":return k(Q(c.e[0],d));case "attribute":return A(w(c.e[0]),Q(c.e[1],d));case "value":return t(c.text);case "data":return f=c.a&&c.a.type,void 0===f&&(f=""),x(f);case "list":return h()}throw"No support for "+c.name;};this.makePattern=function(a,b){var c={},d;for(d in b)b.hasOwnProperty(d)&&(c[d]=b[d]);return d=v(a,c)};this.validate=function(a,b){var c;a.currentNode=a.root;c=s(null,H,a);c.nullable?b(null):(runtime.log("Error i [...]
- c),b(["Error in Relax NG validation: "+c]))};this.init=function(a){H=a}};
- // Input 53
- runtime.loadClass("xmldom.RelaxNGParser");
- xmldom.RelaxNG2=function(){function g(f,d){this.message=function(){d&&(f+=d.nodeType===Node.ELEMENT_NODE?" Element ":" Node ",f+=d.nodeName,d.nodeValue&&(f+=" with value '"+d.nodeValue+"'"),f+=".");return f}}function l(f,d,g,c){return"empty"===f.name?null:r(f,d,g,c)}function f(f,d){if(2!==f.e.length)throw"Element with wrong # of elements: "+f.e.length;for(var m=d.currentNode,c=m?m.nodeType:0,e=null;c>Node.ELEMENT_NODE;){if(c!==Node.COMMENT_NODE&&(c!==Node.TEXT_NODE||!/^\s+$/.test(d.curr [...]
- c+".")];c=(m=d.nextSibling())?m.nodeType:0}if(!m)return[new g("Missing element "+f.names)];if(f.names&&-1===f.names.indexOf(n[m.namespaceURI]+":"+m.localName))return[new g("Found "+m.nodeName+" instead of "+f.names+".",m)];if(d.firstChild()){for(e=l(f.e[1],d,m);d.nextSibling();)if(c=d.currentNode.nodeType,!(d.currentNode&&d.currentNode.nodeType===Node.TEXT_NODE&&/^\s+$/.test(d.currentNode.nodeValue)||c===Node.COMMENT_NODE))return[new g("Spurious content.",d.currentNode)];if(d.parentNode [...]
- l(f.e[1],d,m);d.nextSibling();return e}var p,r,n;r=function(h,d,m,c){var e=h.name,a=null;if("text"===e)a:{for(var b=(h=d.currentNode)?h.nodeType:0;h!==m&&3!==b;){if(1===b){a=[new g("Element not allowed here.",h)];break a}b=(h=d.nextSibling())?h.nodeType:0}d.nextSibling();a=null}else if("data"===e)a=null;else if("value"===e)c!==h.text&&(a=[new g("Wrong value, should be '"+h.text+"', not '"+c+"'",m)]);else if("list"===e)a=null;else if("attribute"===e)a:{if(2!==h.e.length)throw"Attribute w [...]
- h.e.length;e=h.localnames.length;for(a=0;a<e;a+=1){c=m.getAttributeNS(h.namespaces[a],h.localnames[a]);""!==c||m.hasAttributeNS(h.namespaces[a],h.localnames[a])||(c=void 0);if(void 0!==b&&void 0!==c){a=[new g("Attribute defined too often.",m)];break a}b=c}a=void 0===b?[new g("Attribute not found: "+h.names,m)]:l(h.e[1],d,m,b)}else if("element"===e)a=f(h,d);else if("oneOrMore"===e){c=0;do b=d.currentNode,e=r(h.e[0],d,m),c+=1;while(!e&&b!==d.currentNode);1<c?(d.currentNode=b,a=null):a=e}e [...]
- e){if(2!==h.e.length)throw"Choice with wrong # of options: "+h.e.length;b=d.currentNode;if("empty"===h.e[0].name){if(e=r(h.e[1],d,m,c))d.currentNode=b;a=null}else{if(e=l(h.e[0],d,m,c))d.currentNode=b,e=r(h.e[1],d,m,c);a=e}}else if("group"===e){if(2!==h.e.length)throw"Group with wrong # of members: "+h.e.length;a=r(h.e[0],d,m)||r(h.e[1],d,m)}else if("interleave"===e)a:{b=h.e.length;c=[b];for(var q=b,k,n,p,w;0<q;){k=0;n=d.currentNode;for(a=0;a<b;a+=1)p=d.currentNode,!0!==c[a]&&c[a]!==p&&( [...]
- r(w,d,m))?(d.currentNode=p,void 0===c[a]&&(c[a]=!1)):p===d.currentNode||"oneOrMore"===w.name||"choice"===w.name&&("oneOrMore"===w.e[0].name||"oneOrMore"===w.e[1].name)?(k+=1,c[a]=p):(k+=1,c[a]=!0));if(n===d.currentNode&&k===q){a=null;break a}if(0===k){for(a=0;a<b;a+=1)if(!1===c[a]){a=[new g("Interleave does not match.",m)];break a}a=null;break a}for(a=q=0;a<b;a+=1)!0!==c[a]&&(q+=1)}a=null}else throw e+" not allowed in nonEmptyPattern.";return a};this.validate=function(f,d){f.currentNode [...]
- l(p.e[0],f,f.root);d(g)};this.init=function(f,d){p=f;n=d}};
- // Input 54
- runtime.loadClass("core.DomUtils");runtime.loadClass("gui.Avatar");runtime.loadClass("ops.OdtCursor");
- gui.Caret=function(g,l,f){function p(c){e&&m.parentNode&&(!a||c)&&(c&&void 0!==b&&runtime.clearTimeout(b),a=!0,h.style.opacity=c||"0"===h.style.opacity?"1":"0",b=runtime.setTimeout(function(){a=!1;p(!1)},500))}function r(a,b){var c=a.getBoundingClientRect(),d=0,e=0;c&&b&&(d=Math.max(c.top,b.top),e=Math.min(c.bottom,b.bottom));return e-d}function n(){var a;a=g.getSelectedRange().cloneRange();var b=g.getNode(),d,e=null;b.previousSibling&&(d=b.previousSibling.nodeType===Node.TEXT_NODE?b.pr [...]
- b.previousSibling.childNodes.length,a.setStart(b.previousSibling,0<d?d-1:0),a.setEnd(b.previousSibling,d),(d=a.getBoundingClientRect())&&d.height&&(e=d));b.nextSibling&&(a.setStart(b.nextSibling,0),a.setEnd(b.nextSibling,0<(b.nextSibling.nodeType===Node.TEXT_NODE?b.nextSibling.textContent.length:b.nextSibling.childNodes.length)?1:0),(d=a.getBoundingClientRect())&&d.height&&(!e||r(b,d)>r(b,e))&&(e=d));a=e;b=g.getOdtDocument().getOdfCanvas().getZoomLevel();c&&g.getSelectionType()===ops.Od [...]
- h.style.visibility="visible":h.style.visibility="hidden";a?(h.style.top="0",e=q.getBoundingClientRect(h),8>a.height&&(a={top:a.top-(8-a.height)/2,height:8}),h.style.height=q.adaptRangeDifferenceToZoomLevel(a.height,b)+"px",h.style.top=q.adaptRangeDifferenceToZoomLevel(a.top-e.top,b)+"px"):(h.style.height="1em",h.style.top="5%")}var h,d,m,c=!0,e=!1,a=!1,b,q=new core.DomUtils;this.handleUpdate=n;this.refreshCursorBlinking=function(){f||g.getSelectedRange().collapsed?(e=!0,p(!0)):(e=!1,h.s [...]
- "0")};this.setFocus=function(){e=!0;d.markAsFocussed(!0);p(!0)};this.removeFocus=function(){e=!1;d.markAsFocussed(!1);h.style.opacity="1"};this.show=function(){c=!0;n();d.markAsFocussed(!0)};this.hide=function(){c=!1;n();d.markAsFocussed(!1)};this.setAvatarImageUrl=function(a){d.setImageUrl(a)};this.setColor=function(a){h.style.borderColor=a;d.setColor(a)};this.getCursor=function(){return g};this.getFocusElement=function(){return h};this.toggleHandleVisibility=function(){d.isVisible()?d [...]
- this.showHandle=function(){d.show()};this.hideHandle=function(){d.hide()};this.ensureVisible=function(){var a,b,c,d,e=g.getOdtDocument().getOdfCanvas().getElement().parentNode,f;c=e.offsetWidth-e.clientWidth+5;d=e.offsetHeight-e.clientHeight+5;f=h.getBoundingClientRect();a=f.left-c;b=f.top-d;c=f.right+c;d=f.bottom+d;f=e.getBoundingClientRect();b<f.top?e.scrollTop-=f.top-b:d>f.bottom&&(e.scrollTop+=d-f.bottom);a<f.left?e.scrollLeft-=f.left-a:c>f.right&&(e.scrollLeft+=c-f.right);n()};this [...]
- a(b):(m.removeChild(h),a())})};(function(){var a=g.getOdtDocument().getDOM();h=a.createElementNS(a.documentElement.namespaceURI,"span");h.style.top="5%";m=g.getNode();m.appendChild(h);d=new gui.Avatar(m,l);n()})()};
- // Input 55
- gui.EventManager=function(g){function l(){return g.getOdfCanvas().getElement()}function f(){var c=this,a=[];this.handlers=[];this.isSubscribed=!1;this.handleEvent=function(b){-1===a.indexOf(b)&&(a.push(b),c.handlers.forEach(function(a){a(b)}),runtime.setTimeout(function(){a.splice(a.indexOf(b),1)},0))}}function p(c){var a=c.scrollX,b=c.scrollY;this.restore=function(){c.scrollX===a&&c.scrollY===b||c.scrollTo(a,b)}}function r(c){var a=c.scrollTop,b=c.scrollLeft;this.restore=function(){if( [...]
- a||c.scrollLeft!==b)c.scrollTop=a,c.scrollLeft=b}}function n(c,a,b){var f="on"+a,h=!1;c.attachEvent&&(h=c.attachEvent(f,b));!h&&c.addEventListener&&(c.addEventListener(a,b,!1),h=!0);h&&!d[a]||!c.hasOwnProperty(f)||(c[f]=b)}var h=runtime.getWindow(),d={beforecut:!0,beforepaste:!0},m,c;this.subscribe=function(d,a){var b=m[d],f=l();b?(b.handlers.push(a),b.isSubscribed||(b.isSubscribed=!0,n(h,d,b.handleEvent),n(f,d,b.handleEvent),n(c,d,b.handleEvent))):n(f,d,a)};this.unsubscribe=function(c, [...]
- d=b&&b.handlers.indexOf(a),f=l();b?-1!==d&&b.handlers.splice(d,1):(b="on"+c,f.detachEvent&&f.detachEvent(b,a),f.removeEventListener&&f.removeEventListener(c,a,!1),f[b]===a&&(f[b]=null))};this.focus=function(){var d,a=l(),b=h.getSelection();if(g.getDOM().activeElement!==l()){for(d=a;d&&!d.scrollTop&&!d.scrollLeft;)d=d.parentNode;d=d?new r(d):new p(h);a.focus();d&&d.restore()}b&&b.extend&&(c.parentNode!==a&&a.appendChild(c),b.collapse(c.firstChild,0),b.extend(c,c.childNodes.length))};(fun [...]
- l(),a=d.ownerDocument;runtime.assert(Boolean(h),"EventManager requires a window object to operate correctly");m={mousedown:new f,mouseup:new f,focus:new f};c=a.createElement("div");c.id="eventTrap";c.setAttribute("contenteditable","true");c.style.position="absolute";c.style.left="-10000px";c.appendChild(a.createTextNode("dummy content"));d.appendChild(c)})()};
- // Input 56
- runtime.loadClass("gui.SelectionMover");gui.ShadowCursor=function(g){var l=g.getDOM().createRange(),f=!0;this.removeFromOdtDocument=function(){};this.getMemberId=function(){return gui.ShadowCursor.ShadowCursorMemberId};this.getSelectedRange=function(){return l};this.setSelectedRange=function(g,r){l=g;f=!1!==r};this.hasForwardSelection=function(){return f};this.getOdtDocument=function(){return g};this.getSelectionType=function(){return ops.OdtCursor.RangeSelection};l.setStart(g.getRootNo [...]
- gui.ShadowCursor.ShadowCursorMemberId="";(function(){return gui.ShadowCursor})();
- // Input 57
++odf.TextStyleApplicator=function(m,h,b){function g(b){function d(a,b){return"object"===typeof a&&"object"===typeof b?Object.keys(a).every(function(e){return d(a[e],b[e])}):a===b}var a={};this.isStyleApplied=function(c){c=h.getAppliedStylesForElement(c,a);return d(b,c)}}function d(d){var g={};this.applyStyleToContainer=function(a){var c;c=a.getAttributeNS(k,"style-name");var l=a.ownerDocument;c=c||"";if(!g.hasOwnProperty(c)){var f=c,n;n=c?h.createDerivedStyleObject(c,"text",d):d;l=l.crea [...]
++"style:style");h.updateStyle(l,n);l.setAttributeNS(q,"style:name",m.generateStyleName());l.setAttributeNS(q,"style:family","text");l.setAttributeNS("urn:webodf:names:scope","scope","document-content");b.appendChild(l);g[f]=l}c=g[c].getAttributeNS(q,"name");a.setAttributeNS(k,"text:style-name",c)}}function n(b,d){var a=b.ownerDocument,c=b.parentNode,g,f,h=new core.LoopWatchDog(1E4);f=[];"span"!==c.localName||c.namespaceURI!==k?(g=a.createElementNS(k,"text:span"),c.insertBefore(g,b),c=!1) [...]
++!p.rangeContainsNode(d,c.firstChild)?(g=c.cloneNode(!1),c.parentNode.insertBefore(g,c.nextSibling)):g=c,c=!0);f.push(b);for(a=b.nextSibling;a&&p.rangeContainsNode(d,a);)h.check(),f.push(a),a=a.nextSibling;f.forEach(function(a){a.parentNode!==g&&g.appendChild(a)});if(a&&c)for(f=g.cloneNode(!1),g.parentNode.insertBefore(f,g.nextSibling);a;)h.check(),c=a.nextSibling,f.appendChild(a),a=c;return g}var p=new core.DomUtils,k=odf.Namespaces.textns,q=odf.Namespaces.stylens;this.applyStyle=functi [...]
++{},l,f,h,m;runtime.assert(a&&a.hasOwnProperty("style:text-properties"),"applyStyle without any text properties");c["style:text-properties"]=a["style:text-properties"];h=new d(c);m=new g(c);b.forEach(function(a){l=m.isStyleApplied(a);!1===l&&(f=n(a,k),h.applyStyleToContainer(f))})}};
++// Input 51
 +/*
 +
-  Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
++ Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- gui.UndoManager=function(){};gui.UndoManager.prototype.subscribe=function(g,l){};gui.UndoManager.prototype.unsubscribe=function(g,l){};gui.UndoManager.prototype.setOdtDocument=function(g){};gui.UndoManager.prototype.saveInitialState=function(){};gui.UndoManager.prototype.resetInitialState=function(){};gui.UndoManager.prototype.setPlaybackFunction=function(g){};gui.UndoManager.prototype.hasUndoStates=function(){};gui.UndoManager.prototype.hasRedoStates=function(){};
- gui.UndoManager.prototype.moveForward=function(g){};gui.UndoManager.prototype.moveBackward=function(g){};gui.UndoManager.prototype.onOperationExecuted=function(g){};gui.UndoManager.signalUndoStackChanged="undoStackChanged";gui.UndoManager.signalUndoStateCreated="undoStateCreated";gui.UndoManager.signalUndoStateModified="undoStateModified";(function(){return gui.UndoManager})();
- // Input 58
++ops.OpApplyDirectStyling=function(){function m(b,d,g){var a=b.getOdfCanvas().odfContainer(),c=k.splitBoundaries(d),l=p.getTextNodes(d,!1);d={startContainer:d.startContainer,startOffset:d.startOffset,endContainer:d.endContainer,endOffset:d.endOffset};(new odf.TextStyleApplicator(new odf.ObjectNameGenerator(a,h),b.getFormatting(),a.rootElement.automaticStyles)).applyStyle(l,d,g);c.forEach(k.normalizeTextNodes)}var h,b,g,d,n,p=new odf.OdfUtils,k=new core.DomUtils;this.init=function(k){h=k. [...]
++k.timestamp;g=parseInt(k.position,10);d=parseInt(k.length,10);n=k.setProperties};this.isEdit=!0;this.group=void 0;this.execute=function(k){var e=k.convertCursorToDomRange(g,d),r=p.getParagraphElements(e);m(k,e,n);e.detach();k.getOdfCanvas().refreshCSS();k.fixCursorPositions();r.forEach(function(a){k.emit(ops.OdtDocument.signalParagraphChanged,{paragraphElement:a,memberId:h,timeStamp:b})});k.getOdfCanvas().rerenderAnnotations();return!0};this.spec=function(){return{optype:"ApplyDirectSty [...]
++timestamp:b,position:g,length:d,setProperties:n}}};
++// Input 52
 +/*
 +
-  Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
++ Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- gui.UndoStateRules=function(){function g(f){return f.spec().optype}function l(f){return f.isEdit}this.getOpType=g;this.isEditOperation=l;this.isPartOfOperationSet=function(f,p){if(f.isEdit){if(0===p.length)return!0;var r;if(r=p[p.length-1].isEdit)a:{r=p.filter(l);var n=g(f),h;b:switch(n){case "RemoveText":case "InsertText":h=!0;break b;default:h=!1}if(h&&n===g(r[0])){if(1===r.length){r=!0;break a}n=r[r.length-2].spec().position;r=r[r.length-1].spec().position;h=f.spec().position;if(r=== [...]
- !0;break a}}r=!1}return r}return!0}};
- // Input 59
++ops.OpApplyHyperlink=function(){function m(b){for(;b;){if(k.isHyperlink(b))return!0;b=b.parentNode}return!1}var h,b,g,d,n,p=new core.DomUtils,k=new odf.OdfUtils;this.init=function(k){h=k.memberid;b=k.timestamp;g=k.position;d=k.length;n=k.hyperlink};this.isEdit=!0;this.group=void 0;this.execute=function(q){var e=q.getDOMDocument(),r=q.convertCursorToDomRange(g,d),a=p.splitBoundaries(r),c=[],l=k.getTextNodes(r,!1);if(0===l.length)return!1;l.forEach(function(a){var b=k.getParagraphElement( [...]
++m(a),"The given range should not contain any link.");var d=n,g=e.createElementNS(odf.Namespaces.textns,"text:a");g.setAttributeNS(odf.Namespaces.xlinkns,"xlink:type","simple");g.setAttributeNS(odf.Namespaces.xlinkns,"xlink:href",d);a.parentNode.insertBefore(g,a);g.appendChild(a);-1===c.indexOf(b)&&c.push(b)});a.forEach(p.normalizeTextNodes);r.detach();q.getOdfCanvas().refreshSize();q.getOdfCanvas().rerenderAnnotations();c.forEach(function(a){q.emit(ops.OdtDocument.signalParagraphChanged [...]
++memberId:h,timeStamp:b})});return!0};this.spec=function(){return{optype:"ApplyHyperlink",memberid:h,timestamp:b,position:g,length:d,hyperlink:n}}};
++// Input 53
 +/*
 +
-  Copyright (C) 2012 KO GmbH <aditya.bhatt at kogmbh.com>
++ Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- ops.EditInfo=function(g,l){function f(){var f=[],h;for(h in r)r.hasOwnProperty(h)&&f.push({memberid:h,time:r[h].time});f.sort(function(d,f){return d.time-f.time});return f}var p,r={};this.getNode=function(){return p};this.getOdtDocument=function(){return l};this.getEdits=function(){return r};this.getSortedEdits=function(){return f()};this.addEdit=function(f,h){r[f]={time:h}};this.clearEdits=function(){r={}};this.destroy=function(f){g.parentNode&&g.removeChild(p);f()};p=l.getDOM().create [...]
- "editinfo");g.insertBefore(p,g.firstChild)};
- // Input 60
++ops.OpInsertImage=function(){var m,h,b,g,d,n,p,k,q=odf.Namespaces.drawns,e=odf.Namespaces.svgns,r=odf.Namespaces.textns,a=odf.Namespaces.xlinkns;this.init=function(a){m=a.memberid;h=a.timestamp;b=a.position;g=a.filename;d=a.frameWidth;n=a.frameHeight;p=a.frameStyleName;k=a.frameName};this.isEdit=!0;this.group=void 0;this.execute=function(c){var l=c.getOdfCanvas(),f=c.getTextNodeAtStep(b,m),v,w;if(!f)return!1;v=f.textNode;w=c.getParagraphElement(v);var f=f.offset!==v.length?v.splitText(f [...]
++z=c.getDOMDocument(),x=z.createElementNS(q,"draw:image"),z=z.createElementNS(q,"draw:frame");x.setAttributeNS(a,"xlink:href",g);x.setAttributeNS(a,"xlink:type","simple");x.setAttributeNS(a,"xlink:show","embed");x.setAttributeNS(a,"xlink:actuate","onLoad");z.setAttributeNS(q,"draw:style-name",p);z.setAttributeNS(q,"draw:name",k);z.setAttributeNS(r,"text:anchor-type","as-char");z.setAttributeNS(e,"svg:width",d);z.setAttributeNS(e,"svg:height",n);z.appendChild(x);v.parentNode.insertBefore( [...]
++{position:b,length:1});0===v.length&&v.parentNode.removeChild(v);l.addCssForFrameWithImage(z);l.refreshCSS();c.emit(ops.OdtDocument.signalParagraphChanged,{paragraphElement:w,memberId:m,timeStamp:h});l.rerenderAnnotations();return!0};this.spec=function(){return{optype:"InsertImage",memberid:m,timestamp:h,filename:g,position:b,frameWidth:d,frameHeight:n,frameStyleName:p,frameName:k}}};
++// Input 54
 +/*
 +
-  Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
++ Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("core.DomUtils");
- ops.OpAddAnnotation=function(){function g(d,f,c){var e=d.getTextNodeAtStep(c,l);e&&(d=e.textNode,c=d.parentNode,e.offset!==d.length&&d.splitText(e.offset),c.insertBefore(f,d.nextSibling),0===d.length&&c.removeChild(d))}var l,f,p,r,n,h;this.init=function(d){l=d.memberid;f=parseInt(d.timestamp,10);p=parseInt(d.position,10);r=parseInt(d.length,10)||0;n=d.name};this.isEdit=!0;this.execute=function(d){var m={},c=d.getCursor(l),e,a;a=new core.DomUtils;h=d.getDOM();var b=new Date(f),q,k,t,A;e= [...]
- "office:annotation");e.setAttributeNS(odf.Namespaces.officens,"office:name",n);q=h.createElementNS(odf.Namespaces.dcns,"dc:creator");q.setAttributeNS("urn:webodf:names:editinfo","editinfo:memberid",l);q.textContent=d.getMember(l).getProperties().fullName;k=h.createElementNS(odf.Namespaces.dcns,"dc:date");k.appendChild(h.createTextNode(b.toISOString()));b=h.createElementNS(odf.Namespaces.textns,"text:list");t=h.createElementNS(odf.Namespaces.textns,"text:list-item");A=h.createElementNS(o [...]
- "text:p");t.appendChild(A);b.appendChild(t);e.appendChild(q);e.appendChild(k);e.appendChild(b);m.node=e;if(!m.node)return!1;if(r){e=h.createElementNS(odf.Namespaces.officens,"office:annotation-end");e.setAttributeNS(odf.Namespaces.officens,"office:name",n);m.end=e;if(!m.end)return!1;g(d,m.end,p+r)}g(d,m.node,p);d.emit(ops.OdtDocument.signalStepsInserted,{position:p,length:r});c&&(e=h.createRange(),a=a.getElementsByTagNameNS(m.node,odf.Namespaces.textns,"p")[0],e.selectNodeContents(a),c. [...]
- d.emit(ops.OdtDocument.signalCursorMoved,c));d.getOdfCanvas().addAnnotation(m);d.fixCursorPositions();return!0};this.spec=function(){return{optype:"AddAnnotation",memberid:l,timestamp:f,position:p,length:r,name:n}}};
- // Input 61
++ops.OpInsertTable=function(){function m(b,a){var c;if(1===e.length)c=e[0];else if(3===e.length)switch(b){case 0:c=e[0];break;case g-1:c=e[2];break;default:c=e[1]}else c=e[b];if(1===c.length)return c[0];if(3===c.length)switch(a){case 0:return c[0];case d-1:return c[2];default:return c[1]}return c[a]}var h,b,g,d,n,p,k,q,e;this.init=function(m){h=m.memberid;b=m.timestamp;n=m.position;g=m.initialRows;d=m.initialColumns;p=m.tableName;k=m.tableStyleName;q=m.tableColumnStyleName;e=m.tableCellS [...]
++this.isEdit=!0;this.group=void 0;this.execute=function(e){var a=e.getTextNodeAtStep(n),c=e.getRootNode();if(a){var l=e.getDOMDocument(),f=l.createElementNS("urn:oasis:names:tc:opendocument:xmlns:table:1.0","table:table"),v=l.createElementNS("urn:oasis:names:tc:opendocument:xmlns:table:1.0","table:table-column"),w,z,x,t;k&&f.setAttributeNS("urn:oasis:names:tc:opendocument:xmlns:table:1.0","table:style-name",k);p&&f.setAttributeNS("urn:oasis:names:tc:opendocument:xmlns:table:1.0","table:n [...]
++"table:number-columns-repeated",d);q&&v.setAttributeNS("urn:oasis:names:tc:opendocument:xmlns:table:1.0","table:style-name",q);f.appendChild(v);for(x=0;x<g;x+=1){v=l.createElementNS("urn:oasis:names:tc:opendocument:xmlns:table:1.0","table:table-row");for(t=0;t<d;t+=1)w=l.createElementNS("urn:oasis:names:tc:opendocument:xmlns:table:1.0","table:table-cell"),(z=m(x,t))&&w.setAttributeNS("urn:oasis:names:tc:opendocument:xmlns:table:1.0","table:style-name",z),z=l.createElementNS("urn:oasis:n [...]
++"text:p"),w.appendChild(z),v.appendChild(w);f.appendChild(v)}a=e.getParagraphElement(a.textNode);c.insertBefore(f,a.nextSibling);e.emit(ops.OdtDocument.signalStepsInserted,{position:n,length:d*g+1});e.getOdfCanvas().refreshSize();e.emit(ops.OdtDocument.signalTableAdded,{tableElement:f,memberId:h,timeStamp:b});e.getOdfCanvas().rerenderAnnotations();return!0}return!1};this.spec=function(){return{optype:"InsertTable",memberid:h,timestamp:b,position:n,initialRows:g,initialColumns:d,tableNam [...]
++tableColumnStyleName:q,tableCellStyleMatrix:e}}};
++// Input 55
 +/*
 +
 + Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- ops.OpAddCursor=function(){var g,l;this.init=function(f){g=f.memberid;l=f.timestamp};this.isEdit=!1;this.execute=function(f){var l=f.getCursor(g);if(l)return!1;l=new ops.OdtCursor(g,f);f.addCursor(l);f.emit(ops.OdtDocument.signalCursorAdded,l);return!0};this.spec=function(){return{optype:"AddCursor",memberid:g,timestamp:l}}};
- // Input 62
++ops.OpInsertText=function(){var m,h,b,g,d;this.init=function(n){m=n.memberid;h=n.timestamp;b=n.position;d=n.text;g="true"===n.moveCursor||!0===n.moveCursor};this.isEdit=!0;this.group=void 0;this.execute=function(n){var p,k,q,e=null,r=n.getDOMDocument(),a,c=0,l,f=n.getCursor(m),v;n.upgradeWhitespacesAtPosition(b);if(p=n.getTextNodeAtStep(b)){k=p.textNode;e=k.nextSibling;q=k.parentNode;a=n.getParagraphElement(k);for(v=0;v<d.length;v+=1)if(" "===d[v]&&(0===v||v===d.length-1||" "===d[v-1])| [...]
++c?(p.offset!==k.length&&(e=k.splitText(p.offset)),0<v&&k.appendData(d.substring(0,v))):c<v&&(c=d.substring(c,v),q.insertBefore(r.createTextNode(c),e)),c=v+1,l=" "===d[v]?"text:s":"text:tab",l=r.createElementNS("urn:oasis:names:tc:opendocument:xmlns:text:1.0",l),l.appendChild(r.createTextNode(d[v])),q.insertBefore(l,e);0===c?k.insertData(p.offset,d):c<d.length&&(p=d.substring(c),q.insertBefore(r.createTextNode(p),e));q=k.parentNode;e=k.nextSibling;q.removeChild(k);q.insertBefore(k,e);0== [...]
++k.parentNode.removeChild(k);n.emit(ops.OdtDocument.signalStepsInserted,{position:b,length:d.length});f&&g&&(n.moveCursor(m,b+d.length,0),n.emit(ops.Document.signalCursorMoved,f));0<b&&(1<b&&n.downgradeWhitespacesAtPosition(b-2),n.downgradeWhitespacesAtPosition(b-1));n.downgradeWhitespacesAtPosition(b);n.downgradeWhitespacesAtPosition(b+d.length-1);n.downgradeWhitespacesAtPosition(b+d.length);n.getOdfCanvas().refreshSize();n.emit(ops.OdtDocument.signalParagraphChanged,{paragraphElement:a [...]
++timeStamp:h});n.getOdfCanvas().rerenderAnnotations();return!0}return!1};this.spec=function(){return{optype:"InsertText",memberid:m,timestamp:h,position:b,text:d,moveCursor:g}}};
++// Input 56
 +/*
 +
-  Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
++ Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
-  This file is part of WebODF.
++ The JavaScript code in this page is free software: you can redistribute it
++ and/or modify it under the terms of the GNU Affero General Public License
++ (GNU AGPL) as published by the Free Software Foundation, either version 3 of
++ the License, or (at your option) any later version.  The code is distributed
++ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
-  WebODF is free software: you can redistribute it and/or modify it
-  under the terms of the GNU Affero General Public License (GNU AGPL)
-  as published by the Free Software Foundation, either version 3 of
-  the License, or (at your option) any later version.
++ You should have received a copy of the GNU Affero General Public License
++ along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
-  WebODF is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-  GNU Affero General Public License for more details.
++ As additional permission under GNU AGPL version 3 section 7, you
++ may distribute non-source (e.g., minimized or compacted) forms of
++ that code without the copy of the GNU GPL normally required by
++ section 4, provided you include this license notice and a URL
++ through which recipients can access the Corresponding Source.
 +
-  You should have received a copy of the GNU Affero General Public License
-  along with WebODF.  If not, see <http://www.gnu.org/licenses/>.
-  @licend
++ As a special exception to the AGPL, any HTML file which merely makes function
++ calls to this code, and for that purpose includes it by reference shall be
++ deemed a separate work for copyright law purposes. In addition, the copyright
++ holders of this code give you permission to combine this code with free
++ software libraries that are released under the GNU LGPL. You may copy and
++ distribute such a system following the terms of the GNU AGPL for this code
++ and the LGPL for the libraries. If you modify this code, you may extend this
++ exception to your version of the code, but you are not obligated to do so.
++ If you do not wish to do so, delete this exception statement from your
++ version.
 +
++ This license applies to this entire compilation.
++ @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("ops.Member");ops.OpAddMember=function(){var g,l,f;this.init=function(p){g=p.memberid;l=parseInt(p.timestamp,10);f=p.setProperties};this.isEdit=!1;this.execute=function(l){if(l.getMember(g))return!1;var r=new ops.Member(g,f);l.addMember(r);l.emit(ops.OdtDocument.signalMemberAdded,r);return!0};this.spec=function(){return{optype:"AddMember",memberid:g,timestamp:l,setProperties:f}}};
- // Input 63
++ops.OpMoveCursor=function(){var m,h,b,g,d;this.init=function(n){m=n.memberid;h=n.timestamp;b=n.position;g=n.length||0;d=n.selectionType||ops.OdtCursor.RangeSelection};this.isEdit=!1;this.group=void 0;this.execute=function(h){var p=h.getCursor(m),k;if(!p)return!1;k=h.convertCursorToDomRange(b,g);p.setSelectedRange(k,0<=g);p.setSelectionType(d);h.emit(ops.Document.signalCursorMoved,p);return!0};this.spec=function(){return{optype:"MoveCursor",memberid:m,timestamp:h,position:b,length:g,sele [...]
++// Input 57
 +/*
 +
 + Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("odf.Namespaces");
- ops.OpAddStyle=function(){var g,l,f,p,r,n,h=odf.Namespaces.stylens;this.init=function(d){g=d.memberid;l=d.timestamp;f=d.styleName;p=d.styleFamily;r="true"===d.isAutomaticStyle||!0===d.isAutomaticStyle;n=d.setProperties};this.isEdit=!0;this.execute=function(d){var g=d.getOdfCanvas().odfContainer(),c=d.getFormatting(),e=d.getDOM().createElementNS(h,"style:style");if(!e)return!1;n&&c.updateStyle(e,n);e.setAttributeNS(h,"style:family",p);e.setAttributeNS(h,"style:name",f);r?g.rootElement.au [...]
- g.rootElement.styles.appendChild(e);d.getOdfCanvas().refreshCSS();r||d.emit(ops.OdtDocument.signalCommonStyleCreated,{name:f,family:p});return!0};this.spec=function(){return{optype:"AddStyle",memberid:g,timestamp:l,styleName:f,styleFamily:p,isAutomaticStyle:r,setProperties:n}}};
- // Input 64
++ops.OpRemoveAnnotation=function(){var m,h,b,g,d;this.init=function(n){m=n.memberid;h=n.timestamp;b=parseInt(n.position,10);g=parseInt(n.length,10);d=new core.DomUtils};this.isEdit=!0;this.group=void 0;this.execute=function(h){function m(b){q.parentNode.insertBefore(b,q)}for(var k=h.getIteratorAtPosition(b).container(),q;k.namespaceURI!==odf.Namespaces.officens||"annotation"!==k.localName;)k=k.parentNode;if(null===k)return!1;q=k;k=q.annotationEndElement;h.getOdfCanvas().forgetAnnotations [...]
++"urn:webodf:names:cursor","cursor").forEach(m);d.getElementsByTagNameNS(q,"urn:webodf:names:cursor","anchor").forEach(m);q.parentNode.removeChild(q);k&&k.parentNode.removeChild(k);h.emit(ops.OdtDocument.signalStepsRemoved,{position:0<b?b-1:b,length:g});h.fixCursorPositions();h.getOdfCanvas().refreshAnnotations();return!0};this.spec=function(){return{optype:"RemoveAnnotation",memberid:m,timestamp:h,position:b,length:g}}};
++// Input 58
 +/*
 +
 + Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("core.DomUtils");runtime.loadClass("odf.OdfUtils");runtime.loadClass("odf.TextStyleApplicator");
- ops.OpApplyDirectStyling=function(){function g(f,c,e){var a=f.getOdfCanvas().odfContainer(),b=d.splitBoundaries(c),g=h.getTextNodes(c,!1);c={startContainer:c.startContainer,startOffset:c.startOffset,endContainer:c.endContainer,endOffset:c.endOffset};(new odf.TextStyleApplicator(new odf.ObjectNameGenerator(a,l),f.getFormatting(),a.rootElement.automaticStyles)).applyStyle(g,c,e);b.forEach(d.normalizeTextNodes)}var l,f,p,r,n,h=new odf.OdfUtils,d=new core.DomUtils;this.init=function(d){l=d. [...]
- d.timestamp;p=parseInt(d.position,10);r=parseInt(d.length,10);n=d.setProperties};this.isEdit=!0;this.execute=function(d){var c=d.convertCursorToDomRange(p,r),e=h.getImpactedParagraphs(c);g(d,c,n);c.detach();d.getOdfCanvas().refreshCSS();d.fixCursorPositions();e.forEach(function(a){d.emit(ops.OdtDocument.signalParagraphChanged,{paragraphElement:a,memberId:l,timeStamp:f})});d.getOdfCanvas().rerenderAnnotations();return!0};this.spec=function(){return{optype:"ApplyDirectStyling",memberid:l, [...]
- position:p,length:r,setProperties:n}}};
- // Input 65
++ops.OpRemoveBlob=function(){var m,h,b;this.init=function(g){m=g.memberid;h=g.timestamp;b=g.filename};this.isEdit=!0;this.group=void 0;this.execute=function(g){g.getOdfCanvas().odfContainer().removeBlob(b);return!0};this.spec=function(){return{optype:"RemoveBlob",memberid:m,timestamp:h,filename:b}}};
++// Input 59
 +/*
 +
 + Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- ops.OpInsertImage=function(){var g,l,f,p,r,n,h,d,m=odf.Namespaces.drawns,c=odf.Namespaces.svgns,e=odf.Namespaces.textns,a=odf.Namespaces.xlinkns;this.init=function(a){g=a.memberid;l=a.timestamp;f=a.position;p=a.filename;r=a.frameWidth;n=a.frameHeight;h=a.frameStyleName;d=a.frameName};this.isEdit=!0;this.execute=function(b){var q=b.getOdfCanvas(),k=b.getTextNodeAtStep(f,g),t,A;if(!k)return!1;t=k.textNode;A=b.getParagraphElement(t);var k=k.offset!==t.length?t.splitText(k.offset):t.nextSib [...]
- x=w.createElementNS(m,"draw:image"),w=w.createElementNS(m,"draw:frame");x.setAttributeNS(a,"xlink:href",p);x.setAttributeNS(a,"xlink:type","simple");x.setAttributeNS(a,"xlink:show","embed");x.setAttributeNS(a,"xlink:actuate","onLoad");w.setAttributeNS(m,"draw:style-name",h);w.setAttributeNS(m,"draw:name",d);w.setAttributeNS(e,"text:anchor-type","as-char");w.setAttributeNS(c,"svg:width",r);w.setAttributeNS(c,"svg:height",n);w.appendChild(x);t.parentNode.insertBefore(w,k);b.emit(ops.OdtDo [...]
- {position:f,length:1});0===t.length&&t.parentNode.removeChild(t);q.addCssForFrameWithImage(w);q.refreshCSS();b.emit(ops.OdtDocument.signalParagraphChanged,{paragraphElement:A,memberId:g,timeStamp:l});q.rerenderAnnotations();return!0};this.spec=function(){return{optype:"InsertImage",memberid:g,timestamp:l,filename:p,position:f,frameWidth:r,frameHeight:n,frameStyleName:h,frameName:d}}};
- // Input 66
++ops.OpRemoveCursor=function(){var m,h;this.init=function(b){m=b.memberid;h=b.timestamp};this.isEdit=!1;this.group=void 0;this.execute=function(b){return b.removeCursor(m)?!0:!1};this.spec=function(){return{optype:"RemoveCursor",memberid:m,timestamp:h}}};
++// Input 60
 +/*
 +
-  Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
++ Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- ops.OpInsertTable=function(){function g(d,a){var b;if(1===c.length)b=c[0];else if(3===c.length)switch(d){case 0:b=c[0];break;case p-1:b=c[2];break;default:b=c[1]}else b=c[d];if(1===b.length)return b[0];if(3===b.length)switch(a){case 0:return b[0];case r-1:return b[2];default:return b[1]}return b[a]}var l,f,p,r,n,h,d,m,c;this.init=function(e){l=e.memberid;f=e.timestamp;n=e.position;p=e.initialRows;r=e.initialColumns;h=e.tableName;d=e.tableStyleName;m=e.tableColumnStyleName;c=e.tableCellS [...]
- this.isEdit=!0;this.execute=function(c){var a=c.getTextNodeAtStep(n),b=c.getRootNode();if(a){var q=c.getDOM(),k=q.createElementNS("urn:oasis:names:tc:opendocument:xmlns:table:1.0","table:table"),t=q.createElementNS("urn:oasis:names:tc:opendocument:xmlns:table:1.0","table:table-column"),A,w,x,v;d&&k.setAttributeNS("urn:oasis:names:tc:opendocument:xmlns:table:1.0","table:style-name",d);h&&k.setAttributeNS("urn:oasis:names:tc:opendocument:xmlns:table:1.0","table:name",h);t.setAttributeNS(" [...]
- "table:number-columns-repeated",r);m&&t.setAttributeNS("urn:oasis:names:tc:opendocument:xmlns:table:1.0","table:style-name",m);k.appendChild(t);for(x=0;x<p;x+=1){t=q.createElementNS("urn:oasis:names:tc:opendocument:xmlns:table:1.0","table:table-row");for(v=0;v<r;v+=1)A=q.createElementNS("urn:oasis:names:tc:opendocument:xmlns:table:1.0","table:table-cell"),(w=g(x,v))&&A.setAttributeNS("urn:oasis:names:tc:opendocument:xmlns:table:1.0","table:style-name",w),w=q.createElementNS("urn:oasis:n [...]
- "text:p"),A.appendChild(w),t.appendChild(A);k.appendChild(t)}a=c.getParagraphElement(a.textNode);b.insertBefore(k,a.nextSibling);c.emit(ops.OdtDocument.signalStepsInserted,{position:n,length:r*p+1});c.getOdfCanvas().refreshSize();c.emit(ops.OdtDocument.signalTableAdded,{tableElement:k,memberId:l,timeStamp:f});c.getOdfCanvas().rerenderAnnotations();return!0}return!1};this.spec=function(){return{optype:"InsertTable",memberid:l,timestamp:f,position:n,initialRows:p,initialColumns:r,tableNam [...]
- tableColumnStyleName:m,tableCellStyleMatrix:c}}};
- // Input 67
++ops.OpRemoveHyperlink=function(){var m,h,b,g,d=new core.DomUtils,n=new odf.OdfUtils;this.init=function(d){m=d.memberid;h=d.timestamp;b=d.position;g=d.length};this.isEdit=!0;this.group=void 0;this.execute=function(p){var k=p.convertCursorToDomRange(b,g),q=n.getHyperlinkElements(k);runtime.assert(1===q.length,"The given range should only contain a single link.");q=d.mergeIntoParent(q[0]);k.detach();p.getOdfCanvas().refreshSize();p.emit(ops.OdtDocument.signalParagraphChanged,{paragraphElem [...]
++memberId:m,timeStamp:h});p.getOdfCanvas().rerenderAnnotations();return!0};this.spec=function(){return{optype:"RemoveHyperlink",memberid:m,timestamp:h,position:b,length:g}}};
++// Input 61
++/*
++
++ Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
++
++ @licstart
++ This file is part of WebODF.
++
++ WebODF is free software: you can redistribute it and/or modify it
++ under the terms of the GNU Affero General Public License (GNU AGPL)
++ as published by the Free Software Foundation, either version 3 of
++ the License, or (at your option) any later version.
++
++ WebODF is distributed in the hope that it will be useful, but
++ WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ GNU Affero General Public License for more details.
++
++ You should have received a copy of the GNU Affero General Public License
++ along with WebODF.  If not, see <http://www.gnu.org/licenses/>.
++ @licend
++
++ @source: http://www.webodf.org/
++ @source: https://github.com/kogmbh/WebODF/
++*/
++ops.OpRemoveMember=function(){var m,h;this.init=function(b){m=b.memberid;h=parseInt(b.timestamp,10)};this.isEdit=!1;this.group=void 0;this.execute=function(b){if(!b.getMember(m))return!1;b.removeMember(m);b.emit(ops.Document.signalMemberRemoved,m);return!0};this.spec=function(){return{optype:"RemoveMember",memberid:m,timestamp:h}}};
++// Input 62
 +/*
 +
 + Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- ops.OpInsertText=function(){var g,l,f,p,r;this.init=function(n){g=n.memberid;l=n.timestamp;f=n.position;p=n.text;r="true"===n.moveCursor||!0===n.moveCursor};this.isEdit=!0;this.execute=function(n){var h,d,m,c=null,e=n.getDOM(),a,b=0,q,k=n.getCursor(g),t;n.upgradeWhitespacesAtPosition(f);if(h=n.getTextNodeAtStep(f)){d=h.textNode;c=d.nextSibling;m=d.parentNode;a=n.getParagraphElement(d);for(t=0;t<p.length;t+=1)if(" "===p[t]&&(0===t||t===p.length-1||" "===p[t-1])||"\t"===p[t])0===b?(h.offs [...]
- (c=d.splitText(h.offset)),0<t&&d.appendData(p.substring(0,t))):b<t&&(b=p.substring(b,t),m.insertBefore(e.createTextNode(b),c)),b=t+1,q=" "===p[t]?"text:s":"text:tab",q=e.createElementNS("urn:oasis:names:tc:opendocument:xmlns:text:1.0",q),q.appendChild(e.createTextNode(p[t])),m.insertBefore(q,c);0===b?d.insertData(h.offset,p):b<p.length&&(h=p.substring(b),m.insertBefore(e.createTextNode(h),c));m=d.parentNode;c=d.nextSibling;m.removeChild(d);m.insertBefore(d,c);0===d.length&&d.parentNode. [...]
- n.emit(ops.OdtDocument.signalStepsInserted,{position:f,length:p.length});k&&r&&(n.moveCursor(g,f+p.length,0),n.emit(ops.OdtDocument.signalCursorMoved,k));0<f&&(1<f&&n.downgradeWhitespacesAtPosition(f-2),n.downgradeWhitespacesAtPosition(f-1));n.downgradeWhitespacesAtPosition(f);n.downgradeWhitespacesAtPosition(f+p.length-1);n.downgradeWhitespacesAtPosition(f+p.length);n.getOdfCanvas().refreshSize();n.emit(ops.OdtDocument.signalParagraphChanged,{paragraphElement:a,memberId:g,timeStamp:l}) [...]
- return!0}return!1};this.spec=function(){return{optype:"InsertText",memberid:g,timestamp:l,position:f,text:p,moveCursor:r}}};
- // Input 68
++ops.OpRemoveStyle=function(){var m,h,b,g;this.init=function(d){m=d.memberid;h=d.timestamp;b=d.styleName;g=d.styleFamily};this.isEdit=!0;this.group=void 0;this.execute=function(d){var h=d.getStyleElement(b,g);if(!h)return!1;h.parentNode.removeChild(h);d.getOdfCanvas().refreshCSS();d.emit(ops.OdtDocument.signalCommonStyleDeleted,{name:b,family:g});return!0};this.spec=function(){return{optype:"RemoveStyle",memberid:m,timestamp:h,styleName:b,styleFamily:g}}};
++// Input 63
 +/*
 +
 + Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- ops.OpMoveCursor=function(){var g,l,f,p,r;this.init=function(n){g=n.memberid;l=n.timestamp;f=n.position;p=n.length||0;r=n.selectionType||ops.OdtCursor.RangeSelection};this.isEdit=!1;this.execute=function(l){var h=l.getCursor(g),d;if(!h)return!1;d=l.convertCursorToDomRange(f,p);h.setSelectedRange(d,0<=p);h.setSelectionType(r);l.emit(ops.OdtDocument.signalCursorMoved,h);return!0};this.spec=function(){return{optype:"MoveCursor",memberid:g,timestamp:l,position:f,length:p,selectionType:r}}};
- // Input 69
++ops.OpRemoveText=function(){function m(b){function d(a){return k.hasOwnProperty(a.namespaceURI)||"br"===a.localName&&n.isLineBreak(a.parentNode)||a.nodeType===Node.TEXT_NODE&&k.hasOwnProperty(a.parentNode.namespaceURI)}function g(a){if(n.isCharacterElement(a))return!1;if(a.nodeType===Node.TEXT_NODE)return 0===a.textContent.length;for(a=a.firstChild;a;){if(k.hasOwnProperty(a.namespaceURI)||!g(a))return!1;a=a.nextSibling}return!0}function a(c){var l;c.nodeType===Node.TEXT_NODE?(l=c.parent [...]
++l=p.removeUnwantedNodes(c,d);return l&&!n.isParagraph(l)&&l!==b&&g(l)?a(l):l}this.isEmpty=g;this.mergeChildrenIntoParent=a}var h,b,g,d,n,p,k={};this.init=function(m){runtime.assert(0<=m.length,"OpRemoveText only supports positive lengths");h=m.memberid;b=m.timestamp;g=parseInt(m.position,10);d=parseInt(m.length,10);n=new odf.OdfUtils;p=new core.DomUtils;k[odf.Namespaces.dbns]=!0;k[odf.Namespaces.dcns]=!0;k[odf.Namespaces.dr3dns]=!0;k[odf.Namespaces.drawns]=!0;k[odf.Namespaces.chartns]=! [...]
++!0;k[odf.Namespaces.numberns]=!0;k[odf.Namespaces.officens]=!0;k[odf.Namespaces.presentationns]=!0;k[odf.Namespaces.stylens]=!0;k[odf.Namespaces.svgns]=!0;k[odf.Namespaces.tablens]=!0;k[odf.Namespaces.textns]=!0};this.isEdit=!0;this.group=void 0;this.execute=function(k){var e,r,a,c,l=k.getCursor(h),f=new m(k.getRootNode());k.upgradeWhitespacesAtPosition(g);k.upgradeWhitespacesAtPosition(g+d);r=k.convertCursorToDomRange(g,d);p.splitBoundaries(r);e=k.getParagraphElement(r.startContainer); [...]
++!1,!0);c=n.getParagraphElements(r);r.detach();a.forEach(function(a){a.parentNode?f.mergeChildrenIntoParent(a):runtime.log("WARN: text element has already been removed from it's container")});r=c.reduce(function(a,b){var c,d=a,e=b,g,l=null;f.isEmpty(a)&&(b.parentNode!==a.parentNode&&(g=b.parentNode,a.parentNode.insertBefore(b,a.nextSibling)),e=a,d=b,l=d.getElementsByTagNameNS("urn:webodf:names:editinfo","editinfo").item(0)||d.firstChild);for(;e.firstChild;)c=e.firstChild,e.removeChild(c) [...]
++c.localName&&d.insertBefore(c,l);g&&f.isEmpty(g)&&f.mergeChildrenIntoParent(g);f.mergeChildrenIntoParent(e);return d});k.emit(ops.OdtDocument.signalStepsRemoved,{position:g,length:d});k.downgradeWhitespacesAtPosition(g);k.fixCursorPositions();k.getOdfCanvas().refreshSize();k.emit(ops.OdtDocument.signalParagraphChanged,{paragraphElement:r||e,memberId:h,timeStamp:b});l&&(l.resetSelectionType(),k.emit(ops.Document.signalCursorMoved,l));k.getOdfCanvas().rerenderAnnotations();return!0};this. [...]
++memberid:h,timestamp:b,position:g,length:d}}};
++// Input 64
 +/*
 +
 + Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("odf.Namespaces");runtime.loadClass("core.DomUtils");
- ops.OpRemoveAnnotation=function(){var g,l,f,p,r;this.init=function(n){g=n.memberid;l=n.timestamp;f=parseInt(n.position,10);p=parseInt(n.length,10);r=new core.DomUtils};this.isEdit=!0;this.execute=function(g){for(var h=g.getIteratorAtPosition(f).container(),d,l,c;h.namespaceURI!==odf.Namespaces.officens||"annotation"!==h.localName;)h=h.parentNode;if(null===h)return!1;(d=h.getAttributeNS(odf.Namespaces.officens,"name"))&&(l=r.getElementsByTagNameNS(g.getRootNode(),odf.Namespaces.officens, [...]
- c.getAttributeNS(odf.Namespaces.officens,"name")})[0]||null);g.getOdfCanvas().forgetAnnotations();for(c=r.getElementsByTagNameNS(h,"urn:webodf:names:cursor","cursor");c.length;)h.parentNode.insertBefore(c.pop(),h);h.parentNode.removeChild(h);l&&l.parentNode.removeChild(l);g.emit(ops.OdtDocument.signalStepsRemoved,{position:0<f?f-1:f,length:p});g.fixCursorPositions();g.getOdfCanvas().refreshAnnotations();return!0};this.spec=function(){return{optype:"RemoveAnnotation",memberid:g,timestamp [...]
- length:p}}};
- // Input 70
++ops.OpSetBlob=function(){var m,h,b,g,d;this.init=function(n){m=n.memberid;h=n.timestamp;b=n.filename;g=n.mimetype;d=n.content};this.isEdit=!0;this.group=void 0;this.execute=function(h){h.getOdfCanvas().odfContainer().setBlob(b,g,d);return!0};this.spec=function(){return{optype:"SetBlob",memberid:m,timestamp:h,filename:b,mimetype:g,content:d}}};
++// Input 65
 +/*
 +
 + Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- ops.OpRemoveBlob=function(){var g,l,f;this.init=function(p){g=p.memberid;l=p.timestamp;f=p.filename};this.isEdit=!0;this.execute=function(g){g.getOdfCanvas().odfContainer().removeBlob(f);return!0};this.spec=function(){return{optype:"RemoveBlob",memberid:g,timestamp:l,filename:f}}};
- // Input 71
++ops.OpSetParagraphStyle=function(){var m,h,b,g;this.init=function(d){m=d.memberid;h=d.timestamp;b=d.position;g=d.styleName};this.isEdit=!0;this.group=void 0;this.execute=function(d){var n;n=d.getIteratorAtPosition(b);return(n=d.getParagraphElement(n.container()))?(""!==g?n.setAttributeNS("urn:oasis:names:tc:opendocument:xmlns:text:1.0","text:style-name",g):n.removeAttributeNS("urn:oasis:names:tc:opendocument:xmlns:text:1.0","style-name"),d.getOdfCanvas().refreshSize(),d.emit(ops.OdtDocu [...]
++{paragraphElement:n,timeStamp:h,memberId:m}),d.getOdfCanvas().rerenderAnnotations(),!0):!1};this.spec=function(){return{optype:"SetParagraphStyle",memberid:m,timestamp:h,position:b,styleName:g}}};
++// Input 66
 +/*
 +
 + Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- ops.OpRemoveCursor=function(){var g,l;this.init=function(f){g=f.memberid;l=f.timestamp};this.isEdit=!1;this.execute=function(f){return f.removeCursor(g)?!0:!1};this.spec=function(){return{optype:"RemoveCursor",memberid:g,timestamp:l}}};
- // Input 72
++ops.OpSplitParagraph=function(){var m,h,b,g,d;this.init=function(n){m=n.memberid;h=n.timestamp;b=n.position;g="true"===n.moveCursor||!0===n.moveCursor;d=new odf.OdfUtils};this.isEdit=!0;this.group=void 0;this.execute=function(n){var p,k,q,e,r,a,c,l=n.getCursor(m);n.upgradeWhitespacesAtPosition(b);p=n.getTextNodeAtStep(b);if(!p)return!1;k=n.getParagraphElement(p.textNode);if(!k)return!1;q=d.isListItem(k.parentNode)?k.parentNode:k;0===p.offset?(c=p.textNode.previousSibling,a=null):(c=p.te [...]
++p.textNode.length?null:p.textNode.splitText(p.offset));for(e=p.textNode;e!==q;){e=e.parentNode;r=e.cloneNode(!1);a&&r.appendChild(a);if(c)for(;c&&c.nextSibling;)r.appendChild(c.nextSibling);else for(;e.firstChild;)r.appendChild(e.firstChild);e.parentNode.insertBefore(r,e.nextSibling);c=e;a=r}d.isListItem(a)&&(a=a.childNodes.item(0));0===p.textNode.length&&p.textNode.parentNode.removeChild(p.textNode);n.emit(ops.OdtDocument.signalStepsInserted,{position:b,length:1});l&&g&&(n.moveCursor(m [...]
++l));n.fixCursorPositions();n.getOdfCanvas().refreshSize();n.emit(ops.OdtDocument.signalParagraphChanged,{paragraphElement:k,memberId:m,timeStamp:h});n.emit(ops.OdtDocument.signalParagraphChanged,{paragraphElement:a,memberId:m,timeStamp:h});n.getOdfCanvas().rerenderAnnotations();return!0};this.spec=function(){return{optype:"SplitParagraph",memberid:m,timestamp:h,position:b,moveCursor:g}}};
++// Input 67
 +/*
 +
 + Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + This file is part of WebODF.
 +
 + WebODF is free software: you can redistribute it and/or modify it
 + under the terms of the GNU Affero General Public License (GNU AGPL)
 + as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.
 +
 + WebODF is distributed in the hope that it will be useful, but
 + WITHOUT ANY WARRANTY; without even the implied warranty of
 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + GNU Affero General Public License for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with WebODF.  If not, see <http://www.gnu.org/licenses/>.
 + @licend
 +
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("ops.Member");ops.OpRemoveMember=function(){var g,l;this.init=function(f){g=f.memberid;l=parseInt(f.timestamp,10)};this.isEdit=!1;this.execute=function(f){if(!f.getMember(g))return!1;f.removeMember(g);f.emit(ops.OdtDocument.signalMemberRemoved,g);return!0};this.spec=function(){return{optype:"RemoveMember",memberid:g,timestamp:l}}};
- // Input 73
++ops.OpUpdateMember=function(){function m(b){var d="//dc:creator[@editinfo:memberid='"+h+"']";b=xmldom.XPath.getODFElementsWithXPath(b.getRootNode(),d,function(b){return"editinfo"===b?"urn:webodf:names:editinfo":odf.Namespaces.lookupNamespaceURI(b)});for(d=0;d<b.length;d+=1)b[d].textContent=g.fullName}var h,b,g,d;this.init=function(m){h=m.memberid;b=parseInt(m.timestamp,10);g=m.setProperties;d=m.removedProperties};this.isEdit=!1;this.group=void 0;this.execute=function(b){var p=b.getMembe [...]
++d&&p.removeProperties(d);g&&(p.setProperties(g),g.fullName&&m(b));b.emit(ops.Document.signalMemberUpdated,p);return!0};this.spec=function(){return{optype:"UpdateMember",memberid:h,timestamp:b,setProperties:g,removedProperties:d}}};
++// Input 68
++/*
++
++ Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
++
++ @licstart
++ This file is part of WebODF.
++
++ WebODF is free software: you can redistribute it and/or modify it
++ under the terms of the GNU Affero General Public License (GNU AGPL)
++ as published by the Free Software Foundation, either version 3 of
++ the License, or (at your option) any later version.
++
++ WebODF is distributed in the hope that it will be useful, but
++ WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ GNU Affero General Public License for more details.
++
++ You should have received a copy of the GNU Affero General Public License
++ along with WebODF.  If not, see <http://www.gnu.org/licenses/>.
++ @licend
++
++ @source: http://www.webodf.org/
++ @source: https://github.com/kogmbh/WebODF/
++*/
++ops.OpUpdateMetadata=function(){var m,h,b,g;this.init=function(d){m=d.memberid;h=parseInt(d.timestamp,10);b=d.setProperties;g=d.removedProperties};this.isEdit=!0;this.group=void 0;this.execute=function(d){d=d.getOdfCanvas().odfContainer();var h=[];g&&(h=g.attributes.split(","));d.setMetadata(b,h);return!0};this.spec=function(){return{optype:"UpdateMetadata",memberid:m,timestamp:h,setProperties:b,removedProperties:g}}};
++// Input 69
 +/*
 +
 + Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- ops.OpRemoveStyle=function(){var g,l,f,p;this.init=function(r){g=r.memberid;l=r.timestamp;f=r.styleName;p=r.styleFamily};this.isEdit=!0;this.execute=function(g){var l=g.getStyleElement(f,p);if(!l)return!1;l.parentNode.removeChild(l);g.getOdfCanvas().refreshCSS();g.emit(ops.OdtDocument.signalCommonStyleDeleted,{name:f,family:p});return!0};this.spec=function(){return{optype:"RemoveStyle",memberid:g,timestamp:l,styleName:f,styleFamily:p}}};
- // Input 74
++ops.OpUpdateParagraphStyle=function(){function m(b,d){var e,g,a=d?d.split(","):[];for(e=0;e<a.length;e+=1)g=a[e].split(":"),b.removeAttributeNS(odf.Namespaces.lookupNamespaceURI(g[0]),g[1])}var h,b,g,d,n,p=odf.Namespaces.stylens;this.init=function(k){h=k.memberid;b=k.timestamp;g=k.styleName;d=k.setProperties;n=k.removedProperties};this.isEdit=!0;this.group=void 0;this.execute=function(b){var h=b.getFormatting(),e,r,a;return(e=""!==g?b.getParagraphStyleElement(g):h.getDefaultStyleElement [...]
++(r=e.getElementsByTagNameNS(p,"paragraph-properties").item(0),a=e.getElementsByTagNameNS(p,"text-properties").item(0),d&&h.updateStyle(e,d),n&&(h=n["style:paragraph-properties"],r&&h&&(m(r,h.attributes),0===r.attributes.length&&e.removeChild(r)),h=n["style:text-properties"],a&&h&&(m(a,h.attributes),0===a.attributes.length&&e.removeChild(a)),m(e,n.attributes)),b.getOdfCanvas().refreshCSS(),b.emit(ops.OdtDocument.signalParagraphStyleModified,g),b.getOdfCanvas().rerenderAnnotations(),!0):! [...]
++function(){return{optype:"UpdateParagraphStyle",memberid:h,timestamp:b,styleName:g,setProperties:d,removedProperties:n}}};
++// Input 70
 +/*
 +
 + Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("odf.Namespaces");runtime.loadClass("odf.OdfUtils");runtime.loadClass("core.DomUtils");
- ops.OpRemoveText=function(){function g(f){function c(a){return d.hasOwnProperty(a.namespaceURI)||"br"===a.localName&&n.isLineBreak(a.parentNode)||a.nodeType===Node.TEXT_NODE&&d.hasOwnProperty(a.parentNode.namespaceURI)}function e(a){if(n.isCharacterElement(a))return!1;if(a.nodeType===Node.TEXT_NODE)return 0===a.textContent.length;for(a=a.firstChild;a;){if(d.hasOwnProperty(a.namespaceURI)||!e(a))return!1;a=a.nextSibling}return!0}function a(b){var d;b.nodeType===Node.TEXT_NODE?(d=b.parent [...]
- d=h.removeUnwantedNodes(b,c);return!n.isParagraph(d)&&d!==f&&e(d)?a(d):d}this.isEmpty=e;this.mergeChildrenIntoParent=a}var l,f,p,r,n,h,d={};this.init=function(g){runtime.assert(0<=g.length,"OpRemoveText only supports positive lengths");l=g.memberid;f=g.timestamp;p=parseInt(g.position,10);r=parseInt(g.length,10);n=new odf.OdfUtils;h=new core.DomUtils;d[odf.Namespaces.dbns]=!0;d[odf.Namespaces.dcns]=!0;d[odf.Namespaces.dr3dns]=!0;d[odf.Namespaces.drawns]=!0;d[odf.Namespaces.chartns]=!0;d[ [...]
- !0;d[odf.Namespaces.numberns]=!0;d[odf.Namespaces.officens]=!0;d[odf.Namespaces.presentationns]=!0;d[odf.Namespaces.stylens]=!0;d[odf.Namespaces.svgns]=!0;d[odf.Namespaces.tablens]=!0;d[odf.Namespaces.textns]=!0};this.isEdit=!0;this.execute=function(d){var c,e,a,b,q=d.getCursor(l),k=new g(d.getRootNode());d.upgradeWhitespacesAtPosition(p);d.upgradeWhitespacesAtPosition(p+r);e=d.convertCursorToDomRange(p,r);h.splitBoundaries(e);c=d.getParagraphElement(e.startContainer);a=n.getTextElement [...]
- b=n.getParagraphElements(e);e.detach();a.forEach(function(a){k.mergeChildrenIntoParent(a)});e=b.reduce(function(a,b){var c,d=!1,e=a,f=b,h,g=null;k.isEmpty(a)&&(d=!0,b.parentNode!==a.parentNode&&(h=b.parentNode,a.parentNode.insertBefore(b,a.nextSibling)),f=a,e=b,g=e.getElementsByTagNameNS("urn:webodf:names:editinfo","editinfo")[0]||e.firstChild);for(;f.hasChildNodes();)c=d?f.lastChild:f.firstChild,f.removeChild(c),"editinfo"!==c.localName&&e.insertBefore(c,g);h&&k.isEmpty(h)&&k.mergeChil [...]
- k.mergeChildrenIntoParent(f);return e});d.emit(ops.OdtDocument.signalStepsRemoved,{position:p,length:r});d.downgradeWhitespacesAtPosition(p);d.fixCursorPositions();d.getOdfCanvas().refreshSize();d.emit(ops.OdtDocument.signalParagraphChanged,{paragraphElement:e||c,memberId:l,timeStamp:f});q&&(q.resetSelectionType(),d.emit(ops.OdtDocument.signalCursorMoved,q));d.getOdfCanvas().rerenderAnnotations();return!0};this.spec=function(){return{optype:"RemoveText",memberid:l,timestamp:f,position:p [...]
- // Input 75
++ops.OperationFactory=function(){var m;this.register=function(h,b){m[h]=b};this.create=function(h){var b=null,g=m[h.optype];g&&(b=new g,b.init(h));return b};m={AddMember:ops.OpAddMember,UpdateMember:ops.OpUpdateMember,RemoveMember:ops.OpRemoveMember,AddCursor:ops.OpAddCursor,ApplyDirectStyling:ops.OpApplyDirectStyling,SetBlob:ops.OpSetBlob,RemoveBlob:ops.OpRemoveBlob,InsertImage:ops.OpInsertImage,InsertTable:ops.OpInsertTable,InsertText:ops.OpInsertText,RemoveText:ops.OpRemoveText,SplitP [...]
++SetParagraphStyle:ops.OpSetParagraphStyle,UpdateParagraphStyle:ops.OpUpdateParagraphStyle,AddStyle:ops.OpAddStyle,RemoveStyle:ops.OpRemoveStyle,MoveCursor:ops.OpMoveCursor,RemoveCursor:ops.OpRemoveCursor,AddAnnotation:ops.OpAddAnnotation,RemoveAnnotation:ops.OpRemoveAnnotation,UpdateMetadata:ops.OpUpdateMetadata,ApplyHyperlink:ops.OpApplyHyperlink,RemoveHyperlink:ops.OpRemoveHyperlink}};
++// Input 71
 +/*
 +
-  Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
++ Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- ops.OpSetBlob=function(){var g,l,f,p,r;this.init=function(n){g=n.memberid;l=n.timestamp;f=n.filename;p=n.mimetype;r=n.content};this.isEdit=!0;this.execute=function(g){g.getOdfCanvas().odfContainer().setBlob(f,p,r);return!0};this.spec=function(){return{optype:"SetBlob",memberid:g,timestamp:l,filename:f,mimetype:p,content:r}}};
- // Input 76
++ops.OperationRouter=function(){};ops.OperationRouter.prototype.setOperationFactory=function(m){};ops.OperationRouter.prototype.setPlaybackFunction=function(m){};ops.OperationRouter.prototype.push=function(m){};ops.OperationRouter.prototype.close=function(m){};ops.OperationRouter.prototype.subscribe=function(m,h){};ops.OperationRouter.prototype.unsubscribe=function(m,h){};ops.OperationRouter.prototype.hasLocalUnsyncedOps=function(){};ops.OperationRouter.prototype.hasSessionHostConnection [...]
++ops.OperationRouter.signalProcessingBatchStart="router/batchstart";ops.OperationRouter.signalProcessingBatchEnd="router/batchend";
++// Input 72
 +/*
 +
-  Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
++ Copyright (C) 2012 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- ops.OpSetParagraphStyle=function(){var g,l,f,p;this.init=function(r){g=r.memberid;l=r.timestamp;f=r.position;p=r.styleName};this.isEdit=!0;this.execute=function(r){var n;n=r.getIteratorAtPosition(f);return(n=r.getParagraphElement(n.container()))?(""!==p?n.setAttributeNS("urn:oasis:names:tc:opendocument:xmlns:text:1.0","text:style-name",p):n.removeAttributeNS("urn:oasis:names:tc:opendocument:xmlns:text:1.0","style-name"),r.getOdfCanvas().refreshSize(),r.emit(ops.OdtDocument.signalParagra [...]
- {paragraphElement:n,timeStamp:l,memberId:g}),r.getOdfCanvas().rerenderAnnotations(),!0):!1};this.spec=function(){return{optype:"SetParagraphStyle",memberid:g,timestamp:l,position:f,styleName:p}}};
- // Input 77
++ops.TrivialOperationRouter=function(){var m=new core.EventNotifier([ops.OperationRouter.signalProcessingBatchStart,ops.OperationRouter.signalProcessingBatchEnd]),h,b,g=0;this.setOperationFactory=function(b){h=b};this.setPlaybackFunction=function(d){b=d};this.push=function(d){g+=1;m.emit(ops.OperationRouter.signalProcessingBatchStart,{});d.forEach(function(d){d=d.spec();d.timestamp=(new Date).getTime();d=h.create(d);d.group="g"+g;b(d)});m.emit(ops.OperationRouter.signalProcessingBatchEnd [...]
++function(b){b()};this.subscribe=function(b,g){m.subscribe(b,g)};this.unsubscribe=function(b,g){m.unsubscribe(b,g)};this.hasLocalUnsyncedOps=function(){return!1};this.hasSessionHostConnection=function(){return!0}};
++// Input 73
 +/*
 +
 + Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- ops.OpSplitParagraph=function(){var g,l,f,p,r;this.init=function(n){g=n.memberid;l=n.timestamp;f=n.position;p="true"===n.moveCursor||!0===n.moveCursor;r=new odf.OdfUtils};this.isEdit=!0;this.execute=function(n){var h,d,m,c,e,a,b,q=n.getCursor(g);n.upgradeWhitespacesAtPosition(f);h=n.getTextNodeAtStep(f);if(!h)return!1;d=n.getParagraphElement(h.textNode);if(!d)return!1;m=r.isListItem(d.parentNode)?d.parentNode:d;0===h.offset?(b=h.textNode.previousSibling,a=null):(b=h.textNode,a=h.offset> [...]
- null:h.textNode.splitText(h.offset));for(c=h.textNode;c!==m;){c=c.parentNode;e=c.cloneNode(!1);a&&e.appendChild(a);if(b)for(;b&&b.nextSibling;)e.appendChild(b.nextSibling);else for(;c.firstChild;)e.appendChild(c.firstChild);c.parentNode.insertBefore(e,c.nextSibling);b=c;a=e}r.isListItem(a)&&(a=a.childNodes[0]);0===h.textNode.length&&h.textNode.parentNode.removeChild(h.textNode);n.emit(ops.OdtDocument.signalStepsInserted,{position:f,length:1});q&&p&&(n.moveCursor(g,f+1,0),n.emit(ops.OdtD [...]
- q));n.fixCursorPositions();n.getOdfCanvas().refreshSize();n.emit(ops.OdtDocument.signalParagraphChanged,{paragraphElement:d,memberId:g,timeStamp:l});n.emit(ops.OdtDocument.signalParagraphChanged,{paragraphElement:a,memberId:g,timeStamp:l});n.getOdfCanvas().rerenderAnnotations();return!0};this.spec=function(){return{optype:"SplitParagraph",memberid:g,timestamp:l,position:f,moveCursor:p}}};
- // Input 78
++ops.Session=function(m){function h(b){d.emit(ops.OdtDocument.signalProcessingBatchStart,b)}function b(b){d.emit(ops.OdtDocument.signalProcessingBatchEnd,b)}var g=new ops.OperationFactory,d=new ops.OdtDocument(m),n=null;this.setOperationFactory=function(b){g=b;n&&n.setOperationFactory(g)};this.setOperationRouter=function(m){n&&(n.unsubscribe(ops.OperationRouter.signalProcessingBatchStart,h),n.unsubscribe(ops.OperationRouter.signalProcessingBatchEnd,b));n=m;n.subscribe(ops.OperationRouter [...]
++h);n.subscribe(ops.OperationRouter.signalProcessingBatchEnd,b);m.setPlaybackFunction(function(b){d.emit(ops.OdtDocument.signalOperationStart,b);return b.execute(d)?(d.emit(ops.OdtDocument.signalOperationEnd,b),!0):!1});m.setOperationFactory(g)};this.getOperationFactory=function(){return g};this.getOdtDocument=function(){return d};this.enqueue=function(b){n.push(b)};this.close=function(b){n.close(function(g){g?b(g):d.close(b)})};this.destroy=function(b){d.destroy(b)};this.setOperationRou [...]
++// Input 74
 +/*
 +
 + Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + This file is part of WebODF.
 +
 + WebODF is free software: you can redistribute it and/or modify it
 + under the terms of the GNU Affero General Public License (GNU AGPL)
 + as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.
 +
 + WebODF is distributed in the hope that it will be useful, but
 + WITHOUT ANY WARRANTY; without even the implied warranty of
 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + GNU Affero General Public License for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with WebODF.  If not, see <http://www.gnu.org/licenses/>.
 + @licend
 +
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("ops.Member");runtime.loadClass("xmldom.XPath");
- ops.OpUpdateMember=function(){function g(){var f="//dc:creator[@editinfo:memberid='"+l+"']",f=xmldom.XPath.getODFElementsWithXPath(n.getRootNode(),f,function(d){return"editinfo"===d?"urn:webodf:names:editinfo":odf.Namespaces.lookupNamespaceURI(d)}),d;for(d=0;d<f.length;d+=1)f[d].textContent=p.fullName}var l,f,p,r,n;this.init=function(h){l=h.memberid;f=parseInt(h.timestamp,10);p=h.setProperties;r=h.removedProperties};this.isEdit=!1;this.execute=function(f){n=f;var d=f.getMember(l);if(!d) [...]
- d.removeProperties(r);p&&(d.setProperties(p),p.fullName&&g());f.emit(ops.OdtDocument.signalMemberUpdated,d);return!0};this.spec=function(){return{optype:"UpdateMember",memberid:l,timestamp:f,setProperties:p,removedProperties:r}}};
- // Input 79
++gui.AnnotationController=function(m,h){function b(){var b=p.getCursor(h),b=b&&b.getNode(),a=!1;if(b){a:{for(a=p.getRootNode();b&&b!==a;){if(b.namespaceURI===e&&"annotation"===b.localName){b=!0;break a}b=b.parentNode}b=!1}a=!b}a!==k&&(k=a,q.emit(gui.AnnotationController.annotatableChanged,k))}function g(d){d.getMemberId()===h&&b()}function d(d){d===h&&b()}function n(d){d.getMemberId()===h&&b()}var p=m.getOdtDocument(),k=!1,q=new core.EventNotifier([gui.AnnotationController.annotatableCha [...]
++this.isAnnotatable=function(){return k};this.addAnnotation=function(){var b=new ops.OpAddAnnotation,a=p.getCursorSelection(h),c=a.length,a=a.position;k&&(a=0<=c?a:a+c,c=Math.abs(c),b.init({memberid:h,position:a,length:c,name:h+Date.now()}),m.enqueue([b]))};this.removeAnnotation=function(b){var a,c;a=p.convertDomPointToCursorStep(b,0)+1;c=p.convertDomPointToCursorStep(b,b.childNodes.length);b=new ops.OpRemoveAnnotation;b.init({memberid:h,position:a,length:c-a});c=new ops.OpMoveCursor;c.i [...]
++position:0<a?a-1:a,length:0});m.enqueue([b,c])};this.subscribe=function(b,a){q.subscribe(b,a)};this.unsubscribe=function(b,a){q.unsubscribe(b,a)};this.destroy=function(b){p.unsubscribe(ops.Document.signalCursorAdded,g);p.unsubscribe(ops.Document.signalCursorRemoved,d);p.unsubscribe(ops.Document.signalCursorMoved,n);b()};p.subscribe(ops.Document.signalCursorAdded,g);p.subscribe(ops.Document.signalCursorRemoved,d);p.subscribe(ops.Document.signalCursorMoved,n);b()};
++gui.AnnotationController.annotatableChanged="annotatable/changed";(function(){return gui.AnnotationController})();
++// Input 75
++gui.Avatar=function(m,h){var b=this,g,d,n;this.setColor=function(b){d.style.borderColor=b};this.setImageUrl=function(g){b.isVisible()?d.src=g:n=g};this.isVisible=function(){return"block"===g.style.display};this.show=function(){n&&(d.src=n,n=void 0);g.style.display="block"};this.hide=function(){g.style.display="none"};this.markAsFocussed=function(b){b?g.classList.add("active"):g.classList.remove("active")};this.destroy=function(b){m.removeChild(g);b()};(function(){var b=m.ownerDocument,k [...]
++g=b.createElementNS(k,"div");d=b.createElementNS(k,"img");d.width=64;d.height=64;g.appendChild(d);g.style.width="64px";g.style.height="70px";g.style.position="absolute";g.style.top="-80px";g.style.left="-34px";g.style.display=h?"block":"none";g.className="handle";m.appendChild(g)})()};
++// Input 76
++gui.Caret=function(m,h,b){function g(){q.style.opacity="0"===q.style.opacity?"1":"0";v.trigger()}function d(a,b){var c=a.getBoundingClientRect(),d=0,e=0;c&&b&&(d=Math.max(c.top,b.top),e=Math.min(c.bottom,b.bottom));return e-d}function n(){Object.keys(t).forEach(function(a){u[a]=t[a]})}function p(){var f,g,l,h;if(!1===t.isShown||m.getSelectionType()!==ops.OdtCursor.RangeSelection||!b&&!m.getSelectedRange().collapsed)t.visibility="hidden",q.style.visibility="hidden",v.cancel();else{t.visi [...]
++q.style.visibility="visible";if(!1===t.isFocused)q.style.opacity="1",v.cancel();else{if(w||u.visibility!==t.visibility)q.style.opacity="1",v.cancel();v.trigger()}if(x||z||u.visibility!==t.visibility){f=m.getSelectedRange().cloneRange();g=m.getNode();var k=null;g.previousSibling&&(l=g.previousSibling.nodeType===Node.TEXT_NODE?g.previousSibling.textContent.length:g.previousSibling.childNodes.length,f.setStart(g.previousSibling,0<l?l-1:0),f.setEnd(g.previousSibling,l),(l=f.getBoundingClien [...]
++l.height&&(k=l));g.nextSibling&&(f.setStart(g.nextSibling,0),f.setEnd(g.nextSibling,0<(g.nextSibling.nodeType===Node.TEXT_NODE?g.nextSibling.textContent.length:g.nextSibling.childNodes.length)?1:0),(l=f.getBoundingClientRect())&&l.height&&(!k||d(g,l)>d(g,k))&&(k=l));g=k;k=m.getDocument().getCanvas();f=k.getZoomLevel();k=c.getBoundingClientRect(k.getSizer());g?(q.style.top="0",l=c.getBoundingClientRect(q),8>g.height&&(g={top:g.top-(8-g.height)/2,height:8}),q.style.height=c.adaptRangeDiff [...]
++f)+"px",q.style.top=c.adaptRangeDifferenceToZoomLevel(g.top-l.top,f)+"px"):(q.style.height="1em",q.style.top="5%");a&&(g=runtime.getWindow().getComputedStyle(q,null),l=c.getBoundingClientRect(q),a.style.bottom=c.adaptRangeDifferenceToZoomLevel(k.bottom-l.bottom,f)+"px",a.style.left=c.adaptRangeDifferenceToZoomLevel(l.right-k.left,f)+"px",g.font?a.style.font=g.font:(a.style.fontStyle=g.fontStyle,a.style.fontVariant=g.fontVariant,a.style.fontWeight=g.fontWeight,a.style.fontSize=g.fontSize [...]
++g.lineHeight,a.style.fontFamily=g.fontFamily))}if(z){var k=m.getDocument().getCanvas().getElement().parentNode,p;l=k.offsetWidth-k.clientWidth+5;h=k.offsetHeight-k.clientHeight+5;p=q.getBoundingClientRect();f=p.left-l;g=p.top-h;l=p.right+l;h=p.bottom+h;p=k.getBoundingClientRect();g<p.top?k.scrollTop-=p.top-g:h>p.bottom&&(k.scrollTop+=h-p.bottom);f<p.left?k.scrollLeft-=p.left-f:l>p.right&&(k.scrollLeft+=l-p.right)}}u.isFocused!==t.isFocused&&e.markAsFocussed(t.isFocused);n();x=z=w=!1}fun [...]
++a()}var q,e,r,a,c=new core.DomUtils,l=new core.Async,f,v,w=!1,z=!1,x=!1,t={isFocused:!1,isShown:!0,visibility:"hidden"},u={isFocused:!t.isFocused,isShown:!t.isShown,visibility:"hidden"};this.handleUpdate=function(){x=!0;"hidden"!==t.visibility&&(t.visibility="hidden",q.style.visibility="hidden");f.trigger()};this.refreshCursorBlinking=function(){w=!0;f.trigger()};this.setFocus=function(){t.isFocused=!0;f.trigger()};this.removeFocus=function(){t.isFocused=!1;f.trigger()};this.show=functi [...]
++!0;f.trigger()};this.hide=function(){t.isShown=!1;f.trigger()};this.setAvatarImageUrl=function(a){e.setImageUrl(a)};this.setColor=function(a){q.style.borderColor=a;e.setColor(a)};this.getCursor=function(){return m};this.getFocusElement=function(){return q};this.toggleHandleVisibility=function(){e.isVisible()?e.hide():e.show()};this.showHandle=function(){e.show()};this.hideHandle=function(){e.hide()};this.setOverlayElement=function(b){a=b;x=!0;f.trigger()};this.ensureVisible=function(){z [...]
++this.destroy=function(a){l.destroyAll([f.destroy,v.destroy,e.destroy,k],a)};(function(){var a=m.getDocument().getDOMDocument();q=a.createElementNS(a.documentElement.namespaceURI,"span");q.className="caret";q.style.top="5%";r=m.getNode();r.appendChild(q);e=new gui.Avatar(r,h);f=new core.ScheduledTask(p,0);v=new core.ScheduledTask(g,500);f.triggerImmediate()})()};
++// Input 77
++/*
++
++ Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
++
++ @licstart
++ The JavaScript code in this page is free software: you can redistribute it
++ and/or modify it under the terms of the GNU Affero General Public License
++ (GNU AGPL) as published by the Free Software Foundation, either version 3 of
++ the License, or (at your option) any later version.  The code is distributed
++ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
++
++ You should have received a copy of the GNU Affero General Public License
++ along with this code.  If not, see <http://www.gnu.org/licenses/>.
++
++ As additional permission under GNU AGPL version 3 section 7, you
++ may distribute non-source (e.g., minimized or compacted) forms of
++ that code without the copy of the GNU GPL normally required by
++ section 4, provided you include this license notice and a URL
++ through which recipients can access the Corresponding Source.
++
++ As a special exception to the AGPL, any HTML file which merely makes function
++ calls to this code, and for that purpose includes it by reference shall be
++ deemed a separate work for copyright law purposes. In addition, the copyright
++ holders of this code give you permission to combine this code with free
++ software libraries that are released under the GNU LGPL. You may copy and
++ distribute such a system following the terms of the GNU AGPL for this code
++ and the LGPL for the libraries. If you modify this code, you may extend this
++ exception to your version of the code, but you are not obligated to do so.
++ If you do not wish to do so, delete this exception statement from your
++ version.
++
++ This license applies to this entire compilation.
++ @licend
++ @source: http://www.webodf.org/
++ @source: https://github.com/kogmbh/WebODF/
++*/
++odf.TextSerializer=function(){function m(g){var d="",n=h.filter?h.filter.acceptNode(g):NodeFilter.FILTER_ACCEPT,p=g.nodeType,k;if((n===NodeFilter.FILTER_ACCEPT||n===NodeFilter.FILTER_SKIP)&&b.isTextContentContainingNode(g))for(k=g.firstChild;k;)d+=m(k),k=k.nextSibling;n===NodeFilter.FILTER_ACCEPT&&(p===Node.ELEMENT_NODE&&b.isParagraph(g)?d+="\n":p===Node.TEXT_NODE&&g.textContent&&(d+=g.textContent));return d}var h=this,b=new odf.OdfUtils;this.filter=null;this.writeToString=function(b){i [...]
++b=m(b);"\n"===b[b.length-1]&&(b=b.substr(0,b.length-1));return b}};
++// Input 78
 +/*
 +
 + Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + This file is part of WebODF.
 +
 + WebODF is free software: you can redistribute it and/or modify it
 + under the terms of the GNU Affero General Public License (GNU AGPL)
 + as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.
 +
 + WebODF is distributed in the hope that it will be useful, but
 + WITHOUT ANY WARRANTY; without even the implied warranty of
 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + GNU Affero General Public License for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with WebODF.  If not, see <http://www.gnu.org/licenses/>.
 + @licend
 +
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- ops.OpUpdateMetadata=function(){var g,l,f,p;this.init=function(r){g=r.memberid;l=parseInt(r.timestamp,10);f=r.setProperties;p=r.removedProperties};this.isEdit=!0;this.execute=function(g){g=g.getOdfCanvas().odfContainer();var l=[],h=["dc:date","dc:creator","meta:editing-cycles"];f&&h.forEach(function(d){if(f[d])return!1});p&&(h.forEach(function(d){if(-1!==l.indexOf(d))return!1}),l=p.attributes.split(","));g.setMetadata(f,l);return!0};this.spec=function(){return{optype:"UpdateMetadata",me [...]
- setProperties:f,removedProperties:p}}};
- // Input 80
++gui.MimeDataExporter=function(){var m,h;this.exportRangeToDataTransfer=function(b,g){var d;d=g.startContainer.ownerDocument.createElement("span");d.appendChild(g.cloneContents());d=m.writeToString(d);try{b.setData("text/plain",d)}catch(h){b.setData("Text",d)}};m=new odf.TextSerializer;h=new odf.OdfNodeFilter;m.filter=h};
++// Input 79
 +/*
 +
-  Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
++ Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("odf.Namespaces");
- ops.OpUpdateParagraphStyle=function(){function g(d,f){var c,e,a=f?f.split(","):[];for(c=0;c<a.length;c+=1)e=a[c].split(":"),d.removeAttributeNS(odf.Namespaces.lookupNamespaceURI(e[0]),e[1])}var l,f,p,r,n,h=odf.Namespaces.stylens;this.init=function(d){l=d.memberid;f=d.timestamp;p=d.styleName;r=d.setProperties;n=d.removedProperties};this.isEdit=!0;this.execute=function(d){var f=d.getFormatting(),c,e,a;return(c=""!==p?d.getParagraphStyleElement(p):f.getDefaultStyleElement("paragraph"))?(e= [...]
- "paragraph-properties")[0],a=c.getElementsByTagNameNS(h,"text-properties")[0],r&&f.updateStyle(c,r),n&&(n["style:paragraph-properties"]&&(g(e,n["style:paragraph-properties"].attributes),0===e.attributes.length&&c.removeChild(e)),n["style:text-properties"]&&(g(a,n["style:text-properties"].attributes),0===a.attributes.length&&c.removeChild(a)),g(c,n.attributes)),d.getOdfCanvas().refreshCSS(),d.emit(ops.OdtDocument.signalParagraphStyleModified,p),d.getOdfCanvas().rerenderAnnotations(),!0): [...]
- function(){return{optype:"UpdateParagraphStyle",memberid:l,timestamp:f,styleName:p,setProperties:r,removedProperties:n}}};
- // Input 81
++gui.Clipboard=function(m){this.setDataFromRange=function(h,b){var g,d=h.clipboardData;g=runtime.getWindow();!d&&g&&(d=g.clipboardData);d?(g=!0,m.exportRangeToDataTransfer(d,b),h.preventDefault()):g=!1;return g}};
++// Input 80
 +/*
 +
-  Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
++ Copyright (C) 2012-2014 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("ops.OpAddMember");runtime.loadClass("ops.OpUpdateMember");runtime.loadClass("ops.OpRemoveMember");runtime.loadClass("ops.OpAddCursor");runtime.loadClass("ops.OpApplyDirectStyling");runtime.loadClass("ops.OpRemoveCursor");runtime.loadClass("ops.OpMoveCursor");runtime.loadClass("ops.OpSetBlob");runtime.loadClass("ops.OpRemoveBlob");runtime.loadClass("ops.OpInsertImage");runtime.loadClass("ops.OpInsertTable");runtime.loadClass("ops.OpInsertText");runtime.loadClass("ops.O [...]
- runtime.loadClass("ops.OpSplitParagraph");runtime.loadClass("ops.OpSetParagraphStyle");runtime.loadClass("ops.OpUpdateParagraphStyle");runtime.loadClass("ops.OpAddStyle");runtime.loadClass("ops.OpRemoveStyle");runtime.loadClass("ops.OpAddAnnotation");runtime.loadClass("ops.OpRemoveAnnotation");runtime.loadClass("ops.OpUpdateMetadata");
- ops.OperationFactory=function(){function g(f){return function(){return new f}}var l;this.register=function(f,g){l[f]=g};this.create=function(f){var g=null,r=l[f.optype];r&&(g=r(f),g.init(f));return g};l={AddMember:g(ops.OpAddMember),UpdateMember:g(ops.OpUpdateMember),RemoveMember:g(ops.OpRemoveMember),AddCursor:g(ops.OpAddCursor),ApplyDirectStyling:g(ops.OpApplyDirectStyling),SetBlob:g(ops.OpSetBlob),RemoveBlob:g(ops.OpRemoveBlob),InsertImage:g(ops.OpInsertImage),InsertTable:g(ops.OpIns [...]
- InsertText:g(ops.OpInsertText),RemoveText:g(ops.OpRemoveText),SplitParagraph:g(ops.OpSplitParagraph),SetParagraphStyle:g(ops.OpSetParagraphStyle),UpdateParagraphStyle:g(ops.OpUpdateParagraphStyle),AddStyle:g(ops.OpAddStyle),RemoveStyle:g(ops.OpRemoveStyle),MoveCursor:g(ops.OpMoveCursor),RemoveCursor:g(ops.OpRemoveCursor),AddAnnotation:g(ops.OpAddAnnotation),RemoveAnnotation:g(ops.OpRemoveAnnotation),UpdateMetadata:g(ops.OpUpdateMetadata)}};
- // Input 82
++gui.StyleSummary=function(m){function h(b,g){var k=b+"|"+g,h;d.hasOwnProperty(k)||(h=[],m.forEach(function(d){d=(d=d[b])&&d[g];-1===h.indexOf(d)&&h.push(d)}),d[k]=h);return d[k]}function b(b,d,g){return function(){var m=h(b,d);return g.length>=m.length&&m.every(function(b){return-1!==g.indexOf(b)})}}function g(b,d){var g=h(b,d);return 1===g.length?g[0]:void 0}var d={};this.getPropertyValues=h;this.getCommonValue=g;this.isBold=b("style:text-properties","fo:font-weight",["bold"]);this.isI [...]
++"fo:font-style",["italic"]);this.hasUnderline=b("style:text-properties","style:text-underline-style",["solid"]);this.hasStrikeThrough=b("style:text-properties","style:text-line-through-style",["solid"]);this.fontSize=function(){var b=g("style:text-properties","fo:font-size");return b&&parseFloat(b)};this.fontName=function(){return g("style:text-properties","style:font-name")};this.isAlignedLeft=b("style:paragraph-properties","fo:text-align",["left","start"]);this.isAlignedCenter=b("styl [...]
++"fo:text-align",["center"]);this.isAlignedRight=b("style:paragraph-properties","fo:text-align",["right","end"]);this.isAlignedJustified=b("style:paragraph-properties","fo:text-align",["justify"]);this.text={isBold:this.isBold,isItalic:this.isItalic,hasUnderline:this.hasUnderline,hasStrikeThrough:this.hasStrikeThrough,fontSize:this.fontSize,fontName:this.fontName};this.paragraph={isAlignedLeft:this.isAlignedLeft,isAlignedCenter:this.isAlignedCenter,isAlignedRight:this.isAlignedRight,isAl [...]
++// Input 81
 +/*
 +
 + Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- ops.OperationRouter=function(){};ops.OperationRouter.prototype.setOperationFactory=function(g){};ops.OperationRouter.prototype.setPlaybackFunction=function(g){};ops.OperationRouter.prototype.push=function(g){};ops.OperationRouter.prototype.close=function(g){};ops.OperationRouter.prototype.subscribe=function(g,l){};ops.OperationRouter.prototype.unsubscribe=function(g,l){};ops.OperationRouter.prototype.hasLocalUnsyncedOps=function(){};ops.OperationRouter.prototype.hasSessionHostConnection [...]
++gui.DirectFormattingController=function(m,h,b,g){function d(a){var b;a.collapsed?(b=a.startContainer,b.hasChildNodes()&&a.startOffset<b.childNodes.length&&(b=b.childNodes.item(a.startOffset)),a=[b]):a=T.getTextNodes(a,!0);return a}function n(a,b){var c={};Object.keys(a).forEach(function(d){var f=a[d](),e=b[d]();f!==e&&(c[d]=e)});return c}function p(){var a,b,c;a=(a=(a=H.getCursor(h))&&a.getSelectedRange())?d(a):[];a=H.getFormatting().getAppliedStyles(a);a[0]&&G&&(a[0]=U.mergeObjects(a[0 [...]
++c=new gui.StyleSummary(J);a=n(Q.text,c.text);b=n(Q.paragraph,c.paragraph);Q=c;0<Object.keys(a).length&&X.emit(gui.DirectFormattingController.textStylingChanged,a);0<Object.keys(b).length&&X.emit(gui.DirectFormattingController.paragraphStylingChanged,b)}function k(a){("string"===typeof a?a:a.getMemberId())===h&&p()}function q(){p()}function e(a){var b=H.getCursor(h);a=a.paragraphElement;b&&H.getParagraphElement(b.getNode())===a&&p()}function r(a,b){b(!a());return!0}function a(a){var b=H. [...]
++c={"style:text-properties":a};0!==b.length?(a=new ops.OpApplyDirectStyling,a.init({memberid:h,position:b.position,length:b.length,setProperties:c}),m.enqueue([a])):(G=U.mergeObjects(G||{},c),p())}function c(b,c){var d={};d[b]=c;a(d)}function l(a){a=a.spec();G&&a.memberid===h&&"SplitParagraph"!==a.optype&&(G=null,p())}function f(a){c("fo:font-weight",a?"bold":"normal")}function v(a){c("fo:font-style",a?"italic":"normal")}function w(a){c("style:text-underline-style",a?"solid":"none")}func [...]
++a?"solid":"none")}function x(a){return a===ops.StepsTranslator.NEXT_STEP}function t(a){var c=H.getCursor(h).getSelectedRange(),c=T.getParagraphElements(c),d=H.getFormatting(),f=[],e={},g;c.forEach(function(c){var l=H.convertDomPointToCursorStep(c,0,x),k=c.getAttributeNS(odf.Namespaces.textns,"style-name"),m;c=k?e.hasOwnProperty(k)?e[k]:void 0:g;c||(c=b.generateStyleName(),k?(e[k]=c,m=d.createDerivedStyleObject(k,"paragraph",{})):(g=c,m={}),m=a(m),k=new ops.OpAddStyle,k.init({memberid:h, [...]
++styleFamily:"paragraph",isAutomaticStyle:!0,setProperties:m}),f.push(k));k=new ops.OpSetParagraphStyle;k.init({memberid:h,styleName:c.toString(),position:l});f.push(k)});m.enqueue(f)}function u(a){t(function(b){return U.mergeObjects(b,a)})}function s(a){u({"style:paragraph-properties":{"fo:text-align":a}})}function y(a,b){var c=H.getFormatting().getDefaultTabStopDistance(),d=b["style:paragraph-properties"],f;d&&(d=d["fo:margin-left"])&&(f=T.parseLength(d));return U.mergeObjects(b,{"styl [...]
++f.unit===c.unit?f.value+a*c.value+f.unit:a*c.value+c.unit}})}function F(a,b){var c=d(a),f=H.getFormatting().getAppliedStyles(c)[0],e=H.getFormatting().getAppliedStylesForElement(b);if(!f||"text"!==f["style:family"]||!f["style:text-properties"])return!1;if(!e||!e["style:text-properties"])return!0;f=f["style:text-properties"];e=e["style:text-properties"];return!Object.keys(f).every(function(a){return f[a]===e[a]})}function L(){}var O=this,H=m.getOdtDocument(),U=new core.Utils,T=new odf.Od [...]
++gui.DirectFormattingController.paragraphStylingChanged]),D=odf.Namespaces.textns,ba=core.PositionFilter.FilterResult.FILTER_ACCEPT,G,J=[],Q=new gui.StyleSummary(J);this.formatTextSelection=a;this.createCursorStyleOp=function(a,b,c){var d=null;(c=c?J[0]:G)&&c["style:text-properties"]&&(d=new ops.OpApplyDirectStyling,d.init({memberid:h,position:a,length:b,setProperties:{"style:text-properties":c["style:text-properties"]}}),G=null,p());return d};this.setBold=f;this.setItalic=v;this.setHasU [...]
++this.setHasStrikethrough=z;this.setFontSize=function(a){c("fo:font-size",a+"pt")};this.setFontName=function(a){c("style:font-name",a)};this.getAppliedStyles=function(){return J};this.toggleBold=r.bind(O,function(){return Q.isBold()},f);this.toggleItalic=r.bind(O,function(){return Q.isItalic()},v);this.toggleUnderline=r.bind(O,function(){return Q.hasUnderline()},w);this.toggleStrikethrough=r.bind(O,function(){return Q.hasStrikeThrough()},z);this.isBold=function(){return Q.isBold()};this. [...]
++this.hasUnderline=function(){return Q.hasUnderline()};this.hasStrikeThrough=function(){return Q.hasStrikeThrough()};this.fontSize=function(){return Q.fontSize()};this.fontName=function(){return Q.fontName()};this.isAlignedLeft=function(){return Q.isAlignedLeft()};this.isAlignedCenter=function(){return Q.isAlignedCenter()};this.isAlignedRight=function(){return Q.isAlignedRight()};this.isAlignedJustified=function(){return Q.isAlignedJustified()};this.alignParagraphLeft=function(){s("left" [...]
++this.alignParagraphCenter=function(){s("center");return!0};this.alignParagraphRight=function(){s("right");return!0};this.alignParagraphJustified=function(){s("justify");return!0};this.indent=function(){t(y.bind(null,1));return!0};this.outdent=function(){t(y.bind(null,-1));return!0};this.createParagraphStyleOps=function(a){var c=H.getCursor(h),d=c.getSelectedRange(),f=[],e,g;c.hasForwardSelection()?(e=c.getAnchorNode(),g=c.getNode()):(e=c.getNode(),g=c.getAnchorNode());c=H.getParagraphEl [...]
++"DirectFormattingController: Cursor outside paragraph");var l;a:{l=c;var k=gui.SelectionMover.createPositionIterator(l),m=new core.PositionFilterChain;m.addFilter(H.getPositionFilter());m.addFilter(H.createRootFilter(h));for(k.setUnfilteredPosition(d.endContainer,d.endOffset);k.nextPosition();)if(m.acceptPosition(k)===ba){l=H.getParagraphElement(k.getCurrentNode())!==l;break a}l=!0}if(!l)return f;g!==e&&(c=H.getParagraphElement(e));if(!G&&!F(d,c))return f;d=J[0];if(!d)return f;if(e=c.ge [...]
++"style-name"))d={"style:text-properties":d["style:text-properties"]},d=H.getFormatting().createDerivedStyleObject(e,"paragraph",d);c=b.generateStyleName();e=new ops.OpAddStyle;e.init({memberid:h,styleName:c,styleFamily:"paragraph",isAutomaticStyle:!0,setProperties:d});f.push(e);e=new ops.OpSetParagraphStyle;e.init({memberid:h,styleName:c,position:a});f.push(e);return f};this.subscribe=function(a,b){X.subscribe(a,b)};this.unsubscribe=function(a,b){X.unsubscribe(a,b)};this.destroy=functio [...]
++k);H.unsubscribe(ops.Document.signalCursorRemoved,k);H.unsubscribe(ops.Document.signalCursorMoved,k);H.unsubscribe(ops.OdtDocument.signalParagraphStyleModified,q);H.unsubscribe(ops.OdtDocument.signalParagraphChanged,e);H.unsubscribe(ops.OdtDocument.signalOperationEnd,l);a()};(function(){H.subscribe(ops.Document.signalCursorAdded,k);H.subscribe(ops.Document.signalCursorRemoved,k);H.subscribe(ops.Document.signalCursorMoved,k);H.subscribe(ops.OdtDocument.signalParagraphStyleModified,q);H.s [...]
++e);H.subscribe(ops.OdtDocument.signalOperationEnd,l);p();g||(O.alignParagraphCenter=L,O.alignParagraphJustified=L,O.alignParagraphLeft=L,O.alignParagraphRight=L,O.createParagraphStyleOps=function(){return[]},O.indent=L,O.outdent=L)})()};gui.DirectFormattingController.textStylingChanged="textStyling/changed";gui.DirectFormattingController.paragraphStylingChanged="paragraphStyling/changed";(function(){return gui.DirectFormattingController})();
++// Input 82
++gui.HyperlinkClickHandler=function(m){function h(){m().removeAttributeNS("urn:webodf:names:helper","links")}function b(){m().setAttributeNS("urn:webodf:names:helper","links","inactive")}var g=gui.HyperlinkClickHandler.Modifier.None,d=gui.HyperlinkClickHandler.Modifier.Ctrl,n=gui.HyperlinkClickHandler.Modifier.Meta,p=new odf.OdfUtils,k=xmldom.XPath,q=g;this.handleClick=function(b){var h=b.target||b.srcElement,a,c;b.ctrlKey?a=d:b.metaKey&&(a=n);if(q===g||q===a){a:{for(;null!==h;){if(p.isH [...]
++if(p.isParagraph(h))break;h=h.parentNode}h=null}h&&(h=p.getHyperlinkTarget(h),""!==h&&("#"===h[0]?(h=h.substring(1),a=m(),c=k.getODFElementsWithXPath(a,"//text:bookmark-start[@text:name='"+h+"']",odf.Namespaces.lookupNamespaceURI),0===c.length&&(c=k.getODFElementsWithXPath(a,"//text:bookmark[@text:name='"+h+"']",odf.Namespaces.lookupNamespaceURI)),0<c.length&&c[0].scrollIntoView(!0)):runtime.getWindow().open(h),b.preventDefault?b.preventDefault():b.returnValue=!1))}};this.showPointerCur [...]
++b;this.setModifier=function(d){q=d;q!==g?b():h()}};gui.HyperlinkClickHandler.Modifier={None:0,Ctrl:1,Meta:2};
 +// Input 83
++gui.HyperlinkController=function(m,h){var b=new odf.OdfUtils,g=m.getOdtDocument();this.addHyperlink=function(b,n){var p=g.getCursorSelection(h),k=new ops.OpApplyHyperlink,q=[];if(0===p.length||n)n=n||b,k=new ops.OpInsertText,k.init({memberid:h,position:p.position,text:n}),p.length=n.length,q.push(k);k=new ops.OpApplyHyperlink;k.init({memberid:h,position:p.position,length:p.length,hyperlink:b});q.push(k);m.enqueue(q)};this.removeHyperlinks=function(){var d=gui.SelectionMover.createPositi [...]
++n=g.getCursor(h).getSelectedRange(),p=b.getHyperlinkElements(n),k=n.collapsed&&1===p.length,q=g.getDOMDocument().createRange(),e=[],r,a;0!==p.length&&(p.forEach(function(b){q.selectNodeContents(b);r=g.convertDomToCursorRange({anchorNode:q.startContainer,anchorOffset:q.startOffset,focusNode:q.endContainer,focusOffset:q.endOffset});a=new ops.OpRemoveHyperlink;a.init({memberid:h,position:r.position,length:r.length});e.push(a)}),k||(k=p[0],-1===n.comparePoint(k,0)&&(q.setStart(k,0),q.setEnd [...]
++n.startOffset),r=g.convertDomToCursorRange({anchorNode:q.startContainer,anchorOffset:q.startOffset,focusNode:q.endContainer,focusOffset:q.endOffset}),0<r.length&&(a=new ops.OpApplyHyperlink,a.init({memberid:h,position:r.position,length:r.length,hyperlink:b.getHyperlinkTarget(k)}),e.push(a))),p=p[p.length-1],d.moveToEndOfNode(p),d=d.unfilteredDomOffset(),1===n.comparePoint(p,d)&&(q.setStart(n.endContainer,n.endOffset),q.setEnd(p,d),r=g.convertDomToCursorRange({anchorNode:q.startContainer [...]
++focusNode:q.endContainer,focusOffset:q.endOffset}),0<r.length&&(a=new ops.OpApplyHyperlink,a.init({memberid:h,position:r.position,length:r.length,hyperlink:b.getHyperlinkTarget(p)}),e.push(a)))),m.enqueue(e),q.detach())}};
++// Input 84
++gui.EventManager=function(m){function h(){var a=this,b=[];this.filters=[];this.handlers=[];this.handleEvent=function(c){-1===b.indexOf(c)&&(b.push(c),a.filters.every(function(a){return a(c)})&&a.handlers.forEach(function(a){a(c)}),runtime.setTimeout(function(){b.splice(b.indexOf(c),1)},0))}}function b(a,b,c){function d(b){c(b,f,function(b){b.type=a;e.emit("eventTriggered",b)})}var f={},e=new core.EventNotifier(["eventTriggered"]);this.subscribe=function(a){e.subscribe("eventTriggered",a [...]
++function(a){e.unsubscribe("eventTriggered",a)};this.destroy=function(){b.forEach(function(a){y.unsubscribe(a,d)})};(function(){b.forEach(function(a){y.subscribe(a,d)})})()}function g(a){runtime.clearTimeout(a);delete F[a]}function d(a,b){var c=runtime.setTimeout(function(){a();g(c)},b);F[c]=!0;return c}function n(a,b,c){var f=a.touches.length,e=a.touches[0],l=b.timer;"touchmove"===a.type||"touchend"===a.type?l&&g(l):"touchstart"===a.type&&(1!==f?runtime.clearTimeout(l):l=d(function(){c( [...]
++clientY:e.clientY,pageX:e.pageX,pageY:e.pageY,target:a.target||a.srcElement||null,detail:1})},400));b.timer=l}function p(a,b,c){var d=a.touches[0],f=a.target||a.srcElement||null,e=b.target;1!==a.touches.length||"touchend"===a.type?e=null:"touchstart"===a.type&&"draggable"===f.getAttribute("class")?e=f:"touchmove"===a.type&&e&&(a.preventDefault(),a.stopPropagation(),c({clientX:d.clientX,clientY:d.clientY,pageX:d.pageX,pageY:d.pageY,target:e,detail:1}));b.target=e}function k(a,b,c){var d= [...]
++a.srcElement||null,f=b.dragging;"drag"===a.type?f=!0:"touchend"===a.type&&f&&(f=!1,a=a.changedTouches[0],c({clientX:a.clientX,clientY:a.clientY,pageX:a.pageX,pageY:a.pageY,target:d,detail:1}));b.dragging=f}function q(){s.classList.add("webodf-touchEnabled");y.unsubscribe("touchstart",q)}function e(a){var b=a.scrollX,c=a.scrollY;this.restore=function(){a.scrollX===b&&a.scrollY===c||a.scrollTo(b,c)}}function r(a){var b=a.scrollTop,c=a.scrollLeft;this.restore=function(){if(a.scrollTop!==b| [...]
++c)a.scrollTop=b,a.scrollLeft=c}}function a(a,b,c){var d,f=!1;x.hasOwnProperty(b)?x[b].subscribe(c):(d="on"+b,a.attachEvent&&(a.attachEvent(d,c),f=!0),!f&&a.addEventListener&&(a.addEventListener(b,c,!1),f=!0),f&&!w[b]||!a.hasOwnProperty(d)||(a[d]=c))}function c(b,c){var d=t[b]||null;!d&&c&&(d=t[b]=new h,z[b]&&a(v,b,d.handleEvent),a(u,b,d.handleEvent),a(s,b,d.handleEvent));return d}function l(){return m.getDOMDocument().activeElement===u}function f(a){for(var b=[];a;)(a.scrollWidth>a.clie [...]
++a.clientHeight)&&b.push(new r(a)),a=a.parentNode;b.push(new e(v));return b}var v=runtime.getWindow(),w={beforecut:!0,beforepaste:!0,longpress:!0,drag:!0,dragstop:!0},z={mousedown:!0,mouseup:!0,focus:!0},x={},t={},u,s=m.getCanvas().getElement(),y=this,F={};this.addFilter=function(a,b){c(a,!0).filters.push(b)};this.removeFilter=function(a,b){var d=c(a,!0),f=d.filters.indexOf(b);-1!==f&&d.filters.splice(f,1)};this.subscribe=function(a,b){c(a,!0).handlers.push(b)};this.unsubscribe=function( [...]
++c(a,!1),f=d&&d.handlers.indexOf(b);d&&-1!==f&&d.handlers.splice(f,1)};this.hasFocus=l;this.focus=function(){var a;l()||(a=f(u),u.focus(),a.forEach(function(a){a.restore()}))};this.getEventTrap=function(){return u};this.blur=function(){l()&&u.blur()};this.destroy=function(a){Object.keys(F).forEach(function(a){g(parseInt(a,10))});F.length=0;Object.keys(x).forEach(function(a){x[a].destroy()});x={};y.unsubscribe("touchstart",q);u.parentNode.removeChild(u);a()};(function(){var a=m.getOdfCanv [...]
++c=a.ownerDocument;runtime.assert(Boolean(v),"EventManager requires a window object to operate correctly");u=c.createElement("input");u.id="eventTrap";u.setAttribute("tabindex",-1);a.appendChild(u);x.longpress=new b("longpress",["touchstart","touchmove","touchend"],n);x.drag=new b("drag",["touchstart","touchmove","touchend"],p);x.dragstop=new b("dragstop",["drag","touchend"],k);y.subscribe("touchstart",q)})()};
++// Input 85
 +/*
 +
-  Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
++ Copyright (C) 2014 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + This file is part of WebODF.
 +
 + WebODF is free software: you can redistribute it and/or modify it
 + under the terms of the GNU Affero General Public License (GNU AGPL)
 + as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.
 +
 + WebODF is distributed in the hope that it will be useful, but
 + WITHOUT ANY WARRANTY; without even the implied warranty of
 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + GNU Affero General Public License for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with WebODF.  If not, see <http://www.gnu.org/licenses/>.
 + @licend
 +
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- ops.OperationTransformMatrix=function(){function g(a){a.position+=a.length;a.length*=-1}function l(a){var b=0>a.length;b&&g(a);return b}function f(a,b){var c=[];a&&["style:parent-style-name","style:next-style-name"].forEach(function(d){a[d]===b&&c.push(d)});return c}function p(a,b){a&&["style:parent-style-name","style:next-style-name"].forEach(function(c){a[c]===b&&delete a[c]})}function r(a){var b={};Object.keys(a).forEach(function(c){b[c]="object"===typeof a[c]?r(a[c]):a[c]});return b [...]
- b,c,d){var e,f,h=!1,g=!1,l,m,n=d&&d.attributes?d.attributes.split(","):[];a&&(c||0<n.length)&&Object.keys(a).forEach(function(b){e=a[b];"object"!==typeof e&&(l=c&&c[b],void 0!==l?(delete a[b],g=!0,l===e&&(delete c[b],h=!0)):n&&-1!==n.indexOf(b)&&(delete a[b],g=!0))});if(b&&b.attributes&&(c||0<n.length)){m=b.attributes.split(",");for(d=0;d<m.length;d+=1)if(f=m[d],c&&void 0!==c[f]||n&&-1!==n.indexOf(f))m.splice(d,1),d-=1,g=!0;0<m.length?b.attributes=m.join(","):delete b.attributes}return{ [...]
- minorChanged:g}}function h(a){for(var b in a)if(a.hasOwnProperty(b))return!0;return!1}function d(a){for(var b in a)if(a.hasOwnProperty(b)&&("attributes"!==b||0<a.attributes.length))return!0;return!1}function m(a,b,c){var e=a.setProperties?a.setProperties[c]:null,f=a.removedProperties?a.removedProperties[c]:null,g=b.setProperties?b.setProperties[c]:null,l=b.removedProperties?b.removedProperties[c]:null,m;m=n(e,f,g,l);e&&!h(e)&&delete a.setProperties[c];f&&!d(f)&&delete a.removedPropertie [...]
- delete b.setProperties[c];l&&!d(l)&&delete b.removedProperties[c];return m}function c(a,b){return{opSpecsA:[a],opSpecsB:[b]}}var e={AddCursor:{AddCursor:c,AddMember:c,AddStyle:c,ApplyDirectStyling:c,InsertText:c,MoveCursor:c,RemoveCursor:c,RemoveMember:c,RemoveStyle:c,RemoveText:c,SetParagraphStyle:c,SplitParagraph:c,UpdateMember:c,UpdateMetadata:c,UpdateParagraphStyle:c},AddMember:{AddStyle:c,InsertText:c,MoveCursor:c,RemoveCursor:c,RemoveStyle:c,RemoveText:c,SetParagraphStyle:c,SplitP [...]
- UpdateMetadata:c,UpdateParagraphStyle:c},AddStyle:{AddStyle:c,ApplyDirectStyling:c,InsertText:c,MoveCursor:c,RemoveCursor:c,RemoveMember:c,RemoveStyle:function(a,b){var c,d=[a],e=[b];a.styleFamily===b.styleFamily&&(c=f(a.setProperties,b.styleName),0<c.length&&(c={optype:"UpdateParagraphStyle",memberid:b.memberid,timestamp:b.timestamp,styleName:a.styleName,removedProperties:{attributes:c.join(",")}},e.unshift(c)),p(a.setProperties,b.styleName));return{opSpecsA:d,opSpecsB:e}},RemoveText:c [...]
- SplitParagraph:c,UpdateMember:c,UpdateMetadata:c,UpdateParagraphStyle:c},ApplyDirectStyling:{ApplyDirectStyling:function(a,b,c){var d,e,f,g,l,n,p,s;g=[a];f=[b];if(!(a.position+a.length<=b.position||a.position>=b.position+b.length)){d=c?a:b;e=c?b:a;if(a.position!==b.position||a.length!==b.length)n=r(d),p=r(e);b=m(e,d,"style:text-properties");if(b.majorChanged||b.minorChanged)f=[],a=[],g=d.position+d.length,l=e.position+e.length,e.position<d.position?b.minorChanged&&(s=r(p),s.length=d.pos [...]
- a.push(s),e.position=d.position,e.length=l-e.position):d.position<e.position&&b.majorChanged&&(s=r(n),s.length=e.position-d.position,f.push(s),d.position=e.position,d.length=g-d.position),l>g?b.minorChanged&&(n=p,n.position=g,n.length=l-g,a.push(n),e.length=g-e.position):g>l&&b.majorChanged&&(n.position=l,n.length=g-l,f.push(n),d.length=l-d.position),d.setProperties&&h(d.setProperties)&&f.push(d),e.setProperties&&h(e.setProperties)&&a.push(e),c?(g=f,f=a):g=a}return{opSpecsA:g,opSpecsB:f [...]
- b){b.position<=a.position?a.position+=b.text.length:b.position<=a.position+a.length&&(a.length+=b.text.length);return{opSpecsA:[a],opSpecsB:[b]}},MoveCursor:c,RemoveCursor:c,RemoveStyle:c,RemoveText:function(a,b){var c=a.position+a.length,d=b.position+b.length,e=[a],f=[b];d<=a.position?a.position-=b.length:b.position<c&&(a.position<b.position?a.length=d<c?a.length-b.length:b.position-a.position:(a.position=b.position,d<c?a.length=c-d:e=[]));return{opSpecsA:e,opSpecsB:f}},SetParagraphSty [...]
- b){b.position<a.position?a.position+=1:b.position<a.position+a.length&&(a.length+=1);return{opSpecsA:[a],opSpecsB:[b]}},UpdateMetadata:c,UpdateParagraphStyle:c},InsertText:{InsertText:function(a,b,c){a.position<b.position?b.position+=a.text.length:a.position>b.position?a.position+=b.text.length:c?b.position+=a.text.length:a.position+=b.text.length;return{opSpecsA:[a],opSpecsB:[b]}},MoveCursor:function(a,b){var c=l(b);a.position<b.position?b.position+=a.text.length:a.position<b.position+ [...]
- (b.length+=a.text.length);c&&g(b);return{opSpecsA:[a],opSpecsB:[b]}},RemoveCursor:c,RemoveMember:c,RemoveStyle:c,RemoveText:function(a,b){var c;c=b.position+b.length;var d=[a],e=[b];c<=a.position?a.position-=b.length:a.position<=b.position?b.position+=a.text.length:(b.length=a.position-b.position,c={optype:"RemoveText",memberid:b.memberid,timestamp:b.timestamp,position:a.position+a.text.length,length:c-a.position},e.unshift(c),a.position=b.position);return{opSpecsA:d,opSpecsB:e}},SplitP [...]
- b,c){if(a.position<b.position)b.position+=a.text.length;else if(a.position>b.position)a.position+=1;else return c?b.position+=a.text.length:a.position+=1,null;return{opSpecsA:[a],opSpecsB:[b]}},UpdateMember:c,UpdateMetadata:c,UpdateParagraphStyle:c},MoveCursor:{MoveCursor:c,RemoveCursor:function(a,b){return{opSpecsA:a.memberid===b.memberid?[]:[a],opSpecsB:[b]}},RemoveMember:c,RemoveStyle:c,RemoveText:function(a,b){var c=l(a),d=a.position+a.length,e=b.position+b.length;e<=a.position?a.po [...]
- b.position<d&&(a.position<b.position?a.length=e<d?a.length-b.length:b.position-a.position:(a.position=b.position,a.length=e<d?d-e:0));c&&g(a);return{opSpecsA:[a],opSpecsB:[b]}},SetParagraphStyle:c,SplitParagraph:function(a,b){var c=l(a);b.position<a.position?a.position+=1:b.position<a.position+a.length&&(a.length+=1);c&&g(a);return{opSpecsA:[a],opSpecsB:[b]}},UpdateMember:c,UpdateMetadata:c,UpdateParagraphStyle:c},RemoveCursor:{RemoveCursor:function(a,b){var c=a.memberid===b.memberid;re [...]
- []:[a],opSpecsB:c?[]:[b]}},RemoveMember:c,RemoveStyle:c,RemoveText:c,SetParagraphStyle:c,SplitParagraph:c,UpdateMember:c,UpdateMetadata:c,UpdateParagraphStyle:c},RemoveMember:{RemoveStyle:c,RemoveText:c,SetParagraphStyle:c,SplitParagraph:c,UpdateMetadata:c,UpdateParagraphStyle:c},RemoveStyle:{RemoveStyle:function(a,b){var c=a.styleName===b.styleName&&a.styleFamily===b.styleFamily;return{opSpecsA:c?[]:[a],opSpecsB:c?[]:[b]}},RemoveText:c,SetParagraphStyle:function(a,b){var c,d=[a],e=[b]; [...]
- a.styleFamily&&a.styleName===b.styleName&&(c={optype:"SetParagraphStyle",memberid:a.memberid,timestamp:a.timestamp,position:b.position,styleName:""},d.unshift(c),b.styleName="");return{opSpecsA:d,opSpecsB:e}},SplitParagraph:c,UpdateMember:c,UpdateMetadata:c,UpdateParagraphStyle:function(a,b){var c,d=[a],e=[b];"paragraph"===a.styleFamily&&(c=f(b.setProperties,a.styleName),0<c.length&&(c={optype:"UpdateParagraphStyle",memberid:a.memberid,timestamp:a.timestamp,styleName:b.styleName,removed [...]
- d.unshift(c)),a.styleName===b.styleName?e=[]:p(b.setProperties,a.styleName));return{opSpecsA:d,opSpecsB:e}}},RemoveText:{RemoveText:function(a,b){var c=a.position+a.length,d=b.position+b.length,e=[a],f=[b];d<=a.position?a.position-=b.length:c<=b.position?b.position-=a.length:b.position<c&&(a.position<b.position?(a.length=d<c?a.length-b.length:b.position-a.position,c<d?(b.position=a.position,b.length=d-c):f=[]):(c<d?b.length-=a.length:b.position<a.position?b.length=a.position-b.position: [...]
- b.position,a.length=c-d):e=[]));return{opSpecsA:e,opSpecsB:f}},SplitParagraph:function(a,b){var c=a.position+a.length,d=[a],e=[b];b.position<=a.position?a.position+=1:b.position<c&&(a.length=b.position-a.position,c={optype:"RemoveText",memberid:a.memberid,timestamp:a.timestamp,position:b.position+1,length:c-b.position},d.unshift(c));a.position+a.length<=b.position?b.position-=a.length:a.position<b.position&&(b.position=a.position);return{opSpecsA:d,opSpecsB:e}},UpdateMember:c,UpdateMeta [...]
- SetParagraphStyle:{UpdateMember:c,UpdateMetadata:c,UpdateParagraphStyle:c},SplitParagraph:{SplitParagraph:function(a,b,c){a.position<b.position?b.position+=1:a.position>b.position?a.position+=1:a.position===b.position&&(c?b.position+=1:a.position+=1);return{opSpecsA:[a],opSpecsB:[b]}},UpdateMember:c,UpdateMetadata:c,UpdateParagraphStyle:c},UpdateMember:{UpdateMetadata:c,UpdateParagraphStyle:c},UpdateMetadata:{UpdateMetadata:function(a,b,c){var e,f=[a],g=[b];e=c?a:b;a=c?b:a;n(a.setProper [...]
- a.removedProperties||null,e.setProperties||null,e.removedProperties||null);e.setProperties&&h(e.setProperties)||e.removedProperties&&d(e.removedProperties)||(c?f=[]:g=[]);a.setProperties&&h(a.setProperties)||a.removedProperties&&d(a.removedProperties)||(c?g=[]:f=[]);return{opSpecsA:f,opSpecsB:g}},UpdateParagraphStyle:c},UpdateParagraphStyle:{UpdateParagraphStyle:function(a,b,c){var e,f=[a],g=[b];a.styleName===b.styleName&&(e=c?a:b,a=c?b:a,m(a,e,"style:paragraph-properties"),m(a,e,"style [...]
- n(a.setProperties||null,a.removedProperties||null,e.setProperties||null,e.removedProperties||null),e.setProperties&&h(e.setProperties)||e.removedProperties&&d(e.removedProperties)||(c?f=[]:g=[]),a.setProperties&&h(a.setProperties)||a.removedProperties&&d(a.removedProperties)||(c?g=[]:f=[]));return{opSpecsA:f,opSpecsB:g}}}};this.passUnchanged=c;this.extendTransformations=function(a){Object.keys(a).forEach(function(b){var c=a[b],d,f=e.hasOwnProperty(b);runtime.log((f?"Extending":"Adding") [...]
- b);f||(e[b]={});d=e[b];Object.keys(c).forEach(function(a){var e=d.hasOwnProperty(a);runtime.assert(b<=a,"Wrong order:"+b+", "+a);runtime.log("  "+(e?"Overwriting":"Adding")+" entry for optypeB: "+a);d[a]=c[a]})})};this.transformOpspecVsOpspec=function(a,b){var c=a.optype<=b.optype,d;runtime.log("Crosstransforming:");runtime.log(runtime.toJson(a));runtime.log(runtime.toJson(b));c||(d=a,a=b,b=d);(d=(d=e[a.optype])&&d[b.optype])?(d=d(a,b,!c),c||null===d||(d={opSpecsA:d.opSpecsB,opSpecsB:d. [...]
- d=null;runtime.log("result:");d?(runtime.log(runtime.toJson(d.opSpecsA)),runtime.log(runtime.toJson(d.opSpecsB))):runtime.log("null");return d}};
- // Input 84
++gui.IOSSafariSupport=function(m){function h(){b.innerHeight!==b.outerHeight&&(g.style.display="none",runtime.requestAnimationFrame(function(){g.style.display="block"}))}var b=runtime.getWindow(),g=m.getEventTrap();this.destroy=function(b){m.unsubscribe("focus",h);g.removeAttribute("autocapitalize");g.style.WebkitTransform="";b()};m.subscribe("focus",h);g.setAttribute("autocapitalize","off");g.style.WebkitTransform="translateX(-10000px)"};
++// Input 86
++gui.ImageController=function(m,h,b){var g={"image/gif":".gif","image/jpeg":".jpg","image/png":".png"},d=odf.Namespaces.textns,n=m.getOdtDocument(),p=n.getFormatting(),k={};this.insertImage=function(q,e,r,a){var c;runtime.assert(0<r&&0<a,"Both width and height of the image should be greater than 0px.");c=n.getParagraphElement(n.getCursor(h).getNode()).getAttributeNS(d,"style-name");k.hasOwnProperty(c)||(k[c]=p.getContentSize(c,"paragraph"));c=k[c];r*=0.0264583333333334;a*=0.0264583333333 [...]
++1,f=1;r>c.width&&(l=c.width/r);a>c.height&&(f=c.height/a);l=Math.min(l,f);c=r*l;r=a*l;f=n.getOdfCanvas().odfContainer().rootElement.styles;a=q.toLowerCase();var l=g.hasOwnProperty(a)?g[a]:null,v;a=[];runtime.assert(null!==l,"Image type is not supported: "+q);l="Pictures/"+b.generateImageName()+l;v=new ops.OpSetBlob;v.init({memberid:h,filename:l,mimetype:q,content:e});a.push(v);p.getStyleElement("Graphics","graphic",[f])||(q=new ops.OpAddStyle,q.init({memberid:h,styleName:"Graphics",styl [...]
++isAutomaticStyle:!1,setProperties:{"style:graphic-properties":{"text:anchor-type":"paragraph","svg:x":"0cm","svg:y":"0cm","style:wrap":"dynamic","style:number-wrapped-paragraphs":"no-limit","style:wrap-contour":"false","style:vertical-pos":"top","style:vertical-rel":"paragraph","style:horizontal-pos":"center","style:horizontal-rel":"paragraph"}}}),a.push(q));q=b.generateStyleName();e=new ops.OpAddStyle;e.init({memberid:h,styleName:q,styleFamily:"graphic",isAutomaticStyle:!0,setPropertie [...]
++"style:graphic-properties":{"style:vertical-pos":"top","style:vertical-rel":"baseline","style:horizontal-pos":"center","style:horizontal-rel":"paragraph","fo:background-color":"transparent","style:background-transparency":"100%","style:shadow":"none","style:mirror":"none","fo:clip":"rect(0cm, 0cm, 0cm, 0cm)","draw:luminance":"0%","draw:contrast":"0%","draw:red":"0%","draw:green":"0%","draw:blue":"0%","draw:gamma":"100%","draw:color-inversion":"false","draw:image-opacity":"100%","draw:co [...]
++a.push(e);v=new ops.OpInsertImage;v.init({memberid:h,position:n.getCursorPosition(h),filename:l,frameWidth:c+"cm",frameHeight:r+"cm",frameStyleName:q,frameName:b.generateFrameName()});a.push(v);m.enqueue(a)}};
++// Input 87
++gui.ImageSelector=function(m){function h(){var b=m.getSizer(),h=d.createElement("div");h.id="imageSelector";h.style.borderWidth="1px";b.appendChild(h);g.forEach(function(b){var e=d.createElement("div");e.className=b;h.appendChild(e)});return h}var b=odf.Namespaces.svgns,g="topLeft topRight bottomRight bottomLeft topMiddle rightMiddle bottomMiddle leftMiddle".split(" "),d=m.getElement().ownerDocument,n=!1;this.select=function(g){var k,q,e=d.getElementById("imageSelector");e||(e=h());n=!0 [...]
++q=g.getBoundingClientRect();var r=k.getBoundingClientRect(),a=m.getZoomLevel();k=(q.left-r.left)/a-1;q=(q.top-r.top)/a-1;e.style.display="block";e.style.left=k+"px";e.style.top=q+"px";e.style.width=g.getAttributeNS(b,"width");e.style.height=g.getAttributeNS(b,"height")};this.clearSelection=function(){var b;n&&(b=d.getElementById("imageSelector"))&&(b.style.display="none");n=!1};this.isSelectorElement=function(b){var g=d.getElementById("imageSelector");return g?b===g||b.parentNode===g:!1}};
++// Input 88
++(function(){function m(h){function b(b){p=b.which&&String.fromCharCode(b.which)===m;m=void 0;return!1===p}function g(){p=!1}function d(b){m=b.data;p=!1}var m,p=!1;this.destroy=function(k){h.unsubscribe("textInput",g);h.unsubscribe("compositionend",d);h.removeFilter("keypress",b);k()};h.subscribe("textInput",g);h.subscribe("compositionend",d);h.addFilter("keypress",b)}gui.InputMethodEditor=function(h,b){function g(a){l&&(a?l.getNode().setAttributeNS(c,"composing","true"):(l.getNode().rem [...]
++"composing"),w.textContent=""))}function d(){u&&(u=!1,g(!1),y.emit(gui.InputMethodEditor.signalCompositionEnd,{data:s}),s="")}function n(){d();l&&l.getSelectedRange().collapsed?f.value="":f.value=x;f.setSelectionRange(0,f.value.length)}function p(){F=void 0;t.cancel();g(!0);u||y.emit(gui.InputMethodEditor.signalCompositionStart,{data:""})}function k(a){a=F=a.data;u=!0;s+=a;t.trigger()}function q(a){a.data!==F&&(a=a.data,u=!0,s+=a,t.trigger());F=void 0}function e(){w.textContent=f.value} [...]
++f.setAttribute("disabled",!0)}function a(){var a=b.hasFocus();a&&b.blur();H?f.removeAttribute("disabled"):f.setAttribute("disabled",!0);a&&b.focus()}var c="urn:webodf:names:cursor",l=null,f=b.getEventTrap(),v=f.ownerDocument,w,z=new core.Async,x="b",t,u=!1,s="",y=new core.EventNotifier([gui.InputMethodEditor.signalCompositionStart,gui.InputMethodEditor.signalCompositionEnd]),F,L=[],O,H=!1;this.subscribe=y.subscribe;this.unsubscribe=y.unsubscribe;this.registerCursor=function(a){a.getMemb [...]
++(l=a,l.getNode().appendChild(w),b.subscribe("input",e),b.subscribe("compositionupdate",e))};this.removeCursor=function(a){l&&a===h&&(l.getNode().removeChild(w),b.unsubscribe("input",e),b.unsubscribe("compositionupdate",e),l=null)};this.setEditing=function(b){H=b;a()};this.destroy=function(c){b.unsubscribe("compositionstart",p);b.unsubscribe("compositionend",k);b.unsubscribe("textInput",q);b.unsubscribe("keypress",d);b.unsubscribe("mousedown",r);b.unsubscribe("mouseup",a);b.unsubscribe(" [...]
++z.destroyAll(O,c)};(function(){b.subscribe("compositionstart",p);b.subscribe("compositionend",k);b.subscribe("textInput",q);b.subscribe("keypress",d);b.subscribe("mousedown",r);b.subscribe("mouseup",a);b.subscribe("focus",n);L.push(new m(b));O=L.map(function(a){return a.destroy});w=v.createElement("span");w.setAttribute("id","composer");t=new core.ScheduledTask(n,1);O.push(t.destroy)})()};gui.InputMethodEditor.signalCompositionStart="input/compositionstart";gui.InputMethodEditor.signalC [...]
++"input/compositionend";return gui.InputMethodEditor})();
++// Input 89
 +/*
 +
-  Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
++ Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
-  This file is part of WebODF.
++ The JavaScript code in this page is free software: you can redistribute it
++ and/or modify it under the terms of the GNU Affero General Public License
++ (GNU AGPL) as published by the Free Software Foundation, either version 3 of
++ the License, or (at your option) any later version.  The code is distributed
++ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
-  WebODF is free software: you can redistribute it and/or modify it
-  under the terms of the GNU Affero General Public License (GNU AGPL)
-  as published by the Free Software Foundation, either version 3 of
-  the License, or (at your option) any later version.
++ You should have received a copy of the GNU Affero General Public License
++ along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
-  WebODF is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-  GNU Affero General Public License for more details.
++ As additional permission under GNU AGPL version 3 section 7, you
++ may distribute non-source (e.g., minimized or compacted) forms of
++ that code without the copy of the GNU GPL normally required by
++ section 4, provided you include this license notice and a URL
++ through which recipients can access the Corresponding Source.
 +
-  You should have received a copy of the GNU Affero General Public License
-  along with WebODF.  If not, see <http://www.gnu.org/licenses/>.
-  @licend
++ As a special exception to the AGPL, any HTML file which merely makes function
++ calls to this code, and for that purpose includes it by reference shall be
++ deemed a separate work for copyright law purposes. In addition, the copyright
++ holders of this code give you permission to combine this code with free
++ software libraries that are released under the GNU LGPL. You may copy and
++ distribute such a system following the terms of the GNU AGPL for this code
++ and the LGPL for the libraries. If you modify this code, you may extend this
++ exception to your version of the code, but you are not obligated to do so.
++ If you do not wish to do so, delete this exception statement from your
++ version.
 +
++ This license applies to this entire compilation.
++ @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("ops.OperationFactory");runtime.loadClass("ops.OperationTransformMatrix");
- ops.OperationTransformer=function(){function g(g){var l=[];g.forEach(function(h){l.push(f.create(h))});return l}function l(f,g){for(var h,d,m=[],c=[];0<f.length&&g;){h=f.shift();h=p.transformOpspecVsOpspec(h,g);if(!h)return null;m=m.concat(h.opSpecsA);if(0===h.opSpecsB.length){m=m.concat(f);g=null;break}for(;1<h.opSpecsB.length;){d=l(f,h.opSpecsB.shift());if(!d)return null;c=c.concat(d.opSpecsB);f=d.opSpecsA}g=h.opSpecsB.pop()}g&&c.push(g);return{opSpecsA:m,opSpecsB:c}}var f,p=new ops.O [...]
- this.setOperationFactory=function(g){f=g};this.getOperationTransformMatrix=function(){return p};this.transform=function(f,n){for(var h,d=[];0<n.length;){h=l(f,n.shift());if(!h)return null;f=h.opSpecsA;d=d.concat(h.opSpecsB)}return{opsA:g(f),opsB:g(d)}}};
- // Input 85
++gui.KeyboardHandler=function(){function m(b,g){g||(g=h.None);return b+":"+g}var h=gui.KeyboardHandler.Modifier,b=null,g={};this.setDefault=function(d){b=d};this.bind=function(b,h,p,k){b=m(b,h);runtime.assert(k||!1===g.hasOwnProperty(b),"tried to overwrite the callback handler of key combo: "+b);g[b]=p};this.unbind=function(b,h){var p=m(b,h);delete g[p]};this.reset=function(){b=null;g={}};this.handleEvent=function(d){var n=d.keyCode,p=h.None;d.metaKey&&(p|=h.Meta);d.ctrlKey&&(p|=h.Ctrl); [...]
++(p|=h.Alt);d.shiftKey&&(p|=h.Shift);n=m(n,p);n=g[n];p=!1;n?p=n():null!==b&&(p=b(d));p&&(d.preventDefault?d.preventDefault():d.returnValue=!1)}};gui.KeyboardHandler.Modifier={None:0,Meta:1,Ctrl:2,Alt:4,CtrlAlt:6,Shift:8,MetaShift:9,CtrlShift:10,AltShift:12};
++gui.KeyboardHandler.KeyCode={Backspace:8,Tab:9,Clear:12,Enter:13,Ctrl:17,End:35,Home:36,Left:37,Up:38,Right:39,Down:40,Delete:46,A:65,B:66,C:67,D:68,E:69,F:70,G:71,H:72,I:73,J:74,K:75,L:76,M:77,N:78,O:79,P:80,Q:81,R:82,S:83,T:84,U:85,V:86,W:87,X:88,Y:89,Z:90,LeftMeta:91,MetaInMozilla:224};(function(){return gui.KeyboardHandler})();
++// Input 90
 +/*
 +
-  Copyright (C) 2012 KO GmbH <copyright at kogmbh.com>
++ Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- ops.TrivialOperationRouter=function(){var g,l;this.setOperationFactory=function(f){g=f};this.setPlaybackFunction=function(f){l=f};this.push=function(f){f.forEach(function(f){f=f.spec();f.timestamp=(new Date).getTime();f=g.create(f);l(f)})};this.close=function(f){f()};this.subscribe=function(f,g){};this.unsubscribe=function(f,g){};this.hasLocalUnsyncedOps=function(){return!1};this.hasSessionHostConnection=function(){return!0}};
- // Input 86
++gui.PlainTextPasteboard=function(m,h){function b(b,d){b.init(d);return b}this.createPasteOps=function(g){var d=m.getCursorPosition(h),n=d,p=[];g.replace(/\r/g,"").split("\n").forEach(function(d){p.push(b(new ops.OpSplitParagraph,{memberid:h,position:n,moveCursor:!0}));n+=1;p.push(b(new ops.OpInsertText,{memberid:h,position:n,text:d,moveCursor:!0}));n+=d.length});p.push(b(new ops.OpRemoveText,{memberid:h,position:d,length:1}));return p}};
++// Input 91
 +/*
 +
-  Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
++ Copyright (C) 2014 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("ops.EditInfo");runtime.loadClass("gui.EditInfoHandle");
- gui.EditInfoMarker=function(g,l){function f(c,d){return runtime.setTimeout(function(){h.style.opacity=c},d)}var p=this,r,n,h,d,m;this.addEdit=function(c,e){var a=Date.now()-e;g.addEdit(c,e);n.setEdits(g.getSortedEdits());h.setAttributeNS("urn:webodf:names:editinfo","editinfo:memberid",c);d&&runtime.clearTimeout(d);m&&runtime.clearTimeout(m);1E4>a?(f(1,0),d=f(0.5,1E4-a),m=f(0.2,2E4-a)):1E4<=a&&2E4>a?(f(0.5,0),m=f(0.2,2E4-a)):f(0.2,0)};this.getEdits=function(){return g.getEdits()};this.cl [...]
- n.setEdits([]);h.hasAttributeNS("urn:webodf:names:editinfo","editinfo:memberid")&&h.removeAttributeNS("urn:webodf:names:editinfo","editinfo:memberid")};this.getEditInfo=function(){return g};this.show=function(){h.style.display="block"};this.hide=function(){p.hideHandle();h.style.display="none"};this.showHandle=function(){n.show()};this.hideHandle=function(){n.hide()};this.destroy=function(c){r.removeChild(h);n.destroy(function(d){d?c(d):g.destroy(c)})};(function(){var c=g.getOdtDocument [...]
- h=c.createElementNS(c.documentElement.namespaceURI,"div");h.setAttribute("class","editInfoMarker");h.onmouseover=function(){p.showHandle()};h.onmouseout=function(){p.hideHandle()};r=g.getNode();r.appendChild(h);n=new gui.EditInfoHandle(r);l||p.hide()})()};
- // Input 87
++odf.WordBoundaryFilter=function(m,h){function b(a,b,c){for(var d=null,e=m.getRootNode(),g;a!==e&&null!==a&&null===d;)g=0>b?a.previousSibling:a.nextSibling,c(g)===NodeFilter.FILTER_ACCEPT&&(d=g),a=a.parentNode;return d}function g(a,b){var c;return null===a?l.NO_NEIGHBOUR:p.isCharacterElement(a)?l.SPACE_CHAR:a.nodeType===d||p.isTextSpan(a)||p.isHyperlink(a)?(c=a.textContent.charAt(b()),q.test(c)?l.SPACE_CHAR:k.test(c)?l.PUNCTUATION_CHAR:l.WORD_CHAR):l.OTHER}var d=Node.TEXT_NODE,n=Node.ELE [...]
++p=new odf.OdfUtils,k=/[!-#%-*,-\/:-;?-@\[-\]_{}\u00a1\u00ab\u00b7\u00bb\u00bf;\u00b7\u055a-\u055f\u0589-\u058a\u05be\u05c0\u05c3\u05c6\u05f3-\u05f4\u0609-\u060a\u060c-\u060d\u061b\u061e-\u061f\u066a-\u066d\u06d4\u0700-\u070d\u07f7-\u07f9\u0964-\u0965\u0970\u0df4\u0e4f\u0e5a-\u0e5b\u0f04-\u0f12\u0f3a-\u0f3d\u0f85\u0fd0-\u0fd4\u104a-\u104f\u10fb\u1361-\u1368\u166d-\u166e\u169b-\u169c\u16eb-\u16ed\u1735-\u1736\u17d4-\u17d6\u17d8-\u17da\u1800-\u180a\u1944-\u1945\u19de-\u19df\u1a1e-\u1a1f\u1 [...]
++q=/\s/,e=core.PositionFilter.FilterResult.FILTER_ACCEPT,r=core.PositionFilter.FilterResult.FILTER_REJECT,a=odf.WordBoundaryFilter.IncludeWhitespace.TRAILING,c=odf.WordBoundaryFilter.IncludeWhitespace.LEADING,l={NO_NEIGHBOUR:0,SPACE_CHAR:1,PUNCTUATION_CHAR:2,WORD_CHAR:3,OTHER:4};this.acceptPosition=function(d){var k=d.container(),m=d.leftNode(),p=d.rightNode(),q=d.unfilteredDomOffset,t=function(){return d.unfilteredDomOffset()-1};k.nodeType===n&&(null===p&&(p=b(k,1,d.getNodeFilter())),nu [...]
++b(k,-1,d.getNodeFilter())));k!==p&&(q=function(){return 0});k!==m&&null!==m&&(t=function(){return m.textContent.length-1});k=g(m,t);p=g(p,q);return k===l.WORD_CHAR&&p===l.WORD_CHAR||k===l.PUNCTUATION_CHAR&&p===l.PUNCTUATION_CHAR||h===a&&k!==l.NO_NEIGHBOUR&&p===l.SPACE_CHAR||h===c&&k===l.SPACE_CHAR&&p!==l.NO_NEIGHBOUR?r:e}};odf.WordBoundaryFilter.IncludeWhitespace={None:0,TRAILING:1,LEADING:2};(function(){return odf.WordBoundaryFilter})();
++// Input 92
++gui.SelectionController=function(m,h){function b(){var a=x.getCursor(h).getNode();return x.createStepIterator(a,0,[s,F],x.getRootElement(a))}function g(a,b,c){c=new odf.WordBoundaryFilter(x,c);return x.createStepIterator(a,b,[s,F,c],x.getRootElement(a))}function d(a){return function(b){var c=a(b);return function(b,d){return a(d)===c}}}function n(a,b){return b?{anchorNode:a.startContainer,anchorOffset:a.startOffset,focusNode:a.endContainer,focusOffset:a.endOffset}:{anchorNode:a.endContai [...]
++focusNode:a.startContainer,focusOffset:a.startOffset}}function p(a,b,c){var d=new ops.OpMoveCursor;d.init({memberid:h,position:a,length:b||0,selectionType:c});return d}function k(a){var b;b=g(a.startContainer,a.startOffset,L);b.roundToPreviousStep()&&a.setStart(b.container(),b.offset());b=g(a.endContainer,a.endOffset,O);b.roundToNextStep()&&a.setEnd(b.container(),b.offset())}function q(a){var b=u.getParagraphElements(a),c=b[0],b=b[b.length-1];c&&a.setStart(c,0);b&&(u.isParagraph(a.endCo [...]
++0===a.endOffset?a.setEndBefore(b):a.setEnd(b,b.childNodes.length))}function e(a){var b=x.getCursorSelection(h),c=x.getCursor(h).getStepCounter();0!==a&&(a=0<a?c.convertForwardStepsBetweenFilters(a,y,s):-c.convertBackwardStepsBetweenFilters(-a,y,s),a=b.length+a,m.enqueue([p(b.position,a)]))}function r(a){var c=b(),d=x.getCursor(h).getAnchorNode();a(c)&&(a=x.convertDomToCursorRange({anchorNode:d,anchorOffset:0,focusNode:c.container(),focusOffset:c.offset()}),m.enqueue([p(a.position,a.leng [...]
++x.getCursorPosition(h),c=x.getCursor(h).getStepCounter();0!==a&&(a=0<a?c.convertForwardStepsBetweenFilters(a,y,s):-c.convertBackwardStepsBetweenFilters(-a,y,s),m.enqueue([p(b+a,0)]))}function c(a){var c=b();a(c)&&(a=x.convertDomPointToCursorStep(c.container(),c.offset()),m.enqueue([p(a,0)]))}function l(b,c){var d=x.getParagraphElement(x.getCursor(h).getNode());runtime.assert(Boolean(d),"SelectionController: Cursor outside paragraph");d=x.getCursor(h).getStepCounter().countLinesSteps(b,y [...]
++function f(b,c){var d=x.getCursor(h).getStepCounter().countStepsToLineBoundary(b,y);c?e(d):a(d)}function v(a,b){var c=x.getCursor(h),c=n(c.getSelectedRange(),c.hasForwardSelection()),d=g(c.focusNode,c.focusOffset,L);if(0<=a?d.nextStep():d.previousStep())c.focusNode=d.container(),c.focusOffset=d.offset(),b||(c.anchorNode=c.focusNode,c.anchorOffset=c.focusOffset),c=x.convertDomToCursorRange(c),m.enqueue([p(c.position,c.length)])}function w(a,b){var c=x.getCursor(h),f=b(c.getNode()),c=n(c. [...]
++c.hasForwardSelection());runtime.assert(Boolean(f),"SelectionController: Cursor outside root");0>a?(c.focusNode=f,c.focusOffset=0):(c.focusNode=f,c.focusOffset=f.childNodes.length);f=x.convertDomToCursorRange(c,d(b));m.enqueue([p(f.position,f.length)])}function z(a){var b=x.getCursor(h),b=x.getRootElement(b.getNode());runtime.assert(Boolean(b),"SelectionController: Cursor outside root");a=0>a?x.convertDomPointToCursorStep(b,0,function(a){return a===ops.StepsTranslator.NEXT_STEP}):x.conv [...]
++b.childNodes.length);m.enqueue([p(a,0)]);return!0}var x=m.getOdtDocument(),t=new core.DomUtils,u=new odf.OdfUtils,s=x.getPositionFilter(),y=new core.PositionFilterChain,F=x.createRootFilter(h),L=odf.WordBoundaryFilter.IncludeWhitespace.TRAILING,O=odf.WordBoundaryFilter.IncludeWhitespace.LEADING;this.selectionToRange=function(a){var b=0<=t.comparePoints(a.anchorNode,a.anchorOffset,a.focusNode,a.focusOffset),c=a.focusNode.ownerDocument.createRange();b?(c.setStart(a.anchorNode,a.anchorOffs [...]
++a.focusOffset)):(c.setStart(a.focusNode,a.focusOffset),c.setEnd(a.anchorNode,a.anchorOffset));return{range:c,hasForwardSelection:b}};this.rangeToSelection=n;this.selectImage=function(a){var b=x.getRootElement(a),c=x.createRootFilter(b),b=x.createStepIterator(a,0,[c,x.getPositionFilter()],b),d;b.roundToPreviousStep()||runtime.assert(!1,"No walkable position before frame");c=b.container();d=b.offset();b.setPosition(a,a.childNodes.length);b.roundToNextStep()||runtime.assert(!1,"No walkable [...]
++a=x.convertDomToCursorRange({anchorNode:c,anchorOffset:d,focusNode:b.container(),focusOffset:b.offset()});a=p(a.position,a.length,ops.OdtCursor.RegionSelection);m.enqueue([a])};this.expandToWordBoundaries=k;this.expandToParagraphBoundaries=q;this.selectRange=function(a,b,c){var f=x.getOdfCanvas().getElement(),e;e=t.containsNode(f,a.startContainer);f=t.containsNode(f,a.endContainer);if(e||f)if(e&&f&&(2===c?k(a):3<=c&&q(a)),a=n(a,b),b=x.convertDomToCursorRange(a,d(u.getParagraphElement)), [...]
++b.position!==a.position||b.length!==a.length)a=p(b.position,b.length,ops.OdtCursor.RangeSelection),m.enqueue([a])};this.moveCursorToLeft=function(){c(function(a){return a.previousStep()});return!0};this.moveCursorToRight=function(){c(function(a){return a.nextStep()});return!0};this.extendSelectionToLeft=function(){r(function(a){return a.previousStep()});return!0};this.extendSelectionToRight=function(){r(function(a){return a.nextStep()});return!0};this.moveCursorUp=function(){l(-1,!1);re [...]
++function(){l(1,!1);return!0};this.extendSelectionUp=function(){l(-1,!0);return!0};this.extendSelectionDown=function(){l(1,!0);return!0};this.moveCursorBeforeWord=function(){v(-1,!1);return!0};this.moveCursorPastWord=function(){v(1,!1);return!0};this.extendSelectionBeforeWord=function(){v(-1,!0);return!0};this.extendSelectionPastWord=function(){v(1,!0);return!0};this.moveCursorToLineStart=function(){f(-1,!1);return!0};this.moveCursorToLineEnd=function(){f(1,!1);return!0};this.extendSelec [...]
++function(){f(-1,!0);return!0};this.extendSelectionToLineEnd=function(){f(1,!0);return!0};this.extendSelectionToParagraphStart=function(){w(-1,x.getParagraphElement);return!0};this.extendSelectionToParagraphEnd=function(){w(1,x.getParagraphElement);return!0};this.moveCursorToDocumentStart=function(){z(-1);return!0};this.moveCursorToDocumentEnd=function(){z(1);return!0};this.extendSelectionToDocumentStart=function(){w(-1,x.getRootElement);return!0};this.extendSelectionToDocumentEnd=functi [...]
++return!0};this.extendSelectionToEntireDocument=function(){var a=x.getCursor(h),a=x.getRootElement(a.getNode());runtime.assert(Boolean(a),"SelectionController: Cursor outside root");a=x.convertDomToCursorRange({anchorNode:a,anchorOffset:0,focusNode:a,focusOffset:a.childNodes.length},d(x.getRootElement));m.enqueue([p(a.position,a.length)]);return!0};y.addFilter(s);y.addFilter(x.createRootFilter(h))};
++// Input 93
 +/*
 +
 + Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- gui.PlainTextPasteboard=function(g,l){function f(f,g){f.init(g);return f}this.createPasteOps=function(p){var r=g.getCursorPosition(l),n=r,h=[];p.replace(/\r/g,"").split("\n").forEach(function(d){h.push(f(new ops.OpSplitParagraph,{memberid:l,position:n,moveCursor:!0}));n+=1;h.push(f(new ops.OpInsertText,{memberid:l,position:n,text:d,moveCursor:!0}));n+=d.length});h.push(f(new ops.OpRemoveText,{memberid:l,position:r,length:1}));return h}};
- // Input 88
- runtime.loadClass("core.DomUtils");runtime.loadClass("odf.OdfUtils");runtime.loadClass("odf.OdfNodeFilter");runtime.loadClass("gui.SelectionMover");
- gui.SelectionView=function(g){function l(){var a=q.getRootNode();k!==a&&(k=a,t=k.parentNode.parentNode.parentNode,t.appendChild(w),t.appendChild(x),t.appendChild(v))}function f(a,b){a.style.left=b.left+"px";a.style.top=b.top+"px";a.style.width=b.width+"px";a.style.height=b.height+"px"}function p(a){H=a;w.style.display=x.style.display=v.style.display=!0===a?"block":"none"}function r(a){var b=s.getBoundingClientRect(t),c=q.getOdfCanvas().getZoomLevel(),d={};d.top=s.adaptRangeDifferenceToZ [...]
- b.top,c);d.left=s.adaptRangeDifferenceToZoomLevel(a.left-b.left,c);d.bottom=s.adaptRangeDifferenceToZoomLevel(a.bottom-b.top,c);d.right=s.adaptRangeDifferenceToZoomLevel(a.right-b.left,c);d.width=s.adaptRangeDifferenceToZoomLevel(a.width,c);d.height=s.adaptRangeDifferenceToZoomLevel(a.height,c);return d}function n(a){a=a.getBoundingClientRect();return Boolean(a&&0!==a.height)}function h(a){var b=u.getTextElements(a,!0,!1),c=a.cloneRange(),d=a.cloneRange();a=a.cloneRange();if(!b.length)r [...]
- var e;a:{e=0;var f=b[e],g=c.startContainer===f?c.startOffset:0,h=g;c.setStart(f,g);for(c.setEnd(f,h);!n(c);){if(f.nodeType===Node.ELEMENT_NODE&&h<f.childNodes.length)h=f.childNodes.length;else if(f.nodeType===Node.TEXT_NODE&&h<f.length)h+=1;else if(b[e])f=b[e],e+=1,g=h=0;else{e=!1;break a}c.setStart(f,g);c.setEnd(f,h)}e=!0}if(!e)return null;a:{e=b.length-1;f=b[e];h=g=d.endContainer===f?d.endOffset:f.length||f.childNodes.length;d.setStart(f,g);for(d.setEnd(f,h);!n(d);){if(f.nodeType===No [...]
- 0<g)g=0;else if(f.nodeType===Node.TEXT_NODE&&0<g)g-=1;else if(b[e])f=b[e],e-=1,g=h=f.length||f.childNodes.length;else{b=!1;break a}d.setStart(f,g);d.setEnd(f,h)}b=!0}if(!b)return null;a.setStart(c.startContainer,c.startOffset);a.setEnd(d.endContainer,d.endOffset);return{firstRange:c,lastRange:d,fillerRange:a}}function d(a,b){var c={};c.top=Math.min(a.top,b.top);c.left=Math.min(a.left,b.left);c.right=Math.max(a.right,b.right);c.bottom=Math.max(a.bottom,b.bottom);c.width=c.right-c.left;c. [...]
- c.top;return c}function m(a,b){b&&0<b.width&&0<b.height&&(a=a?d(a,b):b);return a}function c(a){function b(a){y.setUnfilteredPosition(a,0);return w.acceptNode(a)===B&&t.acceptPosition(y)===B?B:L}function c(a){var d=null;b(a)===B&&(d=s.getBoundingClientRect(a));return d}var d=a.commonAncestorContainer,e=a.startContainer,f=a.endContainer,g=a.startOffset,h=a.endOffset,k,l,n=null,p,r=A.createRange(),t,w=new odf.OdfNodeFilter,v;if(e===d||f===d)return r=a.cloneRange(),n=r.getBoundingClientRect [...]
- n;for(a=e;a.parentNode!==d;)a=a.parentNode;for(l=f;l.parentNode!==d;)l=l.parentNode;t=q.createRootFilter(e);for(d=a.nextSibling;d&&d!==l;)p=c(d),n=m(n,p),d=d.nextSibling;if(u.isParagraph(a))n=m(n,s.getBoundingClientRect(a));else if(a.nodeType===Node.TEXT_NODE)d=a,r.setStart(d,g),r.setEnd(d,d===l?h:d.length),p=r.getBoundingClientRect(),n=m(n,p);else for(v=A.createTreeWalker(a,NodeFilter.SHOW_TEXT,b,!1),d=v.currentNode=e;d&&d!==f;)r.setStart(d,g),r.setEnd(d,d.length),p=r.getBoundingClient [...]
- p),k=d,g=0,d=v.nextNode();k||(k=e);if(u.isParagraph(l))n=m(n,s.getBoundingClientRect(l));else if(l.nodeType===Node.TEXT_NODE)d=l,r.setStart(d,d===a?g:0),r.setEnd(d,h),p=r.getBoundingClientRect(),n=m(n,p);else for(v=A.createTreeWalker(l,NodeFilter.SHOW_TEXT,b,!1),d=v.currentNode=f;d&&d!==k;)if(r.setStart(d,0),r.setEnd(d,h),p=r.getBoundingClientRect(),n=m(n,p),d=v.previousNode())h=d.length;return n}function e(a,b){var c=a.getBoundingClientRect(),d={width:0};d.top=c.top;d.bottom=c.bottom;d [...]
- d.left=d.right=b?c.right:c.left;return d}function a(){l();if(g.getSelectionType()===ops.OdtCursor.RangeSelection){p(!0);var a=g.getSelectedRange(),b=h(a),k,m,n,q;a.collapsed||!b?p(!1):(p(!0),a=b.firstRange,k=b.lastRange,b=b.fillerRange,m=r(e(a,!1)),q=r(e(k,!0)),n=(n=c(b))?r(n):d(m,q),f(w,{left:m.left,top:m.top,width:Math.max(0,n.width-(m.left-n.left)),height:m.height}),q.top===m.top||q.bottom===m.bottom?x.style.display=v.style.display="none":(f(v,{left:n.left,top:q.top,width:Math.max(0, [...]
- height:q.height}),f(x,{left:n.left,top:m.top+m.height,width:Math.max(0,parseFloat(w.style.left)+parseFloat(w.style.width)-parseFloat(v.style.left)),height:Math.max(0,q.top-m.bottom)})),a.detach(),k.detach(),b.detach())}else p(!1)}function b(b){b===g&&a()}var q=g.getOdtDocument(),k,t,A=q.getDOM(),w=A.createElement("div"),x=A.createElement("div"),v=A.createElement("div"),u=new odf.OdfUtils,s=new core.DomUtils,H=!0,y=gui.SelectionMover.createPositionIterator(q.getRootNode()),B=NodeFilter.F [...]
- L=NodeFilter.FILTER_REJECT;this.show=this.rerender=a;this.hide=function(){p(!1)};this.visible=function(){return H};this.destroy=function(a){t.removeChild(w);t.removeChild(x);t.removeChild(v);g.getOdtDocument().unsubscribe(ops.OdtDocument.signalCursorMoved,b);a()};(function(){var a=g.getMemberId();l();w.setAttributeNS("urn:webodf:names:editinfo","editinfo:memberid",a);x.setAttributeNS("urn:webodf:names:editinfo","editinfo:memberid",a);v.setAttributeNS("urn:webodf:names:editinfo","editinf [...]
- a);w.className=x.className=v.className="selectionOverlay";g.getOdtDocument().subscribe(ops.OdtDocument.signalCursorMoved,b)})()};
- // Input 89
++gui.TextController=function(m,h,b,g){function d(b){var d=new ops.OpRemoveText;d.init({memberid:h,position:b.position,length:b.length});return d}function n(b){0>b.length&&(b.position+=b.length,b.length=-b.length);return b}function p(b,d){var a=new core.PositionFilterChain,c=gui.SelectionMover.createPositionIterator(k.getRootElement(b)),g=d?c.nextPosition:c.previousPosition;a.addFilter(k.getPositionFilter());a.addFilter(k.createRootFilter(h));for(c.setUnfilteredPosition(b,0);g();)if(a.acc [...]
++q)return!0;return!1}var k=m.getOdtDocument(),q=core.PositionFilter.FilterResult.FILTER_ACCEPT;this.enqueueParagraphSplittingOps=function(){var b=n(k.getCursorSelection(h)),p,a=[];0<b.length&&(p=d(b),a.push(p));p=new ops.OpSplitParagraph;p.init({memberid:h,position:b.position,moveCursor:!0});a.push(p);g&&(b=g(b.position+1),a=a.concat(b));m.enqueue(a);return!0};this.removeTextByBackspaceKey=function(){var b=k.getCursor(h),g=n(k.getCursorSelection(h)),a=null;0===g.length?p(b.getNode(),!1)& [...]
++a.init({memberid:h,position:g.position-1,length:1}),m.enqueue([a])):(a=d(g),m.enqueue([a]));return null!==a};this.removeTextByDeleteKey=function(){var b=k.getCursor(h),g=n(k.getCursorSelection(h)),a=null;0===g.length?p(b.getNode(),!0)&&(a=new ops.OpRemoveText,a.init({memberid:h,position:g.position,length:1}),m.enqueue([a])):(a=d(g),m.enqueue([a]));return null!==a};this.removeCurrentSelection=function(){var b=n(k.getCursorSelection(h));0!==b.length&&(b=d(b),m.enqueue([b]));return!0};this [...]
++function(e){var g=n(k.getCursorSelection(h)),a,c=[],l=!1;0<g.length&&(a=d(g),c.push(a),l=!0);a=new ops.OpInsertText;a.init({memberid:h,position:g.position,text:e,moveCursor:!0});c.push(a);b&&(e=b(g.position,e.length,l))&&c.push(e);m.enqueue(c)}};(function(){return gui.TextController})();
++// Input 94
 +/*
 +
 + Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("gui.SelectionView");
- gui.SelectionViewManager=function(){function g(){return Object.keys(l).map(function(f){return l[f]})}var l={};this.getSelectionView=function(f){return l.hasOwnProperty(f)?l[f]:null};this.getSelectionViews=g;this.removeSelectionView=function(f){l.hasOwnProperty(f)&&(l[f].destroy(function(){}),delete l[f])};this.hideSelectionView=function(f){l.hasOwnProperty(f)&&l[f].hide()};this.showSelectionView=function(f){l.hasOwnProperty(f)&&l[f].show()};this.rerenderSelectionViews=function(){Object. [...]
- l[f].rerender()})};this.registerCursor=function(f,g){var r=f.getMemberId(),n=new gui.SelectionView(f);g?n.show():n.hide();return l[r]=n};this.destroy=function(f){var l=g();(function n(g,d){d?f(d):g<l.length?l[g].destroy(function(d){n(g+1,d)}):f()})(0,void 0)}};
- // Input 90
++gui.UndoManager=function(){};gui.UndoManager.prototype.subscribe=function(m,h){};gui.UndoManager.prototype.unsubscribe=function(m,h){};gui.UndoManager.prototype.setDocument=function(m){};gui.UndoManager.prototype.setInitialState=function(){};gui.UndoManager.prototype.initialize=function(){};gui.UndoManager.prototype.purgeInitialState=function(){};gui.UndoManager.prototype.setPlaybackFunction=function(m){};gui.UndoManager.prototype.hasUndoStates=function(){};
++gui.UndoManager.prototype.hasRedoStates=function(){};gui.UndoManager.prototype.moveForward=function(m){};gui.UndoManager.prototype.moveBackward=function(m){};gui.UndoManager.prototype.onOperationExecuted=function(m){};gui.UndoManager.signalUndoStackChanged="undoStackChanged";gui.UndoManager.signalUndoStateCreated="undoStateCreated";gui.UndoManager.signalUndoStateModified="undoStateModified";(function(){return gui.UndoManager})();
++// Input 95
++(function(){var m=core.PositionFilter.FilterResult.FILTER_ACCEPT;gui.SessionController=function(h,b,g,d){function n(a){return a.target||a.srcElement||null}function p(a,b){var c=J.getDOMDocument(),d=null;c.caretRangeFromPoint?(c=c.caretRangeFromPoint(a,b),d={container:c.startContainer,offset:c.startOffset}):c.caretPositionFromPoint&&(c=c.caretPositionFromPoint(a,b))&&c.offsetNode&&(d={container:c.offsetNode,offset:c.offset});return d}function k(a){var c=J.getCursor(b).getSelectedRange(); [...]
++a.preventDefault():I.setDataFromRange(a,c)?aa.removeCurrentSelection():runtime.log("Cut operation failed")}function q(){return!1!==J.getCursor(b).getSelectedRange().collapsed}function e(a){var c=J.getCursor(b).getSelectedRange();c.collapsed?a.preventDefault():I.setDataFromRange(a,c)||runtime.log("Copy operation failed")}function r(a){var b;G.clipboardData&&G.clipboardData.getData?b=G.clipboardData.getData("Text"):a.clipboardData&&a.clipboardData.getData&&(b=a.clipboardData.getData("text [...]
++b&&(aa.removeCurrentSelection(),h.enqueue(na.createPasteOps(b)));a.preventDefault?a.preventDefault():a.returnValue=!1}function a(){return!1}function c(a){if(ca)ca.onOperationExecuted(a)}function l(a){J.emit(ops.OdtDocument.signalUndoStackChanged,a)}function f(){var a=A.getEventTrap(),b,c;return ca?(c=A.hasFocus(),ca.moveBackward(1),b=J.getOdfCanvas().getSizer(),ea.containsNode(b,a)||(b.appendChild(a),c&&A.focus()),!0):!1}function v(){var a;return ca?(a=A.hasFocus(),ca.moveForward(1),a&& [...]
++!0):!1}function w(a){var c=J.getCursor(b).getSelectedRange(),d=n(a).getAttribute("end");c&&d&&(a=p(a.clientX,a.clientY))&&(da.setUnfilteredPosition(a.container,a.offset),fa.acceptPosition(da)===m&&(c=c.cloneRange(),"left"===d?c.setStart(da.container(),da.unfilteredDomOffset()):c.setEnd(da.container(),da.unfilteredDomOffset()),g.setSelectedRange(c,"right"===d),J.emit(ops.Document.signalCursorMoved,g)))}function z(){K.selectRange(g.getSelectedRange(),g.hasForwardSelection(),1)}function x( [...]
++b=0<a.rangeCount&&K.selectionToRange(a);$&&b&&(S=!0,ga.clearSelection(),da.setUnfilteredPosition(a.focusNode,a.focusOffset),fa.acceptPosition(da)===m&&(2===ka?K.expandToWordBoundaries(b.range):3<=ka&&K.expandToParagraphBoundaries(b.range),g.setSelectedRange(b.range,b.hasForwardSelection),J.emit(ops.Document.signalCursorMoved,g)))}function t(a){var c=n(a),d=J.getCursor(b);if($=null!==c&&ea.containsNode(J.getOdfCanvas().getElement(),c))S=!1,fa=J.createRootFilter(c),ka=a.detail,d&&a.shiftK [...]
++0):(a=G.getSelection(),c=d.getSelectedRange(),a.extend?d.hasForwardSelection()?(a.collapse(c.startContainer,c.startOffset),a.extend(c.endContainer,c.endOffset)):(a.collapse(c.endContainer,c.endOffset),a.extend(c.startContainer,c.startOffset)):(a.removeAllRanges(),a.addRange(c.cloneRange()))),1<ka&&x()}function u(a){var b=J.getRootElement(a),c=J.createRootFilter(b),b=J.createStepIterator(a,0,[c,J.getPositionFilter()],b);b.setPosition(a,a.childNodes.length);return b.roundToNextStep()?{con [...]
++offset:b.offset()}:null}function s(a){var b;b=(b=G.getSelection())?{anchorNode:b.anchorNode,anchorOffset:b.anchorOffset,focusNode:b.focusNode,focusOffset:b.focusOffset}:null;var c,d;b.anchorNode||b.focusNode||!(c=p(a.clientX,a.clientY))||(b.anchorNode=c.container,b.anchorOffset=c.offset,b.focusNode=b.anchorNode,b.focusOffset=b.anchorOffset);if(P.isImage(b.focusNode)&&0===b.focusOffset&&P.isCharacterFrame(b.focusNode.parentNode)){if(d=b.focusNode.parentNode,c=d.getBoundingClientRect(),a. [...]
++(c=u(d)))b.anchorNode=b.focusNode=c.container,b.anchorOffset=b.focusOffset=c.offset}else P.isImage(b.focusNode.firstChild)&&1===b.focusOffset&&P.isCharacterFrame(b.focusNode)&&(c=u(b.focusNode))&&(b.anchorNode=b.focusNode=c.container,b.anchorOffset=b.focusOffset=c.offset);b.anchorNode&&b.focusNode&&(b=K.selectionToRange(b),K.selectRange(b.range,b.hasForwardSelection,a.detail));A.focus()}function y(a){var b;if(b=p(a.clientX,a.clientY))a=b.container,b=b.offset,a={anchorNode:a,anchorOffset [...]
++focusOffset:b},a=K.selectionToRange(a),K.selectRange(a.range,a.hasForwardSelection,2),A.focus()}function F(a){var b=n(a),c,d;la.processRequests();P.isImage(b)&&P.isCharacterFrame(b.parentNode)&&G.getSelection().isCollapsed?(K.selectImage(b.parentNode),A.focus()):ga.isSelectorElement(b)?A.focus():$&&(S?(b=g.getSelectedRange(),c=b.collapsed,P.isImage(b.endContainer)&&0===b.endOffset&&P.isCharacterFrame(b.endContainer.parentNode)&&(d=b.endContainer.parentNode,d=u(d))&&(b.setEnd(d.container [...]
++c&&b.collapse(!1)),K.selectRange(b,g.hasForwardSelection(),a.detail),A.focus()):qa?s(a):ma=runtime.setTimeout(function(){s(a)},0));ka=0;S=$=!1}function L(a){var c=J.getCursor(b).getSelectedRange();c.collapsed||N.exportRangeToDataTransfer(a.dataTransfer,c)}function O(){$&&A.focus();ka=0;S=$=!1}function H(a){F(a)}function U(a){var b=n(a),c=null;"annotationRemoveButton"===b.className?(c=ea.getElementsByTagNameNS(b.parentNode,odf.Namespaces.officens,"annotation")[0],Y.removeAnnotation(c),A. [...]
++b.getAttribute("class")&&F(a)}function T(a){(a=a.data)&&aa.insertText(a)}function X(a){return function(){a();return!0}}function D(a){return function(c){return J.getCursor(b).getSelectionType()===ops.OdtCursor.RangeSelection?a(c):!0}}function ba(a){A.unsubscribe("keydown",B.handleEvent);A.unsubscribe("keypress",V.handleEvent);A.unsubscribe("keyup",M.handleEvent);A.unsubscribe("copy",e);A.unsubscribe("mousedown",t);A.unsubscribe("mousemove",la.trigger);A.unsubscribe("mouseup",U);A.unsubsc [...]
++H);A.unsubscribe("dragstart",L);A.unsubscribe("dragend",O);A.unsubscribe("click",Z.handleClick);A.unsubscribe("longpress",y);A.unsubscribe("drag",w);A.unsubscribe("dragstop",z);J.unsubscribe(ops.OdtDocument.signalOperationEnd,ja.trigger);J.unsubscribe(ops.Document.signalCursorAdded,ha.registerCursor);J.unsubscribe(ops.Document.signalCursorRemoved,ha.removeCursor);J.unsubscribe(ops.OdtDocument.signalOperationEnd,c);a()}var G=runtime.getWindow(),J=h.getOdtDocument(),Q=new core.Async,ea=ne [...]
++P=new odf.OdfUtils,N=new gui.MimeDataExporter,I=new gui.Clipboard(N),B=new gui.KeyboardHandler,V=new gui.KeyboardHandler,M=new gui.KeyboardHandler,$=!1,W=new odf.ObjectNameGenerator(J.getOdfCanvas().odfContainer(),b),S=!1,fa=null,ma,ca=null,A=new gui.EventManager(J),Y=new gui.AnnotationController(h,b),R=new gui.DirectFormattingController(h,b,W,d.directParagraphStylingEnabled),aa=new gui.TextController(h,b,R.createCursorStyleOp,R.createParagraphStyleOps),ia=new gui.ImageController(h,b,W) [...]
++da=gui.SelectionMover.createPositionIterator(J.getRootNode()),la,ja,na=new gui.PlainTextPasteboard(J,b),ha=new gui.InputMethodEditor(b,A),ka=0,Z=new gui.HyperlinkClickHandler(J.getRootNode),ra=new gui.HyperlinkController(h,b),K=new gui.SelectionController(h,b),E=gui.KeyboardHandler.Modifier,C=gui.KeyboardHandler.KeyCode,oa=-1!==G.navigator.appVersion.toLowerCase().indexOf("mac"),qa=-1!==["iPad","iPod","iPhone"].indexOf(G.navigator.platform),pa;runtime.assert(null!==G,"Expected to be run [...]
++this.undo=f;this.redo=v;this.insertLocalCursor=function(){runtime.assert(void 0===h.getOdtDocument().getCursor(b),"Inserting local cursor a second time.");var a=new ops.OpAddCursor;a.init({memberid:b});h.enqueue([a]);A.focus()};this.removeLocalCursor=function(){runtime.assert(void 0!==h.getOdtDocument().getCursor(b),"Removing local cursor without inserting before.");var a=new ops.OpRemoveCursor;a.init({memberid:b});h.enqueue([a])};this.startEditing=function(){ha.subscribe(gui.InputMetho [...]
++aa.removeCurrentSelection);ha.subscribe(gui.InputMethodEditor.signalCompositionEnd,T);A.subscribe("beforecut",q);A.subscribe("cut",k);A.subscribe("beforepaste",a);A.subscribe("paste",r);G.addEventListener("focus",Z.showTextCursor,!1);ca&&ca.initialize();ha.setEditing(!0);Z.setModifier(oa?gui.HyperlinkClickHandler.Modifier.Meta:gui.HyperlinkClickHandler.Modifier.Ctrl);B.bind(C.Backspace,E.None,X(aa.removeTextByBackspaceKey),!0);B.bind(C.Delete,E.None,aa.removeTextByDeleteKey);B.bind(C.Ta [...]
++return!0}));oa?(B.bind(C.Clear,E.None,aa.removeCurrentSelection),B.bind(C.B,E.Meta,D(R.toggleBold)),B.bind(C.I,E.Meta,D(R.toggleItalic)),B.bind(C.U,E.Meta,D(R.toggleUnderline)),B.bind(C.L,E.MetaShift,D(R.alignParagraphLeft)),B.bind(C.E,E.MetaShift,D(R.alignParagraphCenter)),B.bind(C.R,E.MetaShift,D(R.alignParagraphRight)),B.bind(C.J,E.MetaShift,D(R.alignParagraphJustified)),B.bind(C.C,E.MetaShift,Y.addAnnotation),B.bind(C.Z,E.Meta,f),B.bind(C.Z,E.MetaShift,v),B.bind(C.LeftMeta,E.Meta,Z. [...]
++B.bind(C.MetaInMozilla,E.Meta,Z.showPointerCursor),M.bind(C.LeftMeta,E.None,Z.showTextCursor),M.bind(C.MetaInMozilla,E.None,Z.showTextCursor)):(B.bind(C.B,E.Ctrl,D(R.toggleBold)),B.bind(C.I,E.Ctrl,D(R.toggleItalic)),B.bind(C.U,E.Ctrl,D(R.toggleUnderline)),B.bind(C.L,E.CtrlShift,D(R.alignParagraphLeft)),B.bind(C.E,E.CtrlShift,D(R.alignParagraphCenter)),B.bind(C.R,E.CtrlShift,D(R.alignParagraphRight)),B.bind(C.J,E.CtrlShift,D(R.alignParagraphJustified)),B.bind(C.C,E.CtrlAlt,Y.addAnnotatio [...]
++E.Ctrl,f),B.bind(C.Z,E.CtrlShift,v),B.bind(C.Ctrl,E.Ctrl,Z.showPointerCursor),M.bind(C.Ctrl,E.None,Z.showTextCursor));V.setDefault(D(function(a){var b;b=null===a.which||void 0===a.which?String.fromCharCode(a.keyCode):0!==a.which&&0!==a.charCode?String.fromCharCode(a.which):null;return!b||a.altKey||a.ctrlKey||a.metaKey?!1:(aa.insertText(b),!0)}));V.bind(C.Enter,E.None,D(aa.enqueueParagraphSplittingOps))};this.endEditing=function(){ha.unsubscribe(gui.InputMethodEditor.signalCompositionSta [...]
++ha.unsubscribe(gui.InputMethodEditor.signalCompositionEnd,T);A.unsubscribe("cut",k);A.unsubscribe("beforecut",q);A.unsubscribe("paste",r);A.unsubscribe("beforepaste",a);G.removeEventListener("focus",Z.showTextCursor,!1);ha.setEditing(!1);Z.setModifier(gui.HyperlinkClickHandler.Modifier.None);B.bind(C.Backspace,E.None,function(){return!0},!0);B.unbind(C.Delete,E.None);B.unbind(C.Tab,E.None);oa?(B.unbind(C.Clear,E.None),B.unbind(C.B,E.Meta),B.unbind(C.I,E.Meta),B.unbind(C.U,E.Meta),B.unbi [...]
++B.unbind(C.E,E.MetaShift),B.unbind(C.R,E.MetaShift),B.unbind(C.J,E.MetaShift),B.unbind(C.C,E.MetaShift),B.unbind(C.Z,E.Meta),B.unbind(C.Z,E.MetaShift),B.unbind(C.LeftMeta,E.Meta),B.unbind(C.MetaInMozilla,E.Meta),M.unbind(C.LeftMeta,E.None),M.unbind(C.MetaInMozilla,E.None)):(B.unbind(C.B,E.Ctrl),B.unbind(C.I,E.Ctrl),B.unbind(C.U,E.Ctrl),B.unbind(C.L,E.CtrlShift),B.unbind(C.E,E.CtrlShift),B.unbind(C.R,E.CtrlShift),B.unbind(C.J,E.CtrlShift),B.unbind(C.C,E.CtrlAlt),B.unbind(C.Z,E.Ctrl),B.un [...]
++B.unbind(C.Ctrl,E.Ctrl),M.unbind(C.Ctrl,E.None));V.setDefault(null);V.unbind(C.Enter,E.None)};this.getInputMemberId=function(){return b};this.getSession=function(){return h};this.setUndoManager=function(a){ca&&ca.unsubscribe(gui.UndoManager.signalUndoStackChanged,l);if(ca=a)ca.setDocument(J),ca.setPlaybackFunction(h.enqueue),ca.subscribe(gui.UndoManager.signalUndoStackChanged,l)};this.getUndoManager=function(){return ca};this.getAnnotationController=function(){return Y};this.getDirectFo [...]
++function(){return R};this.getHyperlinkController=function(){return ra};this.getImageController=function(){return ia};this.getSelectionController=function(){return K};this.getTextController=function(){return aa};this.getEventManager=function(){return A};this.getKeyboardHandlers=function(){return{keydown:B,keypress:V}};this.destroy=function(a){var b=[];pa&&b.push(pa.destroy);b=b.concat([la.destroy,ja.destroy,R.destroy,ha.destroy,A.destroy,ba]);runtime.clearTimeout(ma);Q.destroyAll(b,a)};l [...]
++0);ja=new core.ScheduledTask(function(){var a=J.getCursor(b);if(a&&a.getSelectionType()===ops.OdtCursor.RegionSelection&&(a=P.getImageElements(a.getSelectedRange())[0])){ga.select(a.parentNode);return}ga.clearSelection()},0);B.bind(C.Left,E.None,D(K.moveCursorToLeft));B.bind(C.Right,E.None,D(K.moveCursorToRight));B.bind(C.Up,E.None,D(K.moveCursorUp));B.bind(C.Down,E.None,D(K.moveCursorDown));B.bind(C.Left,E.Shift,D(K.extendSelectionToLeft));B.bind(C.Right,E.Shift,D(K.extendSelectionToRi [...]
++E.Shift,D(K.extendSelectionUp));B.bind(C.Down,E.Shift,D(K.extendSelectionDown));B.bind(C.Home,E.None,D(K.moveCursorToLineStart));B.bind(C.End,E.None,D(K.moveCursorToLineEnd));B.bind(C.Home,E.Ctrl,D(K.moveCursorToDocumentStart));B.bind(C.End,E.Ctrl,D(K.moveCursorToDocumentEnd));B.bind(C.Home,E.Shift,D(K.extendSelectionToLineStart));B.bind(C.End,E.Shift,D(K.extendSelectionToLineEnd));B.bind(C.Up,E.CtrlShift,D(K.extendSelectionToParagraphStart));B.bind(C.Down,E.CtrlShift,D(K.extendSelectio [...]
++B.bind(C.Home,E.CtrlShift,D(K.extendSelectionToDocumentStart));B.bind(C.End,E.CtrlShift,D(K.extendSelectionToDocumentEnd));oa?(B.bind(C.Left,E.Alt,D(K.moveCursorBeforeWord)),B.bind(C.Right,E.Alt,D(K.moveCursorPastWord)),B.bind(C.Left,E.Meta,D(K.moveCursorToLineStart)),B.bind(C.Right,E.Meta,D(K.moveCursorToLineEnd)),B.bind(C.Home,E.Meta,D(K.moveCursorToDocumentStart)),B.bind(C.End,E.Meta,D(K.moveCursorToDocumentEnd)),B.bind(C.Left,E.AltShift,D(K.extendSelectionBeforeWord)),B.bind(C.Right [...]
++D(K.extendSelectionPastWord)),B.bind(C.Left,E.MetaShift,D(K.extendSelectionToLineStart)),B.bind(C.Right,E.MetaShift,D(K.extendSelectionToLineEnd)),B.bind(C.Up,E.AltShift,D(K.extendSelectionToParagraphStart)),B.bind(C.Down,E.AltShift,D(K.extendSelectionToParagraphEnd)),B.bind(C.Up,E.MetaShift,D(K.extendSelectionToDocumentStart)),B.bind(C.Down,E.MetaShift,D(K.extendSelectionToDocumentEnd)),B.bind(C.A,E.Meta,D(K.extendSelectionToEntireDocument))):(B.bind(C.Left,E.Ctrl,D(K.moveCursorBeforeW [...]
++E.Ctrl,D(K.moveCursorPastWord)),B.bind(C.Left,E.CtrlShift,D(K.extendSelectionBeforeWord)),B.bind(C.Right,E.CtrlShift,D(K.extendSelectionPastWord)),B.bind(C.A,E.Ctrl,D(K.extendSelectionToEntireDocument)));qa&&(pa=new gui.IOSSafariSupport(A));A.subscribe("keydown",B.handleEvent);A.subscribe("keypress",V.handleEvent);A.subscribe("keyup",M.handleEvent);A.subscribe("copy",e);A.subscribe("mousedown",t);A.subscribe("mousemove",la.trigger);A.subscribe("mouseup",U);A.subscribe("contextmenu",H);A [...]
++L);A.subscribe("dragend",O);A.subscribe("click",Z.handleClick);A.subscribe("longpress",y);A.subscribe("drag",w);A.subscribe("dragstop",z);J.subscribe(ops.OdtDocument.signalOperationEnd,ja.trigger);J.subscribe(ops.Document.signalCursorAdded,ha.registerCursor);J.subscribe(ops.Document.signalCursorRemoved,ha.removeCursor);J.subscribe(ops.OdtDocument.signalOperationEnd,c)};return gui.SessionController})();
++// Input 96
 +/*
 +
-  Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
++ Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("core.DomUtils");runtime.loadClass("gui.UndoManager");runtime.loadClass("gui.UndoStateRules");
- gui.TrivialUndoManager=function(g){function l(){t.emit(gui.UndoManager.signalUndoStackChanged,{undoAvailable:h.hasUndoStates(),redoAvailable:h.hasRedoStates()})}function f(){b!==c&&b!==q[q.length-1]&&q.push(b)}function p(a){var b=a.previousSibling||a.nextSibling;a.parentNode.removeChild(a);d.normalizeTextNodes(b)}function r(a){return Object.keys(a).map(function(b){return a[b]})}function n(b){function c(a){var b=a.spec();if(f[b.memberid])switch(b.optype){case "AddCursor":d[b.memberid]||( [...]
- a,delete f[b.memberid],g-=1);break;case "MoveCursor":e[b.memberid]||(e[b.memberid]=a)}}var d={},e={},f={},g,h=b.pop();a.getCursors().forEach(function(a){f[a.getMemberId()]=!0});for(g=Object.keys(f).length;h&&0<g;)h.reverse(),h.forEach(c),h=b.pop();return r(d).concat(r(e))}var h=this,d=new core.DomUtils,m,c=[],e,a,b=[],q=[],k=[],t=new core.EventNotifier([gui.UndoManager.signalUndoStackChanged,gui.UndoManager.signalUndoStateCreated,gui.UndoManager.signalUndoStateModified,gui.TrivialUndoMa [...]
- A=g||new gui.UndoStateRules;this.subscribe=function(a,b){t.subscribe(a,b)};this.unsubscribe=function(a,b){t.unsubscribe(a,b)};this.hasUndoStates=function(){return 0<q.length};this.hasRedoStates=function(){return 0<k.length};this.setOdtDocument=function(b){a=b};this.resetInitialState=function(){q.length=0;k.length=0;c.length=0;b.length=0;m=null;l()};this.saveInitialState=function(){var e=a.getOdfCanvas().odfContainer(),g=a.getOdfCanvas().getAnnotationViewManager();g&&g.forgetAnnotations( [...]
- a.getOdfCanvas().refreshAnnotations();e=m;d.getElementsByTagNameNS(e,"urn:webodf:names:cursor","cursor").forEach(p);d.getElementsByTagNameNS(e,"urn:webodf:names:cursor","anchor").forEach(p);f();q.unshift(c);b=c=n(q);q.length=0;k.length=0;l()};this.setPlaybackFunction=function(a){e=a};this.onOperationExecuted=function(a){k.length=0;A.isEditOperation(a)&&b===c||!A.isPartOfOperationSet(a,b)?(f(),b=[a],q.push(b),t.emit(gui.UndoManager.signalUndoStateCreated,{operations:b}),l()):(b.push(a),t [...]
- {operations:b}))};this.moveForward=function(a){for(var c=0,d;a&&k.length;)d=k.pop(),q.push(d),d.forEach(e),a-=1,c+=1;c&&(b=q[q.length-1],l());return c};this.moveBackward=function(d){for(var f=a.getOdfCanvas(),g=f.odfContainer(),h=0;d&&q.length;)k.push(q.pop()),d-=1,h+=1;h&&(g.setRootElement(m.cloneNode(!0)),f.setOdfContainer(g,!0),t.emit(gui.TrivialUndoManager.signalDocumentRootReplaced,{}),a.getCursors().forEach(function(b){a.removeCursor(b.getMemberId())}),c.forEach(e),q.forEach(funct [...]
- f.refreshCSS(),b=q[q.length-1]||c,l());return h}};gui.TrivialUndoManager.signalDocumentRootReplaced="documentRootReplaced";(function(){return gui.TrivialUndoManager})();
- // Input 91
++gui.CaretManager=function(m){function h(a){return c.hasOwnProperty(a)?c[a]:null}function b(){return Object.keys(c).map(function(a){return c[a]})}function g(a){var b=c[a];b&&(b.destroy(function(){}),delete c[a])}function d(a){a=a.getMemberId();a===m.getInputMemberId()&&(a=h(a))&&a.refreshCursorBlinking()}function n(){var a=h(m.getInputMemberId());w=!1;a&&a.ensureVisible()}function p(){var a=h(m.getInputMemberId());a&&(a.handleUpdate(),w||(w=!0,v=runtime.setTimeout(n,50)))}function k(a){a [...]
++m.getInputMemberId()&&p()}function q(){var a=h(m.getInputMemberId());a&&a.setFocus()}function e(){var a=h(m.getInputMemberId());a&&a.removeFocus()}function r(){var a=h(m.getInputMemberId());a&&a.show()}function a(){var a=h(m.getInputMemberId());a&&a.hide()}var c={},l=new core.Async,f=runtime.getWindow(),v,w=!1;this.registerCursor=function(a,b,d){var f=a.getMemberId();b=new gui.Caret(a,b,d);d=m.getEventManager();c[f]=b;f===m.getInputMemberId()?(runtime.log("Starting to track input on new [...]
++f),a.subscribe(ops.OdtCursor.signalCursorUpdated,p),b.setOverlayElement(d.getEventTrap())):a.subscribe(ops.OdtCursor.signalCursorUpdated,b.handleUpdate);return b};this.getCaret=h;this.getCarets=b;this.destroy=function(h){var n=m.getSession().getOdtDocument(),p=m.getEventManager(),u=b().map(function(a){return a.destroy});runtime.clearTimeout(v);n.unsubscribe(ops.OdtDocument.signalParagraphChanged,k);n.unsubscribe(ops.Document.signalCursorMoved,d);n.unsubscribe(ops.Document.signalCursorRe [...]
++q);p.unsubscribe("blur",e);f.removeEventListener("focus",r,!1);f.removeEventListener("blur",a,!1);c={};l.destroyAll(u,h)};(function(){var b=m.getSession().getOdtDocument(),c=m.getEventManager();b.subscribe(ops.OdtDocument.signalParagraphChanged,k);b.subscribe(ops.Document.signalCursorMoved,d);b.subscribe(ops.Document.signalCursorRemoved,g);c.subscribe("focus",q);c.subscribe("blur",e);f.addEventListener("focus",r,!1);f.addEventListener("blur",a,!1)})()};
++// Input 97
++gui.EditInfoHandle=function(m){var h=[],b,g=m.ownerDocument,d=g.documentElement.namespaceURI;this.setEdits=function(m){h=m;var p,k,q,e;b.innerHTML="";for(m=0;m<h.length;m+=1)p=g.createElementNS(d,"div"),p.className="editInfo",k=g.createElementNS(d,"span"),k.className="editInfoColor",k.setAttributeNS("urn:webodf:names:editinfo","editinfo:memberid",h[m].memberid),q=g.createElementNS(d,"span"),q.className="editInfoAuthor",q.setAttributeNS("urn:webodf:names:editinfo","editinfo:memberid",h[m [...]
++e=g.createElementNS(d,"span"),e.className="editInfoTime",e.setAttributeNS("urn:webodf:names:editinfo","editinfo:memberid",h[m].memberid),e.innerHTML=h[m].time,p.appendChild(k),p.appendChild(q),p.appendChild(e),b.appendChild(p)};this.show=function(){b.style.display="block"};this.hide=function(){b.style.display="none"};this.destroy=function(d){m.removeChild(b);d()};b=g.createElementNS(d,"div");b.setAttribute("class","editInfoHandle");b.style.display="none";m.appendChild(b)};
++// Input 98
 +/*
 +
-  Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
++ Copyright (C) 2012 KO GmbH <aditya.bhatt at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("ops.TrivialOperationRouter");runtime.loadClass("ops.OperationFactory");runtime.loadClass("ops.OdtDocument");
- ops.Session=function(g){var l=new ops.OperationFactory,f=new ops.OdtDocument(g),p=null;this.setOperationFactory=function(f){l=f;p&&p.setOperationFactory(l)};this.setOperationRouter=function(g){p=g;g.setPlaybackFunction(function(g){return g.execute(f)?(f.emit(ops.OdtDocument.signalOperationExecuted,g),!0):!1});g.setOperationFactory(l)};this.getOperationFactory=function(){return l};this.getOdtDocument=function(){return f};this.enqueue=function(f){p.push(f)};this.close=function(g){p.close( [...]
- g(l):f.close(g)})};this.destroy=function(g){f.destroy(g)};this.setOperationRouter(new ops.TrivialOperationRouter)};
- // Input 92
++ops.EditInfo=function(m,h){function b(){var b=[],g;for(g in d)d.hasOwnProperty(g)&&b.push({memberid:g,time:d[g].time});b.sort(function(b,d){return b.time-d.time});return b}var g,d={};this.getNode=function(){return g};this.getOdtDocument=function(){return h};this.getEdits=function(){return d};this.getSortedEdits=function(){return b()};this.addEdit=function(b,g){d[b]={time:g}};this.clearEdits=function(){d={}};this.destroy=function(b){m.parentNode&&m.removeChild(g);b()};g=h.getDOMDocument( [...]
++"editinfo");m.insertBefore(g,m.firstChild)};
++// Input 99
 +/*
 +
-  Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
++ Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
-  This file is part of WebODF.
++ The JavaScript code in this page is free software: you can redistribute it
++ and/or modify it under the terms of the GNU Affero General Public License
++ (GNU AGPL) as published by the Free Software Foundation, either version 3 of
++ the License, or (at your option) any later version.  The code is distributed
++ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
-  WebODF is free software: you can redistribute it and/or modify it
-  under the terms of the GNU Affero General Public License (GNU AGPL)
-  as published by the Free Software Foundation, either version 3 of
-  the License, or (at your option) any later version.
++ You should have received a copy of the GNU Affero General Public License
++ along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
-  WebODF is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-  GNU Affero General Public License for more details.
++ As additional permission under GNU AGPL version 3 section 7, you
++ may distribute non-source (e.g., minimized or compacted) forms of
++ that code without the copy of the GNU GPL normally required by
++ section 4, provided you include this license notice and a URL
++ through which recipients can access the Corresponding Source.
 +
-  You should have received a copy of the GNU Affero General Public License
-  along with WebODF.  If not, see <http://www.gnu.org/licenses/>.
-  @licend
++ As a special exception to the AGPL, any HTML file which merely makes function
++ calls to this code, and for that purpose includes it by reference shall be
++ deemed a separate work for copyright law purposes. In addition, the copyright
++ holders of this code give you permission to combine this code with free
++ software libraries that are released under the GNU LGPL. You may copy and
++ distribute such a system following the terms of the GNU AGPL for this code
++ and the LGPL for the libraries. If you modify this code, you may extend this
++ exception to your version of the code, but you are not obligated to do so.
++ If you do not wish to do so, delete this exception statement from your
++ version.
 +
++ This license applies to this entire compilation.
++ @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("core.EventNotifier");runtime.loadClass("core.PositionFilter");runtime.loadClass("ops.Session");runtime.loadClass("ops.OpAddAnnotation");runtime.loadClass("ops.OpRemoveAnnotation");runtime.loadClass("gui.SelectionMover");
- gui.AnnotationController=function(g,l){function f(){var e=h.getCursor(l),e=e&&e.getNode(),a=!1;if(e){a:{for(a=h.getRootNode();e&&e!==a;){if(e.namespaceURI===c&&"annotation"===e.localName){e=!0;break a}e=e.parentNode}e=!1}a=!e}a!==d&&(d=a,m.emit(gui.AnnotationController.annotatableChanged,d))}function p(c){c.getMemberId()===l&&f()}function r(c){c===l&&f()}function n(c){c.getMemberId()===l&&f()}var h=g.getOdtDocument(),d=!1,m=new core.EventNotifier([gui.AnnotationController.annotatableCha [...]
- this.isAnnotatable=function(){return d};this.addAnnotation=function(){var c=new ops.OpAddAnnotation,a=h.getCursorSelection(l),b=a.length,a=a.position;d&&(a=0<=b?a:a+b,b=Math.abs(b),c.init({memberid:l,position:a,length:b,name:l+Date.now()}),g.enqueue([c]))};this.removeAnnotation=function(c){var a,b;a=h.convertDomPointToCursorStep(c,0)+1;b=h.convertDomPointToCursorStep(c,c.childNodes.length);c=new ops.OpRemoveAnnotation;c.init({memberid:l,position:a,length:b-a});b=new ops.OpMoveCursor;b.i [...]
- position:0<a?a-1:a,length:0});g.enqueue([c,b])};this.subscribe=function(c,a){m.subscribe(c,a)};this.unsubscribe=function(c,a){m.unsubscribe(c,a)};this.destroy=function(c){h.unsubscribe(ops.OdtDocument.signalCursorAdded,p);h.unsubscribe(ops.OdtDocument.signalCursorRemoved,r);h.unsubscribe(ops.OdtDocument.signalCursorMoved,n);c()};h.subscribe(ops.OdtDocument.signalCursorAdded,p);h.subscribe(ops.OdtDocument.signalCursorRemoved,r);h.subscribe(ops.OdtDocument.signalCursorMoved,n);f()};
- gui.AnnotationController.annotatableChanged="annotatable/changed";(function(){return gui.AnnotationController})();
- // Input 93
++gui.EditInfoMarker=function(m,h){function b(b,a){return runtime.setTimeout(function(){p.style.opacity=b},a)}var g=this,d,n,p,k,q,e;this.addEdit=function(d,a){var c=Date.now()-a;m.addEdit(d,a);n.setEdits(m.getSortedEdits());p.setAttributeNS("urn:webodf:names:editinfo","editinfo:memberid",d);runtime.clearTimeout(q);runtime.clearTimeout(e);1E4>c?(k=b(1,0),q=b(0.5,1E4-c),e=b(0.2,2E4-c)):1E4<=c&&2E4>c?(k=b(0.5,0),e=b(0.2,2E4-c)):k=b(0.2,0)};this.getEdits=function(){return m.getEdits()};this. [...]
++function(){m.clearEdits();n.setEdits([]);p.hasAttributeNS("urn:webodf:names:editinfo","editinfo:memberid")&&p.removeAttributeNS("urn:webodf:names:editinfo","editinfo:memberid")};this.getEditInfo=function(){return m};this.show=function(){p.style.display="block"};this.hide=function(){g.hideHandle();p.style.display="none"};this.showHandle=function(){n.show()};this.hideHandle=function(){n.hide()};this.destroy=function(b){runtime.clearTimeout(k);runtime.clearTimeout(q);runtime.clearTimeout(e [...]
++n.destroy(function(a){a?b(a):m.destroy(b)})};(function(){var b=m.getOdtDocument().getDOMDocument();p=b.createElementNS(b.documentElement.namespaceURI,"div");p.setAttribute("class","editInfoMarker");p.onmouseover=function(){g.showHandle()};p.onmouseout=function(){g.hideHandle()};d=m.getNode();d.appendChild(p);n=new gui.EditInfoHandle(d);h||g.hide()})()};
++// Input 100
++gui.ShadowCursor=function(m){var h=m.getDOMDocument().createRange(),b=!0;this.removeFromDocument=function(){};this.getMemberId=function(){return gui.ShadowCursor.ShadowCursorMemberId};this.getSelectedRange=function(){return h};this.setSelectedRange=function(g,d){h=g;b=!1!==d};this.hasForwardSelection=function(){return b};this.getDocument=function(){return m};this.getSelectionType=function(){return ops.OdtCursor.RangeSelection};h.setStart(m.getRootNode(),0)};gui.ShadowCursor.ShadowCursor [...]
++(function(){return gui.ShadowCursor})();
++// Input 101
++gui.SelectionView=function(m){};gui.SelectionView.prototype.rerender=function(){};gui.SelectionView.prototype.show=function(){};gui.SelectionView.prototype.hide=function(){};gui.SelectionView.prototype.destroy=function(m){};
++// Input 102
 +/*
 +
 + Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("core.EventNotifier");runtime.loadClass("core.Utils");runtime.loadClass("odf.OdfUtils");runtime.loadClass("ops.OpAddStyle");runtime.loadClass("ops.OpSetParagraphStyle");runtime.loadClass("gui.StyleHelper");
- gui.DirectParagraphStyler=function(g,l,f){function p(){function a(b,d,e){b!==d&&(void 0===c&&(c={}),c[e]=d);return d}var b=k.getCursor(l),b=b&&b.getSelectedRange(),c;v=a(v,b?w.isAlignedLeft(b):!1,"isAlignedLeft");u=a(u,b?w.isAlignedCenter(b):!1,"isAlignedCenter");s=a(s,b?w.isAlignedRight(b):!1,"isAlignedRight");H=a(H,b?w.isAlignedJustified(b):!1,"isAlignedJustified");c&&x.emit(gui.DirectParagraphStyler.paragraphStylingChanged,c)}function r(a){a.getMemberId()===l&&p()}function n(a){a===l [...]
- l&&p()}function d(){p()}function m(a){var b=k.getCursor(l);b&&k.getParagraphElement(b.getNode())===a.paragraphElement&&p()}function c(a){return a===ops.StepsTranslator.NEXT_STEP}function e(a){var b=k.getCursor(l).getSelectedRange(),b=A.getParagraphElements(b),d=k.getFormatting();b.forEach(function(b){var e=k.convertDomPointToCursorStep(b,0,c),h=b.getAttributeNS(odf.Namespaces.textns,"style-name");b=f.generateStyleName();var m;h&&(m=d.createDerivedStyleObject(h,"paragraph",{}));m=a(m||{} [...]
- h.init({memberid:l,styleName:b,styleFamily:"paragraph",isAutomaticStyle:!0,setProperties:m});m=new ops.OpSetParagraphStyle;m.init({memberid:l,styleName:b,position:e});g.enqueue([h,m])})}function a(a){e(function(b){return t.mergeObjects(b,a)})}function b(b){a({"style:paragraph-properties":{"fo:text-align":b}})}function q(a,b){var c=k.getFormatting().getDefaultTabStopDistance(),d=b["style:paragraph-properties"],d=(d=d&&d["fo:margin-left"])&&A.parseLength(d);return t.mergeObjects(b,{"style [...]
- d.unit===c.unit?d.value+a*c.value+d.unit:a*c.value+c.unit}})}var k=g.getOdtDocument(),t=new core.Utils,A=new odf.OdfUtils,w=new gui.StyleHelper(k.getFormatting()),x=new core.EventNotifier([gui.DirectParagraphStyler.paragraphStylingChanged]),v,u,s,H;this.isAlignedLeft=function(){return v};this.isAlignedCenter=function(){return u};this.isAlignedRight=function(){return s};this.isAlignedJustified=function(){return H};this.alignParagraphLeft=function(){b("left");return!0};this.alignParagraph [...]
- return!0};this.alignParagraphRight=function(){b("right");return!0};this.alignParagraphJustified=function(){b("justify");return!0};this.indent=function(){e(q.bind(null,1));return!0};this.outdent=function(){e(q.bind(null,-1));return!0};this.subscribe=function(a,b){x.subscribe(a,b)};this.unsubscribe=function(a,b){x.unsubscribe(a,b)};this.destroy=function(a){k.unsubscribe(ops.OdtDocument.signalCursorAdded,r);k.unsubscribe(ops.OdtDocument.signalCursorRemoved,n);k.unsubscribe(ops.OdtDocument. [...]
- h);k.unsubscribe(ops.OdtDocument.signalParagraphStyleModified,d);k.unsubscribe(ops.OdtDocument.signalParagraphChanged,m);a()};k.subscribe(ops.OdtDocument.signalCursorAdded,r);k.subscribe(ops.OdtDocument.signalCursorRemoved,n);k.subscribe(ops.OdtDocument.signalCursorMoved,h);k.subscribe(ops.OdtDocument.signalParagraphStyleModified,d);k.subscribe(ops.OdtDocument.signalParagraphChanged,m);p()};gui.DirectParagraphStyler.paragraphStylingChanged="paragraphStyling/changed";(function(){return g [...]
- // Input 94
++gui.SelectionViewManager=function(m){function h(){return Object.keys(b).map(function(g){return b[g]})}var b={};this.getSelectionView=function(g){return b.hasOwnProperty(g)?b[g]:null};this.getSelectionViews=h;this.removeSelectionView=function(g){b.hasOwnProperty(g)&&(b[g].destroy(function(){}),delete b[g])};this.hideSelectionView=function(g){b.hasOwnProperty(g)&&b[g].hide()};this.showSelectionView=function(g){b.hasOwnProperty(g)&&b[g].show()};this.rerenderSelectionViews=function(){Object [...]
++this.registerCursor=function(g,d){var h=g.getMemberId(),p=new m(g);d?p.show():p.hide();return b[h]=p};this.destroy=function(b){function d(h,k){k?b(k):h<m.length?m[h].destroy(function(b){d(h+1,b)}):b()}var m=h();d(0,void 0)}};
++// Input 103
 +/*
 +
-  Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
++ Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("core.EventNotifier");runtime.loadClass("core.Utils");runtime.loadClass("ops.OpApplyDirectStyling");runtime.loadClass("gui.StyleHelper");
- gui.DirectTextStyler=function(g,l){function f(a,b){for(var c=0,d=b[c];d&&a;)a=a[d],c+=1,d=b[c];return b.length===c?a:void 0}function p(a,b){var c=f(a[0],b);return a.every(function(a){return c===f(a,b)})?c:void 0}function r(){var a=u.getCursor(l),a=(a=a&&a.getSelectedRange())&&s.getAppliedStyles(a)||[];a[0]&&y&&(a[0]=v.mergeObjects(a[0],y));return a}function n(){function a(b,d,e){b!==d&&(void 0===c&&(c={}),c[e]=d);return d}var b,c;B=r();L=a(L,B?s.isBold(B):!1,"isBold");I=a(I,B?s.isItalic [...]
- W=a(W,B?s.hasUnderline(B):!1,"hasUnderline");Q=a(Q,B?s.hasStrikeThrough(B):!1,"hasStrikeThrough");b=B&&p(B,["style:text-properties","fo:font-size"]);z=a(z,b&&parseFloat(b),"fontSize");ja=a(ja,B&&p(B,["style:text-properties","style:font-name"]),"fontName");c&&H.emit(gui.DirectTextStyler.textStylingChanged,c)}function h(a){a.getMemberId()===l&&n()}function d(a){a===l&&n()}function m(a){a.getMemberId()===l&&n()}function c(){n()}function e(a){var b=u.getCursor(l);b&&u.getParagraphElement(b. [...]
- a.paragraphElement&&n()}function a(a,b){var c=u.getCursor(l);if(!c)return!1;c=s.getAppliedStyles(c.getSelectedRange());b(!a(c));return!0}function b(a){var b=u.getCursorSelection(l),c={"style:text-properties":a};0!==b.length?(a=new ops.OpApplyDirectStyling,a.init({memberid:l,position:b.position,length:b.length,setProperties:c}),g.enqueue([a])):(y=v.mergeObjects(y||{},c),n())}function q(a,c){var d={};d[a]=c;b(d)}function k(a){a=a.spec();y&&a.memberid===l&&"SplitParagraph"!==a.optype&&(y=n [...]
- a?"bold":"normal")}function A(a){q("fo:font-style",a?"italic":"normal")}function w(a){q("style:text-underline-style",a?"solid":"none")}function x(a){q("style:text-line-through-style",a?"solid":"none")}var v=new core.Utils,u=g.getOdtDocument(),s=new gui.StyleHelper(u.getFormatting()),H=new core.EventNotifier([gui.DirectTextStyler.textStylingChanged]),y,B=[],L=!1,I=!1,W=!1,Q=!1,z,ja;this.formatTextSelection=b;this.createCursorStyleOp=function(a,b){var c=null;y&&(c=new ops.OpApplyDirectSty [...]
- position:a,length:b,setProperties:y}),y=null,n());return c};this.setBold=t;this.setItalic=A;this.setHasUnderline=w;this.setHasStrikethrough=x;this.setFontSize=function(a){q("fo:font-size",a+"pt")};this.setFontName=function(a){q("style:font-name",a)};this.getAppliedStyles=function(){return B};this.toggleBold=a.bind(this,s.isBold,t);this.toggleItalic=a.bind(this,s.isItalic,A);this.toggleUnderline=a.bind(this,s.hasUnderline,w);this.toggleStrikethrough=a.bind(this,s.hasStrikeThrough,x);this [...]
- this.isItalic=function(){return I};this.hasUnderline=function(){return W};this.hasStrikeThrough=function(){return Q};this.fontSize=function(){return z};this.fontName=function(){return ja};this.subscribe=function(a,b){H.subscribe(a,b)};this.unsubscribe=function(a,b){H.unsubscribe(a,b)};this.destroy=function(a){u.unsubscribe(ops.OdtDocument.signalCursorAdded,h);u.unsubscribe(ops.OdtDocument.signalCursorRemoved,d);u.unsubscribe(ops.OdtDocument.signalCursorMoved,m);u.unsubscribe(ops.OdtDocu [...]
- c);u.unsubscribe(ops.OdtDocument.signalParagraphChanged,e);u.unsubscribe(ops.OdtDocument.signalOperationExecuted,k);a()};u.subscribe(ops.OdtDocument.signalCursorAdded,h);u.subscribe(ops.OdtDocument.signalCursorRemoved,d);u.subscribe(ops.OdtDocument.signalCursorMoved,m);u.subscribe(ops.OdtDocument.signalParagraphStyleModified,c);u.subscribe(ops.OdtDocument.signalParagraphChanged,e);u.subscribe(ops.OdtDocument.signalOperationExecuted,k);n()};gui.DirectTextStyler.textStylingChanged="textSt [...]
- (function(){return gui.DirectTextStyler})();
- // Input 95
- runtime.loadClass("odf.Namespaces");runtime.loadClass("odf.ObjectNameGenerator");
- gui.ImageManager=function(g,l,f){var p={"image/gif":".gif","image/jpeg":".jpg","image/png":".png"},r=odf.Namespaces.textns,n=g.getOdtDocument(),h=n.getFormatting(),d={};this.insertImage=function(m,c,e,a){var b;runtime.assert(0<e&&0<a,"Both width and height of the image should be greater than 0px.");b=n.getParagraphElement(n.getCursor(l).getNode()).getAttributeNS(r,"style-name");d.hasOwnProperty(b)||(d[b]=h.getContentSize(b,"paragraph"));b=d[b];e*=0.0264583333333334;a*=0.0264583333333334 [...]
- 1;e>b.width&&(q=b.width/e);a>b.height&&(k=b.height/a);q=Math.min(q,k);b=e*q;e=a*q;k=n.getOdfCanvas().odfContainer().rootElement.styles;a=m.toLowerCase();var q=p.hasOwnProperty(a)?p[a]:null,t;a=[];runtime.assert(null!==q,"Image type is not supported: "+m);q="Pictures/"+f.generateImageName()+q;t=new ops.OpSetBlob;t.init({memberid:l,filename:q,mimetype:m,content:c});a.push(t);h.getStyleElement("Graphics","graphic",[k])||(m=new ops.OpAddStyle,m.init({memberid:l,styleName:"Graphics",styleFam [...]
- isAutomaticStyle:!1,setProperties:{"style:graphic-properties":{"text:anchor-type":"paragraph","svg:x":"0cm","svg:y":"0cm","style:wrap":"dynamic","style:number-wrapped-paragraphs":"no-limit","style:wrap-contour":"false","style:vertical-pos":"top","style:vertical-rel":"paragraph","style:horizontal-pos":"center","style:horizontal-rel":"paragraph"}}}),a.push(m));m=f.generateStyleName();c=new ops.OpAddStyle;c.init({memberid:l,styleName:m,styleFamily:"graphic",isAutomaticStyle:!0,setPropertie [...]
- "style:graphic-properties":{"style:vertical-pos":"top","style:vertical-rel":"baseline","style:horizontal-pos":"center","style:horizontal-rel":"paragraph","fo:background-color":"transparent","style:background-transparency":"100%","style:shadow":"none","style:mirror":"none","fo:clip":"rect(0cm, 0cm, 0cm, 0cm)","draw:luminance":"0%","draw:contrast":"0%","draw:red":"0%","draw:green":"0%","draw:blue":"0%","draw:gamma":"100%","draw:color-inversion":"false","draw:image-opacity":"100%","draw:co [...]
- a.push(c);t=new ops.OpInsertImage;t.init({memberid:l,position:n.getCursorPosition(l),filename:q,frameWidth:b+"cm",frameHeight:e+"cm",frameStyleName:m,frameName:f.generateFrameName()});a.push(t);g.enqueue(a)}};
- // Input 96
++gui.SessionViewOptions=function(){this.caretBlinksOnRangeSelect=this.caretAvatarsInitiallyVisible=this.editInfoMarkersInitiallyVisible=!0};
++(function(){gui.SessionView=function(m,h,b,g,d){function n(a,b,c){function d(b,c,f){c=b+'[editinfo|memberid="'+a+'"]'+f+c;a:{var e=l.firstChild;for(b=b+'[editinfo|memberid="'+a+'"]'+f+"{";e;){if(e.nodeType===Node.TEXT_NODE&&0===e.data.indexOf(b)){b=e;break a}e=e.nextSibling}b=null}b?b.data=c:l.appendChild(document.createTextNode(c))}d("div.editInfoMarker","{ background-color: "+c+"; }","");d("span.editInfoColor","{ background-color: "+c+"; }","");d("span.editInfoAuthor",'{ content: "'+b [...]
++d("dc|creator","{ background-color: "+c+"; }","");d(".selectionOverlay","{ fill: "+c+"; stroke: "+c+";}","");a!==gui.ShadowCursor.ShadowCursorMemberId&&a!==h||d(".webodf-touchEnabled .selectionOverlay","{ display: block; }"," > .draggable")}function p(a){var b,c;for(c in v)v.hasOwnProperty(c)&&(b=v[c],a?b.show():b.hide())}function k(a){g.getCarets().forEach(function(b){a?b.showHandle():b.hideHandle()})}function q(a){var b=a.getMemberId();a=a.getProperties();n(b,a.fullName,a.color);h===b [...]
++a.color)}function e(a){var c=a.getMemberId(),f=b.getOdtDocument().getMember(c).getProperties();g.registerCursor(a,z,x);d.registerCursor(a,!0);if(a=g.getCaret(c))a.setAvatarImageUrl(f.imageUrl),a.setColor(f.color);runtime.log("+++ View here +++ eagerly created an Caret for '"+c+"'! +++")}function r(a){a=a.getMemberId();var b=d.getSelectionView(h),c=d.getSelectionView(gui.ShadowCursor.ShadowCursorMemberId),f=g.getCaret(h);a===h?(c.hide(),b&&b.show(),f&&f.show()):a===gui.ShadowCursor.Shado [...]
++(c.show(),b&&b.hide(),f&&f.hide())}function a(a){d.removeSelectionView(a)}function c(a){var c=a.paragraphElement,d=a.memberId;a=a.timeStamp;var e,g="",l=c.getElementsByTagNameNS(f,"editinfo").item(0);l?(g=l.getAttributeNS(f,"id"),e=v[g]):(g=Math.random().toString(),e=new ops.EditInfo(c,b.getOdtDocument()),e=new gui.EditInfoMarker(e,w),l=c.getElementsByTagNameNS(f,"editinfo").item(0),l.setAttributeNS(f,"id",g),v[g]=e);e.addEdit(d,new Date(a))}var l,f="urn:webodf:names:editinfo",v={},w=vo [...]
++Boolean(m.editInfoMarkersInitiallyVisible):!0,z=void 0!==m.caretAvatarsInitiallyVisible?Boolean(m.caretAvatarsInitiallyVisible):!0,x=void 0!==m.caretBlinksOnRangeSelect?Boolean(m.caretBlinksOnRangeSelect):!0;this.showEditInfoMarkers=function(){w||(w=!0,p(w))};this.hideEditInfoMarkers=function(){w&&(w=!1,p(w))};this.showCaretAvatars=function(){z||(z=!0,k(z))};this.hideCaretAvatars=function(){z&&(z=!1,k(z))};this.getSession=function(){return b};this.getCaret=function(a){return g.getCaret( [...]
++function(f){var g=b.getOdtDocument(),h=Object.keys(v).map(function(a){return v[a]});g.unsubscribe(ops.Document.signalMemberAdded,q);g.unsubscribe(ops.Document.signalMemberUpdated,q);g.unsubscribe(ops.Document.signalCursorAdded,e);g.unsubscribe(ops.Document.signalCursorRemoved,a);g.unsubscribe(ops.OdtDocument.signalParagraphChanged,c);g.unsubscribe(ops.Document.signalCursorMoved,r);g.unsubscribe(ops.OdtDocument.signalParagraphChanged,d.rerenderSelectionViews);g.unsubscribe(ops.OdtDocumen [...]
++d.rerenderSelectionViews);g.unsubscribe(ops.OdtDocument.signalParagraphStyleModified,d.rerenderSelectionViews);l.parentNode.removeChild(l);(function F(a,b){b?f(b):a<h.length?h[a].destroy(function(b){F(a+1,b)}):f()})(0,void 0)};(function(){var f=b.getOdtDocument(),g=document.getElementsByTagName("head").item(0);f.subscribe(ops.Document.signalMemberAdded,q);f.subscribe(ops.Document.signalMemberUpdated,q);f.subscribe(ops.Document.signalCursorAdded,e);f.subscribe(ops.Document.signalCursorRe [...]
++c);f.subscribe(ops.Document.signalCursorMoved,r);f.subscribe(ops.OdtDocument.signalParagraphChanged,d.rerenderSelectionViews);f.subscribe(ops.OdtDocument.signalTableAdded,d.rerenderSelectionViews);f.subscribe(ops.OdtDocument.signalParagraphStyleModified,d.rerenderSelectionViews);l=document.createElementNS(g.namespaceURI,"style");l.type="text/css";l.media="screen, print, handheld, projection";l.appendChild(document.createTextNode("@namespace editinfo url(urn:webodf:names:editinfo);"));l. [...]
++g.appendChild(l)})()}})();
++// Input 104
++gui.SvgSelectionView=function(m){function h(){var a=l.getRootNode();f!==a&&(f=a,v=f.parentNode.parentNode.parentNode,v.appendChild(x),x.setAttribute("class","selectionOverlay"),u.setAttribute("class","draggable"),s.setAttribute("class","draggable"),u.setAttribute("end","left"),s.setAttribute("end","right"),u.setAttribute("r",8),s.setAttribute("r",8),x.appendChild(t),x.appendChild(u),x.appendChild(s))}function b(a){var b=F.getBoundingClientRect(v),c=L.getZoomLevel(),d={};d.top=F.adaptRan [...]
++b.top,c);d.left=F.adaptRangeDifferenceToZoomLevel(a.left-b.left,c);d.bottom=F.adaptRangeDifferenceToZoomLevel(a.bottom-b.top,c);d.right=F.adaptRangeDifferenceToZoomLevel(a.right-b.left,c);d.width=F.adaptRangeDifferenceToZoomLevel(a.width,c);d.height=F.adaptRangeDifferenceToZoomLevel(a.height,c);return d}function g(a){a=a.getBoundingClientRect();return Boolean(a&&0!==a.height)}function d(a){var b=y.getTextElements(a,!0,!1),c=a.cloneRange(),d=a.cloneRange();a=a.cloneRange();if(!b.length)r [...]
++var f;a:{f=0;var e=b[f],l=c.startContainer===e?c.startOffset:0,h=l;c.setStart(e,l);for(c.setEnd(e,h);!g(c);){if(e.nodeType===Node.ELEMENT_NODE&&h<e.childNodes.length)h=e.childNodes.length;else if(e.nodeType===Node.TEXT_NODE&&h<e.length)h+=1;else if(b[f])e=b[f],f+=1,l=h=0;else{f=!1;break a}c.setStart(e,l);c.setEnd(e,h)}f=!0}if(!f)return null;a:{f=b.length-1;e=b[f];h=l=d.endContainer===e?d.endOffset:e.nodeType===Node.TEXT_NODE?e.length:e.childNodes.length;d.setStart(e,l);for(d.setEnd(e,h) [...]
++Node.ELEMENT_NODE&&0<l)l=0;else if(e.nodeType===Node.TEXT_NODE&&0<l)l-=1;else if(b[f])e=b[f],f-=1,l=h=e.length||e.childNodes.length;else{b=!1;break a}d.setStart(e,l);d.setEnd(e,h)}b=!0}if(!b)return null;a.setStart(c.startContainer,c.startOffset);a.setEnd(d.endContainer,d.endOffset);return{firstRange:c,lastRange:d,fillerRange:a}}function n(a,b){var c={};c.top=Math.min(a.top,b.top);c.left=Math.min(a.left,b.left);c.right=Math.max(a.right,b.right);c.bottom=Math.max(a.bottom,b.bottom);c.widt [...]
++c.left;c.height=c.bottom-c.top;return c}function p(a,b){b&&0<b.width&&0<b.height&&(a=a?n(a,b):b);return a}function k(a){function b(a){H.setUnfilteredPosition(a,0);return v.acceptNode(a)===U&&s.acceptPosition(H)===U?U:T}function c(a){var d=null;b(a)===U&&(d=F.getBoundingClientRect(a));return d}var d=a.commonAncestorContainer,f=a.startContainer,e=a.endContainer,g=a.startOffset,h=a.endOffset,k,m,n=null,q,r=w.createRange(),s,v=new odf.OdfNodeFilter,t;if(f===d||e===d)return r=a.cloneRange(), [...]
++r.detach(),n;for(a=f;a.parentNode!==d;)a=a.parentNode;for(m=e;m.parentNode!==d;)m=m.parentNode;s=l.createRootFilter(f);for(d=a.nextSibling;d&&d!==m;)q=c(d),n=p(n,q),d=d.nextSibling;if(y.isParagraph(a))n=p(n,F.getBoundingClientRect(a));else if(a.nodeType===Node.TEXT_NODE)d=a,r.setStart(d,g),r.setEnd(d,d===m?h:d.length),q=r.getBoundingClientRect(),n=p(n,q);else for(t=w.createTreeWalker(a,NodeFilter.SHOW_TEXT,b,!1),d=t.currentNode=f;d&&d!==e;)r.setStart(d,g),r.setEnd(d,d.length),q=r.getBou [...]
++n=p(n,q),k=d,g=0,d=t.nextNode();k||(k=f);if(y.isParagraph(m))n=p(n,F.getBoundingClientRect(m));else if(m.nodeType===Node.TEXT_NODE)d=m,r.setStart(d,d===a?g:0),r.setEnd(d,h),q=r.getBoundingClientRect(),n=p(n,q);else for(t=w.createTreeWalker(m,NodeFilter.SHOW_TEXT,b,!1),d=t.currentNode=e;d&&d!==k;)if(r.setStart(d,0),r.setEnd(d,h),q=r.getBoundingClientRect(),n=p(n,q),d=t.previousNode())h=d.length;return n}function q(a,b){var c=a.getBoundingClientRect(),d={width:0};d.top=c.top;d.bottom=c.bo [...]
++c.height;d.left=d.right=b?c.right:c.left;return d}function e(){var a=m.getSelectedRange(),c;if(c=O&&m.getSelectionType()===ops.OdtCursor.RangeSelection&&!a.collapsed){h();var a=d(a),f,e,g,l,p,r,v,w;if(a){c=a.firstRange;f=a.lastRange;e=a.fillerRange;g=b(q(c,!1));p=b(q(f,!0));l=(l=k(e))?b(l):n(g,p);r=l.left;v=g.left+Math.max(0,l.width-(g.left-l.left));l=Math.min(g.top,p.top);w=p.top+p.height;r=[{x:g.left,y:l+g.height},{x:g.left,y:l},{x:v,y:l},{x:v,y:w-p.height},{x:p.right,y:w-p.height},{x [...]
++{x:r,y:w},{x:r,y:l+g.height},{x:g.left,y:l+g.height}];v="";var y;for(y=0;y<r.length;y+=1)v+=r[y].x+","+r[y].y+" ";t.setAttribute("points",v);u.setAttribute("cx",g.left);u.setAttribute("cy",l+g.height/2);s.setAttribute("cx",p.right);s.setAttribute("cy",w-p.height/2);c.detach();f.detach();e.detach()}c=Boolean(a)}x.style.display=c?"block":"none"}function r(a){O&&a===m&&X.trigger()}function a(a){a=8/a;u.setAttribute("r",a);s.setAttribute("r",a)}function c(b){v.removeChild(x);m.getDocument() [...]
++r);L.unsubscribe(gui.ZoomHelper.signalZoomChanged,a);b()}var l=m.getDocument(),f,v,w=l.getDOMDocument(),z=new core.Async,x=w.createElementNS("http://www.w3.org/2000/svg","svg"),t=w.createElementNS("http://www.w3.org/2000/svg","polygon"),u=w.createElementNS("http://www.w3.org/2000/svg","circle"),s=w.createElementNS("http://www.w3.org/2000/svg","circle"),y=new odf.OdfUtils,F=new core.DomUtils,L=l.getCanvas().getZoomHelper(),O=!0,H=gui.SelectionMover.createPositionIterator(l.getRootNode()) [...]
++T=NodeFilter.FILTER_REJECT,X;this.rerender=function(){O&&X.trigger()};this.show=function(){O=!0;X.trigger()};this.hide=function(){O=!1;X.trigger()};this.destroy=function(a){z.destroyAll([X.destroy,c],a)};(function(){var b=m.getMemberId();X=new core.ScheduledTask(e,0);h();x.setAttributeNS("urn:webodf:names:editinfo","editinfo:memberid",b);m.getDocument().subscribe(ops.Document.signalCursorMoved,r);L.subscribe(gui.ZoomHelper.signalZoomChanged,a);a(L.getZoomLevel())})()};
++// Input 105
 +/*
 +
 + Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("core.PositionFilter");
- gui.TextManipulator=function(g,l,f){function p(d){var c=new ops.OpRemoveText;c.init({memberid:l,position:d.position,length:d.length});return c}function r(d){0>d.length&&(d.position+=d.length,d.length=-d.length);return d}function n(f,c){var e=new core.PositionFilterChain,a=gui.SelectionMover.createPositionIterator(h.getRootElement(f)),b=c?a.nextPosition:a.previousPosition;e.addFilter("BaseFilter",h.getPositionFilter());e.addFilter("RootFilter",h.createRootFilter(l));for(a.setUnfilteredPo [...]
- d)return!0;return!1}var h=g.getOdtDocument(),d=core.PositionFilter.FilterResult.FILTER_ACCEPT;this.enqueueParagraphSplittingOps=function(){var d=r(h.getCursorSelection(l)),c,e=[];0<d.length&&(c=p(d),e.push(c));c=new ops.OpSplitParagraph;c.init({memberid:l,position:d.position,moveCursor:!0});e.push(c);g.enqueue(e);return!0};this.removeTextByBackspaceKey=function(){var d=h.getCursor(l),c=r(h.getCursorSelection(l)),e=null;0===c.length?n(d.getNode(),!1)&&(e=new ops.OpRemoveText,e.init({memb [...]
- 1,length:1}),g.enqueue([e])):(e=p(c),g.enqueue([e]));return null!==e};this.removeTextByDeleteKey=function(){var d=h.getCursor(l),c=r(h.getCursorSelection(l)),e=null;0===c.length?n(d.getNode(),!0)&&(e=new ops.OpRemoveText,e.init({memberid:l,position:c.position,length:1}),g.enqueue([e])):(e=p(c),g.enqueue([e]));return null!==e};this.removeCurrentSelection=function(){var d=r(h.getCursorSelection(l));0!==d.length&&(d=p(d),g.enqueue([d]));return!0};this.insertText=function(d){var c=r(h.getCu [...]
- e,a=[];0<c.length&&(e=p(c),a.push(e));e=new ops.OpInsertText;e.init({memberid:l,position:c.position,text:d,moveCursor:!0});a.push(e);f&&(d=f(c.position,d.length))&&a.push(d);g.enqueue(a)}};(function(){return gui.TextManipulator})();
- // Input 97
- runtime.loadClass("core.DomUtils");runtime.loadClass("core.Async");runtime.loadClass("core.ScheduledTask");runtime.loadClass("odf.OdfUtils");runtime.loadClass("odf.ObjectNameGenerator");runtime.loadClass("ops.OdtCursor");runtime.loadClass("ops.OpAddCursor");runtime.loadClass("ops.OpRemoveCursor");runtime.loadClass("gui.Clipboard");runtime.loadClass("gui.DirectTextStyler");runtime.loadClass("gui.DirectParagraphStyler");runtime.loadClass("gui.KeyboardHandler");runtime.loadClass("gui.Image [...]
- runtime.loadClass("gui.ImageSelector");runtime.loadClass("gui.TextManipulator");runtime.loadClass("gui.AnnotationController");runtime.loadClass("gui.EventManager");runtime.loadClass("gui.PlainTextPasteboard");
- gui.SessionController=function(){var g=core.PositionFilter.FilterResult.FILTER_ACCEPT;gui.SessionController=function(l,f,p,r){function n(a){a.preventDefault?a.preventDefault():a.returnValue=!1}function h(a,b,c){var d=new ops.OpMoveCursor;d.init({memberid:f,position:a,length:b||0,selectionType:c});return d}function d(a){var b=/[A-Za-z0-9]/,c=gui.SelectionMover.createPositionIterator(D.getRootNode()),d;for(c.setUnfilteredPosition(a.startContainer,a.startOffset);c.previousPosition();){d=c. [...]
- if(d.nodeType===Node.TEXT_NODE){if(d=d.data[c.unfilteredDomOffset()],!b.test(d))break}else if(!ia.isTextSpan(d))break;a.setStart(c.container(),c.unfilteredDomOffset())}c.setUnfilteredPosition(a.endContainer,a.endOffset);do if(d=c.getCurrentNode(),d.nodeType===Node.TEXT_NODE){if(d=d.data[c.unfilteredDomOffset()],!b.test(d))break}else if(!ia.isTextSpan(d))break;while(c.nextPosition());a.setEnd(c.container(),c.unfilteredDomOffset())}function m(a){var b=D.getParagraphElement(a.startContaine [...]
- b&&a.setStart(b,0);c&&(ia.isParagraph(a.endContainer)&&0===a.endOffset?a.setEndBefore(c):a.setEnd(c,c.childNodes.length))}function c(a){a=D.getDistanceFromCursor(f,a,0);var b=null!==a?a+1:null,c;if(b||a)c=D.getCursorPosition(f),a=h(c+a,b-a,ops.OdtCursor.RegionSelection),l.enqueue([a]);K.focus()}function e(a){var b=0<=ha.comparePoints(a.anchorNode,a.anchorOffset,a.focusNode,a.focusOffset),c=a.focusNode.ownerDocument.createRange();b?(c.setStart(a.anchorNode,a.anchorOffset),c.setEnd(a.focu [...]
- (c.setStart(a.focusNode,a.focusOffset),c.setEnd(a.anchorNode,a.anchorOffset));return{range:c,hasForwardSelection:b}}function a(a){return function(b){var c=a(b);return function(b,d){return a(d)===c}}}function b(b,c,e){var g=D.getOdfCanvas().getElement(),k;k=ha.containsNode(g,b.startContainer);g=ha.containsNode(g,b.endContainer);if(k||g)if(k&&g&&(2===e?d(b):3<=e&&m(b)),b=c?{anchorNode:b.startContainer,anchorOffset:b.startOffset,focusNode:b.endContainer,focusOffset:b.endOffset}:{anchorNode [...]
- anchorOffset:b.endOffset,focusNode:b.startContainer,focusOffset:b.startOffset},c=D.convertDomToCursorRange(b,a(ia.getParagraphElement)),b=D.getCursorSelection(f),c.position!==b.position||c.length!==b.length)b=h(c.position,c.length,ops.OdtCursor.RangeSelection),l.enqueue([b])}function q(a){var b=D.getCursorSelection(f),c=D.getCursor(f).getStepCounter();0!==a&&(a=0<a?c.convertForwardStepsBetweenFilters(a,sa,xa):-c.convertBackwardStepsBetweenFilters(-a,sa,xa),a=b.length+a,l.enqueue([h(b.po [...]
- function k(a){var b=D.getCursorPosition(f),c=D.getCursor(f).getStepCounter();0!==a&&(a=0<a?c.convertForwardStepsBetweenFilters(a,sa,xa):-c.convertBackwardStepsBetweenFilters(-a,sa,xa),l.enqueue([h(b+a,0)]))}function t(){k(-1);return!0}function A(){k(1);return!0}function w(){q(-1);return!0}function x(){q(1);return!0}function v(a,b){var c=D.getParagraphElement(D.getCursor(f).getNode());runtime.assert(Boolean(c),"SessionController: Cursor outside paragraph");c=D.getCursor(f).getStepCounter [...]
- sa);b?q(c):k(c)}function u(){v(-1,!1);return!0}function s(){v(1,!1);return!0}function H(){v(-1,!0);return!0}function y(){v(1,!0);return!0}function B(a,b){var c=D.getCursor(f).getStepCounter().countStepsToLineBoundary(a,sa);b?q(c):k(c)}function L(){B(-1,!1);return!0}function I(){B(1,!1);return!0}function W(){B(-1,!0);return!0}function Q(){B(1,!0);return!0}function z(){var a=D.getParagraphElement(D.getCursor(f).getNode()),b,c;runtime.assert(Boolean(a),"SessionController: Cursor outside pa [...]
- c=D.getDistanceFromCursor(f,a,0);b=gui.SelectionMover.createPositionIterator(D.getRootNode());for(b.setUnfilteredPosition(a,0);0===c&&b.previousPosition();)a=b.getCurrentNode(),ia.isParagraph(a)&&(c=D.getDistanceFromCursor(f,a,0));q(c);return!0}function ja(){var a=D.getParagraphElement(D.getCursor(f).getNode()),b,c;runtime.assert(Boolean(a),"SessionController: Cursor outside paragraph");b=gui.SelectionMover.createPositionIterator(D.getRootNode());b.moveToEndOfNode(a);for(c=D.getDistance [...]
- b.container(),b.unfilteredDomOffset());0===c&&b.nextPosition();)a=b.getCurrentNode(),ia.isParagraph(a)&&(b.moveToEndOfNode(a),c=D.getDistanceFromCursor(f,b.container(),b.unfilteredDomOffset()));q(c);return!0}function ka(a,b){var c=gui.SelectionMover.createPositionIterator(D.getRootNode());0<a&&c.moveToEnd();c=D.getDistanceFromCursor(f,c.container(),c.unfilteredDomOffset());b?q(c):k(c)}function G(){ka(-1,!1);return!0}function Z(){ka(1,!1);return!0}function O(){ka(-1,!0);return!0}function [...]
- !0);return!0}function J(){var a=D.getRootNode(),a=D.convertDomPointToCursorStep(a,a.childNodes.length);l.enqueue([h(0,a)]);return!0}function F(){var a=D.getCursor(f);if(a&&a.getSelectionType()===ops.OdtCursor.RegionSelection&&(a=ia.getImageElements(a.getSelectedRange())[0])){ya.select(a.parentNode);return}ya.clearSelection()}function C(a){var b=D.getCursor(f).getSelectedRange();b.collapsed?a.preventDefault():Da.setDataFromRange(a,b)?oa.removeCurrentSelection():runtime.log("Cut operation [...]
- function Y(){return!1!==D.getCursor(f).getSelectedRange().collapsed}function U(a){var b=D.getCursor(f).getSelectedRange();b.collapsed?a.preventDefault():Da.setDataFromRange(a,b)||runtime.log("Copy operation failed")}function R(a){var b;fa.clipboardData&&fa.clipboardData.getData?b=fa.clipboardData.getData("Text"):a.clipboardData&&a.clipboardData.getData&&(b=a.clipboardData.getData("text/plain"));b&&(oa.removeCurrentSelection(),l.enqueue(Fa.createPasteOps(b)));a.preventDefault?a.preventDe [...]
- !1}function P(){return!1}function M(a){if(V)V.onOperationExecuted(a)}function ba(a){D.emit(ops.OdtDocument.signalUndoStackChanged,a)}function la(){return V?(V.moveBackward(1),va.trigger(),!0):!1}function ca(){return V?(V.moveForward(1),va.trigger(),!0):!1}function ma(){var a=fa.getSelection(),b=0<a.rangeCount&&e(a);ra&&b&&(ta=!0,ya.clearSelection(),Ea.setUnfilteredPosition(a.focusNode,a.focusOffset),Ba.acceptPosition(Ea)===g&&(2===wa?d(b.range):3<=wa&&m(b.range),p.setSelectedRange(b.ran [...]
- D.emit(ops.OdtDocument.signalCursorMoved,p)))}function T(a){var b=a.target||a.srcElement,c=D.getCursor(f);if(ra=b&&ha.containsNode(D.getOdfCanvas().getElement(),b))ta=!1,Ba=D.createRootFilter(b),wa=a.detail,c&&a.shiftKey?fa.getSelection().collapse(c.getAnchorNode(),0):(a=fa.getSelection(),b=c.getSelectedRange(),a.extend?c.hasForwardSelection()?(a.collapse(b.startContainer,b.startOffset),a.extend(b.endContainer,b.endOffset)):(a.collapse(b.endContainer,b.endOffset),a.extend(b.startContain [...]
- (a.removeAllRanges(),a.addRange(b.cloneRange()),D.getOdfCanvas().getElement().setActive())),1<wa&&ma()}function $(a){var d=a.target||a.srcElement,f=a.detail,g=a.clientX,h=a.clientY;za.processRequests();ia.isImage(d)&&ia.isCharacterFrame(d.parentNode)?(c(d.parentNode),K.focus()):ra&&!ya.isSelectorElement(d)&&(ta?(b(p.getSelectedRange(),p.hasForwardSelection(),a.detail),K.focus()):runtime.setTimeout(function(){var a;a=(a=fa.getSelection())?{anchorNode:a.anchorNode,anchorOffset:a.anchorOff [...]
- focusOffset:a.focusOffset}:null;var c;if(!a.anchorNode&&!a.focusNode){var d=D.getDOM();c=null;d.caretRangeFromPoint?(d=d.caretRangeFromPoint(g,h),c={container:d.startContainer,offset:d.startOffset}):d.caretPositionFromPoint&&(d=d.caretPositionFromPoint(g,h))&&d.offsetNode&&(c={container:d.offsetNode,offset:d.offset});c&&(a.anchorNode=c.container,a.anchorOffset=c.offset,a.focusNode=a.anchorNode,a.focusOffset=a.anchorOffset)}a.anchorNode&&a.focusNode&&(a=e(a),b(a.range,a.hasForwardSelecti [...]
- 0));wa=0;ta=ra=!1}function X(){ra&&K.focus();wa=0;ta=ra=!1}function da(a){$(a)}function S(a){var b=a.target||a.srcElement,c=null;"annotationRemoveButton"===b.className?(c=ha.getElementsByTagNameNS(b.parentNode,odf.Namespaces.officens,"annotation")[0],ua.removeAnnotation(c)):$(a)}function ga(a){return function(){a();return!0}}function E(a){return function(b){return D.getCursor(f).getSelectionType()===ops.OdtCursor.RangeSelection?a(b):!0}}var fa=runtime.getWindow(),D=l.getOdtDocument(),pa [...]
- ha=new core.DomUtils,ia=new odf.OdfUtils,Da=new gui.Clipboard,N=new gui.KeyboardHandler,qa=new gui.KeyboardHandler,sa=new core.PositionFilterChain,xa=D.getPositionFilter(),ra=!1,Aa=new odf.ObjectNameGenerator(D.getOdfCanvas().odfContainer(),f),ta=!1,Ba=null,V=null,K=new gui.EventManager(D),ua=new gui.AnnotationController(l,f),na=new gui.DirectTextStyler(l,f),ea=r&&r.directParagraphStylingEnabled?new gui.DirectParagraphStyler(l,f,Aa):null,oa=new gui.TextManipulator(l,f,na.createCursorSty [...]
- f,Aa),ya=new gui.ImageSelector(D.getOdfCanvas()),Ea=gui.SelectionMover.createPositionIterator(D.getRootNode()),za,va,Fa=new gui.PlainTextPasteboard(D,f),wa=0;runtime.assert(null!==fa,"Expected to be run in an environment which has a global window, like a browser.");sa.addFilter("BaseFilter",xa);sa.addFilter("RootFilter",D.createRootFilter(f));this.selectRange=b;this.moveCursorToLeft=t;this.moveCursorToDocumentBoundary=ka;this.extendSelectionToEntireDocument=J;this.startEditing=function( [...]
- K.subscribe("keydown",N.handleEvent);K.subscribe("keypress",qa.handleEvent);K.subscribe("keyup",n);K.subscribe("beforecut",Y);K.subscribe("cut",C);K.subscribe("copy",U);K.subscribe("beforepaste",P);K.subscribe("paste",R);K.subscribe("mousedown",T);K.subscribe("mousemove",za.trigger);K.subscribe("mouseup",S);K.subscribe("contextmenu",da);K.subscribe("dragend",X);D.subscribe(ops.OdtDocument.signalOperationExecuted,va.trigger);D.subscribe(ops.OdtDocument.signalOperationExecuted,M);a=new op [...]
- a.init({memberid:f});l.enqueue([a]);V&&V.saveInitialState()};this.endEditing=function(){var a;a=new ops.OpRemoveCursor;a.init({memberid:f});l.enqueue([a]);V&&V.resetInitialState();D.unsubscribe(ops.OdtDocument.signalOperationExecuted,M);D.unsubscribe(ops.OdtDocument.signalOperationExecuted,va.trigger);K.unsubscribe("keydown",N.handleEvent);K.unsubscribe("keypress",qa.handleEvent);K.unsubscribe("keyup",n);K.unsubscribe("cut",C);K.unsubscribe("beforecut",Y);K.unsubscribe("copy",U);K.unsub [...]
- R);K.unsubscribe("beforepaste",P);K.unsubscribe("mousemove",za.trigger);K.unsubscribe("mousedown",T);K.unsubscribe("mouseup",S);K.unsubscribe("contextmenu",da);K.unsubscribe("dragend",X);D.getOdfCanvas().getElement().classList.remove("virtualSelections")};this.getInputMemberId=function(){return f};this.getSession=function(){return l};this.setUndoManager=function(a){V&&V.unsubscribe(gui.UndoManager.signalUndoStackChanged,ba);if(V=a)V.setOdtDocument(D),V.setPlaybackFunction(function(a){a. [...]
- V.subscribe(gui.UndoManager.signalUndoStackChanged,ba)};this.getUndoManager=function(){return V};this.getAnnotationController=function(){return ua};this.getDirectTextStyler=function(){return na};this.getDirectParagraphStyler=function(){return ea};this.getImageManager=function(){return Ca};this.getTextManipulator=function(){return oa};this.getEventManager=function(){return K};this.getKeyboardHandlers=function(){return{keydown:N,keypress:qa}};this.destroy=function(a){var b=[za.destroy,na. [...]
- b.push(ea.destroy);pa.destroyAll(b,a)};(function(){var a=-1!==fa.navigator.appVersion.toLowerCase().indexOf("mac"),b=gui.KeyboardHandler.Modifier,c=gui.KeyboardHandler.KeyCode;za=new core.ScheduledTask(ma,0);va=new core.ScheduledTask(F,0);N.bind(c.Tab,b.None,E(function(){oa.insertText("\t");return!0}));N.bind(c.Left,b.None,E(t));N.bind(c.Right,b.None,E(A));N.bind(c.Up,b.None,E(u));N.bind(c.Down,b.None,E(s));N.bind(c.Backspace,b.None,ga(oa.removeTextByBackspaceKey));N.bind(c.Delete,b.Non [...]
- N.bind(c.Left,b.Shift,E(w));N.bind(c.Right,b.Shift,E(x));N.bind(c.Up,b.Shift,E(H));N.bind(c.Down,b.Shift,E(y));N.bind(c.Home,b.None,E(L));N.bind(c.End,b.None,E(I));N.bind(c.Home,b.Ctrl,E(G));N.bind(c.End,b.Ctrl,E(Z));N.bind(c.Home,b.Shift,E(W));N.bind(c.End,b.Shift,E(Q));N.bind(c.Up,b.CtrlShift,E(z));N.bind(c.Down,b.CtrlShift,E(ja));N.bind(c.Home,b.CtrlShift,E(O));N.bind(c.End,b.CtrlShift,E(aa));a?(N.bind(c.Clear,b.None,oa.removeCurrentSelection),N.bind(c.Left,b.Meta,E(L)),N.bind(c.Righ [...]
- N.bind(c.Home,b.Meta,E(G)),N.bind(c.End,b.Meta,E(Z)),N.bind(c.Left,b.MetaShift,E(W)),N.bind(c.Right,b.MetaShift,E(Q)),N.bind(c.Up,b.AltShift,E(z)),N.bind(c.Down,b.AltShift,E(ja)),N.bind(c.Up,b.MetaShift,E(O)),N.bind(c.Down,b.MetaShift,E(aa)),N.bind(c.A,b.Meta,E(J)),N.bind(c.B,b.Meta,E(na.toggleBold)),N.bind(c.I,b.Meta,E(na.toggleItalic)),N.bind(c.U,b.Meta,E(na.toggleUnderline)),ea&&(N.bind(c.L,b.MetaShift,E(ea.alignParagraphLeft)),N.bind(c.E,b.MetaShift,E(ea.alignParagraphCenter)),N.bin [...]
- E(ea.alignParagraphRight)),N.bind(c.J,b.MetaShift,E(ea.alignParagraphJustified))),ua&&N.bind(c.C,b.MetaShift,ua.addAnnotation),N.bind(c.Z,b.Meta,la),N.bind(c.Z,b.MetaShift,ca)):(N.bind(c.A,b.Ctrl,E(J)),N.bind(c.B,b.Ctrl,E(na.toggleBold)),N.bind(c.I,b.Ctrl,E(na.toggleItalic)),N.bind(c.U,b.Ctrl,E(na.toggleUnderline)),ea&&(N.bind(c.L,b.CtrlShift,E(ea.alignParagraphLeft)),N.bind(c.E,b.CtrlShift,E(ea.alignParagraphCenter)),N.bind(c.R,b.CtrlShift,E(ea.alignParagraphRight)),N.bind(c.J,b.CtrlSh [...]
- ua&&N.bind(c.C,b.CtrlAlt,ua.addAnnotation),N.bind(c.Z,b.Ctrl,la),N.bind(c.Z,b.CtrlShift,ca));qa.setDefault(E(function(a){var b;b=null===a.which||void 0===a.which?String.fromCharCode(a.keyCode):0!==a.which&&0!==a.charCode?String.fromCharCode(a.which):null;return!b||a.altKey||a.ctrlKey||a.metaKey?!1:(oa.insertText(b),!0)}));qa.bind(c.Enter,b.None,E(oa.enqueueParagraphSplittingOps))})()};return gui.SessionController}();
- // Input 98
++gui.UndoStateRules=function(){function m(b,g){var h=b.length;this.previous=function(){for(h-=1;0<=h;h-=1)if(g(b[h]))return b[h];return null}}function h(b){b=b.spec();var g;b.hasOwnProperty("position")&&(g=b.position);return g}function b(b){return b.isEdit}function g(b,g,m){if(!m)return m=h(b)-h(g),0===m||1===Math.abs(m);b=h(b);g=h(g);m=h(m);return b-g===g-m}this.isEditOperation=b;this.isPartOfOperationSet=function(d,h){var p=void 0!==d.group,k;if(!d.isEdit||0===h.length)return!0;k=h[h.l [...]
++d.group===k.group)return!0;a:switch(d.spec().optype){case "RemoveText":case "InsertText":k=!0;break a;default:k=!1}if(k&&h.some(b)){if(p){var q;p=d.spec().optype;k=new m(h,b);var e=k.previous(),r=null,a,c;runtime.assert(Boolean(e),"No edit operations found in state");c=e.group;runtime.assert(void 0!==c,"Operation has no group");for(a=1;e&&e.group===c;){if(p===e.spec().optype){q=e;break}e=k.previous()}if(q){for(e=k.previous();e;){if(e.group!==c){if(2===a)break;c=e.group;a+=1}if(p===e.spe [...]
++e;break}e=k.previous()}q=g(d,q,r)}else q=!1;return q}q=d.spec().optype;p=new m(h,b);k=p.previous();runtime.assert(Boolean(k),"No edit operations found in state");q=q===k.spec().optype?g(d,k,p.previous()):!1;return q}return!1}};
++// Input 106
 +/*
 +
-  Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
++ Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("gui.Caret");
- gui.CaretManager=function(g){function l(a){return b.hasOwnProperty(a)?b[a]:null}function f(){return Object.keys(b).map(function(a){return b[a]})}function p(a){a===g.getInputMemberId()&&g.getSession().getOdtDocument().getOdfCanvas().getElement().removeAttribute("tabindex");delete b[a]}function r(a){a=a.getMemberId();a===g.getInputMemberId()&&(a=l(a))&&a.refreshCursorBlinking()}function n(){var a=l(g.getInputMemberId());k=!1;a&&a.ensureVisible()}function h(){var a=l(g.getInputMemberId()); [...]
- k||(k=!0,runtime.setTimeout(n,50)))}function d(a){a.memberId===g.getInputMemberId()&&h()}function m(){var a=l(g.getInputMemberId());a&&a.setFocus()}function c(){var a=l(g.getInputMemberId());a&&a.removeFocus()}function e(){var a=l(g.getInputMemberId());a&&a.show()}function a(){var a=l(g.getInputMemberId());a&&a.hide()}var b={},q=runtime.getWindow(),k=!1;this.registerCursor=function(a,c,d){var e=a.getMemberId();c=new gui.Caret(a,c,d);b[e]=c;e===g.getInputMemberId()?(runtime.log("Starting [...]
- e),a.handleUpdate=h,g.getSession().getOdtDocument().getOdfCanvas().getElement().setAttribute("tabindex",-1),g.getEventManager().focus()):a.handleUpdate=c.handleUpdate;return c};this.getCaret=l;this.getCarets=f;this.destroy=function(h){var k=g.getSession().getOdtDocument(),l=g.getEventManager(),n=f();k.unsubscribe(ops.OdtDocument.signalParagraphChanged,d);k.unsubscribe(ops.OdtDocument.signalCursorMoved,r);k.unsubscribe(ops.OdtDocument.signalCursorRemoved,p);l.unsubscribe("focus",m);l.uns [...]
- c);q.removeEventListener("focus",e,!1);q.removeEventListener("blur",a,!1);(function u(a,b){b?h(b):a<n.length?n[a].destroy(function(b){u(a+1,b)}):h()})(0,void 0);b={}};(function(){var b=g.getSession().getOdtDocument(),f=g.getEventManager();b.subscribe(ops.OdtDocument.signalParagraphChanged,d);b.subscribe(ops.OdtDocument.signalCursorMoved,r);b.subscribe(ops.OdtDocument.signalCursorRemoved,p);f.subscribe("focus",m);f.subscribe("blur",c);q.addEventListener("focus",e,!1);q.addEventListener(" [...]
- // Input 99
++gui.TrivialUndoManager=function(m){function h(a){0<a.length&&(u=!0,l(a),u=!1)}function b(){x.emit(gui.UndoManager.signalUndoStackChanged,{undoAvailable:q.hasUndoStates(),redoAvailable:q.hasRedoStates()})}function g(){v!==c&&v!==w[w.length-1]&&w.push(v)}function d(a){var b=a.previousSibling||a.nextSibling;a.parentNode.removeChild(a);r.normalizeTextNodes(b)}function n(a){return Object.keys(a).map(function(b){return a[b]})}function p(a){function b(a){var f=a.spec();if(e[f.memberid])switch( [...]
++(c[f.memberid]=a,delete e[f.memberid],g-=1);break;case "MoveCursor":d[f.memberid]||(d[f.memberid]=a)}}var c={},d={},e={},g,l=a.pop();f.getMemberIds().forEach(function(a){e[a]=!0});for(g=Object.keys(e).length;l&&0<g;)l.reverse(),l.forEach(b),l=a.pop();return n(c).concat(n(d))}function k(){var l=a=f.cloneDocumentElement();r.getElementsByTagNameNS(l,e,"cursor").forEach(d);r.getElementsByTagNameNS(l,e,"anchor").forEach(d);g();v=c=p([c].concat(w));w.length=0;z.length=0;b()}var q=this,e="urn: [...]
++r=new core.DomUtils,a,c=[],l,f,v=[],w=[],z=[],x=new core.EventNotifier([gui.UndoManager.signalUndoStackChanged,gui.UndoManager.signalUndoStateCreated,gui.UndoManager.signalUndoStateModified,gui.TrivialUndoManager.signalDocumentRootReplaced]),t=m||new gui.UndoStateRules,u=!1;this.subscribe=function(a,b){x.subscribe(a,b)};this.unsubscribe=function(a,b){x.unsubscribe(a,b)};this.hasUndoStates=function(){return 0<w.length};this.hasRedoStates=function(){return 0<z.length};this.setDocument=fun [...]
++a};this.purgeInitialState=function(){w.length=0;z.length=0;c.length=0;v.length=0;a=null;b()};this.setInitialState=k;this.initialize=function(){a||k()};this.setPlaybackFunction=function(a){l=a};this.onOperationExecuted=function(a){u||(t.isEditOperation(a)&&(v===c||0<z.length)||!t.isPartOfOperationSet(a,v)?(z.length=0,g(),v=[a],w.push(v),x.emit(gui.UndoManager.signalUndoStateCreated,{operations:v}),b()):(v.push(a),x.emit(gui.UndoManager.signalUndoStateModified,{operations:v})))};this.move [...]
++0,d;a&&z.length;)d=z.pop(),w.push(d),h(d),a-=1,c+=1;c&&(v=w[w.length-1],b());return c};this.moveBackward=function(d){for(var e=0;d&&w.length;)z.push(w.pop()),d-=1,e+=1;e&&(f.setDocumentElement(a.cloneNode(!0)),x.emit(gui.TrivialUndoManager.signalDocumentRootReplaced,{}),f.getMemberIds().forEach(function(a){f.removeCursor(a)}),h(c),w.forEach(h),v=w[w.length-1]||c,b());return e}};gui.TrivialUndoManager.signalDocumentRootReplaced="documentRootReplaced";(function(){return gui.TrivialUndoMan [...]
++// Input 107
 +/*
 +
-  Copyright (C) 2012-2013 KO GmbH <copyright at kogmbh.com>
++ Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
++
++ @licstart
++ This file is part of WebODF.
++
++ WebODF is free software: you can redistribute it and/or modify it
++ under the terms of the GNU Affero General Public License (GNU AGPL)
++ as published by the Free Software Foundation, either version 3 of
++ the License, or (at your option) any later version.
++
++ WebODF is distributed in the hope that it will be useful, but
++ WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ GNU Affero General Public License for more details.
++
++ You should have received a copy of the GNU Affero General Public License
++ along with WebODF.  If not, see <http://www.gnu.org/licenses/>.
++ @licend
++
++ @source: http://www.webodf.org/
++ @source: https://github.com/kogmbh/WebODF/
++*/
++ops.OperationTransformMatrix=function(){function m(a){a.position+=a.length;a.length*=-1}function h(a){var b=0>a.length;b&&m(a);return b}function b(a,b){function d(e){a[e]===b&&f.push(e)}var f=[];a&&["style:parent-style-name","style:next-style-name"].forEach(d);return f}function g(a,b){function d(f){a[f]===b&&delete a[f]}a&&["style:parent-style-name","style:next-style-name"].forEach(d)}function d(a){var b={};Object.keys(a).forEach(function(e){b[e]="object"===typeof a[e]?d(a[e]):a[e]});re [...]
++b,d,f){var e,g=!1,h=!1,k,m=[];f&&f.attributes&&(m=f.attributes.split(","));a&&(d||0<m.length)&&Object.keys(a).forEach(function(b){var c=a[b],f;"object"!==typeof c&&(d&&(f=d[b]),void 0!==f?(delete a[b],h=!0,f===c&&(delete d[b],g=!0)):-1!==m.indexOf(b)&&(delete a[b],h=!0))});if(b&&b.attributes&&(d||0<m.length)){k=b.attributes.split(",");for(f=0;f<k.length;f+=1)if(e=k[f],d&&void 0!==d[e]||m&&-1!==m.indexOf(e))k.splice(f,1),f-=1,h=!0;0<k.length?b.attributes=k.join(","):delete b.attributes}r [...]
++minorChanged:h}}function p(a){for(var b in a)if(a.hasOwnProperty(b))return!0;return!1}function k(a){for(var b in a)if(a.hasOwnProperty(b)&&("attributes"!==b||0<a.attributes.length))return!0;return!1}function q(a,b,d,f,e){var g=a?a[e]:null,h=b?b[e]:null,m=d?d[e]:null,q=f?f[e]:null,r;r=n(g,h,m,q);g&&!p(g)&&delete a[e];h&&!k(h)&&delete b[e];m&&!p(m)&&delete d[e];q&&!k(q)&&delete f[e];return r}function e(a,b){return{opSpecsA:[a],opSpecsB:[b]}}var r;r={AddCursor:{AddCursor:e,AddMember:e,AddS [...]
++InsertText:e,MoveCursor:e,RemoveCursor:e,RemoveMember:e,RemoveStyle:e,RemoveText:e,SetParagraphStyle:e,SplitParagraph:e,UpdateMember:e,UpdateMetadata:e,UpdateParagraphStyle:e},AddMember:{AddStyle:e,InsertText:e,MoveCursor:e,RemoveCursor:e,RemoveStyle:e,RemoveText:e,SetParagraphStyle:e,SplitParagraph:e,UpdateMetadata:e,UpdateParagraphStyle:e},AddStyle:{AddStyle:e,ApplyDirectStyling:e,InsertText:e,MoveCursor:e,RemoveCursor:e,RemoveMember:e,RemoveStyle:function(a,c){var d,f=[a],e=[c];a.sty [...]
++c.styleFamily&&(d=b(a.setProperties,c.styleName),0<d.length&&(d={optype:"UpdateParagraphStyle",memberid:c.memberid,timestamp:c.timestamp,styleName:a.styleName,removedProperties:{attributes:d.join(",")}},e.unshift(d)),g(a.setProperties,c.styleName));return{opSpecsA:f,opSpecsB:e}},RemoveText:e,SetParagraphStyle:e,SplitParagraph:e,UpdateMember:e,UpdateMetadata:e,UpdateParagraphStyle:e},ApplyDirectStyling:{ApplyDirectStyling:function(a,b,e){var f,g,h,k,m,n,r,s;k=[a];h=[b];if(!(a.position+a. [...]
++a.position>=b.position+b.length)){f=e?a:b;g=e?b:a;if(a.position!==b.position||a.length!==b.length)n=d(f),r=d(g);b=q(g.setProperties,null,f.setProperties,null,"style:text-properties");if(b.majorChanged||b.minorChanged)h=[],a=[],k=f.position+f.length,m=g.position+g.length,g.position<f.position?b.minorChanged&&(s=d(r),s.length=f.position-g.position,a.push(s),g.position=f.position,g.length=m-g.position):f.position<g.position&&b.majorChanged&&(s=d(n),s.length=g.position-f.position,h.push(s), [...]
++g.position,f.length=k-f.position),m>k?b.minorChanged&&(n=r,n.position=k,n.length=m-k,a.push(n),g.length=k-g.position):k>m&&b.majorChanged&&(n.position=m,n.length=k-m,h.push(n),f.length=m-f.position),f.setProperties&&p(f.setProperties)&&h.push(f),g.setProperties&&p(g.setProperties)&&a.push(g),e?(k=h,h=a):k=a}return{opSpecsA:k,opSpecsB:h}},InsertText:function(a,b){b.position<=a.position?a.position+=b.text.length:b.position<=a.position+a.length&&(a.length+=b.text.length);return{opSpecsA:[a [...]
++MoveCursor:e,RemoveCursor:e,RemoveStyle:e,RemoveText:function(a,b){var d=a.position+a.length,f=b.position+b.length,e=[a],g=[b];f<=a.position?a.position-=b.length:b.position<d&&(a.position<b.position?a.length=f<d?a.length-b.length:b.position-a.position:(a.position=b.position,f<d?a.length=d-f:e=[]));return{opSpecsA:e,opSpecsB:g}},SetParagraphStyle:e,SplitParagraph:function(a,b){b.position<a.position?a.position+=1:b.position<a.position+a.length&&(a.length+=1);return{opSpecsA:[a],opSpecsB:[ [...]
++UpdateParagraphStyle:e},InsertText:{InsertText:function(a,b,d){a.position<b.position?b.position+=a.text.length:a.position>b.position?a.position+=b.text.length:d?b.position+=a.text.length:a.position+=b.text.length;return{opSpecsA:[a],opSpecsB:[b]}},MoveCursor:function(a,b){var d=h(b);a.position<b.position?b.position+=a.text.length:a.position<b.position+b.length&&(b.length+=a.text.length);d&&m(b);return{opSpecsA:[a],opSpecsB:[b]}},RemoveCursor:e,RemoveMember:e,RemoveStyle:e,RemoveText:fun [...]
++d=b.position+b.length;var f=[a],e=[b];d<=a.position?a.position-=b.length:a.position<=b.position?b.position+=a.text.length:(b.length=a.position-b.position,d={optype:"RemoveText",memberid:b.memberid,timestamp:b.timestamp,position:a.position+a.text.length,length:d-a.position},e.unshift(d),a.position=b.position);return{opSpecsA:f,opSpecsB:e}},SplitParagraph:function(a,b,d){if(a.position<b.position)b.position+=a.text.length;else if(a.position>b.position)a.position+=1;else return d?b.position [...]
++a.position+=1,null;return{opSpecsA:[a],opSpecsB:[b]}},UpdateMember:e,UpdateMetadata:e,UpdateParagraphStyle:e},MoveCursor:{MoveCursor:e,RemoveCursor:function(a,b){return{opSpecsA:a.memberid===b.memberid?[]:[a],opSpecsB:[b]}},RemoveMember:e,RemoveStyle:e,RemoveText:function(a,b){var d=h(a),f=a.position+a.length,e=b.position+b.length;e<=a.position?a.position-=b.length:b.position<f&&(a.position<b.position?a.length=e<f?a.length-b.length:b.position-a.position:(a.position=b.position,a.length=e [...]
++d&&m(a);return{opSpecsA:[a],opSpecsB:[b]}},SetParagraphStyle:e,SplitParagraph:function(a,b){var d=h(a);b.position<a.position?a.position+=1:b.position<a.position+a.length&&(a.length+=1);d&&m(a);return{opSpecsA:[a],opSpecsB:[b]}},UpdateMember:e,UpdateMetadata:e,UpdateParagraphStyle:e},RemoveCursor:{RemoveCursor:function(a,b){var d=a.memberid===b.memberid;return{opSpecsA:d?[]:[a],opSpecsB:d?[]:[b]}},RemoveMember:e,RemoveStyle:e,RemoveText:e,SetParagraphStyle:e,SplitParagraph:e,UpdateMember [...]
++UpdateParagraphStyle:e},RemoveMember:{RemoveStyle:e,RemoveText:e,SetParagraphStyle:e,SplitParagraph:e,UpdateMetadata:e,UpdateParagraphStyle:e},RemoveStyle:{RemoveStyle:function(a,b){var d=a.styleName===b.styleName&&a.styleFamily===b.styleFamily;return{opSpecsA:d?[]:[a],opSpecsB:d?[]:[b]}},RemoveText:e,SetParagraphStyle:function(a,b){var d,f=[a],e=[b];"paragraph"===a.styleFamily&&a.styleName===b.styleName&&(d={optype:"SetParagraphStyle",memberid:a.memberid,timestamp:a.timestamp,position: [...]
++styleName:""},f.unshift(d),b.styleName="");return{opSpecsA:f,opSpecsB:e}},SplitParagraph:e,UpdateMember:e,UpdateMetadata:e,UpdateParagraphStyle:function(a,c){var d,f=[a],e=[c];"paragraph"===a.styleFamily&&(d=b(c.setProperties,a.styleName),0<d.length&&(d={optype:"UpdateParagraphStyle",memberid:a.memberid,timestamp:a.timestamp,styleName:c.styleName,removedProperties:{attributes:d.join(",")}},f.unshift(d)),a.styleName===c.styleName?e=[]:g(c.setProperties,a.styleName));return{opSpecsA:f,opS [...]
++RemoveText:{RemoveText:function(a,b){var d=a.position+a.length,f=b.position+b.length,e=[a],g=[b];f<=a.position?a.position-=b.length:d<=b.position?b.position-=a.length:b.position<d&&(a.position<b.position?(a.length=f<d?a.length-b.length:b.position-a.position,d<f?(b.position=a.position,b.length=f-d):g=[]):(d<f?b.length-=a.length:b.position<a.position?b.length=a.position-b.position:g=[],f<d?(a.position=b.position,a.length=d-f):e=[]));return{opSpecsA:e,opSpecsB:g}},SplitParagraph:function(a [...]
++a.position+a.length,f=[a],e=[b];b.position<=a.position?a.position+=1:b.position<d&&(a.length=b.position-a.position,d={optype:"RemoveText",memberid:a.memberid,timestamp:a.timestamp,position:b.position+1,length:d-b.position},f.unshift(d));a.position+a.length<=b.position?b.position-=a.length:a.position<b.position&&(b.position=a.position);return{opSpecsA:f,opSpecsB:e}},UpdateMember:e,UpdateMetadata:e,UpdateParagraphStyle:e},SetParagraphStyle:{UpdateMember:e,UpdateMetadata:e,UpdateParagraphS [...]
++b,d){a.position<b.position?b.position+=1:a.position>b.position?a.position+=1:a.position===b.position&&(d?b.position+=1:a.position+=1);return{opSpecsA:[a],opSpecsB:[b]}},UpdateMember:e,UpdateMetadata:e,UpdateParagraphStyle:e},UpdateMember:{UpdateMetadata:e,UpdateParagraphStyle:e},UpdateMetadata:{UpdateMetadata:function(a,b,d){var f,e=[a],g=[b];f=d?a:b;a=d?b:a;n(a.setProperties||null,a.removedProperties||null,f.setProperties||null,f.removedProperties||null);f.setProperties&&p(f.setPropert [...]
++k(f.removedProperties)||(d?e=[]:g=[]);a.setProperties&&p(a.setProperties)||a.removedProperties&&k(a.removedProperties)||(d?g=[]:e=[]);return{opSpecsA:e,opSpecsB:g}},UpdateParagraphStyle:e},UpdateParagraphStyle:{UpdateParagraphStyle:function(a,b,d){var f,e=[a],g=[b];a.styleName===b.styleName&&(f=d?a:b,a=d?b:a,q(a.setProperties,a.removedProperties,f.setProperties,f.removedProperties,"style:paragraph-properties"),q(a.setProperties,a.removedProperties,f.setProperties,f.removedProperties,"st [...]
++n(a.setProperties||null,a.removedProperties||null,f.setProperties||null,f.removedProperties||null),f.setProperties&&p(f.setProperties)||f.removedProperties&&k(f.removedProperties)||(d?e=[]:g=[]),a.setProperties&&p(a.setProperties)||a.removedProperties&&k(a.removedProperties)||(d?g=[]:e=[]));return{opSpecsA:e,opSpecsB:g}}}};this.passUnchanged=e;this.extendTransformations=function(a){Object.keys(a).forEach(function(b){var d=a[b],f,e=r.hasOwnProperty(b);runtime.log((e?"Extending":"Adding") [...]
++b);e||(r[b]={});f=r[b];Object.keys(d).forEach(function(a){var e=f.hasOwnProperty(a);runtime.assert(b<=a,"Wrong order:"+b+", "+a);runtime.log("  "+(e?"Overwriting":"Adding")+" entry for optypeB: "+a);f[a]=d[a]})})};this.transformOpspecVsOpspec=function(a,b){var d=a.optype<=b.optype,e;runtime.log("Crosstransforming:");runtime.log(runtime.toJson(a));runtime.log(runtime.toJson(b));d||(e=a,a=b,b=e);(e=(e=r[a.optype])&&e[b.optype])?(e=e(a,b,!d),d||null===e||(e={opSpecsA:e.opSpecsB,opSpecsB:e. [...]
++e=null;runtime.log("result:");e?(runtime.log(runtime.toJson(e.opSpecsA)),runtime.log(runtime.toJson(e.opSpecsB))):runtime.log("null");return e}};
++// Input 108
++/*
++
++ Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
++
++ @licstart
++ This file is part of WebODF.
++
++ WebODF is free software: you can redistribute it and/or modify it
++ under the terms of the GNU Affero General Public License (GNU AGPL)
++ as published by the Free Software Foundation, either version 3 of
++ the License, or (at your option) any later version.
++
++ WebODF is distributed in the hope that it will be useful, but
++ WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ GNU Affero General Public License for more details.
++
++ You should have received a copy of the GNU Affero General Public License
++ along with WebODF.  If not, see <http://www.gnu.org/licenses/>.
++ @licend
++
++ @source: http://www.webodf.org/
++ @source: https://github.com/kogmbh/WebODF/
++*/
++ops.OperationTransformer=function(){function m(d){var g=[];d.forEach(function(d){g.push(b.create(d))});return g}function h(b,m){for(var p,k,q=[],e=[];0<b.length&&m;){p=b.shift();p=g.transformOpspecVsOpspec(p,m);if(!p)return null;q=q.concat(p.opSpecsA);if(0===p.opSpecsB.length){q=q.concat(b);m=null;break}for(;1<p.opSpecsB.length;){k=h(b,p.opSpecsB.shift());if(!k)return null;e=e.concat(k.opSpecsB);b=k.opSpecsA}m=p.opSpecsB.pop()}m&&e.push(m);return{opSpecsA:q,opSpecsB:e}}var b,g=new ops.O [...]
++this.setOperationFactory=function(d){b=d};this.getOperationTransformMatrix=function(){return g};this.transform=function(b,g){for(var p,k=[];0<g.length;){p=h(b,g.shift());if(!p)return null;b=p.opSpecsA;k=k.concat(p.opSpecsB)}return{opsA:m(b),opsB:m(k)}}};
++// Input 109
++/*
++
++ Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
 +
 + @licstart
 + The JavaScript code in this page is free software: you can redistribute it
 + and/or modify it under the terms of the GNU Affero General Public License
 + (GNU AGPL) as published by the Free Software Foundation, either version 3 of
 + the License, or (at your option) any later version.  The code is distributed
 + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + FITNESS FOR A PARTICULAR PURPOSE.  See the GNU AGPL for more details.
 +
 + You should have received a copy of the GNU Affero General Public License
 + along with this code.  If not, see <http://www.gnu.org/licenses/>.
 +
 + As additional permission under GNU AGPL version 3 section 7, you
 + may distribute non-source (e.g., minimized or compacted) forms of
 + that code without the copy of the GNU GPL normally required by
 + section 4, provided you include this license notice and a URL
 + through which recipients can access the Corresponding Source.
 +
 + As a special exception to the AGPL, any HTML file which merely makes function
 + calls to this code, and for that purpose includes it by reference shall be
 + deemed a separate work for copyright law purposes. In addition, the copyright
 + holders of this code give you permission to combine this code with free
 + software libraries that are released under the GNU LGPL. You may copy and
 + distribute such a system following the terms of the GNU AGPL for this code
 + and the LGPL for the libraries. If you modify this code, you may extend this
 + exception to your version of the code, but you are not obligated to do so.
 + If you do not wish to do so, delete this exception statement from your
 + version.
 +
 + This license applies to this entire compilation.
 + @licend
 + @source: http://www.webodf.org/
 + @source: https://github.com/kogmbh/WebODF/
 +*/
- runtime.loadClass("gui.Caret");runtime.loadClass("ops.EditInfo");runtime.loadClass("gui.EditInfoMarker");gui.SessionViewOptions=function(){this.caretBlinksOnRangeSelect=this.caretAvatarsInitiallyVisible=this.editInfoMarkersInitiallyVisible=!0};
- gui.SessionView=function(){return function(g,l,f,p,r){function n(a,b,c){function d(b,c,e){c=b+'[editinfo|memberid="'+a+'"]'+e+c;a:{var f=t.firstChild;for(b=b+'[editinfo|memberid="'+a+'"]'+e+"{";f;){if(f.nodeType===Node.TEXT_NODE&&0===f.data.indexOf(b)){b=f;break a}f=f.nextSibling}b=null}b?b.data=c:t.appendChild(document.createTextNode(c))}d("div.editInfoMarker","{ background-color: "+c+"; }","");d("span.editInfoColor","{ background-color: "+c+"; }","");d("span.editInfoAuthor",'{ content [...]
- ":before");d("dc|creator","{ background-color: "+c+"; }","");d("div.selectionOverlay","{ background-color: "+c+";}","")}function h(a){var b,c;for(c in w)w.hasOwnProperty(c)&&(b=w[c],a?b.show():b.hide())}function d(a){p.getCarets().forEach(function(b){a?b.showHandle():b.hideHandle()})}function m(a){var b=a.getMemberId();a=a.getProperties();n(b,a.fullName,a.color);l===b&&n("","",a.color)}function c(a){var b=a.getMemberId(),c=f.getOdtDocument().getMember(b).getProperties();p.registerCursor [...]
- !0);if(a=p.getCaret(b))a.setAvatarImageUrl(c.imageUrl),a.setColor(c.color);runtime.log("+++ View here +++ eagerly created an Caret for '"+b+"'! +++")}function e(a){a=a.getMemberId();var b=r.getSelectionView(l),c=r.getSelectionView(gui.ShadowCursor.ShadowCursorMemberId),d=p.getCaret(l);a===l?(c.hide(),b&&b.show(),d&&d.show()):a===gui.ShadowCursor.ShadowCursorMemberId&&(c.show(),b&&b.hide(),d&&d.hide())}function a(a){r.removeSelectionView(a)}function b(a){var b=a.paragraphElement,c=a.memb [...]
- var d,e="",g=b.getElementsByTagNameNS(A,"editinfo")[0];g?(e=g.getAttributeNS(A,"id"),d=w[e]):(e=Math.random().toString(),d=new ops.EditInfo(b,f.getOdtDocument()),d=new gui.EditInfoMarker(d,x),g=b.getElementsByTagNameNS(A,"editinfo")[0],g.setAttributeNS(A,"id",e),w[e]=d);d.addEdit(c,new Date(a))}function q(){H=!0}function k(){s=runtime.getWindow().setInterval(function(){H&&(r.rerenderSelectionViews(),H=!1)},200)}var t,A="urn:webodf:names:editinfo",w={},x=void 0!==g.editInfoMarkersInitial [...]
- Boolean(g.editInfoMarkersInitiallyVisible):!0,v=void 0!==g.caretAvatarsInitiallyVisible?Boolean(g.caretAvatarsInitiallyVisible):!0,u=void 0!==g.caretBlinksOnRangeSelect?Boolean(g.caretBlinksOnRangeSelect):!0,s,H=!1;this.showEditInfoMarkers=function(){x||(x=!0,h(x))};this.hideEditInfoMarkers=function(){x&&(x=!1,h(x))};this.showCaretAvatars=function(){v||(v=!0,d(v))};this.hideCaretAvatars=function(){v&&(v=!1,d(v))};this.getSession=function(){return f};this.getCaret=function(a){return p.ge [...]
- this.destroy=function(d){var g=f.getOdtDocument(),h=Object.keys(w).map(function(a){return w[a]});g.unsubscribe(ops.OdtDocument.signalMemberAdded,m);g.unsubscribe(ops.OdtDocument.signalMemberUpdated,m);g.unsubscribe(ops.OdtDocument.signalCursorAdded,c);g.unsubscribe(ops.OdtDocument.signalCursorRemoved,a);g.unsubscribe(ops.OdtDocument.signalParagraphChanged,b);g.unsubscribe(ops.OdtDocument.signalCursorMoved,e);g.unsubscribe(ops.OdtDocument.signalParagraphChanged,q);g.unsubscribe(ops.OdtDo [...]
- q);g.unsubscribe(ops.OdtDocument.signalParagraphStyleModified,q);runtime.getWindow().clearInterval(s);t.parentNode.removeChild(t);(function W(a,b){b?d(b):a<h.length?h[a].destroy(function(b){W(a+1,b)}):d()})(0,void 0)};(function(){var d=f.getOdtDocument(),g=document.getElementsByTagName("head")[0];d.subscribe(ops.OdtDocument.signalMemberAdded,m);d.subscribe(ops.OdtDocument.signalMemberUpdated,m);d.subscribe(ops.OdtDocument.signalCursorAdded,c);d.subscribe(ops.OdtDocument.signalCursorRemo [...]
- b);d.subscribe(ops.OdtDocument.signalCursorMoved,e);k();d.subscribe(ops.OdtDocument.signalParagraphChanged,q);d.subscribe(ops.OdtDocument.signalTableAdded,q);d.subscribe(ops.OdtDocument.signalParagraphStyleModified,q);t=document.createElementNS(g.namespaceURI,"style");t.type="text/css";t.media="screen, print, handheld, projection";t.appendChild(document.createTextNode("@namespace editinfo url(urn:webodf:names:editinfo);"));t.appendChild(document.createTextNode("@namespace dc url(http:// [...]
- g.appendChild(t)})()}}();
- // Input 100
- var webodf_css="@namespace draw url(urn:oasis:names:tc:opendocument:xmlns:drawing:1.0);\n at namespace fo url(urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0);\n at namespace office url(urn:oasis:names:tc:opendocument:xmlns:office:1.0);\n at namespace presentation url(urn:oasis:names:tc:opendocument:xmlns:presentation:1.0);\n at namespace style url(urn:oasis:names:tc:opendocument:xmlns:style:1.0);\n at namespace svg url(urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0);\n at namespace [...]
++ops.Server=function(){};ops.Server.prototype.connect=function(m,h){};ops.Server.prototype.networkStatus=function(){};ops.Server.prototype.login=function(m,h,b,g){};ops.Server.prototype.joinSession=function(m,h,b,g){};ops.Server.prototype.leaveSession=function(m,h,b,g){};ops.Server.prototype.getGenesisUrl=function(m){};
++// Input 110
++var webodf_css='@namespace draw url(urn:oasis:names:tc:opendocument:xmlns:drawing:1.0);\n at namespace fo url(urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0);\n at namespace office url(urn:oasis:names:tc:opendocument:xmlns:office:1.0);\n at namespace presentation url(urn:oasis:names:tc:opendocument:xmlns:presentation:1.0);\n at namespace style url(urn:oasis:names:tc:opendocument:xmlns:style:1.0);\n at namespace svg url(urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0);\n at namespace [...]
diff --cc apps/documents/js/ServerFactory.js
index 0d6b2b4,0000000..c3d4a6e
mode 100644,000000..100644
--- a/apps/documents/js/ServerFactory.js
+++ b/apps/documents/js/ServerFactory.js
@@@ -1,60 -1,0 +1,59 @@@
 +/**
 + * @license
 + * Copyright (C) 2013 KO GmbH <copyright at kogmbh.com>
 + *
 + * @licstart
 + * This file is part of WebODF.
 + *
 + * WebODF is free software: you can redistribute it and/or modify it
 + * under the terms of the GNU Affero General Public License (GNU AGPL)
 + * as published by the Free Software Foundation, either version 3 of
 + * the License, or (at your option) any later version.
 + *
 + * WebODF is distributed in the hope that it will be useful, but
 + * WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU Affero General Public License for more details.
 + *
 + * You should have received a copy of the GNU Affero General Public License
 + * along with WebODF.  If not, see <http://www.gnu.org/licenses/>.
 + * @licend
 + *
 + * @source: http://www.webodf.org/
 + * @source: https://github.com/kogmbh/WebODF/
 + */
 +
 +/*global define, require, OC*/
 +
- define("webodf/editor/server/owncloud/ServerFactory", [
++define("owncloud/ServerFactory", [
 +    "webodf/editor/server/pullbox/Server",
 +    "webodf/editor/server/pullbox/OperationRouter",
 +    "webodf/editor/server/pullbox/SessionList"],
 +    function (PullBoxServer, PullBoxOperationRouter, PullBoxSessionList) {
 +        "use strict";
 +
 +        /**
 +        * @constructor
 +        * @implements ServerFactory
 +        */
 +        return function OwnCloudServerFactory() {
 +            this.createServer = function (args) {
 +                var server;
 +                args = args || {};
 +                args.url = OC.filePath('documents', 'ajax', 'otpoll.php');
 +                args.sessionStateToFileUrl = OC.Router.generate('documents_session_save');
 +
 +                server = new PullBoxServer(args);
 +                server.getGenesisUrl = function(sid) {
-                     // what a dirty hack :)
-                     return OC.Router.generate('documents_genesis') + '/' + sid;
++                    return OC.generateUrl('apps/documents/ajax/genesis/{es_id}', {es_id: sid}) + '?requesttoken=' + oc_requesttoken;
 +                };
 +                return server;
 +            };
 +            this.createOperationRouter = function (sid, mid, server, odfContainer, errorCallback) {
 +                return new PullBoxOperationRouter(sid, mid, server, odfContainer, errorCallback);
 +            };
 +            this.createSessionList = function (server) {
 +                return new PullBoxSessionList(server);
 +            };
 +        };
 +});
diff --cc apps/documents/js/documents.js
index 8e32fc5,0000000..a7a1230
mode 100644,000000..100644
--- a/apps/documents/js/documents.js
+++ b/apps/documents/js/documents.js
@@@ -1,599 -1,0 +1,789 @@@
 +/*globals $,OC,fileDownloadPath,t,document,odf,webodfEditor,alert,require,dojo,runtime */
 +var documentsMain = {
 +	_documents: [],
 +	_sessions: [],
 +	_members: [],
 +	isEditormode : false,
 +	useUnstable : false,
 +	isGuest : false,
 +	memberId : false,
 +	esId : false,
 +	ready :false,
 +	fileName: null,
 +	
 +	UI : {
 +		/* Overlay HTML */
- 		overlay : '<div id="documents-overlay" class="icon icon-loading-dark"></div> <div id="documents-overlay-below" class="icon icon-loading-dark"></div>',
++		overlay : '<div id="documents-overlay" class="icon-loading-dark"></div> <div id="documents-overlay-below" class="icon-loading-dark"></div>',
 +				
 +		/* Toolbar HTML */
 +		toolbar : '<div id="odf-toolbar" class="dijitToolbar">' +
- 					'  <div id="document-title"><div>' +
- 					'%title%' +
- 			        '  </div></div>' +
++					'  <div id="document-title" class="icon-noise">' +
++					'<div class="logo-wide"></div>' +
++					'<div id="document-title-container"></div>' +
++			        '</div>' +
++					'  <span id="toolbar" class="claro">' +
++					'  <button id="odf-invite" class="drop">' +
++						  t('documents', 'Share') +
++					'  </button>' +
 +					'  <button id="odf-close">' +
- 						t('documents', 'Close') +
++					       t('documents', 'Close') +
 +					'  </button>' +
 +					'  <img id="saving-document" alt=""' +
 +					'   src="' + OC.imagePath('core', 'loading.gif') + '"' +
 +					'  />' +
- 					'  <button id="odf-invite" class="drop">' +
- 						  t('documents', 'Share') +
- 					'  </button>' +
- 					'  <span id="toolbar" class="claro"></span>' +
++					'</span>' +
 +					'</div>',
 +					
 +		/* Editor wrapper HTML */
 +		container : '<div id = "mainContainer" class="claro" style="">' +
 +					'  <div id = "editor">' +
 +					'    <div id = "container">' +
 +					'      <div id="canvas"></div>' +
 +					'    </div>' +
 +					'  </div>' +
 +					'  <div id = "collaboration">' +
 +					'    <div id = "collabContainer">' +
 +					'      <div id = "members">' +
 +					'        <div id = "inviteButton"></div>' +
 +					'        <div id = "memberList"></div>' +
 +					'      </div>' +
 +					'    </div>' +
 +					'  </div>' +
 +					'</div>',
 +					
 +		/* Previous window title */
 +		mainTitle : '',
 +				
 +		init : function(){
 +			$(documentsMain.UI.overlay).hide().appendTo(document.body);
 +			documentsMain.UI.mainTitle = $('title').text();
 +		},
 +		
 +		showOverlay : function(){
 +			$('#documents-overlay,#documents-overlay-below').fadeIn('fast');
 +		},
 +		
 +		hideOverlay : function(){
 +			$('#documents-overlay,#documents-overlay-below').fadeOut('fast');
 +		},
 +		
 +		showEditor : function(title, canShare){
- 			$(document.body).prepend(documentsMain.UI.toolbar.replace(/%title%/g, title));
++			$(document.body).prepend(documentsMain.UI.toolbar);
++			$('#document-title-container').text(title);
 +			if (!canShare){
 +				$('#odf-invite').remove();
 +			} else {
 +				//TODO: fill in with users
 +			}
 +			$(document.body).addClass("claro");
 +			$(document.body).prepend(documentsMain.UI.container);
 +			// in case we are on the public sharing page we shall display the odf into the preview tag
 +			$('#preview').html(container);
 +			$('title').text(title + ' - ' + documentsMain.UI.mainTitle);
 +		},
 +		
 +		hideEditor : function(){
 +				// Fade out toolbar
 +				$('#odf-toolbar').fadeOut('fast');
 +				// Fade out editor
 +				$('#mainContainer').fadeOut('fast', function() {
 +					$('#mainContainer').remove();
 +					$('#odf-toolbar').remove();
 +					$('#content').fadeIn('fast');
 +					$(document.body).removeClass('claro');
 +					$('title').text(documentsMain.UI.mainTitle);
 +				});
 +		},
 +		
 +		showSave : function (){
 +			$('#odf-close').hide();
 +			$('#saving-document').show();
 +		},
 +		
 +		hideSave : function(){
 +			$('#saving-document').hide();
 +			$('#odf-close').show();
 +		},
 +		
 +		showProgress : function(message){
 +			if (!message){
 +				message = ' ';
 +			}
 +			$('.documentslist .progress div').text(message);
 +			$('.documentslist .progress').show();
 +		},
 +		
 +		hideProgress : function(){
 +			$('.documentslist .progress').hide();
 +		},
 +		
 +		showLostConnection : function(){
 +			$('#memberList .memberListButton').css({opacity : 0.3});
 +			$('#odf-toolbar').children(':not(#document-title)').hide();
 +			$('<div id="connection-lost"></div>').prependTo('#memberList');
 +			$('<div id="warning-connection-lost">' + t('documents', 'No connection to server. Trying to reconnect.') +'<img src="'+ OC.imagePath('core', 'loading-dark.gif') +'" alt="" /></div>').appendTo('#odf-toolbar');
 +		},
 +		
 +		hideLostConnection : function() {
 +			$('#connection-lost,#warning-connection-lost').remove();
 +			$('#odf-toolbar').children(':not(#document-title,#saving-document)').show();
 +			$('#memberList .memberListButton').css({opacity : 1});
++		},
++		
++		notify : function(message){
++			OC.Notification.show(message);
++			setTimeout(OC.Notification.hide, 10000);
 +		}
 +	},
 +	
 +	onStartup: function() {
 +		var fileId;
 +		"use strict";
 +		documentsMain.useUnstable = $('#webodf-unstable').val()==='true';
 +		documentsMain.UI.init();
 +		
 +		if (!OC.currentUser){
 +			documentsMain.isGuest = true;
 +			
++			
++			if ($("[name='document']").val()){
++				// !Login page mess wih WebODF toolbars
++				$(document.body).attr('id', 'body-user');
++				$('header,footer').hide();
++				documentsMain.prepareSession();
++				documentsMain.joinSession(
++					$("[name='document']").val()
++				);
++			}
++
 +		} else {
 +			// Does anything indicate that we need to autostart a session?
 +			fileId = parent.location.hash.replace(/\W*/g, '');
 +		}
 +		
 +		documentsMain.show();
 +		if (fileId){
 +			documentsMain.UI.showOverlay();
 +		}
 +		
 +		var webodfSource = (oc_debug === true) ? 'webodf-debug' : 'webodf';
 +		OC.addScript('documents', '3rdparty/webodf/' + webodfSource).done(function() {
 +			// preload stuff in the background
 +			require({}, ["dojo/ready"], function(ready) {
 +				ready(function() {
 +					require({}, ["webodf/editor/Editor"], function(Editor) {
 +						runtime.setTranslator(function(s){return t('documents', s);});
 +						documentsMain.ready = true;
 +						if (fileId){
 +							documentsMain.prepareSession();
 +							documentsMain.joinSession(fileId);
 +						}
 +					});
 +				});
 +			});
 +		});
 +	},
 +	
 +	prepareSession : function(){
 +		documentsMain.isEditorMode = true;
 +		documentsMain.UI.showOverlay();
 +		$(window).on('beforeunload', function(){
 +			return t('documents', "Leaving this page in Editor mode might cause unsaved data. It is recommended to use 'Close' button instead."); 
 +		});
++		$(window).on("unload", documentsMain.onTerminate);
 +	},
 +	
 +	prepareGrid : function(){
 +		documentsMain.isEditorMode = false;
 +		documentsMain.UI.hideOverlay();
 +	},
 +	
 +	initSession: function(response) {
 +		"use strict";
 +
 +		if(response && (response.id && !response.es_id)){
 +			return documentsMain.view(response.id);
 +		} 
 +
 +		if (!response || !response.status || response.status==='error'){
 +			documentsMain.onEditorShutdown(t('documents', 'Failed to load this document. Please check if it can be opened with an external odt editor. This might also mean it has been unshared or deleted recently.'));
 +			return;
 +		}
 +		
 +		//Wait for 3 sec if editor is still loading 
 +		if (!documentsMain.ready){
 +			setTimeout(function(){ documentsMain.initSession(response); }, 3000);
 +			console.log('Waiting for the editor to start...');
 +			return;
 +		}
 +
- 		require({ }, ["webodf/editor/server/owncloud/ServerFactory", "webodf/editor/Editor"], function (ServerFactory, Editor) {
++		require({ }, ["owncloud/ServerFactory", "webodf/editor/Editor"], function (ServerFactory, Editor) {
 +			// fade out file list and show WebODF canvas
 +			$('#content').fadeOut('fast').promise().done(function() {
 +				
 +				documentsMain.fileId = response.file_id;
 +				documentsMain.fileName = documentsMain.getNameByFileid(response.file_id);
 +				documentsMain.UI.showEditor(
 +						documentsMain.fileName || response.title,
- 						response.permissions & OC.PERMISSION_SHARE && !documentsMain.isGuest
++						typeof OC.Share !== 'undefined' && response.permissions & OC.PERMISSION_SHARE && !documentsMain.isGuest
 +				);
++				if (documentsMain.isGuest){
++					$('#odf-close').text(t('documents', 'Save') );
++				}
 +				var serverFactory = new ServerFactory();
 +				documentsMain.esId = response.es_id;
 +				documentsMain.memberId = response.member_id;
 +
 +				// TODO: set webodf translation system, by passing a proper function translate(!string):!string in "runtime.setTranslator(translate);"
 +
 +				documentsMain.webodfServerInstance = serverFactory.createServer();
 +				documentsMain.webodfServerInstance.setToken(oc_requesttoken);
 +				documentsMain.webodfEditorInstance = new Editor({unstableFeaturesEnabled: documentsMain.useUnstable}, documentsMain.webodfServerInstance, serverFactory);
 +				documentsMain.webodfEditorInstance.addEventListener(Editor.EVENT_BEFORESAVETOFILE, documentsMain.UI.showSave);
 +				documentsMain.webodfEditorInstance.addEventListener(Editor.EVENT_SAVEDTOFILE, documentsMain.UI.hideSave);
 +				documentsMain.webodfEditorInstance.addEventListener(Editor.EVENT_ERROR, documentsMain.onEditorShutdown);
 +				documentsMain.webodfEditorInstance.addEventListener(Editor.EVENT_HASSESSIONHOSTCONNECTIONCHANGED, function(has) {
 +					if (has){
 +						documentsMain.UI.hideLostConnection();
 +					} else {
 +						documentsMain.UI.showLostConnection();
 +					}
 +				});
 +				// load the document and get called back when it's live
 +				documentsMain.webodfEditorInstance.openSession(documentsMain.esId, documentsMain.memberId, function() {
 +					documentsMain.webodfEditorInstance.startEditing();
 +					documentsMain.UI.hideOverlay();
 +					parent.location.hash = response.file_id;
 +				});
 +			});
 +		});
 +	},
 +	
 +
 +	joinSession: function(fileId) {
 +		console.log('joining session '+fileId);
 +		var url;
 +		if (documentsMain.isGuest){
 +			url = OC.Router.generate('documents_session_joinasguest') + '/' + fileId;
 +		} else {
 +			url = OC.Router.generate('documents_session_joinasuser') + '/' + fileId;
 +		}
 +		$.post(
 +			url,
 +			{ name : $("[name='memberName']").val() },
 +			documentsMain.initSession
 +		);
 +	},
 +	
 +	view : function(id){
 +		OC.addScript('documents', 'viewer/viewer', function() {
 +			documentsMain.prepareGrid();
 +			$(window).off('beforeunload');
++			$(window).off('unload');
 +			var path = $('li[data-id='+ id +']>a').attr('href');
 +			odfViewer.isDocuments = true;
 +			odfViewer.onView(path);
 +		});
 +	},
 +			
 +	onCreate: function(event){
 +		event.preventDefault();
 +		var docElem = $('.documentslist .template').clone();
 +		docElem.removeClass('template');
 +		docElem.addClass('document');
 +		docElem.insertAfter('.documentslist .template');
 +		docElem.show();
 +		$.post(
 +			OC.Router.generate('documents_documents_create'),
 +			{},
- 			documentsMain.show
++			function(response){
++				if (response && response.fileid){
++					documentsMain.prepareSession();
++					documentsMain.joinSession(response.fileid);
++				} else {
++					if (response && response.message){
++						documentsMain.UI.notify(response.message);
++					}
++					documentsMain.show();
++				}
++			}
++			
 +		);
 +	},
 +
 +	onInvite: function(event) {
 +		event.preventDefault();
 +		if (OC.Share.droppedDown) {
 +			OC.Share.hideDropDown();
 +		} else {
 +			(function() {
 +				var target = OC.Share.showLink;
 +				OC.Share.showLink = function() {
 +					var r = target.apply( this, arguments );
 +					$('#linkText').val( $('#linkText').val().replace('service=files', 'service=documents') );
 +					return r;
 +				};
 +			})();
 +
 +			OC.Share.showDropDown(
 +				'file', 
 +				parent.location.hash.replace(/\W*/g, ''),
 +				$("#odf-toolbar"),
 +				true, 
 +				OC.PERMISSION_READ | OC.PERMISSION_SHARE | OC.PERMISSION_UPDATE
 +			);
 +		}
 +	},
++	
++	changeNick: function(memberId, name, node){
++		var url = OC.generateUrl('apps/documents/ajax/user/rename/{member_id}', {member_id: memberId});
++		$.post(
++			url,
++			{ name : name },
++			function(result) {
++				if (result && result.status === 'error') {
++					if (result.message){
++						documentsMain.UI.notify(result.message);
++					}
++					return;
++				}
++			}
++		);
++	},
++	
++	onNickChange: function(memberId, fullNameNode){
++		if (!documentsMain.isGuest || memberId !== documentsMain.memberId){
++			return;
++		}
++		if ($(fullNameNode.parentNode).children('input').length !== 0){
++			return;
++		}
++		
++		var input = $('<input type="text"/>').val($(fullNameNode).attr('fullname'));
++		$(fullNameNode.parentNode).append(input);
++		$(fullNameNode).hide();
++
++		input.on('blur', function(){
++			var newName = input.val();
++			if (!newName || newName === name) {
++				input.tipsy('hide');
++				input.remove();
++				$(fullNameNode).show();
++				return;
++			}
++			else {
++				try {
++					input.tipsy('hide');
++					input.removeClass('error');
++					input.tipsy('hide');
++					input.remove();
++					$(fullNameNode).show();
++					documentsMain.changeNick(memberId, newName, fullNameNode);
++				}
++				catch (error) {
++					input.attr('title', error);
++					input.tipsy({gravity: 'n', trigger: 'manual'});
++					input.tipsy('show');
++					input.addClass('error');
++				}
++			}
++		});
++		input.on('keyup', function(event){
++			if (event.keyCode === 27) {
++				// cancel by putting in an empty value
++				$(this).val('');
++				$(this).blur();
++				event.preventDefault();
++			}
++			if (event.keyCode === 13) {
++				$(this).blur();
++				event.preventDefault();
++			}
++		});
++		input.focus();
++		input.selectRange(0, name.length);
++	},
 +
 +	renameDocument: function(name) {
 +		var url = OC.Router.generate('documents_rename') + '/' + documentsMain.fileId;
 +		$.post(
 +			url,
 +			{ name : name },
 +			function(result) {
 +				if (result && result.status === 'error') {
 +					if (result.message){
- 						OC.Notification.show(result.message);
- 						setTimeout(function() {
- 							OC.Notification.hide();
- 						}, 10000);
++						documentsMain.IU.notify(result.message);
 +					}
 +					return;
 +				}
 +				documentsMain.fileName = name;
 +				$('title').text(documentsMain.UI.mainTitle + '| ' + name);
- 				$('#document-title>div').text(name);
++				$('#document-title-container').text(name);
 +			}
 +		);
 +	},
 +
 +
 +	onRenamePrompt: function() {
 +		var name = documentsMain.fileName;
 +		var lastPos = name.lastIndexOf('.');
 +		var extension = name.substr(lastPos + 1);
 +		name = name.substr(0, lastPos);
 +		var input = $('<input type="text" class="filename"/>').val(name);
 +		$('#document-title').append(input);
 +		$('#document-title>div').hide();
 +
 +		input.on('blur', function(){
 +			var newName = input.val();
 +			if (!newName || newName === name) {
 +				input.tipsy('hide');
 +				input.remove();
 +				$('#document-title>div').show();
 +				return;
 +			}
 +			else {
 +				newName = newName + '.' + extension;
 +				try {
 +					input.tipsy('hide');
 +					input.removeClass('error');
 +					if (Files.isFileNameValid(newName)) {
 +						input.tipsy('hide');
 +						input.remove();
 +						$('#document-title>div').show();
 +						documentsMain.renameDocument(newName);
 +					}
 +				}
 +				catch (error) {
 +					input.attr('title', error);
 +					input.tipsy({gravity: 'n', trigger: 'manual'});
 +					input.tipsy('show');
 +					input.addClass('error');
 +				}
 +			}
 +		});
 +		input.on('keyup', function(event){
 +			if (event.keyCode === 27) {
 +				// cancel by putting in an empty value
 +				$(this).val('');
 +				$(this).blur();
 +				event.preventDefault();
 +			}
 +			if (event.keyCode === 13) {
 +				$(this).blur();
 +				event.preventDefault();
 +			}
 +		});
 +		input.focus();
 +		input.selectRange(0, name.length);
 +	},
 +
 +	onEditorShutdown : function (message){
 +			OC.Notification.show(message);
 +
 +			$(window).off('beforeunload');
++			$(window).off('unload');
 +			if (documentsMain.isEditorMode){
 +				documentsMain.isEditorMode = false;
 +				parent.location.hash = "";
 +			} else {
 +				setTimeout(OC.Notification.hide, 7000);
 +			}
 +			documentsMain.prepareGrid();
 +			try {
 +				documentsMain.webodfEditorInstance.endEditing();
 +				documentsMain.webodfEditorInstance.closeSession(function() {
 +					documentsMain.webodfEditorInstance.destroy(documentsMain.UI.hideEditor);
 +				});
 +			} catch (e){
 +				documentsMain.UI.hideEditor();
 +			}
 +			
 +			documentsMain.show();
- 		},
++	},
 +		
 +
 +	onClose: function() {
 +		"use strict";
 +		
 +		if (!documentsMain.isEditorMode){
 +			return;
 +		}
 +		documentsMain.isEditorMode = false;
 +		$(window).off('beforeunload');
++		$(window).off('unload');
 +		parent.location.hash = "";
 +
 +		documentsMain.webodfEditorInstance.endEditing();
 +		documentsMain.webodfEditorInstance.closeSession(function() {
 +			// successfull shutdown - all is good.
 +			// TODO: proper session leaving call to server, either by webodfServerInstance or custom
 +// 			documentsMain.webodfServerInstance.leaveSession(sessionId, memberId, function() {
 +			if (documentsMain.isGuest){
 +				$(document.body).attr('id', 'body-login');
 +				$('header,footer').show();
 +			}
 +			documentsMain.webodfEditorInstance.destroy(documentsMain.UI.hideEditor);
 +			
 +			if (documentsMain.isGuest){
 +				var url = OC.Router.generate('documents_user_disconnectGuest');
 +			} else {
 +				var url = OC.Router.generate('documents_user_disconnect');
 +			}
 +			
 +			$.post(url + '/' + documentsMain.memberId, {esId: documentsMain.esId});
 +			
 +			documentsMain.show();
 +// 			});
 +		});
 +	},
 +	
++	onTerminate: function(){
++		var url = '';
++		if (documentsMain.isGuest){
++			url = OC.generateUrl('apps/documents/ajax/user/disconnectGuest/{member_id}', {member_id: documentsMain.memberId});
++		} else {
++			url = OC.generateUrl('apps/documents/ajax/user/disconnect/{member_id}', {member_id: documentsMain.memberId});
++		}
++		$.ajax({
++				type: "POST",
++				url: url,
++				data: {esId: documentsMain.esId},
++				dataType: "json",
++				async: false // Should be sync to complete before the page is closed
++		});
++
++		
++		documentsMain.webodfEditorInstance.endEditing();
++		documentsMain.webodfEditorInstance.closeSession(function() {
++			if (documentsMain.isGuest){
++				$(document.body).attr('id', 'body-login');
++				$('header,footer').show();
++			}
++			documentsMain.webodfEditorInstance.destroy(documentsMain.UI.hideEditor);
++		});
++
++	},
++	
 +	getNameByFileid : function(fileid){
 +		return $('.documentslist li[data-id='+ fileid + ']').find('label').text();
 +	},
 +	
 +	show: function(){
 +		if (documentsMain.isGuest){
 +			return;
 +		}
 +		documentsMain.UI.showProgress(t('documents', 'Loading documents...'));
 +		jQuery.when(documentsMain.loadDocuments())
 +			.then(function(){
 +				documentsMain.renderDocuments();
 +				documentsMain.UI.hideProgress();
 +			});
 +	},
 +	
 +	loadDocuments: function () {
 +		var self = this;
 +		var def = new $.Deferred();
 +		OC.Router.registerLoadedCallback(function () {
 +			jQuery.getJSON(OC.Router.generate('documents_documents_list'))
 +				.done(function (data) {
 +					self._documents = data.documents;
 +					self._sessions = data.sessions;
 +					self._members = data.members;
 +					def.resolve();
 +				})
 +				.fail(function(data){
 +					console.log(t('documents','Failed to load documents.'));
 +				});
 +		});
 +		return def;
 +	},
 +	
 +	renderDocuments: function () {
 +		var self = this,
 +		hasDocuments = false;
 +
 +		//remove all but template
 +		$('.documentslist .document:not(.template,.progress)').remove();
 +
 +		jQuery.each(this._documents, function(i,document){
 +			var docElem = $('.documentslist .template').clone();
 +			docElem.removeClass('template');
 +			docElem.addClass('document');
 +			docElem.attr('data-id', document.fileid);
 +
 +			var a = docElem.find('a');
 +			a.attr('href', OC.Router.generate('download',{file:document.path}));
 +			a.find('label').text(document.name);
 +			a.css('background-image', 'url("'+document.icon+'")');
- 
++			Files.lazyLoadPreview(document.path, document.mimetype, function(node){ return function(path){node.css('background-image', 'url("'+ path +'")');}; }(a),  32, 40, document.etag, document.icon);
++//function(path, mime, ready, width, height, etag) {
 +			$('.documentslist').append(docElem);
 +			docElem.show();
 +			hasDocuments = true;
 +		});
 +		jQuery.each(this._sessions, function(i,session){
 +			if (self._members[session.es_id].length > 0) {
 +				var docElem = $('.documentslist .document[data-id="'+session.file_id+'"]');
 +				if (docElem.length > 0) {
 +					docElem.attr('data-esid', session.es_id);
 +					docElem.find('label').after('<img class="svg session-active" src="'+OC.imagePath('core','places/contacts-dark')+'">');
 +					docElem.addClass('session');
 +				} else {
 +					console.log('Could not find file '+session.file_id+' for session '+session.es_id);
 +				}
 +			}
 +		});
 +		
 +		if (!hasDocuments){
 +			$('#documents-content').append('<div id="emptycontent">'
 +				+ t('documents', 'No documents are found. Please upload or create a document!')
 +				+ '</div>'
 +			);
 +		} else {
 +			$('#emptycontent').remove();
 +		}
 +	}
 +};
 +
 +
 +//web odf bootstrap code. Added here to reduce number of requests
 +/*globals navigator,dojoConfig */
 +var usedLocale = "C";
 +
 +if (navigator && navigator.language.match(/^(de)/)) {
 +	usedLocale = navigator.language.substr(0,2);
 +}
 +
 +dojoConfig = {
 +	locale: usedLocale,
 +	paths: {
 +		"webodf/editor": OC.appswebroots.documents + "/js/3rdparty/webodf/editor",
 +		"dijit": OC.appswebroots.documents + "/js/3rdparty/resources/dijit",
 +		"dojox": OC.appswebroots.documents + "/js/3rdparty/resources/dojox",
 +		"dojo": OC.appswebroots.documents + "/js/3rdparty/resources/dojo",
- 		"resources": OC.appswebroots.documents + "/js/3rdparty/resources"
++		"resources": OC.appswebroots.documents + "/js/3rdparty/resources",
++		"owncloud" : OC.appswebroots.documents + "/js"
 +	}
 +};
 +
 +
 +//init
 +var Files = Files || {
 +	// FIXME: copy/pasted from Files.isFileNameValid, needs refactor into core
 +	isFileNameValid:function (name) {
 +		if (name === '.') {
 +			throw t('files', '\'.\' is an invalid file name.');
 +		} else if (name.length === 0) {
 +			throw t('files', 'File name cannot be empty.');
 +		}
 +
 +		// check for invalid characters
 +		var invalid_characters = ['\\', '/', '<', '>', ':', '"', '|', '?', '*'];
 +		for (var i = 0; i < invalid_characters.length; i++) {
 +			if (name.indexOf(invalid_characters[i]) !== -1) {
 +				throw t('files', "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed.");
 +			}
 +		}
 +		return true;
 +	},
 +	
++	generatePreviewUrl : function(urlSpec) {
++		urlSpec = urlSpec || {};
++		if (!urlSpec.x) {
++			urlSpec.x = $('#filestable').data('preview-x');
++		}
++		if (!urlSpec.y) {
++			urlSpec.y = $('#filestable').data('preview-y');
++		}
++		urlSpec.y *= window.devicePixelRatio;
++		urlSpec.x *= window.devicePixelRatio;
++		urlSpec.forceIcon = 0;
++		return OC.generateUrl('/core/preview.png?') + $.param(urlSpec);
++	},
++	
++	lazyLoadPreview : function(path, mime, ready, width, height, etag, defaultIcon) {
++		var urlSpec = {};
++		var previewURL;
++		ready(defaultIcon); // set mimeicon URL
++
++		urlSpec.file = Files.fixPath(path);
++		if (etag){
++			// use etag as cache buster
++			urlSpec.c = etag;
++		} else {
++			console.warn('Files.lazyLoadPreview(): missing etag argument');
++		}
++
++		urlSpec.x = width;
++		urlSpec.y = height;
++		if ( $('#isPublic').length ) {
++			urlSpec.t = $('#dirToken').val();
++		}
++		previewURL = Files.generatePreviewUrl(urlSpec);
++		previewURL = previewURL.replace('(', '%28');
++		previewURL = previewURL.replace(')', '%29');
++
++		// preload image to prevent delay
++		// this will make the browser cache the image
++		var img = new Image();
++		img.onload = function(){
++			//set preview thumbnail URL
++			ready(previewURL);
++		};
++		img.src = previewURL;
++	},
++	
++	fixPath: function(fileName) {
++		if (fileName.substr(0, 2) === '//') {
++			return fileName.substr(1);
++		}
++		return fileName;
++	},
++	
 +	updateStorageStatistics: function(){}
++},
++FileList = FileList || {};
++
++FileList.getCurrentDirectory = function(){
++	return $('#dir').val() || '/';
 +};
 +
 +$(document).ready(function() {
 +	"use strict";
 +	
 +	$('.documentslist').on('click', 'li:not(.add-document)', function(event) {
 +		event.preventDefault();
 +
 +		if (documentsMain.isEditorMode){
 +			return;
 +		}
 +		
 +		documentsMain.prepareSession();
 +		if ($(this).attr('data-id')){
 +			documentsMain.joinSession($(this).attr('data-id'));
 +		}
 +	});
 +	
 +	$(document.body).on('click', '#document-title>div', documentsMain.onRenamePrompt);
 +	$(document.body).on('click', '#odf-close', documentsMain.onClose);
 +	$(document.body).on('click', '#odf-invite', documentsMain.onInvite);
- 	$(document.body).on('click', '#odf-join', function(event){
- 		event.preventDefault();
 +
- 		// !Login page mess wih WebODF toolbars
- 		$(document.body).attr('id', 'body-user');
- 		$('header,footer').hide();
- 		documentsMain.prepareSession();
- 		documentsMain.joinSession(
- 				$("[name='document']").val()
- 		);
- 	});
 +	$('.add-document').on('click', '.add', documentsMain.onCreate);
 +
 +
 +	var file_upload_start = $('#file_upload_start');
- 	file_upload_start.on('fileuploaddone', documentsMain.show);
++	if (typeof supportAjaxUploadWithProgress !== 'undefined' && supportAjaxUploadWithProgress()) {
++		file_upload_start.on('fileuploadstart', function(e, data) {
++			$('#upload').addClass('icon-loading');
++			$('.add-document .upload').css({opacity:0})
++		});
++	}
++	file_upload_start.on('fileuploaddone', function(){
++		$('#upload').removeClass('icon-loading');
++		$('.add-document .upload').css({opacity:0.7})
++		documentsMain.show();
++	});
 +	//TODO when ending a session as the last user close session?
 +	
 +	OC.addScript('documents', '3rdparty/webodf/dojo-amalgamation', documentsMain.onStartup);
 +});
diff --cc apps/documents/lib/config.php
index 0000000,0000000..52ee782
new file mode 100644
--- /dev/null
+++ b/apps/documents/lib/config.php
@@@ -1,0 -1,0 +1,46 @@@
++<?php
++
++/**
++ * ownCloud - Documents App
++ *
++ * @author Victor Dubiniuk
++ * @copyright 2014 Victor Dubiniuk victor.dubiniuk at gmail.com
++ *
++ * This file is licensed under the Affero General Public License version 3 or
++ * later.
++ */
++
++namespace OCA\Documents;
++
++class Config {
++	const APP_NAME = 'documents';
++	
++	public static function getL10n(){
++		return \OCP\Util::getL10N(self::APP_NAME);
++	}
++	
++	public static function getConverter(){
++		return self::getAppValue('converter', 'local');
++	}
++	
++	public static function setConverter($value){
++		return self::setAppValue('converter', $value);
++	}
++	
++	public static function getConverterUrl(){
++		return self::getAppValue('converter_url', 'http://localhost:16080');
++	}
++	
++	public static function setConverterUrl($value){
++		return self::setAppValue('converter_url', $value);
++	}
++
++	protected static function getAppValue($key, $default){
++		return \OCP\Config::getAppValue(self::APP_NAME, $key, $default);
++	}
++	
++	protected static function setAppValue($key, $value){
++		return \OCP\Config::setAppValue(self::APP_NAME, $key, $value);
++	}
++	
++}
diff --cc apps/documents/lib/db.php
index c1a799c,0000000..dd476d4
mode 100644,000000..100644
--- a/apps/documents/lib/db.php
+++ b/apps/documents/lib/db.php
@@@ -1,209 -1,0 +1,220 @@@
 +<?php
 +/**
 + * ownCloud - Documents App
 + *
 + * @author Victor Dubiniuk
 + * @copyright 2013 Victor Dubiniuk victor.dubiniuk at gmail.com
 + *
 + * This file is licensed under the Affero General Public License version 3 or
 + * later.
 + */
 +
 +namespace OCA\Documents;
 +
 +/**
 + * Generic DB class 
 + */
 +
 +abstract class Db {
 +	
 +	protected $data;
 +	
 +	protected $tableName;
 +	
 +	protected $insertStatement;
 +	
 +	protected $loadStatement;
 +	
 +	public function __construct($data = array()){
 +		$this->setData($data);
 +	}
 +	
 +	/**
 +	 * Insert current object data into database
 +	 * @return mixed
 +	 */
 +	public function insert(){
 +		$result = $this->execute($this->insertStatement);
 +		return $result;
 +	}
 +	
 +	/**
 +	 * Get id of the recently inserted record
 +	 * @return mixed
 +	 */
 +	public function getLastInsertId(){
 +		return \OCP\DB::insertid($this->tableName);
 +	}
 +	
 +	/**
 +	 * Get single record by primary key
 +	 * @param type $value primary key value
 +	 * @return \OCA\Documents\Db
 +	 */
 +	public function load($value){
 +		if (!is_array($value)){
 +			$value = array($value);
 +		}
 +		
 +		$result = $this->execute($this->loadStatement, $value);
 +		$data = $result->fetchRow();
 +		if (!is_array($data)){
 +			$data = array();
 +		}
 +		$this->data = $data;
 +		return $this;
 +	}
 +	
 +	/**
 +	 * Get single record matching condition
 +	 * @param string $field for WHERE condition
 +	 * @param mixed $value matching value(s)
 +	 * @return \OCA\Documents\Db
 +	 * @throws Exception
 +	 */
 +	public function loadBy($field, $value){
 +		if (!is_array($value)){
 +			$value = array($value);
 +		}
 +		$result = $this->execute('SELECT * FROM ' . $this->tableName . ' WHERE `'. $field .'` =?', $value);
 +		$data = $result->fetchAll();
 +		if (!is_array($data) || !count($data)){
 +			$this->data = array();
 +		} elseif (count($data)!=1) {
 +			throw new Exception('Duplicate ' . $value . ' for the filed ' . $field);
 +		} else {
 +			$this->data = $data[0];
 +		}
 +		
 +		return $this;
 +	}
 +
 +	/**
 +	 * Delete records matching the condition
 +	 * @param string $field for WHERE condition
 +	 * @param mixed $value matching value(s)
 +	 */
 +	public function deleteBy($field, $value){
 +		if (!is_array($value)){
 +			$value = array($value);
 +		}
 +		$count = count($value);
 +		if ($count===0){
 +			return 0;
 +		} elseif ($count===1){
 +			$result = $this->execute('DELETE FROM ' . $this->tableName . ' WHERE `'. $field .'` =?', $value);
 +		} else {
 +			$stmt = $this->buildInQuery($field, $value);
 +			$result = $this->execute('DELETE FROM ' . $this->tableName . ' WHERE ' . $stmt, $value);
 +		}
 +	}
 +	
 +	/**
 +	 * Get all records from the table
 +	 * @return array
 +	 */
 +	public function getCollection(){
 +		$result = $this->execute('SELECT * FROM ' . $this->tableName);
 +		$data = $result->fetchAll();
 +		if (!is_array($data)){
 +			$data = array();
 +		}
 +		return $data;
 +	}
 +	
 +	/**
 +	 * Get array of matching records
 +	 * @param string $field for WHERE condition
 +	 * @param mixed $value matching value(s)
 +	 * @return array
 +	 */
 +	public function getCollectionBy($field, $value){
 +		if (!is_array($value)){
 +			$value = array($value);
 +		}
 +		$count = count($value);
 +		if ($count===0){
 +			return array();
 +		} elseif ($count===1){
 +			$result = $this->execute('SELECT * FROM ' . $this->tableName . ' WHERE `'. $field .'` =?', $value);
 +		} else {
 +			$stmt = $this->buildInQuery($field, $value);
 +			$result = $this->execute('SELECT * FROM ' . $this->tableName . ' WHERE '. $stmt , $value);
 +		}
 +		
 +		$data = $result->fetchAll();
 +		if (!is_array($data)){
 +			$data = array();
 +		}
 +		return $data;
 +	}
 +	
 +	/**
 +	 * Get object data
 +	 * @return Array
 +	 */
 +	public function getData(){
 +		return $this->data;
 +	}
 +	
 +	/**
 +	 * Set object data
 +	 * @param array $data
 +	 */
 +	public function setData($data){
 +		$this->data = $data;
 +	}
 +	
 +	/**
 +	 * Check if there are any data in current object
 +	 * @return bool 
 +	 */
 +	public function hasData(){
 +		return count($this->data)>0;
 +	}
 +	
 +	/**
 +	 * Build placeholders for the query with variable input data 
 +	 * @param string $field field name
 +	 * @param Array $array data
 +	 * @return String `field` IN (?, ?...) placeholders matching the number of elements in array
 +	 */
 +	protected function buildInQuery($field, $array){
 +		$count = count($array);
 +		$placeholders = array_fill(0, $count, '?');
 +		$stmt = implode(', ', $placeholders);
 +		return '`' . $field . '` IN ('  . $stmt . ')';
 +	}
 +	
 +	/**
 +	 * Execute a query on database
 +	 * @param string $statement query to be executed
 +	 * @param mixed $args value(s) for the query. 
 +	 * If omited the query will be run on the current object $data
 +	 * @return mixed (array/false)
 +	 */
 +	protected function execute($statement, $args = null){
 +		$query = \OCP\DB::prepare($statement);
 +		
 +		if (!is_null($args)){
 +			$result = $query->execute($args);
 +		} elseif (count($this->data)){
 +			$result = $query->execute($this->data);
 +		} else {
 +			$result = $query->execute();
 +		}
 +		
 +		return $result;
 +	}
++	
++	public function __call($name, $arguments){
++		if (substr($name, 0, 3) === 'get'){
++			$requestedProperty = substr($name, 3);
++			$property = strtolower(preg_replace('/(.)([A-Z])/', "$1_$2", $requestedProperty));
++			if (isset($this->data[$property])){
++				return $this->data[$property];
++			}
++		}
++		return null;
++	}
 +}
diff --cc apps/documents/lib/db/member.php
index c98c968,0000000..73b13c2
mode 100644,000000..100644
--- a/apps/documents/lib/db/member.php
+++ b/apps/documents/lib/db/member.php
@@@ -1,118 -1,0 +1,123 @@@
 +<?php
 +
 +/**
 + * ownCloud - Documents App
 + *
 + * @author Victor Dubiniuk
 + * @copyright 2013 Victor Dubiniuk victor.dubiniuk at gmail.com
 + *
 + * This file is licensed under the Affero General Public License version 3 or
 + * later.
 + */
 +
 +namespace OCA\Documents;
 +
 +class Db_Member extends Db{
 +
 +	const DB_TABLE = '`*PREFIX*documents_member`';
- 	
- 	const ACTIVITY_THRESHOLD = 60; // 1 Minute
++
++	const ACTIVITY_THRESHOLD = 90; // 1.5 Minutes
 +	
 +	const MEMBER_STATUS_ACTIVE = 1;
 +	const MEMBER_STATUS_INACTIVE = 2;
 +	
 +	protected $tableName  = '`*PREFIX*documents_member`';
 +
- 	protected $insertStatement  = 'INSERT INTO `*PREFIX*documents_member` (`es_id`, `uid`, `color`, `last_activity`)
- 			VALUES (?, ?, ?, ?)';
++	protected $insertStatement  = 'INSERT INTO `*PREFIX*documents_member` (`es_id`, `uid`, `color`, `last_activity`, `is_guest`, `token`)
++			VALUES (?, ?, ?, ?, ?, ?)';
 +	
 +	protected $loadStatement = 'SELECT * FROM `*PREFIX*documents_member` WHERE `member_id`= ?';
 +
++	public static function getGuestPostfix(){
++		return '(' . Config::getL10n()->t('guest') . ')';
++	}
++
++
 +	public function updateActivity($memberId){
 +		return $this->execute(
 +				'UPDATE ' . $this->tableName . ' SET `last_activity`=?, `status`=? WHERE `member_id`=?',
 +				array(
 +					time(),
 +					self::MEMBER_STATUS_ACTIVE,
 +					$memberId
 +				)
 +		);
 +	}
 +	
 +	
 +	public function getActiveCollection($esId){
 +		$result = $this->execute('
 +			SELECT `es_id`, `member_id`
 +			FROM ' . self::DB_TABLE . '
 +			WHERE `es_id`= ?
 +				AND `status`=?
 +			',
 +			array(
 +				$esId,
 +				self::MEMBER_STATUS_ACTIVE
 +			)
 +		);
 +		$members = $result->fetchAll();
 +		if (!is_array($members)){
 +			$members = array();
 +		}
 +		return $members;
 +		
 +	}
 +	
 +	/**
 +	 * Mark members as inactive
 +	 * @param string $esId - session Id
 +	 * @return array - list of memberId that were marked as inactive
 +	 */
 +	public function updateByTimeout($esId){
 +		$time = $this->getInactivityPeriod();
 +
 +		$result = $this->execute('
 +			SELECT `member_id`
 +			FROM ' . self::DB_TABLE . '
 +			WHERE `es_id`= ?
 +				AND `last_activity`<?
 +				AND `status`=?
 +			',
 +			array(
 +				$esId,
 +				$time,
 +				self::MEMBER_STATUS_ACTIVE
 +			)
 +		);
 +		
 +		$deactivated = $result->fetchAll();
 +		if (is_array($deactivated) && count($deactivated)){
 +			$deactivated = array_map(
 +				function($x){
 +					return ($x['member_id']);
 +				}, $deactivated
 +			);
 +			$this->deactivate($deactivated);
 +		} else {
 +			$deactivated = array();
 +		}
 +
 +		return $deactivated;
 +	}
 +
 +	/**
 +	 * Update members to inactive state
 +	 * @param array $memberIds
 +	 */
 +	public function deactivate($memberIds){
 +		$stmt = $this->buildInQuery('member_id', $memberIds);
 +		array_unshift($memberIds, self::MEMBER_STATUS_INACTIVE);
 +		$this->execute('
 +			UPDATE ' . $this->tableName . '
 +			SET `status`=?
 +			WHERE ' . $stmt,
 +			$memberIds
 +		);
 +	}
 +	
 +	protected function getInactivityPeriod(){
 +		return time() - self::ACTIVITY_THRESHOLD;
 +	}
 +}
diff --cc apps/documents/lib/db/op.php
index 9e8c94d,0000000..31ca7d3
mode 100644,000000..100644
--- a/apps/documents/lib/db/op.php
+++ b/apps/documents/lib/db/op.php
@@@ -1,130 -1,0 +1,159 @@@
 +<?php
 +/**
 + * ownCloud - Documents App
 + *
 + * @author Victor Dubiniuk
 + * @copyright 2013 Victor Dubiniuk victor.dubiniuk at gmail.com
 + *
 + * This file is licensed under the Affero General Public License version 3 or
 + * later.
 + */
 +
 +namespace OCA\Documents;
 +
 +class Db_Op extends Db {
 +
 +	const DB_TABLE = '`*PREFIX*documents_op`';
 +	
 +	protected $tableName = '`*PREFIX*documents_op`';
 +	
 +	protected $insertStatement = 'INSERT INTO `*PREFIX*documents_op` (`es_id`, `member`, `opspec`) VALUES (?, ?, ?)';
 +
 +	public static function addOpsArray($esId, $memberId, $ops){
 +		$lastSeq = "";
 +		$opObj = new Db_Op();
 +		foreach ($ops as $op) {
 +			$opObj->setData(array(
 +				$esId, 
 +				$memberId, 
 +				json_encode($op)
 +			));
 +			$opObj->insert();
 +			$lastSeq = $opObj->getLastInsertId();
 +		}
 +		return $lastSeq;
 +	}
 +	
 +	/**
 +	 * @returns "" when there are no Ops, or the seq of the last Op
 +	 */
 +	public function getHeadSeq($esId){
 +		$query = \OCP\DB::prepare('
 +			SELECT `seq`
 +			FROM ' . $this->tableName . '
 +			WHERE `es_id`=?
 +			ORDER BY `seq` DESC
 +			', 1);
 +		$result = $query->execute(array(
 +				$esId
 +			))
 +			->fetchOne()	
 +		;
 +		return !$result ? "" : $result;
 +	}
 +	
 +	public function getOpsAfterJson($esId, $seq){
 +		$ops = $this->getOpsAfter($esId, $seq);
 +		if (!is_array($ops)){
 +			$ops = array();
 +		}
 +		$ops =  array_map(
 +				function($x){
 +					$decoded = json_decode($x['opspec'], true);
 +					$decoded['memberid'] = strval($decoded['memberid']);
 +					return $decoded;
 +				}, 
 +				$ops
 +		);
 +		return $ops;
 +	}
 +	
 +	public function getOpsAfter($esId, $seq){
 +		if ($seq == ""){
 +			$seq = -1;
 +		}
 +		$query = \OCP\DB::prepare('
 +			SELECT `opspec`
 +			FROM ' . self::DB_TABLE . '
 +			WHERE `es_id`=?
 +				AND `seq`>?
 +			ORDER BY `seq` ASC
 +			');
 +		$result = $query->execute(array($esId, $seq));
 +		return $result->fetchAll();
 +	}
 +	
 +	public function addMember($esId, $memberId, $fullName, $color, $imageUrl){
 +		$op = '{"optype":"AddMember","memberid":"'. $memberId .'","timestamp":"'. time() .'", "setProperties":{"fullName":"'. $fullName .'","color":"'. $color .'","imageUrl":"'. $imageUrl .'"}}';
- 		$this->insertOp($esId, $op);
++		$this->insertOp($esId, $memberId, $op);
 +	}
 +	
 +	public function removeCursor($esId, $memberId){
- 		if ($this->hasOp($esId, $memberId, 'AddCursor')){
++		if ($this->hasOp($esId, $memberId, 'AddCursor') && !$this->hasLastOp($esId, $memberId, 'RemoveCursor')){
 +			$op = '{"optype":"RemoveCursor","memberid":"'. $memberId .'","reason":"server-idle","timestamp":'. time() .'}';
- 			$this->insertOp($esId, $op);
++			$this->insertOp($esId, $memberId, $op);
 +		}
 +	}
 +	
 +	public function removeMember($esId, $memberId){
- 		if ($this->hasOp($esId, $memberId, 'AddMember')){
++		if ($this->hasOp($esId, $memberId, 'AddMember') && !$this->hasLastOp($esId, $memberId, 'RemoveMember')){
 +			$op ='{"optype":"RemoveMember","memberid":"'. $memberId .'","timestamp":'. time() .'}';
- 			$this->insertOp($esId, $op);
++			$this->insertOp($esId, $memberId, $op);
 +		}
 +	}
 +	
 +	public function updateMember($esId, $memberId, $fullName, $color, $imageUrl){
 +		//TODO: Follow the spec https://github.com/kogmbh/WebODF/blob/master/webodf/lib/ops/OpUpdateMember.js#L95
 +		$op = '{"optype":"UpdateMember","memberid":"'. $memberId .'","fullName":"'. $fullName .'","color":"'. $color .'","imageUrl":"'. $imageUrl .'","timestamp":'. time() .'}'
 +		;
- 		$this->insertOp($esId, $op);
++		$this->insertOp($esId, $memberId, $op);
 +	}
 +	
- 	protected function insertOp($esId, $op){
++	public function changeNick($esId, $memberId, $fullName){
++		$op = '{"optype":"UpdateMember","memberid":"'. $memberId .'", "setProperties":{"fullName":"'. $fullName .'"},"timestamp":'. time() .'}'
++		;
++		$this->insertOp($esId, $memberId, $op);
++	}
++	
++	protected function insertOp($esId, $memberId, $op){
 +		$op = new Db_Op(array(
 +			$esId, 
- 			0,
++			$memberId,
 +			$op
 +		));
 +		$op->insert();
 +	}
 +	
++	protected function hasLastOp($esId, $memberId, $opType){
++		$query = \OCP\DB::prepare('
++			SELECT `opspec`
++			FROM ' . self::DB_TABLE . '
++			WHERE `es_id`=?
++				AND `member`=?
++				
++			ORDER BY `seq` DESC
++			', 
++			2,0
++		);
++		
++		$result = $query->execute(array($esId, $memberId));
++		$ops = $result->fetchAll();
++		foreach ($ops as $op){
++			$decoded = json_decode($op['opspec'], true);
++			if ($decoded['optype']==$opType){
++				return true;
++			}
++		}
++		return false;
++	}
++	
 +	protected function hasOp($esId, $memberId, $opType){
 +		$ops = $this->execute(
 +			'SELECT * FROM ' . $this->tableName . ' WHERE `es_id`=? AND `opspec` LIKE \'%"' . $opType . '","memberid":"' . $memberId .'"%\'',
 +			array($esId)
 +		);
 +		$result = $ops->fetchAll();
 +		return is_array($result) && count($result)>0;
 +	}
 +	
 +}
diff --cc apps/documents/lib/db/session.php
index f892859,0000000..0c4b40d
mode 100644,000000..100644
--- a/apps/documents/lib/db/session.php
+++ b/apps/documents/lib/db/session.php
@@@ -1,210 -1,0 +1,185 @@@
 +<?php
 +
 +/**
 + * ownCloud - Documents App
 + *
 + * @author Victor Dubiniuk
 + * @copyright 2013 Victor Dubiniuk victor.dubiniuk at gmail.com
 + *
 + * This file is licensed under the Affero General Public License version 3 or
 + * later.
 + */
 +
 +namespace OCA\Documents;
 +
 +/**
 + *  Session management 
 + */
 +class Db_Session extends \OCA\Documents\Db {
 +
 +	/**
 +	 * DB table
 +	 */
 +	const DB_TABLE = '`*PREFIX*documents_session`';
 +	protected $tableName  = '`*PREFIX*documents_session`';
 +
 +	protected $insertStatement  = 'INSERT INTO `*PREFIX*documents_session` (`es_id`, `genesis_url`, `genesis_hash`, `owner`, `file_id`)
 +			VALUES (?, ?, ?, ?, ?)';
 +	
 +	protected $loadStatement = 'SELECT * FROM `*PREFIX*documents_session` WHERE `es_id`= ?';
 +
 +	/**
 +	 * Start a editing session or return an existing one
 +	 * @param string $uid of the user starting a session
 +	 * @param \OCA\Documents\File $file - file object
 +	 * @return array
 +	 * @throws \Exception
 +	 */
- 	public static function start($uid, File $file){
- 		list($ownerView, $path) = $file->getOwnerViewAndPath();
- 		
++	public static function start($uid, $file){
 +		// Create a directory to store genesis
++		$genesis = new Genesis($file);
 +		
- 		$genesis = new Genesis($ownerView, $path, $file->getOwner());
- 		
++		list($ownerView, $path) = $file->getOwnerViewAndPath();
 +		$oldSession = new Db_Session();
 +		$oldSession->loadBy('file_id', $file->getFileId());
 +		
 +		//If there is no existing session we need to start a new one
 +		if (!$oldSession->hasData()){
 +			$newSession = new Db_Session(array(
 +				$genesis->getPath(),
 +				$genesis->getHash(),
 +				$file->getOwner(),
 +				$file->getFileId()
 +			));
 +			
 +			if (!$newSession->insert()){
 +				throw new \Exception('Failed to add session into database');
 +			}
 +		}
 +		
- 		$session = $oldSession
++		$sessionData = $oldSession
 +					->loadBy('file_id', $file->getFileId())
 +					->getData()
 +		;
- 		$session['title'] = basename($path);
 +		
 +		$memberColor = Helper::getMemberColor($uid);
- 		
 +		$member = new Db_Member(array(
- 			$session['es_id'], 
++			$sessionData['es_id'], 
 +			$uid,
 +			$memberColor,
- 			time()
++			time(),
++			intval($file->isPublicShare()),
++			$file->getToken()
 +		));
 +		
 +		if ($member->insert()){
 +			// Do we have OC_Avatar in out disposal?
 +			if (!class_exists('\OC_Avatar') || \OC_Config::getValue('enable_avatars', true) !== true){
- 				//$x['avatar_url'] = \OCP\Util::linkToRoute('documents_user_avatar');
 +				$imageUrl = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAAAAACH5BAAAAAAALAAAAAABAAEAAAICTAEAOw==';
 +			} else {
- 				// https://github.com/owncloud/documents/issues/51
- 				// Temporary stub
 +				$imageUrl = $uid;
- 							
- 			/*
- 				$avatar = new \OC_Avatar($uid);
- 				$image = $avatar->get(64);
- 					// User has an avatar 
- 				if ($image instanceof \OC_Image) {
- 					$imageUrl = \OC_Helper::linkToRoute(
- 							'core_avatar_get',
- 							array( 'user' => $uid, 'size' => 64)
- 					) . '?requesttoken=' . \OC::$session->get('requesttoken');
- 				} else {
- 					//shortcircuit if it's not an image
- 					$imageUrl = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAAAAACH5BAAAAAAALAAAAAABAAEAAAICTAEAOw==';
- 				}
- 							 
- 			 */
 +			}
++
++			$displayName = $file->isPublicShare() ? $uid . ' ' . Db_Member::getGuestPostfix() : \OCP\User::getDisplayName($uid);
 +			
- 			
- 			$session['member_id'] = (string) $member->getLastInsertId();
++			$sessionData['member_id'] = (string) $member->getLastInsertId();
 +			$op = new Db_Op();
 +			$op->addMember(
- 					$session['es_id'],
- 					$session['member_id'],
- 					\OCP\User::getDisplayName($uid),
++					$sessionData['es_id'],
++					$sessionData['member_id'],
++					$displayName,
 +					$memberColor,
 +					$imageUrl
 +			);
 +		} else {
 +			throw new \Exception('Failed to add member into database');
 +		}
 +		
- 		$session['permissions'] = $ownerView->getFilePermissions($path);
++		$sessionData['title'] = basename($path);
++		$sessionData['permissions'] = $ownerView->getFilePermissions($path);
 +		
- 		return $session;
++		return $sessionData;
 +	}
 +	
 +	public static function cleanUp($esId){
 +		$session = new Db_Session();
 +		$session->deleteBy('es_id', $esId);
 +		
 +		$member = new Db_Member();
 +		$member->deleteBy('es_id', $esId);
 +		
 +		$op= new Db_Op();
 +		$op->deleteBy('es_id', $esId);
 +	}
 +	
 +	public function insert(){
 +		$esId = $this->getUniqueSessionId();
 +		array_unshift($this->data, $esId);
 +		return parent::insert($this->data);
 +	}
 +	
 +	public function updateGenesisHash($esId, $genesisHash){
 +		return $this->execute(
 +			'UPDATE `*PREFIX*documents_session` SET `genesis_hash`=? WHERE `es_id`=?',
 +			array(
 +				$genesisHash, $esId
 +			)
 +		);
 +	}
 +
 +	public function getInfo($esId){
 +		$result = $this->execute('
 +			SELECT `s`.*, COUNT(`m`.`member_id`) AS `users`
 +			FROM ' . $this->tableName . ' AS `s`
 +			LEFT JOIN `*PREFIX*documents_member` AS `m` ON `s`.`es_id`=`m`.`es_id`
 +				AND `m`.`status`=' . Db_Member::MEMBER_STATUS_ACTIVE . '
 +				AND `m`.`uid` != ?
 +			WHERE `s`.`es_id` = ?
 +			GROUP BY `m`.`es_id`
 +			',
 +			array(
 +					\OCP\User::getUser(),
 +					$esId
 +			)
 +		);
 +
 +		$info = $result->fetchRow();
 +		if (!is_array($info)){
 +			$info = array();
 +		}
 +		return $info;
 +	}
 +
 +	public function getInfoByFileId($fileIds){
 +		if (!is_array($fileIds)){
 +			return array();
 +		}
 +
 +		$stmt = $this->buildInQuery('file_id', $fileIds);
 +
 +		$result = $this->execute('
 +			SELECT `s`.*, COUNT(`m`.`member_id`) AS `users`
 +			FROM ' . $this->tableName . ' AS `s`
 +			LEFT JOIN `*PREFIX*documents_member` AS `m` ON `s`.`es_id`=`m`.`es_id`
 +				AND `m`.`status`=' . Db_Member::MEMBER_STATUS_ACTIVE . '
 +			WHERE `s`.`file_id` ' . $stmt .'
 +			GROUP BY `m`.`es_id`',
 +			$fileIds
 +		);
 +
 +		$info = $result->fetchAll();
 +		if (!is_array($info)){
 +			$info = array();
 +		}
 +		return $info;
 +	}
 +
 +	protected function getUniqueSessionId(){
 +		$testSession = new Db_Session();
 +		do{
- 			// this prevents branching for stable5 for now:
- 			// OC_Util::generate_random_bytes was camelCased
- 			if (method_exists('\OC_Util', 'generate_random_bytes')){
- 				$id = \OC_Util::generate_random_bytes(30);
- 			} else {
- 				$id = \OC_Util::generateRandomBytes(30);
- 			}
- 		}while ($testSession->load($id)->hasData());
++			$id = \OC_Util::generateRandomBytes(30);
++		} while ($testSession->load($id)->hasData());
 +
 +		return $id;
 +	}
 +}
diff --cc apps/documents/lib/file.php
index 4520dcd,0000000..4ccf43f
mode 100644,000000..100644
--- a/apps/documents/lib/file.php
+++ b/apps/documents/lib/file.php
@@@ -1,274 -1,0 +1,229 @@@
 +<?php
 +/**
 + * ownCloud - Documents App
 + *
 + * @author Victor Dubiniuk
 + * @copyright 2013 Victor Dubiniuk victor.dubiniuk at gmail.com
 + *
 + * This library is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
 + * License as published by the Free Software Foundation; either 
 + * version 3 of the License, or any later version.
 + * 
 + * This library is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
 + *  
 + * You should have received a copy of the GNU Lesser General Public 
 + * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
 + * 
 + */
 +
 +
 +namespace OCA\Documents;
 +
 +class File {
 +	protected $fileId;
 +	protected $owner;
 +	protected $path;
 +	protected $sharing;
++	protected $token ='';
 +	protected $passwordProtected = false;
 +
 +
 +	public function __construct($fileId, $shareOps = null){
 +		if (!$fileId){
 +			throw new \Exception('No valid file has been passed');
 +		}
 +
 +		$this->fileId = $fileId;
 +		
 +		//if you know how to get sharing info by fileId via API, 
 +		//please send me a link to video tutorial :/
 +		if (!is_null($shareOps)){
 +			$this->sharing = $shareOps;
 +		} else {
 +			$this->sharing = $this->getSharingOps();
 +		}
 +	}
 +	
++	
 +	public static function getByShareToken($token){
- 		$linkItem = \OCP\Share::getShareByToken($token);
++		$linkItem = \OCP\Share::getShareByToken($token, false);
 +		if (is_array($linkItem) && isset($linkItem['uid_owner'])) {
 +			// seems to be a valid share
 +			$rootLinkItem = \OCP\Share::resolveReShare($linkItem);
- 			$fileOwner = $rootLinkItem['uid_owner'];
 +		} else {
 +			throw new \Exception('This file was probably unshared');
 +		}
 +		
- 		if (!isset($rootLinkItem['path']) && isset($rootLinkItem['file_target'])){
- 			$rootLinkItem['path'] = $rootLinkItem['file_target'];
- 		}
 +		$file = new File($rootLinkItem['file_source'], array($rootLinkItem));
- 		
- 
- 		if (isset($rootLinkItem['uid_owner'])){
- 			\OC_Util::tearDownFS();
- 			\OC_Util::setupFS($rootLinkItem['uid_owner']);
- 			$file->setOwner($rootLinkItem['uid_owner']);
- 			$file->setPath(\OC\Files\Filesystem::getPath($linkItem['file_source']));
- 		}
++		$file->setToken($token);
 +		
 +		if (isset($linkItem['share_with']) && !empty($linkItem['share_with'])){
 +			$file->setPasswordProtected(true);
 +		}
 +		
 +		return $file;
 +	}
 +
++	public function getToken(){
++		return $this->token;
++	}
++	
 +	public function getFileId(){
 +		return $this->fileId;
 +	}
 +	
 +	public function setOwner($owner){
 +		$this->owner = $owner;
 +	}
 +	
 +	public function setPath($path){
 +		$this->path = $path;
 +	}
 +	
++	public function setToken($token){
++		$this->token = $token;
++	}
++	
 +	public function isPublicShare(){
- 		foreach ($this->sharing as $share){
- 			if (
- 					$share['share_type'] == \OCP\Share::SHARE_TYPE_LINK 
- 					|| $share['share_type'] == \OCP\Share::SHARE_TYPE_EMAIL
- 				){
- 				return true;
- 			}
- 		}
- 		return false;
++		return  !empty($this->token);
 +	}
 +	
 +	public function isPasswordProtected(){
 +		return $this->passwordProtected;
 +	}
 +	
 +	public function checkPassword($password){
 +		$shareId  = $this->getShareId();
 +		if (!$this->isPasswordProtected()
 +			|| (\OC::$session->exists('public_link_authenticated')
 +				&& \OC::$session->get('public_link_authenticated') === $shareId)	
 +			){
 +				return true;
 +		}
 +		
 +		// Check Password
 +		$forcePortable = (CRYPT_BLOWFISH != 1);
 +		$hasher = new \PasswordHash(8, $forcePortable);
 +		if ($hasher->CheckPassword($password.\OC_Config::getValue('passwordsalt', ''),
 +									 $this->getPassword())) {
 +			// Save item id in session for future request
 +			\OC::$session->set('public_link_authenticated', $shareId);
 +			return true;
 +		}
 +		return false;
 +	}
 +	
 +	public function setPasswordProtected($value){
 +		$this->passwordProtected = $value;
 +	}
 +	
 +	public function getPermissions(){
 +		if (count($this->sharing)){
 +			if ($this->isPublicShare()){
 +				$permissions = \OCP\PERMISSION_READ | \OCP\PERMISSION_UPDATE;
 +			} else {
 +				$permissions = $this->sharing[0]['permissions'];
 +			}
 +		} else {
 +			list($owner, $path) = $this->getOwnerViewAndPath();
 +			$permissions = 0;
 +			if (\OC\Files\Filesystem::isReadable($path)){
 +				$permissions |= \OCP\PERMISSION_READ;
 +			}
 +			if (\OC\Files\Filesystem::isUpdatable($path)){
 +				$permissions |= \OCP\PERMISSION_UPDATE;
 +			}
 +				
 +		}
 +		return $permissions;
 +	}
 +
- 	/**
- 	 * Rename this file to the given name
- 	 * @param string $newName name to give (without path)
- 	 * @return boolean true if rename succeeded, false otherwise
- 	 */
- 	public function renameTo($newName) {
- 		list($owner, $path) = $this->getOwnerViewAndPath();
- 		$newPath = dirname($path) . '/' . $newName;
- 		return \OC\Files\Filesystem::rename($path, $newPath);
- 	}
 +
 +	/**
 +	 * 
 +	 * @return string owner of the current file item
 +	 * @throws \Exception
 +	 */
 +	public function getOwnerViewAndPath(){
- 		if (!$this->owner || !$this->path){
- 			if ($this->isPublicShare()){
- 				list($owner, $path) = $this->getSharedFileOwnerAndPath();
++		if ($this->isPublicShare()){
++			$rootLinkItem = \OCP\Share::resolveReShare($this->sharing[0]);
++			if (isset($rootLinkItem['uid_owner'])){
++				$owner = $rootLinkItem['uid_owner'];
 +			} else {
- 				$owner = \OCP\User::getUser();
- 				$path = Storage::resolvePath($this->fileId);
- 				if (!$path){
- 					throw new \Exception($this->fileId . ' can not be resolved');
- 				}
++				throw new \Exception($this->fileId . ' is a broken share');
 +			}
++			$view = new View('/' . $owner . '/files');
++			$path = $rootLinkItem['file_target'];
++		} else {
++			$owner = \OCP\User::getUser();
++			$view = new View('/' . $this->owner);
++			$path = $view->getPath($this->fileId);
++		}
 +			
- 			$this->path = $path;
- 			$this->owner = $owner;
++		if (!$path){
++			throw new \Exception($this->fileId . ' can not be resolved');
 +		}
++		$this->path = $path;
++		$this->owner = $owner;
 +		
- 		$view = new View('/' . $this->owner . '/files');
 +		if (!$view->file_exists($this->path)){
 +			throw new \Exception($this->path . ' doesn\'t exist');
 +		}
 +
 +		return array($view, $this->path);
 +	}
++	
 +
 +	public function getOwner(){
 +		if (!$this->owner){
 +			$this->getOwnerViewAndPath();
 +		}
 +		return $this->owner;
 +	}
 +	
- 	/**
- 	 * public links only
- 	 * @return array
- 	 */
- 	protected function getSharedFileOwnerAndPath(){
- 		foreach ($this->sharing as $share){
- 			$rootLinkItem = \OCP\Share::resolveReShare($share);
- 			if (isset($rootLinkItem['uid_owner'])){
- 				$owner = $rootLinkItem['uid_owner'];
- 			} else {
- 				$owner = false;
- 			}
- 			\OC_Util::tearDownFS();
- 			\OC_Util::setupFS($owner);
- 			return array(
- 					$owner,
- 					\OC\Files\Filesystem::getPath($rootLinkItem['file_source'])
-                 );
- 		}
- 
- 		return $result;
- 	}
- 
- 	protected function getLocalFileOwnerAndPath(){
- 		$fileInfo = \OC\Files\Cache\Cache::getById($this->fileId);
- 		$owner = \OCP\User::getUser();
- 		if (!$owner){
- 			throw new Exception('Guest users can\'t access local files. This one was probably unshared recently.');
- 		}
- 
- 		return array ($owner, @$fileInfo[1]);
- 	}
 +	
 +	protected function getPassword(){
 +		return $this->sharing[0]['share_with'];
 +	}
 +	
 +	protected function getShareId(){
 +		return $this->sharing[0]['id'];
 +	}
 +
 +	protected function getSharingOps(){
 +		
 +		$where  = 'AND `file_source`=?';
 +		$values = array($this->fileId);
 +		
 +		if (\OCP\User::isLoggedIn()){
 +			$where .= ' AND ((`share_type`=' . \OCP\Share::SHARE_TYPE_USER . ' AND `share_with`=?) OR  `share_type`=' . \OCP\Share::SHARE_TYPE_LINK . ')';
 +			$values[] = \OCP\User::getUser();
 +		} else {
 +			$where .= ' AND (`share_type`=' . \OCP\Share::SHARE_TYPE_LINK . ')';
 +		}
 +		
 +		$query = \OC_DB::prepare('SELECT `*PREFIX*share`.`id`, `item_type`, `*PREFIX*share`.`parent`, `uid_owner`, '
 +							.'`share_type`, `share_with`, `file_source`, `path`, `file_target`, '
 +							.'`permissions`, `expiration`, `storage`, `*PREFIX*filecache`.`parent` as `file_parent`, '
 +							.'`name`, `mtime`, `mimetype`, `mimepart`, `size`, `encrypted`, `etag`' 
 +							.'FROM `*PREFIX*share` INNER JOIN `*PREFIX*filecache` ON `file_source` = `*PREFIX*filecache`.`fileid` WHERE `item_type` = \'file\' ' . $where);
 +		$result = $query->execute($values);
 +		$shares = $result->fetchAll();
 +		
 +		$origins = array();
 +		if (is_array($shares)){
 +			foreach ($shares as $share){
 +				$origin = \OCP\Share::resolveReShare($share);
 +				if (!isset($origin['path']) && isset($origin['file_target'])){
 +					$origin['path'] = 'files/' . $origin['file_target'];
 +				}
 +				$origins[] = $origin;
 +			}
 +		}
 +		return $origins;
 +	}
 +}
diff --cc apps/documents/lib/filter/office.php
index 0000000,0000000..6b375d7
new file mode 100644
--- /dev/null
+++ b/apps/documents/lib/filter/office.php
@@@ -1,0 -1,0 +1,85 @@@
++<?php
++
++/**
++ * ownCloud - Documents App
++ *
++ * @author Victor Dubiniuk
++ * @copyright 2014 Victor Dubiniuk victor.dubiniuk at gmail.com
++ *
++ * This file is licensed under the Affero General Public License version 3 or
++ * later.
++ */
++
++namespace OCA\Documents;
++
++class Filter_Office {
++	const NATIVE_MIMETYPE = 'application/vnd.oasis.opendocument.text';
++	
++	private $readSpec;
++	private $writeSpec;
++	
++	/* sample mimespec 	
++			array (
++				'read' => 
++					array (
++						'target' => 'application/vnd.oasis.opendocument.text',
++						'format' => 'odt:writer8',
++						'extension' => 'odt'
++					),
++				'write' => 
++					array (
++						'target' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
++						'format' => 'docx',
++						'extension' => 'docx'
++					)
++			);
++
++			array(
++				'read' => 
++					array (
++						'target' => 'application/vnd.oasis.opendocument.text',
++						'format' => 'odt:writer8',
++						'extension' => 'odt'
++					),
++				'write' => 
++					array (
++						'target' => 'application/msword',
++						'format' => 'doc',
++						'extension' => 'doc'
++					)
++			);
++
++		 */
++	
++	public function __construct($mimeSpec){
++		$this->readSpec = $mimeSpec['read'];
++		$this->writeSpec = $mimeSpec['write'];
++		
++		Filter::add($mimeSpec['write']['target'], $this);
++	}
++
++	public function read($data){
++		return array(
++			'mimetype' => $this->readSpec['target'],
++			'content' => 
++				Converter::convert(
++						$data['content'], 
++						$this->readSpec['format'],
++						$this->readSpec['extension']
++				)
++		);
++	}
++	
++	public function write($data){
++		return array(
++			'mimetype' => $this->writeSpec['target'],
++			'content' => 
++				Converter::convert(
++						$data['content'], 
++						$this->writeSpec['format'],
++						$this->writeSpec['extension']
++				)
++		);
++	}
++
++}
diff --cc apps/documents/lib/genesis.php
index c038d69,0000000..c00c197
mode 100644,000000..100644
--- a/apps/documents/lib/genesis.php
+++ b/apps/documents/lib/genesis.php
@@@ -1,112 -1,0 +1,113 @@@
 +<?php
 +/**
 + * ownCloud - Documents App
 + *
 + * @author Victor Dubiniuk
 + * @copyright 2013 Victor Dubiniuk victor.dubiniuk at gmail.com
 + *
 + * This library is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
 + * License as published by the Free Software Foundation; either 
 + * version 3 of the License, or any later version.
 + * 
 + * This library is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
 + *  
 + * You should have received a copy of the GNU Lesser General Public 
 + * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
 + * 
 + */
 +
 +namespace OCA\Documents;
 +
 +class Genesis {
 +	
 +	const DOCUMENTS_DIRNAME='/documents';
 +	
 +	protected $view;
 +	
 +	protected $path;
 +	
 +	protected $hash;
 +	
 +	
 +	/**
 +	 * Create new genesis document
- 	 * @param OCA\Documents\View $view Filesystem view with root '/user/files'
- 	 * @param string $path relative path
- 	 * @param string $owner file owner
++	 * @param OCA\Documents\File $file 
 +	 * */	
- 	public function __construct(\OCA\Documents\View $view, $path, $owner){
++	public function __construct(\OCA\Documents\File $file){
++		list($view, $path) = $file->getOwnerViewAndPath();
++		$owner = $file->getOwner();
++		
 +		$this->view = new View('/' . $owner);
 +		
 +		if (!$this->view->file_exists(self::DOCUMENTS_DIRNAME)){
 +			$this->view->mkdir(self::DOCUMENTS_DIRNAME );
 +		}
 +		
 +		$this->hash = $this->getDocumentHash($view, $path);
 +		$this->path = self::DOCUMENTS_DIRNAME . '/' . $this->hash . '.odt';
 +		if (!$this->view->file_exists($this->path)){
 +			//copy new genesis to /user/documents/{hash}.odt
 +			// get decrypted content
 +			$content = $view->file_get_contents($path);
 +			$mimetype = $view->getMimeType($path);
 +			
 +			$data = Filter::read($content, $mimetype);
 +			
 +			$proxyStatus = \OC_FileProxy::$enabled;
 +			\OC_FileProxy::$enabled = false;	
 +			
 +			$this->view->file_put_contents($this->path, $data['content']);
 +			\OC_FileProxy::$enabled = $proxyStatus;
 +		}
 +		
 +		try {
 +			$this->validate($this->view, $this->path);
 +		} catch (\Exception $e){
 +			throw new \Exception('Failed to copy genesis');
 +		}
 +	}
 +	
 +	public function getPath(){
 +		return $this->path;
 +	}
 +	
 +	public function getHash(){
 +		return $this->hash;
 +	}
 +	
 +	public static function getHashByPath($path){
 +		return preg_replace('|([a-zA-Z0-9])*\..*$|', '\1', $path);
 +	}
 +	
 +	protected function getDocumentHash($view, $path){
 +		$this->validate($view, $path);
 +		$proxyStatus = \OC_FileProxy::$enabled;
 +		\OC_FileProxy::$enabled = false;
 +		
 +		$hash = sha1($view->file_get_contents($path));
 +		
 +		\OC_FileProxy::$enabled = $proxyStatus;
 +		return $hash;
 +	}
 +	
 +	/**
 +	 * Check if genesis is valid
 +	 * @param OCA\Documents\View $view 
 +	 * @param string $path relative to the view
 +	 * @throws \Exception
 +	 */
 +	protected function validate($view, $path){
 +		if (!$view->file_exists($path)){
 +			throw new \Exception('Document not found ' . $path);
 +		}
 +		if (!$view->is_file($path)){
 +			throw new \Exception('Object ' . $path . ' is not a file.');
 +		}
 +		//TODO check if it is a valid odt
 +	}
 +
 +}
diff --cc apps/documents/lib/helper.php
index 2bd9cd6,0000000..7b0016f
mode 100644,000000..100644
--- a/apps/documents/lib/helper.php
+++ b/apps/documents/lib/helper.php
@@@ -1,144 -1,0 +1,151 @@@
 +<?php
 +
 +/**
 + * ownCloud - Documents App
 + *
 + * @author Victor Dubiniuk
 + * @copyright 2013 Victor Dubiniuk victor.dubiniuk at gmail.com
 + *
 + * This file is licensed under the Affero General Public License version 3 or
 + * later.
 + */
 +
 +namespace OCA\Documents;
 +
 +class Helper {
 +
 +	const APP_ID = 'documents';
 +
 +	public static function getNewFileName($view, $path, $prepend = ' '){
 +		$fileNum = 1;
 +
 +		while ($view->file_exists($path)){
 +			$fileNum += 1;
 +			$path = preg_replace('/(\.odt|' . $prepend . '\(\d+\)\.odt)$/', $prepend . '(' . $fileNum . ').odt', $path);
 +		};
 +
 +		return $path;
 +	}
++	
++	public static function getArrayValueByKey($array, $key, $default=''){
++		if (array_key_exists($key, $array)){
++			return $array[$key];
++		}
++		return $default;
++	}
 +
 +	public static function isVersionsEnabled(){
 +		return \OCP\App::isEnabled('files_versions');
 +	}
 +
 +	public static function getRandomColor(){
 +		$str = dechex(floor(rand(0, 16777215)));
 +		return '#' . str_pad($str, 6, "0", STR_PAD_LEFT);
 +	}
 +
 +	public static function getMemberColor($name){
 +		$hash = md5($name);
 +		$maxRange = hexdec('ffffffffffffffffffffffffffffffff');
 +		$hue = hexdec($hash) / $maxRange * 256;
 +		return '#' . self::convertHSLToRGB($hue, 90, 60);
 +	}
 +
 +	public static function debugLog($message){
 +		self::log($message, \OCP\Util::DEBUG);
 +	}
 +
 +	public static function warnLog($message){
 +		self::log($message, \OCP\Util::WARN);
 +	}
 +
 +	public static function errorLog($message){
 +		self::log($message, \OCP\Util::ERROR);
 +	}
 +
 +	public static function log($message, $level){
 +		\OCP\Util::writeLog(self::APP_ID, $message, $level);
 +	}
 +
 +	protected static function convertHSLToRGB($iH, $iS, $iV){
 +		if ($iH < 0){
 +			$iH = 0;   // Hue:
 +		}
 +		if ($iH > 360){
 +			$iH = 360; //   0-360
 +		}
 +		if ($iS < 0){
 +			$iS = 0;   // Saturation:
 +		}
 +		if ($iS > 100){
 +			$iS = 100; //   0-100
 +		}
 +		if ($iV < 0){
 +			$iV = 0;   // Lightness:
 +		}
 +		if ($iV > 100){
 +			$iV = 100; //   0-100
 +		}
 +
 +		$dS = $iS / 100.0; // Saturation: 0.0-1.0
 +		$dV = $iV / 100.0; // Lightness:  0.0-1.0
 +		$dC = $dV * $dS;   // Chroma:     0.0-1.0
 +		$dH = $iH / 60.0;  // H-Prime:    0.0-6.0
 +		$dT = $dH;	   // Temp variable
 +
 +		while ($dT >= 2.0)
 +			$dT -= 2.0; // php modulus does not work with float
 +		$dX = $dC * (1 - abs($dT - 1));	 // as used in the Wikipedia link
 +
 +		switch ($dH){
 +			case($dH >= 0.0 && $dH < 1.0):
 +				$dR = $dC;
 +				$dG = $dX;
 +				$dB = 0.0;
 +				break;
 +			case($dH >= 1.0 && $dH < 2.0):
 +				$dR = $dX;
 +				$dG = $dC;
 +				$dB = 0.0;
 +				break;
 +			case($dH >= 2.0 && $dH < 3.0):
 +				$dR = 0.0;
 +				$dG = $dC;
 +				$dB = $dX;
 +				break;
 +			case($dH >= 3.0 && $dH < 4.0):
 +				$dR = 0.0;
 +				$dG = $dX;
 +				$dB = $dC;
 +				break;
 +			case($dH >= 4.0 && $dH < 5.0):
 +				$dR = $dX;
 +				$dG = 0.0;
 +				$dB = $dC;
 +				break;
 +			case($dH >= 5.0 && $dH < 6.0):
 +				$dR = $dC;
 +				$dG = 0.0;
 +				$dB = $dX;
 +				break;
 +			default:
 +				$dR = 0.0;
 +				$dG = 0.0;
 +				$dB = 0.0;
 +				break;
 +		}
 +
 +		$dM = $dV - $dC;
 +		$dR += $dM;
 +		$dG += $dM;
 +		$dB += $dM;
 +		$dR *= 255;
 +		$dG *= 255;
 +		$dB *= 255;
 +
 +		$dR = str_pad(dechex(round($dR)), 2, "0", STR_PAD_LEFT);
 +		$dG = str_pad(dechex(round($dG)), 2, "0", STR_PAD_LEFT);
 +		$dB = str_pad(dechex(round($dB)), 2, "0", STR_PAD_LEFT);
 +		return $dR.$dG.$dB;
 +	}
 +
 +}
diff --cc apps/documents/lib/storage.php
index e8f8f16,0000000..3efd58c
mode 100644,000000..100644
--- a/apps/documents/lib/storage.php
+++ b/apps/documents/lib/storage.php
@@@ -1,101 -1,0 +1,106 @@@
 +<?php
 +
 +/**
 + * ownCloud - Documents App
 + *
 + * @author Frank Karlitschek
-  * @copyright 2012 Frank Karlitschek frank at owncloud.org
++ * @copyright 2013-2014 Frank Karlitschek frank at owncloud.org
 + * 
 + * This library is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
 + * License as published by the Free Software Foundation; either 
 + * version 3 of the License, or any later version.
 + * 
 + * This library is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
 + *  
 + * You should have received a copy of the GNU Lesser General Public 
 + * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
 + * 
 + */
 +
 +
 +namespace OCA\Documents;
 +
 +class Storage {
 +	const MIMETYPE_LIBREOFFICE_WORDPROCESSOR = 'application/vnd.oasis.opendocument.text';
 +
 +	public static function getDocuments() {
 +		$list = array_filter(
 +				self::searchDocuments(),
 +				function($item){
 +					//filter Deleted
 +					if (strpos($item['path'], '_trashbin')===0){
 +						return false;
 +					}
 +					return true;
 +				}
 +		);
 +		
 +		return $list;
 +	}
 +	
 +	public static function resolvePath($fileId){
 +		$list = array_filter(
 +				self::searchDocuments(),
 +				function($item) use ($fileId){
 +					return intval($item['fileid'])==$fileId;
 +				}
 +		);
 +		if (count($list)>0){
 +			$item = current($list);
 +			return $item['path'];
 +		}
 +		return false;
 +	}
 +	
 +	/**
 +	 * @brief Cleanup session data on removing the document
 +	 * @param array
 +	 *
 +	 * This function is connected to the delete signal of OC_Filesystem
 +	 * to delete the related info from database
 +	 */
 +	public static function onDelete($params) {
 +		$info = \OC\Files\Filesystem::getFileInfo($params['path']);
 +		
 +		$fileId = @$info['fileid'];
 +		if (!$fileId){
 +			return;
 +		}
 +		
- 		$sessionObj = new Db_Session();
- 		$session = $sessionObj
- 					->loadBy('file_id', $fileId)
- 					->getData()
- 				;
++		$session = new Db_Session();
++		$session->loadBy('file_id', $fileId);
 +
- 		if (!is_array($session) || !isset($session['es_id'])){
++		if (!$session->getEsId()){
 +			return;
 +		}
 +		
- 		Db_Session::cleanUp($session['es_id']);
++		$member = new Db_Member();
++		$sessionMembers = $member->getCollectionBy('es_id', $session->getEsId());
++		foreach ($sessionMembers as $memberData){
++			if (intval($memberData['status'])===Db_Member::MEMBER_STATUS_ACTIVE){
++				return;
++			}
++		}
++		
++		Db_Session::cleanUp($session->getEsId());
 +	}
 +	
 +	protected static function searchDocuments(){
 +		$documents = array();
 +		foreach (self::getSupportedMimetypes() as $mime){
 +			$documents = array_merge($documents, \OCP\Files::searchByMime($mime));
 +		}
 +		return $documents;
 +	}
 +	
 +	protected static function getSupportedMimetypes(){
 +		return array_merge(
 +			array(self::MIMETYPE_LIBREOFFICE_WORDPROCESSOR),
 +			Filter::getAll()	
 +		);
 +	}
 +}
diff --cc apps/documents/public.php
index a0c1631,0000000..22938b9
mode 100644,000000..100644
--- a/apps/documents/public.php
+++ b/apps/documents/public.php
@@@ -1,47 -1,0 +1,61 @@@
 +<?php
 +
 +/**
 + * ownCloud - Documents App
 + *
 + * @author Victor Dubiniuk
 + * @copyright 2013 Victor Dubiniuk victor.dubiniuk at gmail.com
 + *
 + * This file is licensed under the Affero General Public License version 3 or
 + * later.
 + */
 +
 +
 +namespace OCA\Documents;
 +
 +\OCP\JSON::checkAppEnabled('documents');
 +
 +\OCP\Util::addStyle( 'documents', 'style' );
 +
 +if (\OC_Appconfig::getValue('core', 'shareapi_allow_links', 'yes') !== 'yes') {
 +	header('HTTP/1.0 404 Not Found');
 +	$tmpl = new OCP\Template('', '404', 'guest');
 +	$tmpl->printPage();
 +	exit();
 +}
 +
 +if (isset($_GET['t'])) {
 +	$token = $_GET['t'];
 +	$tmpl = new \OCP\Template('documents', 'public', 'guest');
 +	try {
 +		$file = File::getByShareToken($token);
 +		if ($file->isPasswordProtected() && !$file->checkPassword(@$_POST['password'])){
 +			if (isset($_POST['password'])){
 +				$tmpl->assign('wrongpw', true);
 +			}
 +			$tmpl->assign('hasPassword', true);
 +		} else {
 +			\OCP\Util::addStyle( 'documents', '3rdparty/webodf/dojo-app');
 +			\OCP\Util::addStyle( 'documents', '3rdparty/webodf/editor' );
 +			\OCP\Util::addScript('documents', 'documents');
++			if ($file->getFileId()){
++				$session = new Db_Session();
++				$session->loadBy('file_id', $file->getFileId());
++				
++				if ($session->getEsId()){
++					$member = new Db_Member();
++					$members = $member->getCollectionBy('es_id', $session->getEsId());
++				} else {
++					$members = 0;
++				}
++				$tmpl->assign('total', count($members)+1);
++			} else {
++				$tmpl->assign('total', 1);
++			}
 +			$tmpl->assign('document', $token);
 +		}
 +	} catch (\Exception $e){
 +		$tmpl->assign('notFound', true);
 +	}
 +	$tmpl->printPage();
 +}
diff --cc apps/documents/src/patches/MemberListView-OCnick.patch
index 0000000,0000000..36d3436
new file mode 100644
--- /dev/null
+++ b/apps/documents/src/patches/MemberListView-OCnick.patch
@@@ -1,0 -1,0 +1,10 @@@
++--- MemberListView-old.js	2014-03-21 20:54:57.764793256 +0300
+++++ MemberListView.js	2014-03-21 20:55:12.761110324 +0300
++@@ -116,6 +116,7 @@
++                 //avatar.getCaret().hideHandle();
++             };
++             avatarDiv.onclick = function () {
+++                documentsMain.onNickChange(memberId, fullnameNode);
++                 var caret = editorSession.sessionView.getCaret(memberId);
++                 if (caret) {
++                     //caret.toggleHandleVisibility();
diff --cc apps/documents/src/updateWebODF.sh
index a91b658,0000000..7e2cbb9
mode 100644,000000..100644
--- a/apps/documents/src/updateWebODF.sh
+++ b/apps/documents/src/updateWebODF.sh
@@@ -1,42 -1,0 +1,43 @@@
 +#!/bin/bash
 +# Copies the needed files from the build dir of the WebODF pullbox branch
 +#
 +# Prepare the webodf build dir by calling: make webodf-debug.js-target editor-compiled.js-target
 +
 +WEBODF_BUILDDIR=${1%/}
 +
 +if [ ! -d "$WEBODF_BUILDDIR" ]; then
 +   echo "Provide the toplevel build directory of WebODF pullbox branch."
 +        exit 1
 +fi
 +if [ ! -e "README.md" ]; then
 +   echo "Call me in the toplevel dir of OwnCloud Documents."
 +        exit 1
 +fi
 +
 +# copy files
 +
 +# webodf.js
 +cp "$WEBODF_BUILDDIR"/webodf/webodf.js ./js/3rdparty/webodf
 +cp "$WEBODF_BUILDDIR"/webodf/webodf-debug.js ./js/3rdparty/webodf
 +# dojo
 +cp "$WEBODF_BUILDDIR"/programs/editor/dojo-amalgamation.js ./js/3rdparty/webodf
 +
 +# Tools, Editor, EditorSession, MemberListView:
 +cp "$WEBODF_BUILDDIR"/programs/editor/{Tools,Editor,EditorSession,MemberListView}.js ./js/3rdparty/webodf/editor
 +cp "$WEBODF_BUILDDIR"/programs/editor/server/pullbox/* ./js/3rdparty/webodf/editor/server/pullbox -R
 +cp "$WEBODF_BUILDDIR"/programs/editor/server/ServerFactory.js ./js/3rdparty/webodf/editor/server -R
 +cp "$WEBODF_BUILDDIR"/programs/editor/widgets ./js/3rdparty/webodf/editor -R
 +cp "$WEBODF_BUILDDIR"/programs/editor/editor.css ./css/3rdparty/webodf
 +
 +# patches against upstream
 +patch -p1 -i src/patches/fontsCssPath.patch
 +patch -p1 -i src/patches/hideCaretAvatar.patch
 +patch -p1 -i src/patches/MemberListView-OCavatar.patch
++patch -p1 -i src/patches/MemberListView-OCnick.patch
 +patch -p1 -i src/patches/keepBodyStyle.patch
 +
 +
 +# files which need to be adapted manually:
 +# "$WEBODF_BUILDDIR"/programs/editor/dojo-deps/src/app/resources/app.css  -> ./css/3rdparty/webodf/dojo-app.css
 +# dojo-app.css has other paths then upstream, needs to be manually adapted to changes
 +# also is dojo.css is not imported here, other than in upstream
diff --cc apps/documents/templates/documents.php
index 5270700,0000000..036b626
mode 100644,000000..100644
--- a/apps/documents/templates/documents.php
+++ b/apps/documents/templates/documents.php
@@@ -1,38 -1,0 +1,38 @@@
 +<div id="documents-content">
 +	<ul class="documentslist">
 +		<li class="add-document">
- 			<a class="icon icon-add add svg" target="_blank" href="">
++			<a class="icon-add add svg" target="_blank" href="">
 +				<label><?php p($l->t('New document')) ?></label>
 +			</a> 
 +			<div id="upload" title="<?php p($l->t('Upload') . ' max. '.$_['uploadMaxHumanFilesize']) ?>">
 +				<form data-upload-id="1"
 +					  id="data-upload-form"
 +					  class="file_upload_form"
 +					  action="<?php print_unescaped(OCP\Util::linkTo('files', 'ajax/upload.php')); ?>"
 +					  method="post"
 +					  enctype="multipart/form-data"
 +					  target="file_upload_target_1">
 +					<?php if($_['uploadMaxFilesize'] >= 0):?>
 +					<input type="hidden" name="MAX_FILE_SIZE" id="max_upload"
 +						   value="<?php p($_['uploadMaxFilesize']) ?>" />
 +					<?php endif;?>
 +					<!-- Send the requesttoken, this is needed for older IE versions
 +						 because they don't send the CSRF token via HTTP header in this case -->
 +					<input type="hidden" name="requesttoken" value="<?php p($_['requesttoken']) ?>" id="requesttoken" />
 +					<input type="hidden" class="max_human_file_size"
 +						   value="(max <?php p($_['uploadMaxHumanFilesize']); ?>)" />
 +					<input type="hidden" name="dir" value="<?php p($_['savePath']) ?>" id="dir" />
 +					<input type="file" id="file_upload_start" name='files[]' />
- 					<a href="#" class="icon icon-upload upload svg">
++					<a href="#" class="icon-upload upload svg">
 +					<label><?php p($l->t('Upload')) ?></label></a>
 +				</form>
 +			</div>
 +		</li>
- 		<li class="progress icon icon-loading"><div><?php p($l->t('Loading documents...')); ?></div></li>
++		<li class="progress icon-loading"><div><?php p($l->t('Loading documents...')); ?></div></li>
 +		<li class="document template" data-id="" style="display:none;">
 +			<a target="_blank" href=""><label></label></a>
 +		</li>
 +	</ul>
 +</div>
 +<input type="hidden" id="webodf-unstable" value="<?php p($_['useUnstable']) ?>" />
 +<input type="hidden" name="allowShareWithLink" id="allowShareWithLink" value="<?php p($_['allowShareWithLink']) ?>" />
diff --cc apps/documents/templates/public.php
index cc9efbf,0000000..6f018e8
mode 100644,000000..100644
--- a/apps/documents/templates/public.php
+++ b/apps/documents/templates/public.php
@@@ -1,26 -1,0 +1,23 @@@
 +<div id="notification-container">
 +	<div id="notification" style="display: none;"></div>
 +</div>
 +<div id="documents-content">
 +	<?php if (isset($_['hasPassword'])): ?>
 +		<?php if (isset($_['wrongpw'])): ?>
 +			<div class="push"></div>
 +			<div class="warning"><?php p($l->t('Wrong password. Please retry.')) ?></div>
 +		<?php endif; ?>
 +		<form method="post">
 +			<input type="password" name="password" placeholder="<?php p($l->t('Password')) ?>" />
 +			<input type="submit" name="submit" value="<?php p($l->t('OK')) ?>" />
 +		</form>
 +	<?php endif; ?>
- 	<?php if (isset($_['document'])): ?>
- 		<form>
- 			<input type="text" name="memberName" placeholder="<?php p($l->t('Please enter your nickname')) ?>" />
- 			<button id="odf-join"><?php p($l->t('Join')) ?></button>
- 		</form>
++	<?php if (isset($_['document']) && !isset($_['wrongpw'])): ?>
 +		<input type="hidden" name="document" value ="<?php p($_['document']) ?>" />
++		<input type="hidden" name="memberName" value ="<?php p($l->t('Guest %s' ,$_['total'])) ?>" />
 +	<?php endif; ?>
 +	<?php if (isset($_['notFound'])): ?>
 +		<div class="push"></div>
 +		<div class="warning"><?php p($l->t('This link has been expired or is never existed. Please contact the person who shared it with you for details.')) ?></div>
 +	<?php endif; ?>
 +</div>
diff --cc apps/files_encryption/lib/helper.php
index 584935f,bb06a57..bb06a57
mode 100644,100755..100644
--- a/apps/files_encryption/lib/helper.php
+++ b/apps/files_encryption/lib/helper.php
diff --cc apps/files_encryption/tests/util.php
index af422a3,863ea73..863ea73
mode 100644,100755..100644
--- a/apps/files_encryption/tests/util.php
+++ b/apps/files_encryption/tests/util.php
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/compatibility.js
index 0230dc5,0000000..64ce745
mode 100644,000000..100644
--- a/apps/files_pdfviewer/3rdparty/pdfjs/compatibility.js
+++ b/apps/files_pdfviewer/3rdparty/pdfjs/compatibility.js
@@@ -1,440 -1,0 +1,495 @@@
 +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 +/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
 +/* 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.
 + */
- /* globals VBArray */
++/* globals VBArray, PDFJS */
 +
 +'use strict';
 +
++// Initializing PDFJS global object here, it case if we need to change/disable
++// some PDF.js features, e.g. range requests
++if (typeof PDFJS === 'undefined') {
++  (typeof window !== 'undefined' ? window : this).PDFJS = {};
++}
++
 +// Checking if the typed arrays are supported
 +(function checkTypedArrayCompatibility() {
 +  if (typeof Uint8Array !== 'undefined') {
 +    // some mobile versions do not support subarray (e.g. safari 5 / iOS)
 +    if (typeof Uint8Array.prototype.subarray === 'undefined') {
 +        Uint8Array.prototype.subarray = function subarray(start, end) {
 +          return new Uint8Array(this.slice(start, end));
 +        };
 +        Float32Array.prototype.subarray = function subarray(start, end) {
 +          return new Float32Array(this.slice(start, end));
 +        };
 +    }
 +
 +    // some mobile version might not support Float64Array
 +    if (typeof Float64Array === 'undefined')
 +      window.Float64Array = Float32Array;
 +
 +    return;
 +  }
 +
 +  function subarray(start, end) {
 +    return new TypedArray(this.slice(start, end));
 +  }
 +
 +  function setArrayOffset(array, offset) {
 +    if (arguments.length < 2)
 +      offset = 0;
 +    for (var i = 0, n = array.length; i < n; ++i, ++offset)
 +      this[offset] = array[i] & 0xFF;
 +  }
 +
 +  function TypedArray(arg1) {
 +    var result;
 +    if (typeof arg1 === 'number') {
 +      result = [];
 +      for (var 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) {
 +        result[i] = arg1[i];
 +      }
 +    }
 +
 +    result.subarray = subarray;
 +    result.buffer = result;
 +    result.byteLength = result.length;
 +    result.set = setArrayOffset;
 +
 +    if (typeof arg1 === 'object' && arg1.buffer)
 +      result.buffer = arg1.buffer;
 +
 +    return result;
 +  }
 +
 +  window.Uint8Array = TypedArray;
 +
 +  // we don't need support for set, byteLength for 32-bit array
 +  // so we can use the TypedArray as well
 +  window.Uint32Array = TypedArray;
 +  window.Int32Array = TypedArray;
 +  window.Uint16Array = TypedArray;
 +  window.Float32Array = TypedArray;
 +  window.Float64Array = TypedArray;
 +})();
 +
++// URL = URL || webkitURL
++(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() ?
 +(function checkObjectDefinePropertyCompatibility() {
 +  if (typeof Object.defineProperty !== 'undefined') {
 +    var definePropertyPossible = true;
 +    try {
 +      // some browsers (e.g. safari) cannot use defineProperty() on DOM objects
 +      // and thus the native version is not sufficient
 +      Object.defineProperty(new Image(), 'id', { value: 'test' });
 +      // ... another test for android gb browser for non-DOM objects
 +      var Test = function Test() {};
 +      Test.prototype = { get id() { } };
 +      Object.defineProperty(new Test(), 'id',
 +        { value: '', configurable: true, enumerable: true, writable: false });
 +    } catch (e) {
 +      definePropertyPossible = false;
 +    }
 +    if (definePropertyPossible) return;
 +  }
 +
 +  Object.defineProperty = function objectDefineProperty(obj, name, def) {
 +    delete obj[name];
 +    if ('get' in def)
 +      obj.__defineGetter__(name, def['get']);
 +    if ('set' in def)
 +      obj.__defineSetter__(name, def['set']);
 +    if ('value' in def) {
 +      obj.__defineSetter__(name, function objectDefinePropertySetter(value) {
 +        this.__defineGetter__(name, function objectDefinePropertyGetter() {
 +          return value;
 +        });
 +        return value;
 +      });
 +      obj[name] = def.value;
 +    }
 +  };
 +})();
 +
 +// 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 ?
 +(function checkXMLHttpRequestResponseCompatibility() {
 +  var xhrPrototype = XMLHttpRequest.prototype;
 +  if (!('overrideMimeType' in xhrPrototype)) {
 +    // IE10 might have response, but not overrideMimeType
 +    Object.defineProperty(xhrPrototype, 'overrideMimeType', {
 +      value: function xmlHttpRequestOverrideMimeType(mimeType) {}
 +    });
 +  }
 +  if ('response' in xhrPrototype ||
 +      'mozResponseArrayBuffer' in xhrPrototype ||
 +      'mozResponse' in xhrPrototype ||
 +      'responseArrayBuffer' in xhrPrototype)
 +    return;
 +  // IE9 ?
 +  if (typeof VBArray !== 'undefined') {
 +    Object.defineProperty(xhrPrototype, 'response', {
 +      get: function xmlHttpRequestResponseGet() {
 +        return new Uint8Array(new VBArray(this.responseBody).toArray());
 +      }
 +    });
 +    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 });
 +})();
 +
 +// window.btoa (base64 encode function) ?
 +(function checkWindowBtoaCompatibility() {
 +  if ('btoa' in window)
 +    return;
 +
 +  var digits =
 +    'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
 +
 +  window.btoa = function windowBtoa(chars) {
 +    var buffer = '';
 +    var i, n;
 +    for (i = 0, n = chars.length; i < n; i += 3) {
 +      var b1 = chars.charCodeAt(i) & 0xFF;
 +      var b2 = chars.charCodeAt(i + 1) & 0xFF;
 +      var b3 = chars.charCodeAt(i + 2) & 0xFF;
 +      var d1 = b1 >> 2, d2 = ((b1 & 3) << 4) | (b2 >> 4);
 +      var d3 = i + 1 < n ? ((b2 & 0xF) << 2) | (b3 >> 6) : 64;
 +      var d4 = i + 2 < n ? (b3 & 0x3F) : 64;
 +      buffer += (digits.charAt(d1) + digits.charAt(d2) +
 +                 digits.charAt(d3) + digits.charAt(d4));
 +    }
 +    return buffer;
 +  };
 +})();
 +
++// window.atob (base64 encode function) ?
++(function checkWindowAtobCompatibility() {
++  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');
++    for (
++      // initialize result and counters
++      var bc = 0, bs, buffer, idx = 0, output = '';
++      // get next character
++      buffer = input.charAt(idx++);
++      // character found in table?
++      // initialize bit storage and add its ascii value
++      ~buffer && (bs = bc % 4 ? bs * 64 + buffer : buffer,
++        // and if not first of each 4 characters,
++        // convert the first 8 bits to one ascii character
++        bc++ % 4) ? output += String.fromCharCode(255 & bs >> (-2 * bc & 6)) : 0
++    ) {
++      // try to find character in table (0-63, not found => -1)
++      buffer = digits.indexOf(buffer);
++    }
++    return output;
++  };
++})();
++
 +// Function.prototype.bind ?
 +(function checkFunctionPrototypeBindCompatibility() {
 +  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;
 +  };
 +})();
 +
- // IE9/10 text/html data URI
- (function checkDataURICompatibility() {
-   if (!('documentMode' in document) ||
-       document.documentMode !== 9 && document.documentMode !== 10)
-     return;
-   // overriding the src property
-   var originalSrcDescriptor = Object.getOwnPropertyDescriptor(
-     HTMLIFrameElement.prototype, 'src');
-   Object.defineProperty(HTMLIFrameElement.prototype, 'src', {
-     get: function htmlIFrameElementPrototypeSrcGet() { return this.$src; },
-     set: function htmlIFrameElementPrototypeSrcSet(src) {
-       this.$src = src;
-       if (src.substr(0, 14) != 'data:text/html') {
-         originalSrcDescriptor.set.call(this, src);
-         return;
-       }
-       // for text/html, using blank document and then
-       // document's open, write, and close operations
-       originalSrcDescriptor.set.call(this, 'about:blank');
-       setTimeout((function htmlIFrameElementPrototypeSrcOpenWriteClose() {
-         var doc = this.contentDocument;
-         doc.open('text/html');
-         doc.write(src.substr(src.indexOf(',') + 1));
-         doc.close();
-       }).bind(this), 0);
-     },
-     enumerable: true
-   });
- })();
- 
 +// HTMLElement dataset property
 +(function checkDatasetProperty() {
 +  var div = document.createElement('div');
 +  if ('dataset' in div)
 +    return; // dataset property exists
 +
 +  Object.defineProperty(HTMLElement.prototype, 'dataset', {
 +    get: function() {
 +      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-')
 +          continue;
 +        var key = attribute.name.substring(5).replace(/\-([a-z])/g,
 +          function(all, ch) { return ch.toUpperCase(); });
 +        dataset[key] = attribute.value;
 +      }
 +
 +      Object.defineProperty(this, '_dataset', {
 +        value: dataset,
 +        writable: false,
 +        enumerable: false
 +      });
 +      return dataset;
 +    },
 +    enumerable: true
 +  });
 +})();
 +
 +// HTMLElement classList property
 +(function checkClassListProperty() {
 +  var div = document.createElement('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();
 +    var index = list.indexOf(itemName);
 +    if (index < 0 && add)
 +      list.push(itemName);
 +    if (index >= 0 && remove)
 +      list.splice(index, 1);
 +    element.className = list.join(' ');
++    return (index >= 0);
 +  }
 +
 +  var classListPrototype = {
 +    add: function(name) {
 +      changeList(this.element, name, true, false);
 +    },
++    contains: function(name) {
++      return changeList(this.element, name, false, false);
++    },
 +    remove: function(name) {
 +      changeList(this.element, name, false, true);
 +    },
 +    toggle: function(name) {
 +      changeList(this.element, name, true, true);
 +    }
 +  };
 +
 +  Object.defineProperty(HTMLElement.prototype, 'classList', {
 +    get: function() {
 +      if (this._classList)
 +        return this._classList;
 +
 +      var classList = Object.create(classListPrototype, {
 +        element: {
 +          value: this,
 +          writable: false,
 +          enumerable: true
 +        }
 +      });
 +      Object.defineProperty(this, '_classList', {
 +        value: classList,
 +        writable: false,
 +        enumerable: false
 +      });
 +      return classList;
 +    },
 +    enumerable: true
 +  });
 +})();
 +
- // Check console compatability
++// Check console compatibility
 +(function checkConsoleCompatibility() {
 +  if (!('console' in window)) {
 +    window.console = {
 +      log: function() {},
 +      error: function() {},
 +      warn: function() {}
 +    };
 +  } else if (!('bind' in console.log)) {
 +    // native functions in IE9 might not have bind
 +    console.log = (function(fn) {
 +      return function(msg) { return fn(msg); };
 +    })(console.log);
 +    console.error = (function(fn) {
 +      return function(msg) { return fn(msg); };
 +    })(console.error);
 +    console.warn = (function(fn) {
 +      return function(msg) { return fn(msg); };
 +    })(console.warn);
 +  }
 +})();
 +
 +// Check onclick compatibility in Opera
 +(function checkOnClickCompatibility() {
 +  // workaround for reported Opera bug DSK-354448:
 +  // onclick fires on disabled buttons with opaque content
 +  function ignoreIfTargetDisabled(event) {
 +    if (isDisabled(event.target)) {
 +      event.stopPropagation();
 +    }
 +  }
 +  function isDisabled(node) {
 +    return node.disabled || (node.parentNode && isDisabled(node.parentNode));
 +  }
 +  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()
++(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.
++  var isSafari = Object.prototype.toString.call(
++                  window.HTMLElement).indexOf('Constructor') > 0;
++
++  // Older versions of Android (pre 3.0) has issues with range requests, see:
++  // https://github.com/mozilla/pdf.js/issues/3381.
++  // Make sure that we only match webkit-based Android browsers,
++  // since Firefox/Fennec works as expected.
++  var regex = /Android\s[0-2][^\d]/;
++  var isOldAndroid = regex.test(navigator.userAgent);
++
++  if (isSafari || isOldAndroid) {
++    PDFJS.disableRange = true;
++  }
++})();
++
++// Check if the browser supports manipulation of the history.
++(function checkHistoryManipulation() {
++  if (!window.history.pushState) {
++    PDFJS.disableHistory = true;
++  }
 +})();
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/annotation-check.svg
index 27ad047,0000000..71cd16d
mode 100644,000000..100644
--- a/apps/files_pdfviewer/3rdparty/pdfjs/images/annotation-check.svg
+++ b/apps/files_pdfviewer/3rdparty/pdfjs/images/annotation-check.svg
@@@ -1,4 -1,0 +1,11 @@@
 +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
- <svg width="40" xmlns="http://www.w3.org/2000/svg" height="40">
-  <path d="m1.5007 23.536 5.3919-4.542 7.6934 7.044 19.434-21.497 4.479 4.6825-23.913 26.236z" stroke="#000" stroke-width="1.254" fill="#ff0"/>
++<svg
++   xmlns="http://www.w3.org/2000/svg"
++   width="40"
++   height="40"
++   viewBox="0 0 40 40">
++  <path
++     d="M 1.5006714,23.536225 6.8925879,18.994244 14.585721,26.037937 34.019683,4.5410479 38.499329,9.2235032 14.585721,35.458952 z"
++     id="path4"
++     style="fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-width:1.25402856;stroke-opacity:1" />
 +</svg>
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/annotation-comment.svg
index 5f1e4c0,0000000..86f1f17
mode 100644,000000..100644
--- a/apps/files_pdfviewer/3rdparty/pdfjs/images/annotation-comment.svg
+++ b/apps/files_pdfviewer/3rdparty/pdfjs/images/annotation-comment.svg
@@@ -1,5 -1,0 +1,16 @@@
 +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
- <svg width="40" xmlns="http://www.w3.org/2000/svg" height="40">
-  <rect fill-rule="evenodd" height="33.76" width="33.76" stroke="#000" y="3.1199" x="3.1199" fill="#ff0"/>
-  <path d="m20.678 8.545c-7.3428 0-13.295 4.9543-13.295 11.066 0 2.0888 0.36472 3.4844 1.5755 5.1506l-2.9313 6.693 7.5343-2.444c2.2213 1.388 4.1259 1.6654 7.1174 1.6654 7.3428 0 13.295-4.9543 13.295-11.066 0-6.1115-5.9525-11.066-13.295-11.066z" stroke="#000" stroke-width=".93032" fill="#fff"/>
++<svg
++   xmlns="http://www.w3.org/2000/svg"
++   height="40"
++   width="40"
++   viewBox="0 0 40 40">
++  <rect
++     style="fill:#ffff00;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
++     width="33.76017"
++     height="33.76017"
++     x="3.119915"
++     y="3.119915" />
++  <path
++     d="m 20.677967,8.54499 c -7.342801,0 -13.295293,4.954293 -13.295293,11.065751 0,2.088793 0.3647173,3.484376 1.575539,5.150563 L 6.0267418,31.45501 13.560595,29.011117 c 2.221262,1.387962 4.125932,1.665377 7.117372,1.665377 7.3428,0 13.295291,-4.954295 13.295291,-11.065753 0,-6.111458 -5.952491,-11.065751 -13.295291,-11.065751 z"
++     style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.93031836;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"/>
 +</svg>
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/annotation-help.svg
index 1c3720f,0000000..00938fe
mode 100644,000000..100644
--- a/apps/files_pdfviewer/3rdparty/pdfjs/images/annotation-help.svg
+++ b/apps/files_pdfviewer/3rdparty/pdfjs/images/annotation-help.svg
@@@ -1,10 -1,0 +1,26 @@@
 +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
- <svg width="40" xmlns="http://www.w3.org/2000/svg" height="40">
-  <g transform="translate(0,-60)">
-   <rect fill-rule="evenodd" height="34.806" width="36.461" stroke="#000" y="62.597" x="1.7695" stroke-width="1.3083" fill="#ff0"/>
-   <g transform="matrix(.88764 0 0 .88764 2.2473 8.9891)">
-    <path d="m20 64.526c-8.546 0-15.474 6.928-15.474 15.474 0.0003 8.546 6.928 15.474 15.474 15.474s15.474-6.928 15.474-15.474-6.928-15.474-15.474-15.474zm-0.40874 9.4886c3.5271 0 6.3938 2.8406 6.3938 6.3354s-2.8668 6.3354-6.3938 6.3354c-3.5271 0-6.3938-2.8406-6.3938-6.3354s2.8668-6.3354 6.3938-6.3354z" stroke="#000" stroke-width="1.0277" fill="#fff"/>
-    <path d="m7.2335 71.82 4.9703 4.1618c-1.68 2.5816-1.4439 6.0696 0.15932 8.6777l-5.1263 3.4245c0.67516 1.2315 3.0166 3.5477 4.2332 4.1948l3.9077-4.5673c2.542 1.4598 5.7307 1.3922 8.4387-0.12614l3.4695 6.1083c1.1298-0.44367 4.7422-3.4496 5.4164-5.0039l-5.462-4.4155c1.4432-2.4241 1.6512-5.2675 0.5573-7.7486l5.9032-3.834c-0.557-0.986-3.084-3.672-4.67-4.698l-4.1188 4.9817c-2.499-1.77-6.01-2.037-8.87-0.646l-3.5954-5.3221c-1.346 0.57949-4.1294 2.9212-5.2124 4.8129zm8.101 3.4267c2.7528-2.446 [...]
++<svg
++   xmlns="http://www.w3.org/2000/svg"
++   width="40"
++   height="40"
++   viewBox="0 0 40 40">
++  <g
++     transform="translate(0,-60)"
++     id="layer1">
++    <rect
++       width="36.460953"
++       height="34.805603"
++       x="1.7695236"
++       y="62.597198"
++       style="fill:#ffff00;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.30826771;stroke-opacity:1" />
++    <g
++       transform="matrix(0.88763677,0,0,0.88763677,2.2472646,8.9890584)">
++      <path
++         d="M 20,64.526342 C 11.454135,64.526342 4.5263421,71.454135 4.5263421,80 4.5263421,88.545865 11.454135,95.473658 20,95.473658 28.545865,95.473658 35.473658,88.545865 35.473658,80 35.473658,71.454135 28.545865,64.526342 20,64.526342 z m -0.408738,9.488564 c 3.527079,0 6.393832,2.84061 6.393832,6.335441 0,3.494831 -2.866753,6.335441 -6.393832,6.335441 -3.527079,0 -6.393832,-2.84061 -6.393832,-6.335441 0,-3.494831 2.866753,-6.335441 6.393832,-6.335441 z"
++         style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.02768445;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
++      <path
++         d="m 7.2335209,71.819938 4.9702591,4.161823 c -1.679956,2.581606 -1.443939,6.069592 0.159325,8.677725 l -5.1263071,3.424463 c 0.67516,1.231452 3.0166401,3.547686 4.2331971,4.194757 l 3.907728,-4.567277 c 2.541952,1.45975 5.730694,1.392161 8.438683,-0.12614 l 3.469517,6.108336 c 1.129779,-0.44367 4.742234,-3.449633 5.416358,-5.003859 l -5.46204,-4.415541 c 1.44319,-2.424098 1.651175,-5.267515 0.557303,-7.748623 l 5.903195,-3.833951 C 33.14257,71.704996 30.616217,69.018606 29.029 [...]
++         style="fill:#000000;fill-opacity:1;stroke:none" />
++    </g>
 +  </g>
-  </g>
 +</svg>
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/annotation-insert.svg
index e05305d,0000000..519ef68
mode 100644,000000..100644
--- a/apps/files_pdfviewer/3rdparty/pdfjs/images/annotation-insert.svg
+++ b/apps/files_pdfviewer/3rdparty/pdfjs/images/annotation-insert.svg
@@@ -1,4 -1,0 +1,10 @@@
 +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
- <svg width="64" xmlns="http://www.w3.org/2000/svg" height="64">
-  <path d="m32.003 1.4045 25.43 61.228-50.866-0.004z" fill-opacity=".94118" stroke="#000" stroke-width="1.0049" fill="#ff0"/>
++<svg
++   xmlns="http://www.w3.org/2000/svg"
++   width="64"
++   height="64"
++   viewBox="0 0 64 64">
++  <path
++     d="M 32.003143,1.4044602 57.432701,62.632577 6.5672991,62.627924 z"
++     style="fill:#ffff00;fill-opacity:0.94117647;fill-rule:nonzero;stroke:#000000;stroke-width:1.00493038;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
 +</svg>
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/annotation-key.svg
index 3764cb0,0000000..8d09d53
mode 100644,000000..100644
--- a/apps/files_pdfviewer/3rdparty/pdfjs/images/annotation-key.svg
+++ b/apps/files_pdfviewer/3rdparty/pdfjs/images/annotation-key.svg
@@@ -1,4 -1,0 +1,11 @@@
 +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
- <svg width="64" xmlns="http://www.w3.org/2000/svg" height="64">
-  <path d="m25.471 9.4934c-0.169 2.6486 4.668 4.9526 9.234 4.0356 5.921-0.987 6.694-6.1434 1.27-7.7511-4.574-1.623-10.817 0.7667-10.504 3.7155zm-20.946 8.1586c-0.4564-5.819 4.7497-11.725 13.912-14.554 11.315-3.9698 27.059-1.6972 35.167 4.0124 9.2758 6.1889 7.1581 16.208-3.1711 21.594-1.7843 1.6358-6.3802 1.2142-7.0684 3.1862-1.04 0.97243-1.288 2.0502-1.2329 3.1682 1.0151 2.0001-3.8315 1.6332-3.2706 3.7596 0.58948 5.2645-0.17928 10.537-0.36284 15.806-0.49201 2.185 1.1635 4.5742-0.73489 6. [...]
++<svg
++   xmlns="http://www.w3.org/2000/svg"
++   width="64"
++   height="64"
++   viewBox="0 0 64 64">
++  <path
++     d="M 25.470843,9.4933766 C 25.30219,12.141818 30.139101,14.445969 34.704831,13.529144 40.62635,12.541995 41.398833,7.3856498 35.97505,5.777863 31.400921,4.1549155 25.157674,6.5445892 25.470843,9.4933766 z M 4.5246282,17.652051 C 4.068249,11.832873 9.2742983,5.9270407 18.437379,3.0977088 29.751911,-0.87185184 45.495663,1.4008022 53.603953,7.1104009 c 9.275765,6.1889221 7.158128,16.2079421 -3.171076,21.5939521 -1.784316,1.635815 -6.380222,1.21421 -7.068351,3.186186 -1.04003,0.972427  [...]
++     id="path604"
++     style="fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-width:1.72665179;stroke-opacity:1" />
 +</svg>
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/annotation-newparagraph.svg
index 1f8930b,0000000..38d2497
mode 100644,000000..100644
--- a/apps/files_pdfviewer/3rdparty/pdfjs/images/annotation-newparagraph.svg
+++ b/apps/files_pdfviewer/3rdparty/pdfjs/images/annotation-newparagraph.svg
@@@ -1,4 -1,0 +1,11 @@@
 +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
- <svg width="64" xmlns="http://www.w3.org/2000/svg" height="64">
-  <path d="m32.003 10.913 25.43 42.174-50.866-0.003z" fill-opacity=".94118" stroke="#000" stroke-width=".83403" fill="#ff0"/>
++<svg
++   xmlns="http://www.w3.org/2000/svg"
++   width="64"
++   height="64"
++   viewBox="0 0 64 64">
++  <path
++     d="M 32.003143,10.913072 57.432701,53.086929 6.567299,53.083723 z"
++     id="path2985"
++     style="fill:#ffff00;fill-opacity:0.94117647;fill-rule:nonzero;stroke:#000000;stroke-width:0.83403099;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
 +</svg>
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/annotation-noicon.svg
index 0000000,0000000..c07d108
new file mode 100644
--- /dev/null
+++ b/apps/files_pdfviewer/3rdparty/pdfjs/images/annotation-noicon.svg
@@@ -1,0 -1,0 +1,7 @@@
++<?xml version="1.0" encoding="UTF-8" standalone="no"?>
++<svg
++   xmlns="http://www.w3.org/2000/svg"
++   width="40"
++   height="40"
++   viewBox="0 0 40 40">
++</svg>
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/annotation-note.svg
index fe493f8,0000000..7017365
mode 100644,000000..100644
--- a/apps/files_pdfviewer/3rdparty/pdfjs/images/annotation-note.svg
+++ b/apps/files_pdfviewer/3rdparty/pdfjs/images/annotation-note.svg
@@@ -1,10 -1,0 +1,42 @@@
 +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
- <svg width="40" xmlns="http://www.w3.org/2000/svg" height="40">
-  <rect fill-rule="evenodd" height="31.097" width="36.075" stroke="#000" y="4.4517" x="1.9623" stroke-width="1.23" fill="#ff0"/>
-  <g>
-   <rect height="1.5012" width="27.969" y="10.285" x="6.0157"/>
-   <rect height=".85784" width="27.969" y="23.217" x="6.0157"/>
-   <rect height=".85784" width="27.969" y="28.964" x="5.813"/>
-   <rect height=".85784" width="27.969" y="17.426" x="6.0157"/>
-  </g>
++<svg
++   xmlns="http://www.w3.org/2000/svg"
++   width="40"
++   height="40"
++   viewBox="0 0 40 40">
++  <rect
++     width="36.075428"
++     height="31.096582"
++     x="1.962286"
++     y="4.4517088"
++     id="rect4"
++     style="fill:#ffff00;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.23004246;stroke-opacity:1" />
++  <rect
++     width="27.96859"
++     height="1.5012145"
++     x="6.0157046"
++     y="10.285"
++     id="rect6"
++     style="fill:#000000;fill-opacity:1;stroke:none" />
++  <rect
++     width="27.96859"
++     height="0.85783684"
++     x="6.0157056"
++     y="23.21689"
++     id="rect8"
++     style="fill:#000000;fill-opacity:1;stroke:none" />
++  <rect
++     width="27.96859"
++     height="0.85783684"
++     x="5.8130345"
++     y="28.964394"
++     id="rect10"
++     style="fill:#000000;fill-opacity:1;stroke:none" />
++  <rect
++     width="27.96859"
++     height="0.85783684"
++     x="6.0157046"
++     y="17.426493"
++     id="rect12"
++     style="fill:#000000;fill-opacity:1;stroke:none" />
 +</svg>
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/annotation-paragraph.svg
index 0a715ac,0000000..6ae5212
mode 100644,000000..100644
--- a/apps/files_pdfviewer/3rdparty/pdfjs/images/annotation-paragraph.svg
+++ b/apps/files_pdfviewer/3rdparty/pdfjs/images/annotation-paragraph.svg
@@@ -1,5 -1,0 +1,16 @@@
 +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
- <svg width="40" xmlns="http://www.w3.org/2000/svg" height="40">
-  <rect fill-rule="evenodd" height="33.76" width="33.76" stroke="#000" y="3.1199" x="3.1199" fill="#ff0"/>
-  <path d="m17.693 34.502v-16.182c-1.9305-0.10322-3.4558-0.73038-4.5759-1.8815s-1.6802-2.6196-1.6802-4.4056c0-1.9924 0.622-3.5797 1.866-4.7618 1.244-1.182 3.0635-1.7731 5.4586-1.7731h9.8022v2.679h-2.2299v26.325h-2.6325v-26.325h-3.4532v26.325z" stroke="#000" stroke-width="1.078" fill="#fff"/>
++<svg
++   xmlns="http://www.w3.org/2000/svg"
++   width="40"
++   height="40"
++   viewBox="0 0 40 40">
++  <rect
++     width="33.76017"
++     height="33.76017"
++     x="3.119915"
++     y="3.119915"
++     style="fill:#ffff00;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
++  <path
++     d="m 17.692678,34.50206 0,-16.182224 c -1.930515,-0.103225 -3.455824,-0.730383 -4.57593,-1.881473 -1.12011,-1.151067 -1.680164,-2.619596 -1.680164,-4.405591 0,-1.992435 0.621995,-3.5796849 1.865988,-4.7617553 1.243989,-1.1820288 3.06352,-1.7730536 5.458598,-1.7730764 l 9.802246,0 0,2.6789711 -2.229895,0 0,26.3251486 -2.632515,0 0,-26.3251486 -3.45324,0 0,26.3251486 z"
++     style="font-size:29.42051125px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.07795751;stroke-opacity:1;font-family:Arial;-inkscape-font-specification:Arial" />
 +</svg>
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/findbarButton-next-rtl.png
index 08a2c25,0000000..bef0274
mode 100644,000000..100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/findbarButton-next-rtl at 2x.png
index 0000000,0000000..1da6dc9
new file mode 100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/findbarButton-next.png
index beef8cc,0000000..de1d0fc
mode 100644,000000..100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/findbarButton-next at 2x.png
index 0000000,0000000..0250307
new file mode 100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/findbarButton-previous-rtl.png
index beef8cc,0000000..de1d0fc
mode 100644,000000..100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/findbarButton-previous-rtl at 2x.png
index 0000000,0000000..0250307
new file mode 100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/findbarButton-previous.png
index 08a2c25,0000000..bef0274
mode 100644,000000..100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/findbarButton-previous at 2x.png
index 0000000,0000000..1da6dc9
new file mode 100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/grab.cur
index 0000000,0000000..db7ad5a
new file mode 100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/grabbing.cur
index 0000000,0000000..e0dfd04
new file mode 100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/loading-small.png
index 290d052,0000000..51848a7
mode 100644,000000..100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/secondaryToolbarButton-documentProperties.png
index 0000000,0000000..40925e2
new file mode 100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/secondaryToolbarButton-documentProperties at 2x.png
index 0000000,0000000..adb240e
new file mode 100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/secondaryToolbarButton-firstPage.png
index 0000000,0000000..e68846a
new file mode 100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/secondaryToolbarButton-firstPage at 2x.png
index 0000000,0000000..3ad8af5
new file mode 100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/secondaryToolbarButton-handTool.png
index 0000000,0000000..cb85a84
new file mode 100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/secondaryToolbarButton-handTool at 2x.png
index 0000000,0000000..5c13f77
new file mode 100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/secondaryToolbarButton-lastPage.png
index 0000000,0000000..be763e0
new file mode 100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/secondaryToolbarButton-lastPage at 2x.png
index 0000000,0000000..8570984
new file mode 100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/secondaryToolbarButton-rotateCcw.png
index 0000000,0000000..675d6da
new file mode 100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/secondaryToolbarButton-rotateCcw at 2x.png
index 0000000,0000000..b9e7431
new file mode 100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/secondaryToolbarButton-rotateCw.png
index 0000000,0000000..e1c7598
new file mode 100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/secondaryToolbarButton-rotateCw at 2x.png
index 0000000,0000000..cb257b4
new file mode 100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/shadow.png
index dd009dc,0000000..31d3bdb
mode 100644,000000..100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/texture.png
index df00864,0000000..eb5ccb5
mode 100644,000000..100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/toolbarButton-bookmark.png
index 1e5259a,0000000..a187be6
mode 100644,000000..100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/toolbarButton-bookmark at 2x.png
index 0000000,0000000..4efbaa6
new file mode 100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/toolbarButton-download.png
index 3f4a3b7,0000000..eaab35f
mode 100644,000000..100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/toolbarButton-download at 2x.png
index 0000000,0000000..896face
new file mode 100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/toolbarButton-menuArrows.png
index 31b06b5,0000000..306eb43
mode 100644,000000..100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/toolbarButton-menuArrows at 2x.png
index 0000000,0000000..f7570bc
new file mode 100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/toolbarButton-openFile.png
index 97e9a17,0000000..b5cf1bd
mode 100644,000000..100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/toolbarButton-openFile at 2x.png
index 0000000,0000000..91ab765
new file mode 100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/toolbarButton-pageDown-rtl.png
index 926bc79,0000000..1957f79
mode 100644,000000..100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/toolbarButton-pageDown-rtl at 2x.png
index 0000000,0000000..16ebcb8
new file mode 100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/toolbarButton-pageDown.png
index 762ac43,0000000..8219ecf
mode 100644,000000..100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/toolbarButton-pageDown at 2x.png
index 0000000,0000000..758c01d
new file mode 100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/toolbarButton-pageUp-rtl.png
index 90c5796,0000000..98e7ce4
mode 100644,000000..100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/toolbarButton-pageUp-rtl at 2x.png
index 0000000,0000000..a01b023
new file mode 100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/toolbarButton-pageUp.png
index 3155b8b,0000000..fb9daa3
mode 100644,000000..100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/toolbarButton-pageUp at 2x.png
index 0000000,0000000..a5cfd75
new file mode 100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/toolbarButton-presentationMode.png
index 0000000,0000000..3ac2124
new file mode 100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/toolbarButton-presentationMode at 2x.png
index 0000000,0000000..cada9e7
new file mode 100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/toolbarButton-print.png
index fef84dd,0000000..51275e5
mode 100644,000000..100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/toolbarButton-print at 2x.png
index 0000000,0000000..53d18da
new file mode 100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/toolbarButton-search.png
index e52370e,0000000..f9b7557
mode 100644,000000..100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/toolbarButton-search at 2x.png
index 0000000,0000000..456b133
new file mode 100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/toolbarButton-secondaryToolbarToggle-rtl.png
index 0000000,0000000..8437095
new file mode 100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/toolbarButton-secondaryToolbarToggle-rtl at 2x.png
index 0000000,0000000..9d9bfa4
new file mode 100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/toolbarButton-secondaryToolbarToggle.png
index 0000000,0000000..1f90f83
new file mode 100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/toolbarButton-secondaryToolbarToggle at 2x.png
index 0000000,0000000..b066fe5
new file mode 100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/toolbarButton-sidebarToggle-rtl.png
index 0000000,0000000..6f85ec0
new file mode 100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/toolbarButton-sidebarToggle-rtl at 2x.png
index 0000000,0000000..291e006
new file mode 100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/toolbarButton-sidebarToggle.png
index 5a937c7,0000000..025dc90
mode 100644,000000..100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/toolbarButton-sidebarToggle at 2x.png
index 0000000,0000000..7f834df
new file mode 100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/toolbarButton-viewOutline-rtl.png
index 0000000,0000000..aaa9430
new file mode 100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/toolbarButton-viewOutline-rtl at 2x.png
index 0000000,0000000..3410f70
new file mode 100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/toolbarButton-viewOutline.png
index cb3967b,0000000..976365a5
mode 100644,000000..100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/toolbarButton-viewOutline at 2x.png
index 0000000,0000000..b6a197f
new file mode 100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/toolbarButton-viewThumbnail.png
index 3a27f04,0000000..584ba55
mode 100644,000000..100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/toolbarButton-viewThumbnail at 2x.png
index 0000000,0000000..fb7db93
new file mode 100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/toolbarButton-zoomIn.png
index 670acd9,0000000..513d081
mode 100644,000000..100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/toolbarButton-zoomIn at 2x.png
index 0000000,0000000..d5d49d5
new file mode 100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/toolbarButton-zoomOut.png
index 810fbf9,0000000..156c26b
mode 100644,000000..100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/images/toolbarButton-zoomOut at 2x.png
index 0000000,0000000..959e191
new file mode 100644
Binary files differ
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/l10n.js
index 5435631,0000000..37f3950
mode 100644,000000..100644
--- a/apps/files_pdfviewer/3rdparty/pdfjs/l10n.js
+++ b/apps/files_pdfviewer/3rdparty/pdfjs/l10n.js
@@@ -1,922 -1,0 +1,1004 @@@
- /** Copyright (c) 2011-2012 Fabien Cazenave, Mozilla.
-   *
-   * Permission is hereby granted, free of charge, to any person obtaining a copy
-   * of this software and associated documentation files (the "Software"), to
-   * deal in the Software without restriction, including without limitation the
-   * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
-   * sell copies of the Software, and to permit persons to whom the Software is
-   * furnished to do so, subject to the following conditions:
-   *
-   * The above copyright notice and this permission notice shall be included in
-   * all copies or substantial portions of the Software.
-   *
-   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-   * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-   * IN THE SOFTWARE.
-   */
++/**
++ * Copyright (c) 2011-2013 Fabien Cazenave, Mozilla.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this software and associated documentation files (the "Software"), to
++ * deal in the Software without restriction, including without limitation the
++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
++ * sell copies of the Software, and to permit persons to whom the Software is
++ * furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ */
 +/*
 +  Additional modifications for PDF.js project:
 +    - Disables language initialization on page loading;
-     - Adds fallback argument to the getL10nData;
-     - Removes consoleLog and simplifies consoleWarn;
++    - Removes consoleWarn and consoleLog and use console.log/warn directly.
 +    - 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) {
 +  var gL10nData = {};
 +  var gTextData = '';
 +  var gTextProp = 'textContent';
 +  var gLanguage = '';
 +  var gMacros = {};
 +  var gReadyState = 'loading';
 +
-   // read-only setting -- we recommend to load l10n resources synchronously
-   var gAsyncResourceLoading = true;
 +
-   // debug helpers
-   function consoleWarn(message) {
-     console.log('[l10n] ' + message);
-   };
++  /**
++   * Synchronously loading l10n resources significantly minimizes flickering
++   * from displaying the app with non-localized strings and then updating the
++   * strings. Although this will block all script execution on this page, we
++   * expect that the l10n resources are available locally on flash-storage.
++   *
++   * As synchronous XHR is generally considered as a bad idea, we're still
++   * loading l10n resources asynchronously -- but we keep this in a setting,
++   * just in case... and applications using this library should hide their
++   * content until the `localized' event happens.
++   */
++
++  var gAsyncResourceLoading = true; // read-only
++
 +
 +  /**
 +   * DOM helpers for the so-called "HTML API".
 +   *
 +   * These functions are written for modern browsers. For old versions of IE,
 +   * they're overridden in the 'startup' section at the end of this file.
 +   */
 +
 +  function getL10nResourceLinks() {
 +    return document.querySelectorAll('link[type="application/l10n"]');
 +  }
 +
++  function getL10nDictionary() {
++    var script = document.querySelector('script[type="application/l10n"]');
++    // TODO: support multiple and external JSON dictionaries
++    return script ? JSON.parse(script.innerHTML) : null;
++  }
++
 +  function getTranslatableChildren(element) {
 +    return element ? element.querySelectorAll('*[data-l10n-id]') : [];
 +  }
 +
 +  function getL10nAttributes(element) {
 +    if (!element)
 +      return {};
 +
 +    var l10nId = element.getAttribute('data-l10n-id');
 +    var l10nArgs = element.getAttribute('data-l10n-args');
 +    var args = {};
 +    if (l10nArgs) {
 +      try {
 +        args = JSON.parse(l10nArgs);
 +      } catch (e) {
-         consoleWarn('could not parse arguments for #' + l10nId);
++        console.warn('could not parse arguments for #' + l10nId);
 +      }
 +    }
 +    return { id: l10nId, args: args };
 +  }
 +
 +  function fireL10nReadyEvent(lang) {
 +    var evtObject = document.createEvent('Event');
-     evtObject.initEvent('localized', false, false);
++    evtObject.initEvent('localized', true, false);
 +    evtObject.language = lang;
-     window.dispatchEvent(evtObject);
++    document.dispatchEvent(evtObject);
++  }
++
++  function xhrLoadText(url, onSuccess, onFailure, asynchronous) {
++    onSuccess = onSuccess || function _onSuccess(data) {};
++    onFailure = onFailure || function _onFailure() {
++      console.warn(url + ' not found.');
++    };
++
++    var xhr = new XMLHttpRequest();
++    xhr.open('GET', url, asynchronous);
++    if (xhr.overrideMimeType) {
++      xhr.overrideMimeType('text/plain; charset=utf-8');
++    }
++    xhr.onreadystatechange = function() {
++      if (xhr.readyState == 4) {
++        if (xhr.status == 200 || xhr.status === 0) {
++          onSuccess(xhr.responseText);
++        } else {
++          onFailure();
++        }
++      }
++    };
++    xhr.onerror = onFailure;
++    xhr.ontimeout = onFailure;
++
++    // in Firefox OS with the app:// protocol, trying to XHR a non-existing
++    // URL will raise an exception here -- hence this ugly try...catch.
++    try {
++      xhr.send(null);
++    } catch (e) {
++      onFailure();
++    }
 +  }
 +
 +
 +  /**
 +   * l10n resource parser:
 +   *  - reads (async XHR) the l10n resource matching `lang';
 +   *  - imports linked resources (synchronously) when specified;
 +   *  - parses the text data (fills `gL10nData' and `gTextData');
 +   *  - triggers success/failure callbacks when done.
 +   *
 +   * @param {string} href
 +   *    URL of the l10n resource to parse.
 +   *
 +   * @param {string} lang
 +   *    locale (language) to parse.
 +   *
 +   * @param {Function} successCallback
 +   *    triggered when the l10n resource has been successully parsed.
 +   *
 +   * @param {Function} failureCallback
 +   *    triggered when the an error has occured.
 +   *
 +   * @return {void}
 +   *    uses the following global variables: gL10nData, gTextData, gTextProp.
 +   */
 +
 +  function parseResource(href, lang, successCallback, failureCallback) {
-     var baseURL = href.replace(/\/[^\/]*$/, '/');
++    var baseURL = href.replace(/[^\/]*$/, '') || './';
 +
 +    // handle escaped characters (backslashes) in a string
 +    function evalString(text) {
 +      if (text.lastIndexOf('\\') < 0)
 +        return text;
 +      return text.replace(/\\\\/g, '\\')
 +                 .replace(/\\n/g, '\n')
 +                 .replace(/\\r/g, '\r')
 +                 .replace(/\\t/g, '\t')
 +                 .replace(/\\b/g, '\b')
 +                 .replace(/\\f/g, '\f')
 +                 .replace(/\\{/g, '{')
 +                 .replace(/\\}/g, '}')
 +                 .replace(/\\"/g, '"')
 +                 .replace(/\\'/g, "'");
 +    }
 +
 +    // parse *.properties text data into an l10n dictionary
 +    function parseProperties(text) {
 +      var dictionary = [];
 +
 +      // token expressions
 +      var reBlank = /^\s*|\s*$/;
 +      var reComment = /^\s*#|^\s*$/;
 +      var reSection = /^\s*\[(.*)\]\s*$/;
 +      var reImport = /^\s*@import\s+url\((.*)\)\s*$/i;
 +      var reSplit = /^([^=\s]*)\s*=\s*(.+)$/; // TODO: escape EOLs with '\'
 +
 +      // parse the *.properties file into an associative array
 +      function parseRawLines(rawText, extendedSyntax) {
 +        var entries = rawText.replace(reBlank, '').split(/[\r\n]+/);
 +        var currentLang = '*';
 +        var genericLang = lang.replace(/-[a-z]+$/i, '');
 +        var skipLang = false;
 +        var match = '';
 +
 +        for (var i = 0; i < entries.length; i++) {
 +          var line = entries[i];
 +
 +          // comment or blank line?
 +          if (reComment.test(line))
 +            continue;
 +
 +          // the extended syntax supports [lang] sections and @import rules
 +          if (extendedSyntax) {
 +            if (reSection.test(line)) { // section start?
 +              match = reSection.exec(line);
 +              currentLang = match[1];
 +              skipLang = (currentLang !== '*') &&
 +                  (currentLang !== lang) && (currentLang !== genericLang);
 +              continue;
 +            } else if (skipLang) {
 +              continue;
 +            }
 +            if (reImport.test(line)) { // @import rule?
 +              match = reImport.exec(line);
 +              loadImport(baseURL + match[1]); // load the resource synchronously
 +            }
 +          }
 +
 +          // key-value pair
 +          var tmp = line.match(reSplit);
-           if (tmp && tmp.length == 3)
++          if (tmp && tmp.length == 3) {
 +            dictionary[tmp[1]] = evalString(tmp[2]);
++          }
 +        }
 +      }
 +
 +      // import another *.properties file
 +      function loadImport(url) {
-         loadResource(url, function(content) {
++        xhrLoadText(url, function(content) {
 +          parseRawLines(content, false); // don't allow recursive imports
-         }, false, false); // load synchronously
++        }, null, false); // load synchronously
 +      }
 +
 +      // fill the dictionary
 +      parseRawLines(text, true);
 +      return dictionary;
 +    }
 +
-     // load the specified resource file
-     function loadResource(url, onSuccess, onFailure, asynchronous) {
-       var xhr = new XMLHttpRequest();
-       xhr.open('GET', url, asynchronous);
-       if (xhr.overrideMimeType) {
-         xhr.overrideMimeType('text/plain; charset=utf-8');
-       }
-       xhr.onreadystatechange = function() {
-         if (xhr.readyState == 4) {
-           if (xhr.status == 200 || xhr.status === 0) {
-             if (onSuccess)
-               onSuccess(xhr.responseText);
-           } else {
-             if (onFailure)
-               onFailure();
-           }
-         }
-       };
-       xhr.send(null);
-     }
- 
 +    // load and parse l10n data (warning: global variables are used here)
-     loadResource(href, function(response) {
++    xhrLoadText(href, function(response) {
 +      gTextData += response; // mostly for debug
 +
 +      // parse *.properties text data into an l10n dictionary
 +      var data = parseProperties(response);
 +
 +      // find attribute descriptions, if any
 +      for (var key in data) {
 +        var id, prop, index = key.lastIndexOf('.');
 +        if (index > 0) { // an attribute has been specified
 +          id = key.substring(0, index);
 +          prop = key.substr(index + 1);
 +        } else { // no attribute: assuming text content by default
 +          id = key;
 +          prop = gTextProp;
 +        }
 +        if (!gL10nData[id]) {
 +          gL10nData[id] = {};
 +        }
 +        gL10nData[id][prop] = data[key];
 +      }
 +
 +      // trigger callback
-       if (successCallback)
++      if (successCallback) {
 +        successCallback();
++      }
 +    }, failureCallback, gAsyncResourceLoading);
-   };
++  }
 +
 +  // load and parse all resources for the specified locale
 +  function loadLocale(lang, callback) {
++    callback = callback || function _callback() {};
++
 +    clear();
 +    gLanguage = lang;
 +
 +    // check all <link type="application/l10n" href="..." /> nodes
 +    // and load the resource files
 +    var langLinks = getL10nResourceLinks();
 +    var langCount = langLinks.length;
-     if (langCount == 0) {
-       consoleWarn('no resource to load, early way out');
++    if (langCount === 0) {
++      // we might have a pre-compiled dictionary instead
++      var dict = getL10nDictionary();
++      if (dict && dict.locales && dict.default_locale) {
++        console.log('using the embedded JSON directory, early way out');
++        gL10nData = dict.locales[lang] || dict.locales[dict.default_locale];
++        callback();
++      } else {
++        console.log('no resource to load, early way out');
++      }
++      // early way out
 +      fireL10nReadyEvent(lang);
 +      gReadyState = 'complete';
 +      return;
 +    }
 +
 +    // start the callback when all resources are loaded
 +    var onResourceLoaded = null;
 +    var gResourceCount = 0;
 +    onResourceLoaded = function() {
 +      gResourceCount++;
 +      if (gResourceCount >= langCount) {
-         if (callback) // execute the [optional] callback
-           callback();
++        callback();
 +        fireL10nReadyEvent(lang);
 +        gReadyState = 'complete';
 +      }
 +    };
 +
 +    // load all resource files
-     function l10nResourceLink(link) {
++    function L10nResourceLink(link) {
 +      var href = link.href;
 +      var type = link.type;
 +      this.load = function(lang, callback) {
 +        var applied = lang;
 +        parseResource(href, lang, callback, function() {
-           consoleWarn(href + ' not found.');
++          console.warn(href + ' not found.');
 +          applied = '';
 +        });
 +        return applied; // return lang if found, an empty string if not found
 +      };
 +    }
 +
 +    for (var i = 0; i < langCount; i++) {
-       var resource = new l10nResourceLink(langLinks[i]);
++      var resource = new L10nResourceLink(langLinks[i]);
 +      var rv = resource.load(lang, onResourceLoaded);
 +      if (rv != lang) { // lang not found, used default resource instead
-         consoleWarn('"' + lang + '" resource not found');
++        console.warn('"' + lang + '" resource not found');
 +        gLanguage = '';
 +      }
 +    }
 +  }
 +
 +  // clear all l10n data
 +  function clear() {
 +    gL10nData = {};
 +    gTextData = '';
 +    gLanguage = '';
 +    // TODO: clear all non predefined macros.
 +    // There's no such macro /yet/ but we're planning to have some...
 +  }
 +
 +
 +  /**
 +   * Get rules for plural forms (shared with JetPack), see:
 +   * http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html
 +   * https://github.com/mozilla/addon-sdk/blob/master/python-lib/plural-rules-generator.p
 +   *
 +   * @param {string} lang
 +   *    locale (language) used.
 +   *
 +   * @return {Function}
 +   *    returns a function that gives the plural form name for a given integer:
 +   *       var fun = getPluralRules('en');
 +   *       fun(1)    -> 'one'
 +   *       fun(0)    -> 'other'
 +   *       fun(1000) -> 'other'.
 +   */
 +
 +  function getPluralRules(lang) {
 +    var locales2rules = {
 +      'af': 3,
 +      'ak': 4,
 +      'am': 4,
 +      'ar': 1,
 +      'asa': 3,
 +      'az': 0,
 +      'be': 11,
 +      'bem': 3,
 +      'bez': 3,
 +      'bg': 3,
 +      'bh': 4,
 +      'bm': 0,
 +      'bn': 3,
 +      'bo': 0,
 +      'br': 20,
 +      'brx': 3,
 +      'bs': 11,
 +      'ca': 3,
 +      'cgg': 3,
 +      'chr': 3,
 +      'cs': 12,
 +      'cy': 17,
 +      'da': 3,
 +      'de': 3,
 +      'dv': 3,
 +      'dz': 0,
 +      'ee': 3,
 +      'el': 3,
 +      'en': 3,
 +      'eo': 3,
 +      'es': 3,
 +      'et': 3,
 +      'eu': 3,
 +      'fa': 0,
 +      'ff': 5,
 +      'fi': 3,
 +      'fil': 4,
 +      'fo': 3,
 +      'fr': 5,
 +      'fur': 3,
 +      'fy': 3,
 +      'ga': 8,
 +      'gd': 24,
 +      'gl': 3,
 +      'gsw': 3,
 +      'gu': 3,
 +      'guw': 4,
 +      'gv': 23,
 +      'ha': 3,
 +      'haw': 3,
 +      'he': 2,
 +      'hi': 4,
 +      'hr': 11,
 +      'hu': 0,
 +      'id': 0,
 +      'ig': 0,
 +      'ii': 0,
 +      'is': 3,
 +      'it': 3,
 +      'iu': 7,
 +      'ja': 0,
 +      'jmc': 3,
 +      'jv': 0,
 +      'ka': 0,
 +      'kab': 5,
 +      'kaj': 3,
 +      'kcg': 3,
 +      'kde': 0,
 +      'kea': 0,
 +      'kk': 3,
 +      'kl': 3,
 +      'km': 0,
 +      'kn': 0,
 +      'ko': 0,
 +      'ksb': 3,
 +      'ksh': 21,
 +      'ku': 3,
 +      'kw': 7,
 +      'lag': 18,
 +      'lb': 3,
 +      'lg': 3,
 +      'ln': 4,
 +      'lo': 0,
 +      'lt': 10,
 +      'lv': 6,
 +      'mas': 3,
 +      'mg': 4,
 +      'mk': 16,
 +      'ml': 3,
 +      'mn': 3,
 +      'mo': 9,
 +      'mr': 3,
 +      'ms': 0,
 +      'mt': 15,
 +      'my': 0,
 +      'nah': 3,
 +      'naq': 7,
 +      'nb': 3,
 +      'nd': 3,
 +      'ne': 3,
 +      'nl': 3,
 +      'nn': 3,
 +      'no': 3,
 +      'nr': 3,
 +      'nso': 4,
 +      'ny': 3,
 +      'nyn': 3,
 +      'om': 3,
 +      'or': 3,
 +      'pa': 3,
 +      'pap': 3,
 +      'pl': 13,
 +      'ps': 3,
 +      'pt': 3,
 +      'rm': 3,
 +      'ro': 9,
 +      'rof': 3,
 +      'ru': 11,
 +      'rwk': 3,
 +      'sah': 0,
 +      'saq': 3,
 +      'se': 7,
 +      'seh': 3,
 +      'ses': 0,
 +      'sg': 0,
 +      'sh': 11,
 +      'shi': 19,
 +      'sk': 12,
 +      'sl': 14,
 +      'sma': 7,
 +      'smi': 7,
 +      'smj': 7,
 +      'smn': 7,
 +      'sms': 7,
 +      'sn': 3,
 +      'so': 3,
 +      'sq': 3,
 +      'sr': 11,
 +      'ss': 3,
 +      'ssy': 3,
 +      'st': 3,
 +      'sv': 3,
 +      'sw': 3,
 +      'syr': 3,
 +      'ta': 3,
 +      'te': 3,
 +      'teo': 3,
 +      'th': 0,
 +      'ti': 4,
 +      'tig': 3,
 +      'tk': 3,
 +      'tl': 4,
 +      'tn': 3,
 +      'to': 0,
 +      'tr': 0,
 +      'ts': 3,
 +      'tzm': 22,
 +      'uk': 11,
 +      'ur': 3,
 +      've': 3,
 +      'vi': 0,
 +      'vun': 3,
 +      'wa': 4,
 +      'wae': 3,
 +      'wo': 0,
 +      'xh': 3,
 +      'xog': 3,
 +      'yo': 0,
 +      'zh': 0,
 +      'zu': 3
 +    };
 +
 +    // utility functions for plural rules methods
 +    function isIn(n, list) {
 +      return list.indexOf(n) !== -1;
 +    }
 +    function isBetween(n, start, end) {
 +      return start <= n && n <= end;
 +    }
 +
 +    // list of all plural rules methods:
 +    // map an integer to the plural form name to use
 +    var pluralRules = {
 +      '0': function(n) {
 +        return 'other';
 +      },
 +      '1': function(n) {
 +        if ((isBetween((n % 100), 3, 10)))
 +          return 'few';
 +        if (n === 0)
 +          return 'zero';
 +        if ((isBetween((n % 100), 11, 99)))
 +          return 'many';
 +        if (n == 2)
 +          return 'two';
 +        if (n == 1)
 +          return 'one';
 +        return 'other';
 +      },
 +      '2': function(n) {
 +        if (n !== 0 && (n % 10) === 0)
 +          return 'many';
 +        if (n == 2)
 +          return 'two';
 +        if (n == 1)
 +          return 'one';
 +        return 'other';
 +      },
 +      '3': function(n) {
 +        if (n == 1)
 +          return 'one';
 +        return 'other';
 +      },
 +      '4': function(n) {
 +        if ((isBetween(n, 0, 1)))
 +          return 'one';
 +        return 'other';
 +      },
 +      '5': function(n) {
 +        if ((isBetween(n, 0, 2)) && n != 2)
 +          return 'one';
 +        return 'other';
 +      },
 +      '6': function(n) {
 +        if (n === 0)
 +          return 'zero';
 +        if ((n % 10) == 1 && (n % 100) != 11)
 +          return 'one';
 +        return 'other';
 +      },
 +      '7': function(n) {
 +        if (n == 2)
 +          return 'two';
 +        if (n == 1)
 +          return 'one';
 +        return 'other';
 +      },
 +      '8': function(n) {
 +        if ((isBetween(n, 3, 6)))
 +          return 'few';
 +        if ((isBetween(n, 7, 10)))
 +          return 'many';
 +        if (n == 2)
 +          return 'two';
 +        if (n == 1)
 +          return 'one';
 +        return 'other';
 +      },
 +      '9': function(n) {
 +        if (n === 0 || n != 1 && (isBetween((n % 100), 1, 19)))
 +          return 'few';
 +        if (n == 1)
 +          return 'one';
 +        return 'other';
 +      },
 +      '10': function(n) {
 +        if ((isBetween((n % 10), 2, 9)) && !(isBetween((n % 100), 11, 19)))
 +          return 'few';
 +        if ((n % 10) == 1 && !(isBetween((n % 100), 11, 19)))
 +          return 'one';
 +        return 'other';
 +      },
 +      '11': function(n) {
 +        if ((isBetween((n % 10), 2, 4)) && !(isBetween((n % 100), 12, 14)))
 +          return 'few';
 +        if ((n % 10) === 0 ||
 +            (isBetween((n % 10), 5, 9)) ||
 +            (isBetween((n % 100), 11, 14)))
 +          return 'many';
 +        if ((n % 10) == 1 && (n % 100) != 11)
 +          return 'one';
 +        return 'other';
 +      },
 +      '12': function(n) {
 +        if ((isBetween(n, 2, 4)))
 +          return 'few';
 +        if (n == 1)
 +          return 'one';
 +        return 'other';
 +      },
 +      '13': function(n) {
 +        if ((isBetween((n % 10), 2, 4)) && !(isBetween((n % 100), 12, 14)))
 +          return 'few';
 +        if (n != 1 && (isBetween((n % 10), 0, 1)) ||
 +            (isBetween((n % 10), 5, 9)) ||
 +            (isBetween((n % 100), 12, 14)))
 +          return 'many';
 +        if (n == 1)
 +          return 'one';
 +        return 'other';
 +      },
 +      '14': function(n) {
 +        if ((isBetween((n % 100), 3, 4)))
 +          return 'few';
 +        if ((n % 100) == 2)
 +          return 'two';
 +        if ((n % 100) == 1)
 +          return 'one';
 +        return 'other';
 +      },
 +      '15': function(n) {
 +        if (n === 0 || (isBetween((n % 100), 2, 10)))
 +          return 'few';
 +        if ((isBetween((n % 100), 11, 19)))
 +          return 'many';
 +        if (n == 1)
 +          return 'one';
 +        return 'other';
 +      },
 +      '16': function(n) {
 +        if ((n % 10) == 1 && n != 11)
 +          return 'one';
 +        return 'other';
 +      },
 +      '17': function(n) {
 +        if (n == 3)
 +          return 'few';
 +        if (n === 0)
 +          return 'zero';
 +        if (n == 6)
 +          return 'many';
 +        if (n == 2)
 +          return 'two';
 +        if (n == 1)
 +          return 'one';
 +        return 'other';
 +      },
 +      '18': function(n) {
 +        if (n === 0)
 +          return 'zero';
 +        if ((isBetween(n, 0, 2)) && n !== 0 && n != 2)
 +          return 'one';
 +        return 'other';
 +      },
 +      '19': function(n) {
 +        if ((isBetween(n, 2, 10)))
 +          return 'few';
 +        if ((isBetween(n, 0, 1)))
 +          return 'one';
 +        return 'other';
 +      },
 +      '20': function(n) {
 +        if ((isBetween((n % 10), 3, 4) || ((n % 10) == 9)) && !(
 +            isBetween((n % 100), 10, 19) ||
 +            isBetween((n % 100), 70, 79) ||
 +            isBetween((n % 100), 90, 99)
 +            ))
 +          return 'few';
 +        if ((n % 1000000) === 0 && n !== 0)
 +          return 'many';
 +        if ((n % 10) == 2 && !isIn((n % 100), [12, 72, 92]))
 +          return 'two';
 +        if ((n % 10) == 1 && !isIn((n % 100), [11, 71, 91]))
 +          return 'one';
 +        return 'other';
 +      },
 +      '21': function(n) {
 +        if (n === 0)
 +          return 'zero';
 +        if (n == 1)
 +          return 'one';
 +        return 'other';
 +      },
 +      '22': function(n) {
 +        if ((isBetween(n, 0, 1)) || (isBetween(n, 11, 99)))
 +          return 'one';
 +        return 'other';
 +      },
 +      '23': function(n) {
 +        if ((isBetween((n % 10), 1, 2)) || (n % 20) === 0)
 +          return 'one';
 +        return 'other';
 +      },
 +      '24': function(n) {
 +        if ((isBetween(n, 3, 10) || isBetween(n, 13, 19)))
 +          return 'few';
 +        if (isIn(n, [2, 12]))
 +          return 'two';
 +        if (isIn(n, [1, 11]))
 +          return 'one';
 +        return 'other';
 +      }
 +    };
 +
 +    // return a function that gives the plural form name for a given integer
 +    var index = locales2rules[lang.replace(/-.*$/, '')];
 +    if (!(index in pluralRules)) {
-       consoleWarn('plural form unknown for [' + lang + ']');
++      console.warn('plural form unknown for [' + lang + ']');
 +      return function() { return 'other'; };
 +    }
 +    return pluralRules[index];
 +  }
 +
 +  // pre-defined 'plural' macro
 +  gMacros.plural = function(str, param, key, prop) {
 +    var n = parseFloat(param);
 +    if (isNaN(n))
 +      return str;
 +
 +    // TODO: support other properties (l20n still doesn't...)
 +    if (prop != gTextProp)
 +      return str;
 +
 +    // initialize _pluralRules
-     if (!gMacros._pluralRules)
++    if (!gMacros._pluralRules) {
 +      gMacros._pluralRules = getPluralRules(gLanguage);
++    }
 +    var index = '[' + gMacros._pluralRules(n) + ']';
 +
 +    // try to find a [zero|one|two] key if it's defined
 +    if (n === 0 && (key + '[zero]') in gL10nData) {
 +      str = gL10nData[key + '[zero]'][prop];
 +    } else if (n == 1 && (key + '[one]') in gL10nData) {
 +      str = gL10nData[key + '[one]'][prop];
 +    } else if (n == 2 && (key + '[two]') in gL10nData) {
 +      str = gL10nData[key + '[two]'][prop];
 +    } else if ((key + index) in gL10nData) {
 +      str = gL10nData[key + index][prop];
++    } else if ((key + '[other]') in gL10nData) {
++      str = gL10nData[key + '[other]'][prop];
 +    }
 +
 +    return str;
 +  };
 +
 +
 +  /**
 +   * l10n dictionary functions
 +   */
 +
 +  // fetch an l10n object, warn if not found, apply `args' if possible
 +  function getL10nData(key, args, fallback) {
 +    var data = gL10nData[key];
 +    if (!data) {
-       consoleWarn('#' + key + ' missing for [' + gLanguage + ']');
++      console.warn('#' + key + ' is undefined.');
 +      if (!fallback) {
 +        return null;
 +      }
 +      data = fallback;
 +    }
 +
 +    /** This is where l10n expressions should be processed.
 +      * The plan is to support C-style expressions from the l20n project;
 +      * until then, only two kinds of simple expressions are supported:
 +      *   {[ index ]} and {{ arguments }}.
 +      */
 +    var rv = {};
 +    for (var prop in data) {
 +      var str = data[prop];
 +      str = substIndexes(str, args, key, prop);
-       str = substArguments(str, args);
++      str = substArguments(str, args, key);
 +      rv[prop] = str;
 +    }
 +    return rv;
 +  }
 +
 +  // replace {[macros]} with their values
 +  function substIndexes(str, args, key, prop) {
 +    var reIndex = /\{\[\s*([a-zA-Z]+)\(([a-zA-Z]+)\)\s*\]\}/;
 +    var reMatch = reIndex.exec(str);
 +    if (!reMatch || !reMatch.length)
 +      return str;
 +
 +    // an index/macro has been found
 +    // Note: at the moment, only one parameter is supported
 +    var macroName = reMatch[1];
 +    var paramName = reMatch[2];
 +    var param;
 +    if (args && paramName in args) {
 +      param = args[paramName];
 +    } else if (paramName in gL10nData) {
 +      param = gL10nData[paramName];
 +    }
 +
 +    // there's no macro parser yet: it has to be defined in gMacros
 +    if (macroName in gMacros) {
 +      var macro = gMacros[macroName];
 +      str = macro(str, param, key, prop);
 +    }
 +    return str;
 +  }
 +
 +  // replace {{arguments}} with their values
-   function substArguments(str, args) {
-     var reArgs = /\{\{\s*([a-zA-Z\.]+)\s*\}\}/;
++  function substArguments(str, args, key) {
++    var reArgs = /\{\{\s*(.+?)\s*\}\}/;
 +    var match = reArgs.exec(str);
 +    while (match) {
 +      if (!match || match.length < 2)
 +        return str; // argument key not found
 +
 +      var arg = match[1];
 +      var sub = '';
-       if (arg in args) {
++      if (args && arg in args) {
 +        sub = args[arg];
 +      } else if (arg in gL10nData) {
 +        sub = gL10nData[arg][gTextProp];
 +      } else {
-         consoleWarn('could not find argument {{' + arg + '}}');
++        console.log('argument {{' + arg + '}} for #' + key + ' is undefined.');
 +        return str;
 +      }
 +
 +      str = str.substring(0, match.index) + sub +
 +            str.substr(match.index + match[0].length);
 +      match = reArgs.exec(str);
 +    }
 +    return str;
 +  }
 +
 +  // translate an HTML element
 +  function translateElement(element) {
 +    var l10n = getL10nAttributes(element);
 +    if (!l10n.id)
 +      return;
 +
 +    // get the related l10n object
 +    var data = getL10nData(l10n.id, l10n.args);
 +    if (!data) {
-       consoleWarn('#' + l10n.id + ' missing for [' + gLanguage + ']');
++      console.warn('#' + l10n.id + ' is undefined.');
 +      return;
 +    }
 +
 +    // translate element (TODO: security checks?)
-     // for the node content, replace the content of the first child textNode
-     // and clear other child textNodes
 +    if (data[gTextProp]) { // XXX
-       if (element.children.length === 0) {
++      if (getChildElementCount(element) === 0) {
 +        element[gTextProp] = data[gTextProp];
 +      } else {
-         var children = element.childNodes,
-             found = false;
++        // this element has element children: replace the content of the first
++        // (non-empty) child textNode and clear other child textNodes
++        var children = element.childNodes;
++        var found = false;
 +        for (var i = 0, l = children.length; i < l; i++) {
-           if (children[i].nodeType === 3 &&
-               /\S/.test(children[i].textContent)) { // XXX
-             // using nodeValue seems cross-browser
++          if (children[i].nodeType === 3 && /\S/.test(children[i].nodeValue)) {
 +            if (found) {
 +              children[i].nodeValue = '';
 +            } else {
 +              children[i].nodeValue = data[gTextProp];
 +              found = true;
 +            }
 +          }
 +        }
++        // if no (non-empty) textNode is found, insert a textNode before the
++        // first element child.
 +        if (!found) {
-           consoleWarn('unexpected error, could not translate element content');
++          var textNode = document.createTextNode(data[gTextProp]);
++          element.insertBefore(textNode, element.firstChild);
 +        }
 +      }
 +      delete data[gTextProp];
 +    }
 +
 +    for (var k in data) {
 +      element[k] = data[k];
 +    }
 +  }
 +
++  // webkit browsers don't currently support 'children' on SVG elements...
++  function getChildElementCount(element) {
++    if (element.children) {
++      return element.children.length;
++    }
++    if (typeof element.childElementCount !== 'undefined') {
++      return element.childElementCount;
++    }
++    var count = 0;
++    for (var i = 0; i < element.childNodes.length; i++) {
++      count += element.nodeType === 1 ? 1 : 0;
++    }
++    return count;
++  }
++
 +  // translate an HTML subtree
 +  function translateFragment(element) {
 +    element = element || document.documentElement;
 +
 +    // check all translatable children (= w/ a `data-l10n-id' attribute)
 +    var children = getTranslatableChildren(element);
 +    var elementCount = children.length;
 +    for (var i = 0; i < elementCount; i++) {
 +      translateElement(children[i]);
 +    }
 +
 +    // translate element itself if necessary
 +    translateElement(element);
 +  }
 +
 +  // cross-browser API (sorry, oldIE doesn't support getters & setters)
 +  return {
 +    // get a localized string
-     get: function(key, args, fallback) {
-       var data = getL10nData(key, args, {textContent: fallback});
-       if (data) { // XXX double-check this
-         return 'textContent' in data ? data.textContent : '';
++    get: function(key, args, fallbackString) {
++      var index = key.lastIndexOf('.');
++      var prop = gTextProp;
++      if (index > 0) { // An attribute has been specified
++        prop = key.substr(index + 1);
++        key = key.substring(0, index);
++      }
++      var fallback;
++      if (fallbackString) {
++        fallback = {};
++        fallback[prop] = fallbackString;
++      }
++      var data = getL10nData(key, args, fallback);
++      if (data && prop in data) {
++        return data[prop];
 +      }
 +      return '{{' + key + '}}';
 +    },
 +
 +    // debug
 +    getData: function() { return gL10nData; },
 +    getText: function() { return gTextData; },
 +
 +    // get|set the document language
 +    getLanguage: function() { return gLanguage; },
 +    setLanguage: function(lang) { loadLocale(lang, translateFragment); },
 +
 +    // get the direction (ltr|rtl) of the current language
 +    getDirection: function() {
 +      // http://www.w3.org/International/questions/qa-scripts
 +      // Arabic, Hebrew, Farsi, Pashto, Urdu
 +      var rtlList = ['ar', 'he', 'fa', 'ps', 'ur'];
 +      return (rtlList.indexOf(gLanguage) >= 0) ? 'rtl' : 'ltr';
 +    },
 +
 +    // translate an element or document fragment
 +    translate: translateFragment,
 +
 +    // this can be used to prevent race conditions
-     getReadyState: function() { return gReadyState; }
++    getReadyState: function() { return gReadyState; },
++    ready: function(callback) {
++      if (!callback) {
++        return;
++      } else if (gReadyState == 'complete' || gReadyState == 'interactive') {
++        window.setTimeout(callback);
++      } else if (document.addEventListener) {
++        document.addEventListener('localized', callback);
++      } else if (document.attachEvent) {
++        document.documentElement.attachEvent('onpropertychange', function(e) {
++          if (e.propertyName === 'localized') {
++            callback();
++          }
++        });
++      }
++    }
 +  };
- 
 +}) (window, document);
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/locale/ar/viewer.properties
index 954436e,0000000..0c6e943
mode 100644,000000..100644
--- a/apps/files_pdfviewer/3rdparty/pdfjs/locale/ar/viewer.properties
+++ b/apps/files_pdfviewer/3rdparty/pdfjs/locale/ar/viewer.properties
@@@ -1,111 -1,0 +1,112 @@@
 +# 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=طباعة
 +fullscreen.title=ملء الشاشة
 +fullscreen_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=تدوير عكس عقارب الساعة
++
 +# 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=بحث
 +
- # 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}}
 +
- # Context menu
- page_rotate_cw.label=تدوير مع عقارب الساعة
- page_rotate_ccw.label=تدوير عكس عقارب الساعة
- 
 +# Find panel button title and messages
 +find=بحث
 +find_terms_not_found=(لا يوجد)
 +
 +# 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}}
 +# 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
 +
- # 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}}]
++text_annotation_type.alt=[ملاحظة {{type}}]
 +request_password=الـPDF محمي بكلمة مرور:
 +
 +printing_not_supported=تحذير: الطباعة ليست مدعومة كليًا في هذا المتصفح.
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/locale/bn-BD/viewer.properties
index 0000000,0000000..22466ab
new file mode 100644
--- /dev/null
+++ b/apps/files_pdfviewer/3rdparty/pdfjs/locale/bn-BD/viewer.properties
@@@ -1,0 -1,0 +1,157 @@@
++# 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=পাতা:
++
++zoom_out.title=জুম-আউট করুন
++zoom_out_label=জুম-আউট করুন
++zoom_in.title=জুম-ইন করুন
++zoom_in_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=বর্তমান ভিউ
++
++# 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 করুন
++toggle_sidebar_label=সাইডবার Toggle করুন
++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_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=অসমর্থিত বা করাপ্ট হওয়া পিডিএফ ফাইল।
++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"
++password_label=পিডিএফ টি খুলতে পাসওয়ার্ড প্রবেশ করান।
++password_invalid=ভুল পাসওয়ার্ড । অনুগ্রহ করে আবার চেষ্টা করুন।
++password_ok=ঠিক আছে
++password_cancel=বাতিল
++
++printing_not_supported=সতর্কবার্তা: এই ব্রাউজারে প্রিন্ট করা সম্পুর্নভাবে সমর্থিত নয়
++printing_not_ready=সতর্কবার্তা: পিডিএফ ফাইল সম্পুর্নভাবে প্রিন্ট করার জন্য লোড হয়নি।
++web_fonts_disabled=ওয়েব ফন্ট Disable রয়েছে: এমবেডেড পিডিএফ ফন্ট ব্যাবহার করা যাচ্ছে না
++document_colors_disabled=পিডিএফ ফাইলসমূহ তাদের নিজস্ব রঙ ব্যাবহার করতে পারবে না: \'Allow pages to choose their own colors\' অপশনটি ব্রাউজারে বন্ধ রয়েছে।
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/locale/ca/viewer.properties
index 26e8774,0000000..b3f97c3
mode 100644,000000..100644
--- a/apps/files_pdfviewer/3rdparty/pdfjs/locale/ca/viewer.properties
+++ b/apps/files_pdfviewer/3rdparty/pdfjs/locale/ca/viewer.properties
@@@ -1,127 -1,0 +1,131 @@@
 +# 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ó
- print.title=Imprimir
- print_label=Imprimir
- fullscreen.title=Pantalla completa
- fullscreen_label=Pantalla completa
 +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
 +
- # Document outline messages
- no_outline=No hi ha cap esquema disponible
- 
 +# 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)
- # Context menu
- first_page.label=Primera pàgina
- last_page.label=Darrera pàgina
- page_rotate_cw.label=Rotar sentit horari
- page_rotate_ccw.label=Rotar sentit anti-horari
 +
 +# 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): 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=[Anotació {{type}}]
++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.
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/locale/cs/viewer.properties
index 629480f,0000000..cd6f409
mode 100644,000000..100644
--- a/apps/files_pdfviewer/3rdparty/pdfjs/locale/cs/viewer.properties
+++ b/apps/files_pdfviewer/3rdparty/pdfjs/locale/cs/viewer.properties
@@@ -1,59 -1,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.
 +
- 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
++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šit
++zoom_out_label=Zmenšit
 +zoom_in.title=Zvětšit
++zoom_in_label=Přiblížit
++zoom.title=Zvětšit
++presentation_mode.title=Přepnout do prezentačního režimu
++presentation_mode_label=Prezentační režim
++open_file.title=Otevřít soubor
++open_file_label=Otevřít
++print.title=Tisk
++print_label=Tisk
++download.title=Stáhnout
++download_label=Stáhnout
++bookmark.title=Aktuální zobrazení (zkopírovat nebo otevřít v novém okně)
++bookmark_label=Aktuální zobrazení
++
++# Secondary toolbar and context menu
++tools.title=Nástroje
++tools_label=Nástroje
++first_page.title=Přejít 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řejít 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čit ve směru hodinových ručiček
++page_rotate_cw.label=Otočit ve směru hodinových ručiček
++page_rotate_cw_label=Otočit ve směru hodinových ručiček
++page_rotate_ccw.title=Otočit proti směru hodinových ručiček
++page_rotate_ccw.label=Otočit proti směru hodinových ručiček
++page_rotate_ccw_label=Otočit proti směru hodinových ručiček
++
++hand_tool_enable.title=Zapnout ručičku
++hand_tool_enable_label=Zapnout ručičku
++hand_tool_disable.title=Vypnout ručičku
++hand_tool_disable_label=Vypnout ručičku
++
++# 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=Název:
++document_properties_author=Autor:
++document_properties_subject=Předmět:
++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=Tvůrce:
++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=Přepnout posuvník
++toggle_sidebar_label=Přepnout posuvník
++outline.title=Zobrazit osnovu dokumentu
++outline_label=Přehled dokumentu
++thumbs.title=Zobrazit náhledy
++thumbs_label=Náhledy
++findbar.title=Najít 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=Stránka {{page}}
++# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
++# number.
++thumb_page_canvas=Náhled stránky {{page}}
++
++# Find panel button title and messages
++find_label=Najít:
++find_previous.title=Najít předchozí výskyt výrazu
++find_previous_label=Předchozí
++find_next.title=Najít další výskyt výrazu
++find_next_label=Další
++find_highlight=Zvýraznit vše
++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 od začátku
++find_not_found=Výraz nenalezen
++
++# 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}}
- error_file=Soubor:{{file}}
- error_line=Řádek:{{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}} (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=Stack: {{stack}}
++# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
++error_file=Soubor: {{file}}
++# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
++error_line=Řádek: {{line}}
++rendering_error=Došlo k chybě při vykreslování stránky.
++
++# Predefined zoom values
 +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}}%
++
++# 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}}
- no_outline=Žádné osnovy k dispozici
- open_file.title=Otevřít soubor
- text_annotation_type=[{{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:
++invalid_file_error=Nesprávný nebo poškozený soubor PDF.
++missing_file_error=Chybějící 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=[{{type}} anotace]
++password_label=Zadejte heslo k otevření tohoto soubor PDF.
++password_invalid=Nesprávné heslo. Prosím, zkuste to znovu.
++password_ok=OK
++password_cancel=Zrušit
++
++printing_not_supported=Varování: Tisk není plně podporován tímto prohlížečem.
++printing_not_ready=Varování: PDF není zcela nahrán pro tisk.
++web_fonts_disabled=Webové písma jsou vypnuty: Není možnost použít vložené fonty PDF.
++document_colors_disabled=Dokumentu PDF není povoleno používat jejich vlastní barvy: \'Povolit stránkám vybrat si jejich vlastní barvy\' je deaktivováno v prohlížeči.
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/locale/cy/viewer.properties
index 0000000,0000000..2133dab
new file mode 100644
--- /dev/null
+++ b/apps/files_pdfviewer/3rdparty/pdfjs/locale/cy/viewer.properties
@@@ -1,0 -1,0 +1,134 @@@
++# 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=Tudalen Flaenorol
++previous_label=Blaenorol
++next.title=Nesaf Tudalen
++next_label=Nesaf
++
++# 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=Tudalen:
++page_of=o {{pageCount}}
++
++zoom_out.title=Chwyddo Allan
++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
++open_file.title=Agor Ffeil
++open_file_label=Agor
++print.title=Llwyth
++print_label=Argraffu
++download.title=Lawrlwytho
++download_label=Llwytho i Lawr
++bookmark.title=Golwg cyfredol (copïo neu agor ffenestr newydd)
++bookmark_label=Golwg cyfredol
++
++# Secondary toolbar and context menu
++tools.title=Offer
++tools_label=Offer
++first_page.title=Mynd i'r Dudalen Gyntaf
++first_page.label=Mynd i'r Dudalen Gyntaf
++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
++
++# 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=Toglo'r Bar Ochr
++toggle_sidebar_label=Toglo'r Bar Ochr
++outline.title=Dangos Amlinell Dogfen
++outline_label=Amlinelliad Dogfen
++thumbs.title=Dangos Lluniau Bach
++thumbs_label=Lluniau Bach
++findbar.title=Canfod yn y Ddogfen
++findbar_label=Canfod
++
++# 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=Tudalen {{page}}
++# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
++# number.
++thumb_page_canvas=Llun Bach Tudalen {{page}}
++
++# Find panel button title and messages
++find_label=Canfod:
++find_previous.title=Canfod enghraifft flaenorol o'r ymadrodd
++find_previous_label=Blaenorol
++find_next.title=Canfod enghraifft nesaf yr ymadrodd
++find_next_label=Nesaf
++find_highlight=Amlygu popeth
++find_match_case_label=Cydweddu maint
++find_reached_top=Wedi cyrraedd brig y dudalen, parhau o'r gwaelod
++find_reached_bottom=Wedi cyrraedd diwedd y dudalen, parhau o'r brig
++find_not_found=Heb ganfod ymadrodd
++
++# Error panel labels
++error_more_info=Rhagor o Wybodaeth
++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}})
++# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
++# english string describing the error.
++error_message=Neges: {{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=Ffeil: {{file}}
++# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
++error_line=Llinell: {{line}}
++rendering_error=Digwyddodd gwall wrth adeiladu'r dudalen.
++
++# Predefined zoom values
++page_scale_width=Lled Tudalen
++page_scale_fit=Ffit Tudalen
++page_scale_auto=Chwyddo Awtomatig
++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.
++
++# 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.
++
++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.
++web_fonts_disabled=Ffontiau gwe wedi eu hanablu: methu defnyddio ffontiau PDF mewnblanedig.
++document_colors_disabled=Nid oes caniatâd i ddogfennau PDF i ddefnyddio eu lliwiau eu hunain: Mae 'Caniatáu i dudalennau ddefnyddio eu lliwiau eu hunain' wedi ei atal yn y porwr.
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/locale/da/viewer.properties
index c710189,0000000..fe97b4b
mode 100644,000000..100644
--- a/apps/files_pdfviewer/3rdparty/pdfjs/locale/da/viewer.properties
+++ b/apps/files_pdfviewer/3rdparty/pdfjs/locale/da/viewer.properties
@@@ -1,107 -1,0 +1,132 @@@
 +# 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.
 +
 +# Værktøjslinje knapper (tooltups og billedtekster)
 +previous.title=Forrige
 +previous_label=Forrige
 +next.title=Næste
 +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
 +page_label=Side:
 +page_of=af {{pageCount}}
 +
 +zoom_out.title=Zoom ud
 +zoom_out_label=Zoom ud
 +zoom_in.title=Zoom ind
 +zoom_in_label=Zoom ind
 +zoom.title=Zoom
- print_label=Udskriv
- print.title=Udskriv
 +fullscreen.title=Fuldskærm
 +fullscreen_label=Fuldskærm
 +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
++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
++
 +# 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
 +
- # Dokumentoversigtsbeskeder
- no_outline=Ingen dokumentoversigt tilgængelig
- 
 +# Thumbnails panelet (tooltips og alt. billedtekst)
 +# Oversættelsesnote: "{{page}}" vil blive erstattet af det
 +# egentlige sidetal
 +thumb_page_title=Side {{page}}
 +# Oversættelsesnote: "{{page}}" vil blive erstattet af det
 +# egentlige sidetal
 +thumb_page_canvas=Thumbnail af side {{page}}
 +
- # Søgepanelet
- find=Søg
- find_terms_not_found=(Ikke fundet)
++# Søgepanelet samt knapper og beskeder
++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_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_more_info=Mere information
 +error_less_info=Mindre information
 +error_close=Luk
- # Oversættelsesnote: "{{build}}" vil blive erstattet af PDF.JS build nummer
- #
- error_build=PDF.JS Build: {{build}}
- # Oversættelsesnote: "{{message}}" vil blive erstattet af en (engelsk) fejlbesked
- #
++# Oversættelsesnote: "{{version}}" og "{{build}}" vil blive erstattet af
++# PDF.JS versionen og 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
 +error_file=Fil: {{file}}
 +# Oversættelsesnote: "{{line}}" vil blive erstattet af et linjetal
 +error_line=Linje: {{line}}
 +rendering_error=Der skete en fejl under gengivelsen af PDF-filen
 +
 +# Prædefinerede zoom værdier
 +page_scale_width=Sidebredde
 +page_scale_fit=Helside
 +page_scale_auto=Automatisk zoom
 +page_scale_actual=Faktisk størrelse
 +
 +# Indlæsningsindikator (load ikon)
 +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
 +
 +# 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=[{{type}} Kommentar]
++text_annotation_type.alt=[{{type}} Kommentar]
 +request_password=PDF filen er beskyttet med et kodeord:
++invalid_password=Ugyldigt kodeord.
 +
- printing_not_supported=Advarsel: Denne browser er ikke fuldt understøttet ved udskrift
++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.
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/locale/de/viewer.properties
index 0e37c01,0000000..cb7761b
mode 100644,000000..100644
--- a/apps/files_pdfviewer/3rdparty/pdfjs/locale/de/viewer.properties
+++ b/apps/files_pdfviewer/3rdparty/pdfjs/locale/de/viewer.properties
@@@ -1,123 -1,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=Eine Seite zurück
 +previous_label=Zurück
 +next.title=Eine Seite vor
 +next_label=Vor
 +
 +# 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=Seite:
 +page_of=von {{pageCount}}
 +
 +zoom_out.title=Verkleinern
 +zoom_out_label=Verkleinern
 +zoom_in.title=Vergrößern
 +zoom_in_label=Vergrößern
 +zoom.title=Zoom
- print.title=Drucken
- print_label=Drucken
 +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)
 +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
++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
++
++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=Verfasser:
++document_properties_subject=Thema:
++document_properties_keywords=Stichwörter:
++document_properties_creation_date=Erstellt am:
++document_properties_modification_date=Geändert am:
++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=Seitenanzahl:
++document_properties_close=OK
++
 +# 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=Seitenleiste anzeigen
- toggle_slider_label=Seitenleiste
++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
 +findbar_label=Suchen
 +
- # Document outline messages
- no_outline=Kein Inhaltsverzeichnis verfügbar
- 
 +# 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=Seite {{page}}
 +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
 +# number.
 +thumb_page_canvas=Vorschau von Seite {{page}}
 +
- # Context menu
- first_page.label=Erste Seite
- last_page.label=Letzte Seite
- page_rotate_cw.label=Im Uhrzeigersinn drehen
- page_rotate_ccw.label=Entgegen dem Uhrzeigersinn drehen
- 
 +# 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
 +
 +# Error panel labels
 +error_more_info=Mehr Info
 +error_less_info=Weniger Info
 +error_close=Schließen
- # LOCALIZATION NOTE (error_build): "{{build}}" will be replaced by the PDF.JS
- # build ID.
- error_build=PDF.JS Build: {{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=Nachricht: {{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=Datei: {{file}}
 +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
 +error_line=Zeile: {{line}}
- rendering_error=Das PDF konnte nicht angezeigt werden.
++rendering_error=Die PDF-Datei konnte nicht angezeigt werden.
 +
 +# Predefined zoom values
 +page_scale_width=Seitenbreite
 +page_scale_fit=Ganze Seite
 +page_scale_auto=Automatisch
 +page_scale_actual=Originalgröße
 +
 +# Loading indicator messages
 +loading_error_indicator=Fehler
- loading_error=Das PDF konnte nicht geladen werden.
++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.
 +
- # 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}} Annotation]
- request_password=Das PDF ist passwortgeschützt:
++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.
++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.
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/locale/el/viewer.properties
index 0000000,0000000..dfa852f
new file mode 100644
--- /dev/null
+++ b/apps/files_pdfviewer/3rdparty/pdfjs/locale/el/viewer.properties
@@@ -1,0 -1,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= {{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: {{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): 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 προστατεύεται από κωδικό:
++invalid_password=Μη έγκυρος κωδικός.
++
++printing_not_supported=Προειδοποίηση: Η εκτύπωση δεν υποστηρίζεται πλήρως από αυτόν τον περιηγητή.
++printing_not_ready=Προσοχή: Το PDF δεν είναι πλήρως φορτωμένο για εκτύπωση.
++web_fonts_disabled=Οι γραμματοσειρές Web είναι απενεργοποιημένες: δεν είναι δυνατή η χρήση ενσωματωμένων γραμματοσειρών PDF.
++document_colors_disabled=Στα έγγραφα PDF δεν επιτρέπεται να χρησιμοποιούν τα δικά τους χρώματα: Η ρύθμιση \'Επιτρέπεται στις σελίδες να επιλέξουν τα δικά τους χρώματα \' είναι απενεργοποιημένη στο πρόγραμμα περιήγησης.
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/locale/en-US/viewer.properties
index 9255bfc,0000000..a10bb8f
mode 100644,000000..100644
--- a/apps/files_pdfviewer/3rdparty/pdfjs/locale/en-US/viewer.properties
+++ b/apps/files_pdfviewer/3rdparty/pdfjs/locale/en-US/viewer.properties
@@@ -1,125 -1,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
- print.title=Print
- print_label=Print
 +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
 +
- # Document outline messages
- no_outline=No Outline Available
- 
 +# 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=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): 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}} Annotation]
- request_password=PDF is protected by a password:
++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 colors: \'Allow pages to choose their own colors\' is deactivated in the browser.
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/locale/es/viewer.properties
index 7fea36d,0000000..fc8848f
mode 100644,000000..100644
--- a/apps/files_pdfviewer/3rdparty/pdfjs/locale/es/viewer.properties
+++ b/apps/files_pdfviewer/3rdparty/pdfjs/locale/es/viewer.properties
@@@ -1,107 -1,0 +1,141 @@@
- # 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=Ampliar
- zoom_in_label=Ampliar
- zoom.title=Ampliación
- print.title=Imprimir
- print_label=Imprimir
- fullscreen.title=Pantalla completa
- fullscreen_label=Pantalla completa
- open_file.title=Abrir archivo
- open_file_label=Abrir
- download.title=Descargar
- download_label=Descargar
- bookmark.title=Vista actual (copie o abra en una ventana nueva)
- 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_slider.title=Alternar deslizador
- toggle_slider_label=Alternar deslizador
- outline.title=Mostrar esquema del documento
- outline_label=Esquema del documento
- thumbs.title=Mostrar miniaturas
- thumbs_label=Miniaturas
- findbar.title=Buscar en el documento
- findbar_label=Buscar
- 
- # Document outline messages
- no_outline=No hay un esquema disponible
- 
- # 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=Buscar
- find_terms_not_found=(No encontrado)
- 
- # Error panel labels
- error_more_info=Más información
- error_less_info=Menos información
- error_close=Cerrar
- # LOCALIZATION NOTE (error_build): "{{build}}" will be replaced by the PDF.JS
- # build ID.
- error_build=Compilación de PDF.JS: {{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 mientras se renderizaba la página.
- 
- # Predefined zoom values
- page_scale_width=Anchura de página
- page_scale_fit=Ajustar a la página
- page_scale_auto=Ampliación automática
- page_scale_actual=Tamaño real
- 
- # Loading indicator messages
- loading_error_indicator=Error
- loading_error=Ocurrió un error mientras se cargaba el 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=El PDF está protegido con una contraseña:
- 
- printing_not_supported=Aviso: La impresión no es compatible totalmente con este 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 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=Ampliación
++presentation_mode.title=Cambiar al modo de presentación
++presentation_mode_label=Modo de presentación
++open_file.title=Abrir un archivo
++open_file_label=Abrir
++print.title=Imprimir
++print_label=Imprimir
++download.title=Descargar
++download_label=Descargar
++bookmark.title=Vista actual (para copiar o abrir en otra ventana)
++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 la herramienta Mano
++hand_tool_enable_label=Activar la herramienta Mano
++hand_tool_disable.title=Desactivar la herramienta Mano
++hand_tool_disable_label=Desactivar la herramienta Mano
++
++# 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=Mostrar u ocultar la barra lateral
++toggle_sidebar_label=Conmutar la barra lateral
++outline.title=Mostrar el esquema del documento
++outline_label=Esquema del documento
++thumbs.title=Mostrar las 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=Buscar:
++find_previous.title=Ir a la frase encontrada anterior
++find_previous_label=Anterior
++find_next.title=Ir a la frase encontrada siguiente
++find_next_label=Siguiente
++find_highlight=Resaltar todo
++find_match_case_label=Coincidir mayúsculas y minúsculas
++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=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}} (compilación: {{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 renderizar la página.
++
++# Predefined zoom values
++page_scale_width=Anchura de la página
++page_scale_fit=Ajustar a la página
++page_scale_auto=Ampliación automática
++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=El archivo PDF no es válido o está dañado.
++missing_file_error=Falta el archivo 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=Escriba la contraseña para abrir este archivo PDF.
++password_invalid=La contraseña no es válida. Inténtelo de nuevo.
++password_ok=Aceptar
++password_cancel=Cancelar
++
++printing_not_supported=Aviso: Este navegador no es compatible completamente con la impresión.
++printing_not_ready=Aviso: El PDF no se ha cargado completamente para su impresión.
++web_fonts_disabled=Se han desactivado los tipos de letra web: no se pueden usar los tipos de letra incrustados en el PDF.
++document_colors_disabled=No se permite que los documentos PDF usen sus propios colores: la opción «Permitir que las páginas elijan sus propios colores» está desactivada en el navegador.
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/locale/fa/viewer.properties
index 0000000,0000000..8586490
new file mode 100644
--- /dev/null
+++ b/apps/files_pdfviewer/3rdparty/pdfjs/locale/fa/viewer.properties
@@@ -1,0 -1,0 +1,134 @@@
++# Copyright 2013 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=چرخش در خلاف جهت عقربه‌های ساعت
++
++# 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=پی‌دی‌اف.جی‌اس نسخهٔ {{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=خطایی هنگامی بارگیری پی‌دی‌اف روی داد.
++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}}]
++request_password=پی‌دی‌اف توسط یک گذرواژه محافظت شده‌است:
++invalid_password=گذرواژهٔ نامعتبر.
++
++printing_not_supported=اخطار: چاپ توسط این مرورگر به‌صورت کامل پشتبانی نشده‌است.
++printing_not_ready=اخطار: پی‌دی‌اف برای چاپ به‌طور کامل بار نشده‌است.
++web_fonts_disabled=قلم‌های وبی غیر فعال هستند: از قلم‌های توکار پی‌دی‌اف نتوانست استفاده شود.
++document_colors_disabled=اسناد پی‌دی‌اف اجازه ندارند که رنگ‌های خودشان را استفاده کنند: «اجازهٔ انتخاب صفحه‌ها برای انتخاب رنگ‌های خود» در مرورگر غیرفعال شده‌است.
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/locale/fi/viewer.properties
index 809ef0d,0000000..560c948
mode 100644,000000..100644
--- a/apps/files_pdfviewer/3rdparty/pdfjs/locale/fi/viewer.properties
+++ b/apps/files_pdfviewer/3rdparty/pdfjs/locale/fi/viewer.properties
@@@ -1,124 -1,0 +1,129 @@@
 +# 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=Edellinen sivu
 +previous_label=Edellinen
 +next.title=Seuraava sivu
 +next_label=Seuraava
 +
 +# 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=Sivu:
 +page_of=/ {{pageCount}}
 +
 +zoom_out.title=Suurenna
 +zoom_out_label=Suurenna
 +zoom_in.title=Pienennä
 +zoom_in_label=Pienennä
 +zoom.title=Sivun suurennus
- print.title=Tulosta
- print_label=Tulosta
 +presentation_mode.title=Esitystila
 +presentation_mode_label=Esitystila
 +open_file.title=Avaa tiedosto
 +open_file_label=Avaa
++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ä
 +
++# 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
++
 +# 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
 +findbar_label=Etsi
 +
- # Document outline messages
- no_outline=Jäsennystä ei ole tarjolla
- 
 +# 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=Sivu {{page}}
 +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
 +# number.
 +thumb_page_canvas=Sivun {{page}} esikatselukuva
 +
- # Context menu
- first_page.label=Ensimmäinen sivu
- last_page.label=Viimeinen sivu
- page_rotate_cw.label=Kierrä myötäpäivään
- page_rotate_ccw.label=Kierrä vastapäivään
- 
 +# Find panel button title and messages
 +find_label=Etsi
 +find_previous.title=Etsi edellinen
 +find_previous_label=Edellinen
 +find_next.title=Etsi seuraava
 +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
 +
 +# Error panel labels
 +error_more_info=Enemmän tietoa
 +error_less_info=Vähemmän tietoa
 +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}})
 +# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
 +# english string describing the error.
 +error_message=Viesti: {{message}}
 +# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
 +# trace.
 +error_stack=Kutsupino: {{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.
 +
 +# Predefined zoom values
 +page_scale_width=Sivun leveys
 +page_scale_fit=Sivun sovitus
 +page_scale_auto=Automaatinen sivun 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.
 +
- # 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}} Selite]
++text_annotation_type.alt=[{{type}} Selite]
 +request_password=PDF on salasanasuojattu:
 +
 +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ää.
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/locale/fr/viewer.properties
index 1c9abfc,0000000..8c4da82
mode 100644,000000..100644
--- a/apps/files_pdfviewer/3rdparty/pdfjs/locale/fr/viewer.properties
+++ b/apps/files_pdfviewer/3rdparty/pdfjs/locale/fr/viewer.properties
@@@ -1,71 -1,0 +1,159 @@@
- # 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/.
++# 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=Page précédente
 +previous_label=Précédent
 +next.title=Page suivante
 +next_label=Suivant
++
++# 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=sur {{pageCount}}
++
 +zoom_out.title=Zoom arrière
 +zoom_out_label=Zoom arrière
 +zoom_in.title=Zoom avant
 +zoom_in_label=Zoom avant
 +zoom.title=Zoom
- print.title=Imprimer
- print_label=Imprimer
 +presentation_mode.title=Basculer en mode présentation
 +presentation_mode_label=Mode présentation
 +open_file.title=Ouvrir le fichier
- open_file_label=Ouvrir
++open_file_label=Ouvrir le fichier
++print.title=Imprimer
++print_label=Imprimer
 +download.title=Télécharger
 +download_label=Télécharger
 +bookmark.title=Affichage courant (copier ou ouvrir dans une nouvelle fenêtre)
 +bookmark_label=Affichage actuel
- toggle_slider.title=Afficher/masquer le panneau latéral
- toggle_slider_label=Afficher/masquer le panneau latéral
++
++# Secondary toolbar and context menu
++first_page.title=Aller à la première page
++first_page.label=Aller à la première page
++first_page_label=Aller à la première page
++last_page.title=Aller à la dernière page
++last_page.label=Aller à la dernière page
++last_page_label=Aller à la dernière page
++page_rotate_cw.title=Rotation horaire
++page_rotate_cw.label=Rotation horaire
++page_rotate_cw_label=Rotation horaire
++page_rotate_ccw.title=Rotation anti-horaire
++page_rotate_ccw.label=Rotation anti-horaire
++page_rotate_ccw_label=Rotation anti-horaire
++
++# 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=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
 +thumbs.title=Afficher les vignettes
 +thumbs_label=Vignettes
 +findbar.title=Rechercher dans le document
 +findbar_label=Rechercher
- no_outline=Aucun signet disponible
++
++# 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=Vignette de la page {{page}}
- first_page.label=Aller à la première page
- last_page.label=Aller à la dernière page
- page_rotate_cw.label=Rotation horaire
- page_rotate_ccw.label=Rotation anti-horaire
++
++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
 +find_previous_label=Précédent
 +find_next.title=Trouver la prochaine occurrence de la phrase
 +find_next_label=Suivant
 +find_highlight=Tout surligner
 +find_match_case_label=Respecter la casse
- find_wrapped_to_bottom=Bas de la page atteint, poursuite depuis la fin
- find_wrapped_to_top=Bas de la page atteint, poursuite au début
++find_reached_top=Haut de la page atteint, poursuite depuis la fin
++find_reached_bottom=Bas de la page atteint, poursuite au début
 +find_not_found=Phrase introuvable
 +
++# Error panel labels
 +error_more_info=Plus d'informations
 +error_less_info=Moins d'informations
 +error_close=Fermer
- error_build=Version de PDF.JS : {{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}} (identifiant de compilation : {{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=Pile : {{stack}}
++# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
 +error_file=Fichier : {{file}}
++# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
 +error_line=Ligne : {{line}}
 +rendering_error=Une erreur s'est produite lors de l'affichage de la page.
++
++# Predefined zoom values
 +page_scale_width=Pleine largeur
 +page_scale_fit=Page entière
 +page_scale_auto=Zoom automatique
 +page_scale_actual=Taille réelle
++
++# Loading indicator messages
 +loading_error_indicator=Erreur
 +loading_error=Une erreur s'est produite lors du chargement du fichier PDF.
- text_annotation_type=[Annotation {{type}}]
- request_password=Le PDF est protégé par un mot de passe :
++invalid_file_error=Fichier PDF invalide ou corrompu.
++missing_file_error=Fichier PDF manquant.
++
++# 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}}]
++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 --cc apps/files_pdfviewer/3rdparty/pdfjs/locale/he/viewer.properties
index 6073521,0000000..38f280c
mode 100644,000000..100644
--- a/apps/files_pdfviewer/3rdparty/pdfjs/locale/he/viewer.properties
+++ b/apps/files_pdfviewer/3rdparty/pdfjs/locale/he/viewer.properties
@@@ -1,60 -1,0 +1,59 @@@
 +# 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.
 +
 +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=מחסנית: {{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}}
- no_outline=אין מתאר זמין
 +open_file.title=פתיחת קובץ
- text_annotation_type=[{{type}} Annotation]
++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=מרחק מתצוגה
 +thumb_page_title=דף {{page}}
 +thumb_page_canvas=תמונה ממוזערת של דף {{page}}
 +request_password=קובץ PDF מוגן בססמה:
 +open_file_label=פתיחה
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/locale/it/viewer.properties
index ac7ba36,0000000..a9311d7
mode 100644,000000..100644
--- a/apps/files_pdfviewer/3rdparty/pdfjs/locale/it/viewer.properties
+++ b/apps/files_pdfviewer/3rdparty/pdfjs/locale/it/viewer.properties
@@@ -1,45 -1,0 +1,44 @@@
 +# 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.
 +
 +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_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.
++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}}
- no_outline=Nessun Indice Disponibile
 +open_file.title=Apri File
- text_annotation_type=[{{type}} Annotazione]
++text_annotation_type.alt=[{{type}} Annotazione]
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/locale/ja/viewer.properties
index 104f944,0000000..34d7360
mode 100644,000000..100644
--- a/apps/files_pdfviewer/3rdparty/pdfjs/locale/ja/viewer.properties
+++ b/apps/files_pdfviewer/3rdparty/pdfjs/locale/ja/viewer.properties
@@@ -1,124 -1,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=of {{pageCount}}
++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=開く
++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=文書の目次
 +thumbs.title=縮小版
 +thumbs_label=縮小版
 +findbar.title=検索
 +findbar_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}}
 +
- # 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=指定文字列に一致する 1 つ前の部分を検索します
 +find_previous_label=前へ
 +find_next.title=指定文字列に一致する次の部分を検索します
 +find_next_label=次へ
 +find_highlight=すべて強調表示
 +find_match_case_label=大文字/小文字を区別
- find_reached_top=文書先頭まで検索したので末尾に戻って検索しました。
- find_reached_bottom=文書末尾まで検索したので先頭に戻って検索しました。
++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.
++# 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 ファイルが見つかりません。
++loading_error=PDF の読み込み中にエラーが発生しました
++invalid_file_error=無効または破損した PDF ファイル
++missing_file_error=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}} 注釈]
- request_password=PDFはパスワードによって保護されています
++text_annotation_type.alt=[{{type}} 注釈]
++password_label=この PDF ファイルを開くためのパスワードを入力してください。
++password_invalid=無効なパスワードです。もう一度やり直してください。
++password_ok=OK
++password_cancel=キャンセル
 +
 +printing_not_supported=警告:このブラウザでは印刷が完全にサポートされていません
- web_fonts_disabled=Webフォントが無効になっています: 埋め込まれたPDFのフォントを使用することができません
++printing_not_ready=警告:PDF を印刷するための読み込みが終了していません
++web_fonts_disabled=Web フォントが無効になっています: 埋め込まれた PDF のフォントを使用することができません
++document_colors_disabled=PDF文書は、Web ページが指定した配色を使用することができません: \'Web ページが指定した配色\' はブラウザで無効になっています。
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/locale/ko/viewer.properties
index 0000000,0000000..4454f82
new file mode 100644
--- /dev/null
+++ b/apps/files_pdfviewer/3rdparty/pdfjs/locale/ko/viewer.properties
@@@ -1,0 -1,0 +1,131 @@@
++# 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
++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=찾기
++
++# 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): 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파일입니다:
++
++printing_not_supported=경고: 이 브라우져는 출력을 완전히는 지원하지 않습니다.
++printing_not_ready=경고: 이 PDF 파일은 완전히 적재되지 않았습니다.
++web_fonts_disabled=웹 폰트 사용이 비활성되었습니다: 내장 PDF 폰트를 사용할 수 없습니다.
++web_colors_disabled=웹 컬러가 비활성되었습니다.
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/locale/locale.properties
index a373ad0,0000000..ead305c
mode 100644,000000..100644
--- a/apps/files_pdfviewer/3rdparty/pdfjs/locale/locale.properties
+++ b/apps/files_pdfviewer/3rdparty/pdfjs/locale/locale.properties
@@@ -1,72 -1,0 +1,90 @@@
 +[ar]
 + at import url(ar/viewer.properties)
 +
++[bn-BD]
++ at import url(bn-BD/viewer.properties)
++
 +[ca]
 + at import url(ca/viewer.properties)
 +
 +[cs]
 + at import url(cs/viewer.properties)
 +
++[cy]
++ at import url(cy/viewer.properties)
++
 +[da]
 + at import url(da/viewer.properties)
 +
 +[de]
 + at import url(de/viewer.properties)
 +
++[el]
++ at import url(el/viewer.properties)
++
 +[en-US]
 + at import url(en-US/viewer.properties)
 +
 +[es]
 + at import url(es/viewer.properties)
 +
- [es-MX]
- @import url(es-MX/viewer.properties)
++[fa]
++ at import url(fa/viewer.properties)
 +
 +[fi]
 + at import url(fi/viewer.properties)
 +
 +[fr]
 + at import url(fr/viewer.properties)
 +
 +[he]
 + at import url(he/viewer.properties)
 +
 +[it]
 + at import url(it/viewer.properties)
 +
 +[ja]
 + at import url(ja/viewer.properties)
 +
++[ko]
++ at import url(ko/viewer.properties)
++
 +[lt]
 + at import url(lt/viewer.properties)
 +
 +[nl]
 + at import url(nl/viewer.properties)
 +
++[no]
++ at import url(no/viewer.properties)
++
 +[pl]
 + at import url(pl/viewer.properties)
 +
 +[pt-BR]
 + at import url(pt-BR/viewer.properties)
 +
 +[ro]
 + at import url(ro/viewer.properties)
 +
 +[ru]
 + at import url(ru/viewer.properties)
 +
 +[sr]
 + at import url(sr/viewer.properties)
 +
- [sv]
- @import url(sv/viewer.properties)
++[sv-SE]
++ at import url(sv-SE/viewer.properties)
 +
 +[tr]
 + at import url(tr/viewer.properties)
 +
++[vi]
++ at import url(vi/viewer.properties)
++
 +[zh-CN]
 + at import url(zh-CN/viewer.properties)
 +
 +[zh-TW]
 + at import url(zh-TW/viewer.properties)
 +
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/locale/lt/viewer.properties
index 241505c,0000000..a1c35d7
mode 100644,000000..100644
--- a/apps/files_pdfviewer/3rdparty/pdfjs/locale/lt/viewer.properties
+++ b/apps/files_pdfviewer/3rdparty/pdfjs/locale/lt/viewer.properties
@@@ -1,124 -1,0 +1,129 @@@
 +# 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=Ankstesnis puslapis
 +previous_label=Ankstesnis
 +next.title=Sekantis puslapis
 +next_label=Sekantis
 +
 +# 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=Puslapis:
 +page_of=iš {{pageCount}}
 +
 +zoom_out.title=Mažinti
 +zoom_out_label=Mažinti
 +zoom_in.title=Didinti
 +zoom_in_label=Didinti
 +zoom.title=Mastelis
- print.title=Spausdinti
- print_label=Spausdinti
 +presentation_mode.title=Įjungti pateikimo būseną
 +presentation_mode_label=Pateikimo būsena
 +open_file.title=Atverti bylą
 +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
 +
++# 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ę
++
 +# 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 
 +thumbs_label=Miniatiūros
 +findbar.title=Paieška dokumente
 +findbar_label=Paieška
 +
- # Document outline messages
- no_outline=Turinys nėra galimas
- 
 +# 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}}
 +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
 +# number.
 +thumb_page_canvas=Miniatūra iš {{page}} puslapio
 +
- # Context menu
- first_page.label=Nukreipimas į pirmą puslapį
- last_page.label=Nukreipimas į paskutinį puslapį
- page_rotate_cw.label=Sukimas pagal laikrodžio rodyklę
- page_rotate_ccw.label=Sukimas prieš laikrodžio rodyklę
- 
 +# Find panel button title and messages
 +find_label=Paieška:
 +find_previous.title=Ankstesnis paieškos atitikmuo
 +find_previous_label=Ankstesnis
 +find_next.title=Sekantis paieškos atitikmuo
 +find_next_label=Sekantis
 +find_highlight=Pažymėti visus
 +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
 +
 +# Error panel labels
 +error_more_info=Daugiau informacijos
 +error_less_info=Mažiau informacijos
 +error_close=Uždaryti
 +# 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=Žinutė: {{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}}
 +# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
 +error_line=Eilutė: {{line}}
 +rendering_error=Įvyko klaida atvaizduojant puslapį.
 +
 +# Predefined zoom values
 +page_scale_width=Puslapio plotis
 +page_scale_fit=Puslapio priderinimas
 +page_scale_auto=Automatinis mastelis
 +page_scale_actual=Numatytas 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.
 +
- # 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}} Pastaba]
++text_annotation_type.alt=[{{type}} Pastaba]
 +request_password=PDF byla yra apsaugota slaptažodžiu:
 +
 +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.
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/locale/nl/viewer.properties
index a7776c7,0000000..9058c15
mode 100644,000000..100644
--- a/apps/files_pdfviewer/3rdparty/pdfjs/locale/nl/viewer.properties
+++ b/apps/files_pdfviewer/3rdparty/pdfjs/locale/nl/viewer.properties
@@@ -1,125 -1,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=Vorige pagina
 +previous_label=Vorige
 +next.title=Volgende pagina
 +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=Pagina:
 +page_of=van {{pageCount}}
 +
 +zoom_out.title=Uitzoomen
 +zoom_out_label=Uitzoomen
 +zoom_in.title=Inzoomen
 +zoom_in_label=Inzoomen
 +zoom.title=Zoomen
- print.title=Afdrukken
- print_label=Afdrukken
 +presentation_mode.title=Omschakelen naar presentatiemodus
 +presentation_mode_label=Presentatiemodus
 +open_file.title=Bestand openen
 +open_file_label=Openen
++print.title=Afdrukken
++print_label=Afdrukken
 +download.title=Downloaden
 +download_label=Downloaden
 +bookmark.title=Huidige weergave (kopiëren of openen in nieuw venster)
 +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
++
++hand_tool_enable.title=Handcursor inschakelen
++hand_tool_enable_label=Handcursor inschakelen
++hand_tool_disable.title=Handcursor uitschakelen
++hand_tool_disable_label=Handcursor 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=Toepassing:
++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
 +thumbs.title=Miniaturen tonen
 +thumbs_label=Miniaturen
 +findbar.title=Zoeken in document
 +findbar_label=Zoeken
 +
- # Document outline messages
- no_outline=Geen documentstructuur beschikbaar
- 
 +# 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=Miniatuur van pagina {{page}}
 +
- # Context menu
- first_page.label=Naar de eerste pagina gaan
- last_page.label=Naar de laatste pagina gaan
- page_rotate_cw.label=Met de klok mee roteren
- page_rotate_ccw.label=Tegen de klok in roteren
- 
 +# Find panel button title and messages
 +find_label=Zoeken:
 +find_previous.title=Het vorige voorkomen van de tekst zoeken
 +find_previous_label=Vorige
 +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_not_found=Tekst niet gevonden
 +
 +# Error panel labels
 +error_more_info=Meer informatie
 +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}})
 +# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
 +# english string describing the error.
 +error_message=Bericht: {{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=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.
 +
 +# Predefined zoom values
 +page_scale_width=Paginabreed maken
 +page_scale_fit=Passend maken
 +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.
 +
- # 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}}-aantekening]
- request_password=Dit PDF-bestand is beveiligd met een wachtwoord:
++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_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.
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/locale/no/viewer.properties
index 0000000,0000000..6c160fc
new file mode 100644
--- /dev/null
+++ b/apps/files_pdfviewer/3rdparty/pdfjs/locale/no/viewer.properties
@@@ -1,0 -1,0 +1,134 @@@
++# 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=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=Opne fil
++open_file_label=Opne
++print.title=Skriv ut
++print_label=Skriv ut
++download.title=Last ned
++download_label=Last ned
++bookmark.title=Gjeldande visning (kopier eller opne i nytt vindauge)
++bookmark_label=Gjeldende 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 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
++
++# 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=Veksle Sidebar
++toggle_sidebar_label=Veksle Sidebar
++outline.title=Vis Document Outline
++outline_label=Document Outline
++thumbs.title=Vis miniatyrbilder
++thumbs_label=Miniatyrbilder
++findbar.title=Finne i Dokument
++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=Thumbnail av siden {{page}}
++
++# Find panel button title and messages
++find_label=Finn:
++find_previous.title=Finn tidlegare førekomst av frasa
++find_previous_label=Førre
++find_next.title=Finn neste førekomst av frasa
++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}} (build: {{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 zoom
++page_scale_actual=Verkeleg størrelse
++
++# 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]
++request_password=PDF er beskytta av eit passord:
++invalid_password=Ugyldig passord.
++
++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=Web-fontar er avslått: Kan ikkje bruke innbundne PDF-fontar.
++document_colors_disabled=PDF-dokument har ikkje løyve til å nytte eigne fargar: \'Tillat sider å velje eigne fargar\' er slått av i nettlesaren.
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/locale/pl/viewer.properties
index 204f212,0000000..61c3847
mode 100644,000000..100644
--- a/apps/files_pdfviewer/3rdparty/pdfjs/locale/pl/viewer.properties
+++ b/apps/files_pdfviewer/3rdparty/pdfjs/locale/pl/viewer.properties
@@@ -1,125 -1,0 +1,132 @@@
 +# 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=Poprzednia strona
 +previous_label=Wstecz
 +next.title=Następna strona
 +next_label=Dalej
 +
 +# 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=Pomniejsz
 +zoom_out_label=Pomniejsz
 +zoom_in.title=Powiększ
 +zoom_in_label=Powiększ
 +zoom.title=Powiększenie
- print.title=Drukuj
- print_label=Drukuj
 +presentation_mode.title=Przełącz do trybu prezentacji
 +presentation_mode_label=Tryb prezentacji
 +open_file.title=Otwórz plik
 +open_file_label=Otwórz
++print.title=Drukuj
++print_label=Drukuj
 +download.title=Pobierz
 +download_label=Pobierz
 +bookmark.title=Aktualny widok (kopiuj lub otwórz w nowym oknie)
 +bookmark_label=Aktualny widok
 +
++# 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
++
 +# 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
 +findbar_label=Znajdź
 +
- # Document outline messages
- no_outline=Konspekt nie jest dostępny
- 
 +# 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 strony {{page}}
 +
- # Context menu
- first_page.label=Idź do pierwszej strony
- last_page.label=Idź do ostatniej strony
- page_rotate_cw.label=Obróć w prawo
- page_rotate_ccw.label=Obróć w lewo
- 
 +# Find panel button title and messages
 +find_label=Znajdź:
 +find_previous.title=Znajdź poprzednie wystąpienie ostatnio szukanej frazy
 +find_previous_label=Poprzednie
 +find_next.title=Znajdź następne wystąpienie ostatnio szukanej frazy
 +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.
 +
 +# Error panel labels
 +error_more_info=Więcej informacji
 +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}})
 +# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
 +# english string describing the error.
 +error_message=Wiadomość: {{message}}
 +# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
 +# trace.
 +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.
 +
 +# Predefined zoom values
 +page_scale_width=Szerokość strony
 +page_scale_fit=Cała strona
 +page_scale_auto=Automatyczne dopasowanie
 +page_scale_actual=Rzeczywisty rozmiar
 +
 +# 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.
 +
- # 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=[Komentarz {{type}}]
++text_annotation_type.alt=[Komentarz {{type}}]
 +request_password=Plik PDF jest chroniony przez hasło:
++invalid_password=Nieprawidłowe hasło.
 +
 +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.
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/locale/pt-BR/viewer.properties
index 84ab287,0000000..edea5f1
mode 100644,000000..100644
--- a/apps/files_pdfviewer/3rdparty/pdfjs/locale/pt-BR/viewer.properties
+++ b/apps/files_pdfviewer/3rdparty/pdfjs/locale/pt-BR/viewer.properties
@@@ -1,45 -1,0 +1,44 @@@
 +# 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.
 +
 +bookmark.title=Marcar posição atual (bookmark)
 +previous.title=Página anterior
 +next.title=Próxima página
 +print.title=Imprimir
 +download.title=Baixar arquivo
 +zoom_out.title=Diminuir Zoom
 +zoom_in.title=Aumentar Zoom
 +error_more_info=Mais informações
 +error_less_info=Menos informações
 +error_close=Fechar
 +error_build=PDF.JS Versão: {{build}}
 +error_message=Mensagem: {{message}}
 +error_stack=Pilha: {{stack}}
 +error_file=Arquivo: {{file}}
 +error_line=Linha: {{line}}
 +page_scale_width=Largura da página
 +page_scale_fit=Página inteira
 +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}}%
 +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}}
- no_outline=Índice não disponível
 +open_file.title=Abrir arquivo
- text_annotation_type=[{{type}} Anotações]
++text_annotation_type.alt=[{{type}} Anotações]
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/locale/ro/viewer.properties
index af983ab,0000000..ae37ec7
mode 100644,000000..100644
--- a/apps/files_pdfviewer/3rdparty/pdfjs/locale/ro/viewer.properties
+++ b/apps/files_pdfviewer/3rdparty/pdfjs/locale/ro/viewer.properties
@@@ -1,56 -1,0 +1,55 @@@
 +# 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.
 +
 +bookmark.title=Vederea curentă (copiază sau deschide în fereastră nouă)
 +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}}
- no_outline=Cuprins indisponibil
 +open_file.title=Deschide fișier
- text_annotation_type=[Adnotare {{type}}]
++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_label=Înainte
 +print_label=Tipărește
 +download_label=Descarcă
 +zoom_out_label=Micșorează
 +zoom_in_label=Mărește
 +zoom.title=Mărime
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/locale/ru/viewer.properties
index 7f2019b,0000000..f86b601
mode 100644,000000..100644
--- a/apps/files_pdfviewer/3rdparty/pdfjs/locale/ru/viewer.properties
+++ b/apps/files_pdfviewer/3rdparty/pdfjs/locale/ru/viewer.properties
@@@ -1,63 -1,0 +1,62 @@@
 +# 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.
 +
 +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}}
- no_outline=Содержание не доступно
 +open_file.title=Открыть файл
- text_annotation_type=[Аннотация {{type}}]
++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=Повернуть против часовой стрелки
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/locale/sr/viewer.properties
index 04498a9,0000000..9fe3666
mode 100644,000000..100644
--- a/apps/files_pdfviewer/3rdparty/pdfjs/locale/sr/viewer.properties
+++ b/apps/files_pdfviewer/3rdparty/pdfjs/locale/sr/viewer.properties
@@@ -1,56 -1,0 +1,55 @@@
 +# 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.
 +
 +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: {{build}}
 +error_message=Message: {{message}}
 +error_stack=Stack: {{stack}}
 +error_file=File: {{file}}
 +error_line=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=Дошло је до грешке током учитавања ПДФ-а.
 +rendering_error=Дошло је до грешке приликом приказивања стране.
 +page_label=Страна:
 +page_of=од {{pageCount}}
- no_outline=Нема линија
 +open_file.title=Отвори датотеку
- text_annotation_type=[{{type}} Annotation]
++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=Скала
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/locale/sv-SE/viewer.properties
index d51c451,0000000..cd14552
mode 100644,000000..100644
--- a/apps/files_pdfviewer/3rdparty/pdfjs/locale/sv-SE/viewer.properties
+++ b/apps/files_pdfviewer/3rdparty/pdfjs/locale/sv-SE/viewer.properties
@@@ -1,125 -1,0 +1,162 @@@
 +# 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=Zooma
- print.title=Skriv ut
- print_label=Skriv ut
 +presentation_mode.title=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=Ladda ner
 +download_label=Ladda ner
 +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 handverktyget
++hand_tool_enable_label=Aktivera handverktyget
++hand_tool_disable.title=Avaktivera handverktyget
++hand_tool_disable_label=Avaktivera handverktyget
++
++# 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=Program:
++document_properties_producer=PDF-framställning:
++document_properties_version=PDF-version:
++document_properties_page_count=Antal sidor:
++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 sidopanel
 +toggle_sidebar_label=Visa/Dölj sidopanel
 +outline.title=Visa bokmärken
 +outline_label=Bokmärken
 +thumbs.title=Visa sidminiatyrer
 +thumbs_label=Sidminiatyrer
 +findbar.title=Sök i dokumentet
 +findbar_label=Sök
 +
- # Document outline messages
- no_outline=Inga bokmärken tillgängliga
- 
 +# 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}}
 +
- # Context menu
- first_page.label=Gå till första sidan
- last_page.label=Gå till sista sidan
- page_rotate_cw.label=Rotera medurs
- page_rotate_ccw.label=Rotera moturs
- 
 +# 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 VERSALER/gemener
 +find_reached_top=Kommit till början av dokumentet, börjat om
 +find_reached_bottom=Kommit till slutet av dokumentet, börjat om
 +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}} (bygge: {{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 inträffade när sidan renderades.
 +
 +# Predefined zoom values
 +page_scale_width=Sidbredd
 +page_scale_fit=Helsida
 +page_scale_auto=Automatisk zoom
 +page_scale_actual=Faktisk storlek
 +
 +# Loading indicator messages
 +loading_error_indicator=Fel
 +loading_error=Ett fel inträffade när PDF-filen laddades.
 +invalid_file_error=Ogiltig eller korrupt PDF-fil.
 +missing_file_error=PDF-filen saknas.
 +
- # 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}}-anteckning]
- request_password=PDF-filen är lösenordsskyddad:
++text_annotation_type.alt=[{{type}}-anteckning]
++
++password_label=Ange lösenordet för att öppna PDF-filen.
++password_invalid=Felaktigt lösenord. Försök igen.
++password_ok=OK
++password_cancel=Avbryt
 +
 +printing_not_supported=Varning: Utskrifter stöds inte fullt ut av denna webbläsare.
 +printing_not_ready=Varning: Hela PDF-filen måste laddas innan utskrift kan ske.
- web_fonts_disabled=Webbtypsnitt är inaktiverade: Typsnitt inkluderade i PDF-filer kan ej användas.
++web_fonts_disabled=Webbtypsnitt är inaktiverade: Typsnitt inbäddade i PDF-filer kan inte användas.
++document_colors_disabled=PDF-dokument kan inte använda egna färger: \'Låt sidor använda egna färger\' är inaktiverat i webbläsaren.
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/locale/tr/viewer.properties
index ffb95f5,0000000..c4b172c
mode 100644,000000..100644
--- a/apps/files_pdfviewer/3rdparty/pdfjs/locale/tr/viewer.properties
+++ b/apps/files_pdfviewer/3rdparty/pdfjs/locale/tr/viewer.properties
@@@ -1,124 -1,0 +1,129 @@@
 +# 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=Önceki Sayfa
 +previous_label=Önceki
 +next.title=Sonraki Sayfa
 +next_label=Sonraki
 +
 +# 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=Sayfa:
 +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
- print.title=Yazdır
- print_label=Yazdır
 +presentation_mode.title=Sunum moduna geçiş yap
 +presentation_mode_label=Sunum Modu
 +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
 +
++# 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
++
 +# 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
 +findbar_label=Bul
 +
- # Document outline messages
- no_outline=Kenarlık Mevcut Değil
- 
 +# 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=Sayfa {{page}}
 +# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
 +# number.
 +thumb_page_canvas={{page}} sayfasının ön izlemesi
 +
- # Context menu
- first_page.label=İlk Sayfaya Git
- last_page.label=Son Sayfaya Git
- page_rotate_cw.label=Sağa Çevir
- page_rotate_ccw.label=Sola Çevir
- 
 +# Find panel button title and messages
 +find_label=Bul:
 +find_previous.title=Önceki cümleyi bul
 +find_previous_label=Önceki
 +find_next.title=Sonraki cümleyi 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
 +
 +# Error panel labels
 +error_more_info=Daha falza 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}})
 +# 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=Yığın: {{stack}}
 +# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
 +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.
 +
 +# 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_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ı.
 +
- # 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}} Not]
++text_annotation_type.alt=[{{type}} Not]
 +request_password=PDF Şifre ile korunmakta:
 +
 +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.
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/locale/vi/viewer.properties
index 0000000,0000000..a92af25
new file mode 100644
--- /dev/null
+++ b/apps/files_pdfviewer/3rdparty/pdfjs/locale/vi/viewer.properties
@@@ -1,0 -1,0 +1,131 @@@
++# 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=Trang Trước
++previous_label=Trước
++next.title=Trang Tiếp
++next_label=Tiế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=Trang:
++page_of=trên {{pageCount}}
++
++zoom_out.title=Phóng to
++zoom_out_label=Phóng to
++zoom_in.title=Thu nhỏ
++zoom_in_label=Thu nhỏ
++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
++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
++
++# 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
++
++# 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
++
++# 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=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
++
++# Error panel labels
++error_more_info=Thông tim thêm
++error_less_info=Thông tin giản lược
++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}})
++# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
++# english string describing the error.
++error_message=Thông báo: {{message}}
++# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
++# trace.
++error_stack=Ngăn xếp: {{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.
++
++# Predefined zoom values
++page_scale_width=Ngang
++page_scale_fit=Xem Toàn Trang
++page_scale_auto=Tự Độ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.
++
++# 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}} Đánh dấu]
++request_password=PDF được bảo vệ bởi mật mã:
++
++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.
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/locale/zh-CN/viewer.properties
index 80ee751,0000000..bbc77c2
mode 100644,000000..100644
--- a/apps/files_pdfviewer/3rdparty/pdfjs/locale/zh-CN/viewer.properties
+++ b/apps/files_pdfviewer/3rdparty/pdfjs/locale/zh-CN/viewer.properties
@@@ -1,124 -1,0 +1,141 @@@
 +# 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=打开
++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=查找
 +
- # 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}} 的缩略图
 +
- # 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): 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}} 注解]
- 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=Web 页面字体已被禁用,无法使用嵌入到 PDF 中的字体。
++document_colors_disabled=PDF 文件不被允许使用自己的颜色:\‘允许页面选择自己的颜色’\没有在该浏览器中被激活。
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/locale/zh-TW/viewer.properties
index 69e5d41,0000000..8bb2236
mode 100644,000000..100644
--- a/apps/files_pdfviewer/3rdparty/pdfjs/locale/zh-TW/viewer.properties
+++ b/apps/files_pdfviewer/3rdparty/pdfjs/locale/zh-TW/viewer.properties
@@@ -1,115 -1,0 +1,162 @@@
- # 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=上一頁
- previous_label=上一頁
- next.title=下一頁
- next_label=下一頁
- 
- # 本地化提示 (page_label, page_of):
- # 這些字符串會連接成 "Page: X of Y" 的表示方式。
- # 不要翻譯 "{{pageCount}}" , 因為它用來表示總頁數。
- 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=目前檢視
- 
- # 側邊欄工具列按鍵 (工具提示和圖像的替代文字)
- # (_label 字符串是按鍵的替代文字, .title 字符串是工具提示)
- toggle_sidebar.title=切換側邊欄
- toggle_sidebar_label=切換側邊欄
- outline.title=顯示文件綱要
- outline_label=文件綱要
- thumbs.title=顯示縮圖
- thumbs_label=縮圖
- findbar.title=在文件中搜尋
- findbar_label=搜索
- 
- # 文件綱要相關訊息
- no_outline=無可用的綱要
- 
- # 縮圖面板項目 (工具提示和圖像的替代文字)
- # 本地化提示 (thumb_page_title): "{{page}}" 會被頁數取代。
- thumb_page_title=第 {{page}} 頁
- # 本地化提示 (thumb_page_canvas): "{{page}}" 會被頁數取代。
- thumb_page_canvas=第 {{page}} 頁的縮圖
- 
- # 右鍵菜單
- page_rotate_cw.label=順時針旋轉
- page_rotate_ccw.label=逆時針旋轉
- 
- # 搜尋面板按鍵文字及訊息
- 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): "{{version}}" and "{{build}}" 會被PDF.JS版本編號及組建編號取代。
- error_version_info=PDF.js v{{version}} (組建: {{build}})
- # 本地化提示 (error_message): "{{message}}" 會被英文的錯誤描述取代。
- error_message=錯誤信息:{{message}}
- # 本地化提示 (error_stack): "{{stack}}" 會被錯誤堆疊取代。
- error_stack=堆疊:{{stack}}
- # 本地化提示 (error_file): "{{file}}" 會被檔案名稱取代。
- error_file=檔案:{{file}}
- # 本地化提示 (error_line): "{{line}}" 會被行數取代。
- 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檔案。
- 
- # 其他標籤和訊息
- # "{{type}}" 用來表示PDF格式規範 (32000-1:2008 Table 169 – Annotation types) 入面所定義的註解種類。
- # 一些常見的類型有: "Check"、 "Text"、 "Comment"、 "Note"
- text_annotation_type=[{{type}} 註解]
- request_password=PDF檔案受密碼保護:
- 
- printing_not_supported=警告:這個瀏覽器不完全支援列印。
- printing_not_ready=警告:PDF檔案未完全加載以進行打印。
- web_fonts_disabled=禁止使用網路字型:無法使用嵌入PDF檔案的字型。
++# 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_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)
++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=已停用網路字型 (Web fonts): 無法使用 PDF 內嵌字型。
++document_colors_disabled=瀏覽器的「優先使用網頁指定的色彩」未被勾選,PDF 文件無法使用自己的色彩。
++
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/pdf.js
index e8cb6fc,0000000..96248d3
mode 100644,000000..100644
--- a/apps/files_pdfviewer/3rdparty/pdfjs/pdf.js
+++ b/apps/files_pdfviewer/3rdparty/pdfjs/pdf.js
@@@ -1,38754 -1,0 +1,7921 @@@
 +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 +/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
 +/* 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.
 + */
++/*jshint globalstrict: false */
 +
- var PDFJS = {};
- PDFJS.version = '0.7.416';
- PDFJS.build = '79c3546';
++// Initializing PDFJS global object (if still undefined)
++if (typeof PDFJS === 'undefined') {
++  (typeof window !== 'undefined' ? window : this).PDFJS = {};
++}
++
++PDFJS.version = '0.8.1136';
++PDFJS.build = 'ca612e5';
 +
 +(function pdfjsWrapper() {
 +  // Use strict in our context only - users might not want it
 +  'use strict';
 +
 +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 +/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
 +/* 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.
 + */
- /* globals assertWellFormed, calculateMD5, Catalog, error, info, isArray,
-            isArrayBuffer, isDict, isName, isStream, isString, Lexer,
-            Linearization, NullStream, PartialEvaluator, shadow, Stream,
-            StreamsSequenceStream, stringToPDFString, TODO, Util, warn, XRef */
++/* globals Cmd, ColorSpace, Dict, MozBlobBuilder, Name, PDFJS, Ref, URL,
++           Promise */
 +
 +'use strict';
 +
 +var globalScope = (typeof window === 'undefined') ? this : window;
 +
 +var isWorker = (typeof window == 'undefined');
 +
- var ERRORS = 0, WARNINGS = 1, INFOS = 5;
- var verbosity = WARNINGS;
++var FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0];
++
++var TextRenderingMode = {
++  FILL: 0,
++  STROKE: 1,
++  FILL_STROKE: 2,
++  INVISIBLE: 3,
++  FILL_ADD_TO_PATH: 4,
++  STROKE_ADD_TO_PATH: 5,
++  FILL_STROKE_ADD_TO_PATH: 6,
++  ADD_TO_PATH: 7,
++  FILL_STROKE_MASK: 3,
++  ADD_TO_PATH_FLAG: 4
++};
++
++var ImageKind = {
++  GRAYSCALE_1BPP: 1,
++  RGB_24BPP: 2,
++  RGBA_32BPP: 3
++};
 +
 +// The global PDFJS object exposes the API
 +// In production, it will be declared outside a global wrapper
 +// In development, it will be declared here
 +if (!globalScope.PDFJS) {
 +  globalScope.PDFJS = {};
 +}
 +
- // getPdf()
- // Convenience function to perform binary Ajax GET
- // Usage: getPdf('http://...', callback)
- //        getPdf({
- //                 url:String ,
- //                 [,progress:Function, error:Function]
- //               },
- //               callback)
- function getPdf(arg, callback) {
-   var params = arg;
-   if (typeof arg === 'string')
-     params = { url: arg };
-   var xhr = new XMLHttpRequest();
-   xhr.open('GET', params.url);
- 
-   var headers = params.headers;
-   if (headers) {
-     for (var property in headers) {
-       if (typeof headers[property] === 'undefined')
-         continue;
- 
-       xhr.setRequestHeader(property, params.headers[property]);
-     }
-   }
- 
-   xhr.mozResponseType = xhr.responseType = 'arraybuffer';
- 
-   var protocol = params.url.substring(0, params.url.indexOf(':') + 1);
-   xhr.expected = (protocol === 'http:' || protocol === 'https:') ? 200 : 0;
- 
-   if ('progress' in params)
-     xhr.onprogress = params.progress || undefined;
- 
-   var calledErrorBack = false;
- 
-   if ('error' in params) {
-     xhr.onerror = function errorBack() {
-       if (!calledErrorBack) {
-         calledErrorBack = true;
-         params.error();
-       }
-     };
-   }
- 
-   xhr.onreadystatechange = function getPdfOnreadystatechange(e) {
-     if (xhr.readyState === 4) {
-       if (xhr.status === xhr.expected) {
-         var data = (xhr.mozResponseArrayBuffer || xhr.mozResponse ||
-                     xhr.responseArrayBuffer || xhr.response);
-         callback(data);
-       } else if (params.error && !calledErrorBack) {
-         calledErrorBack = true;
-         params.error(e);
-       }
-     }
-   };
-   xhr.send(null);
- }
- globalScope.PDFJS.getPdf = getPdf;
 +globalScope.PDFJS.pdfBug = false;
 +
- var Page = (function PageClosure() {
-   function Page(xref, pageIndex, pageDict, ref) {
-     this.pageIndex = pageIndex;
-     this.pageDict = pageDict;
-     this.xref = xref;
-     this.ref = ref;
- 
-     this.displayReadyPromise = null;
-   }
- 
-   Page.prototype = {
-     getPageProp: function Page_getPageProp(key) {
-       return this.pageDict.get(key);
-     },
-     inheritPageProp: function Page_inheritPageProp(key) {
-       var dict = this.pageDict;
-       var obj = dict.get(key);
-       while (obj === undefined) {
-         dict = dict.get('Parent');
-         if (!dict)
-           break;
-         obj = dict.get(key);
-       }
-       return obj;
-     },
-     get content() {
-       return shadow(this, 'content', this.getPageProp('Contents'));
-     },
-     get resources() {
-       return shadow(this, 'resources', this.inheritPageProp('Resources'));
-     },
-     get mediaBox() {
-       var obj = this.inheritPageProp('MediaBox');
-       // Reset invalid media box to letter size.
-       if (!isArray(obj) || obj.length !== 4)
-         obj = [0, 0, 612, 792];
-       return shadow(this, 'mediaBox', obj);
-     },
-     get view() {
-       var mediaBox = this.mediaBox;
-       var cropBox = this.inheritPageProp('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)
-         return shadow(this, 'view', mediaBox);
- 
-       return shadow(this, 'view', cropBox);
-     },
-     get annotations() {
-       return shadow(this, 'annotations', this.inheritPageProp('Annots'));
-     },
-     get rotate() {
-       var rotate = this.inheritPageProp('Rotate') || 0;
-       // Normalize rotation so it's a multiple of 90 and between 0 and 270
-       if (rotate % 90 !== 0) {
-         rotate = 0;
-       } else if (rotate >= 360) {
-         rotate = rotate % 360;
-       } else if (rotate < 0) {
-         // The spec doesn't cover negatives, assume its counterclockwise
-         // rotation. The following is the other implementation of modulo.
-         rotate = ((rotate % 360) + 360) % 360;
-       }
-       return shadow(this, 'rotate', rotate);
-     },
-     getContentStream: function Page_getContentStream() {
-       var content = this.content;
-       if (isArray(content)) {
-         // fetching items
-         var xref = this.xref;
-         var i, n = content.length;
-         var streams = [];
-         for (i = 0; i < n; ++i)
-           streams.push(xref.fetchIfRef(content[i]));
-         content = new StreamsSequenceStream(streams);
-       } else if (isStream(content)) {
-         content.reset();
-       } else if (!content) {
-         // replacing non-existent page content with empty one
-         content = new NullStream();
-       }
-       return content;
-     },
-     getOperatorList: function Page_getOperatorList(handler, dependency) {
-       var xref = this.xref;
-       var contentStream = this.getContentStream();
-       var resources = this.resources;
-       var pe = this.pe = new PartialEvaluator(
-                                 xref, handler, this.pageIndex,
-                                 'p' + this.pageIndex + '_');
- 
-       var list = pe.getOperatorList(contentStream, resources, dependency);
-       pe.optimizeQueue(list);
-       return list;
-     },
-     extractTextContent: function Page_extractTextContent() {
-       var handler = {
-         on: function nullHandlerOn() {},
-         send: function nullHandlerSend() {}
-       };
- 
-       var xref = this.xref;
-       var contentStream = this.getContentStream();
-       var resources = xref.fetchIfRef(this.resources);
- 
-       var pe = new PartialEvaluator(
-                      xref, handler, this.pageIndex,
-                      'p' + this.pageIndex + '_');
-       return pe.getTextContent(contentStream, resources);
-     },
-     getLinks: function Page_getLinks() {
-       var links = [];
-       var annotations = this.getAnnotations();
-       var i, n = annotations.length;
-       for (i = 0; i < n; ++i) {
-         if (annotations[i].type != 'Link')
-           continue;
-         links.push(annotations[i]);
-       }
-       return links;
-     },
-     getAnnotations: function Page_getAnnotations() {
-       var xref = this.xref;
-       function getInheritableProperty(annotation, name) {
-         var item = annotation;
-         while (item && !item.has(name)) {
-           item = item.get('Parent');
-         }
-         if (!item)
-           return null;
-         return item.get(name);
-       }
-       function isValidUrl(url) {
-         if (!url)
-           return false;
-         var colon = url.indexOf(':');
-         if (colon < 0)
-           return false;
-         var protocol = url.substr(0, colon);
-         switch (protocol) {
-           case 'http':
-           case 'https':
-           case 'ftp':
-           case 'mailto':
-             return true;
-           default:
-             return false;
-         }
-       }
- 
-       var annotations = this.annotations || [];
-       var i, n = annotations.length;
-       var items = [];
-       for (i = 0; i < n; ++i) {
-         var annotationRef = annotations[i];
-         var annotation = xref.fetchIfRef(annotationRef);
-         if (!isDict(annotation))
-           continue;
-         var subtype = annotation.get('Subtype');
-         if (!isName(subtype))
-           continue;
-         var rect = annotation.get('Rect');
- 
-         var item = {};
-         item.type = subtype.name;
-         item.rect = rect;
-         switch (subtype.name) {
-           case 'Link':
-             var a = annotation.get('A');
-             if (a) {
-               switch (a.get('S').name) {
-                 case 'URI':
-                   var url = a.get('URI');
-                   // TODO: pdf spec mentions urls can be relative to a Base
-                   // entry in the dictionary.
-                   if (!isValidUrl(url))
-                     url = '';
-                   item.url = url;
-                   break;
-                 case 'GoTo':
-                   item.dest = a.get('D');
-                   break;
-                 case 'GoToR':
-                   var url = a.get('F');
-                   if (isDict(url)) {
-                     // We assume that the 'url' is a Filspec dictionary
-                     // and fetch the url without checking any further
-                     url = url.get('F') || '';
-                   }
- 
-                   // TODO: pdf reference says that GoToR
-                   // can also have 'NewWindow' attribute
-                   if (!isValidUrl(url))
-                     url = '';
-                   item.url = url;
-                   item.dest = a.get('D');
-                   break;
-                 default:
-                   TODO('unrecognized link type: ' + a.get('S').name);
-               }
-             } else if (annotation.has('Dest')) {
-               // simple destination link
-               var dest = annotation.get('Dest');
-               item.dest = isName(dest) ? dest.name : dest;
-             }
-             break;
-           case 'Widget':
-             var fieldType = getInheritableProperty(annotation, 'FT');
-             if (!isName(fieldType))
-               break;
-             item.fieldType = fieldType.name;
-             // Building the full field name by collecting the field and
-             // its ancestors 'T' properties and joining them using '.'.
-             var fieldName = [];
-             var namedItem = annotation, ref = annotationRef;
-             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;
-             }
-             item.fullName = fieldName.join('.');
-             var alternativeText = stringToPDFString(annotation.get('TU') || '');
-             item.alternativeText = alternativeText;
-             var da = getInheritableProperty(annotation, 'DA') || '';
-             var m = /([\d\.]+)\sTf/.exec(da);
-             if (m)
-               item.fontSize = parseFloat(m[1]);
-             item.textAlignment = getInheritableProperty(annotation, 'Q');
-             item.flags = getInheritableProperty(annotation, 'Ff') || 0;
-             break;
-           case 'Text':
-             var content = annotation.get('Contents');
-             var title = annotation.get('T');
-             item.content = stringToPDFString(content || '');
-             item.title = stringToPDFString(title || '');
-             item.name = !annotation.has('Name') ? 'Note' :
-               annotation.get('Name').name;
-             break;
-           default:
-             TODO('unimplemented annotation type: ' + subtype.name);
-             break;
-         }
-         items.push(item);
-       }
-       return items;
-     }
-   };
- 
-   return Page;
- })();
- 
- /**
-  * The `PDFDocument` holds all the data of the PDF file. Compared to the
-  * `PDFDoc`, this one doesn't have any job management code.
-  * Right now there exists one PDFDocument on the main thread + one object
-  * for each worker. If there is no worker support enabled, there are two
-  * `PDFDocument` objects on the main thread created.
-  */
- var PDFDocument = (function PDFDocumentClosure() {
-   function PDFDocument(arg, password) {
-     if (isStream(arg))
-       init.call(this, arg, password);
-     else if (isArrayBuffer(arg))
-       init.call(this, new Stream(arg), password);
-     else
-       error('PDFDocument: Unknown argument type');
-   }
- 
-   function init(stream, password) {
-     assertWellFormed(stream.length > 0, 'stream must have data');
-     this.stream = stream;
-     this.setup(password);
-     this.acroForm = this.catalog.catDict.get('AcroForm');
-   }
- 
-   function find(stream, needle, limit, backwards) {
-     var pos = stream.pos;
-     var end = stream.end;
-     var str = '';
-     if (pos + limit > end)
-       limit = end - pos;
-     for (var n = 0; n < limit; ++n)
-       str += stream.getChar();
-     stream.pos = pos;
-     var index = backwards ? str.lastIndexOf(needle) : str.indexOf(needle);
-     if (index == -1)
-       return false; /* not found */
-     stream.pos += index;
-     return true; /* found */
-   }
- 
-   var DocumentInfoValidators = {
-     get entries() {
-       // Lazily build this since all the validation functions below are not
-       // defined until after this file loads.
-       return shadow(this, 'entries', {
-         Title: isString,
-         Author: isString,
-         Subject: isString,
-         Keywords: isString,
-         Creator: isString,
-         Producer: isString,
-         CreationDate: isString,
-         ModDate: isString,
-         Trapped: isName
-       });
-     }
-   };
- 
-   PDFDocument.prototype = {
-     get linearization() {
-       var length = this.stream.length;
-       var linearization = false;
-       if (length) {
-         try {
-           linearization = new Linearization(this.stream);
-           if (linearization.length != length)
-             linearization = false;
-         } catch (err) {
-           warn('The linearization data is not available ' +
-                'or unreadable pdf data is found');
-           linearization = false;
-         }
-       }
-       // shadow the prototype getter with a data property
-       return shadow(this, 'linearization', linearization);
-     },
-     get startXRef() {
-       var stream = this.stream;
-       var startXRef = 0;
-       var linearization = this.linearization;
-       if (linearization) {
-         // Find end of first obj.
-         stream.reset();
-         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)
-             pos = 0;
-           stream.pos = pos;
-           found = find(stream, 'startxref', step, true);
-         }
-         if (found) {
-           stream.skip(9);
-           var ch;
-           do {
-             ch = stream.getChar();
-           } while (Lexer.isSpace(ch));
-           var str = '';
-           while ((ch - '0') <= 9) {
-             str += ch;
-             ch = stream.getChar();
-           }
-           startXRef = parseInt(str, 10);
-           if (isNaN(startXRef))
-             startXRef = 0;
-         }
-       }
-       // shadow the prototype getter with a data property
-       return shadow(this, 'startXRef', startXRef);
-     },
-     get mainXRefEntriesOffset() {
-       var mainXRefEntriesOffset = 0;
-       var linearization = this.linearization;
-       if (linearization)
-         mainXRefEntriesOffset = linearization.mainXRefEntriesOffset;
-       // shadow the prototype getter with a data property
-       return shadow(this, 'mainXRefEntriesOffset', mainXRefEntriesOffset);
-     },
-     // Find the header, remove leading garbage and setup the stream
-     // starting from the header.
-     checkHeader: function PDFDocument_checkHeader() {
-       var stream = this.stream;
-       stream.reset();
-       if (find(stream, '%PDF-', 1024)) {
-         // Found the header, trim off any garbage before it.
-         stream.moveStart();
-         // Reading file format version
-         var MAX_VERSION_LENGTH = 12;
-         var version = '', ch;
-         while ((ch = stream.getChar()) > ' ') {
-           if (version.length >= MAX_VERSION_LENGTH) {
-             break;
-           }
-           version += ch;
-         }
-         // removing "%PDF-"-prefix
-         this.pdfFormatVersion = version.substring(5);
-         return;
-       }
-       // May not be a PDF file, continue anyway.
-     },
-     setup: function PDFDocument_setup(password) {
-       this.checkHeader();
-       var xref = new XRef(this.stream,
-                           this.startXRef,
-                           this.mainXRefEntriesOffset,
-                           password);
-       this.xref = xref;
-       this.catalog = new Catalog(xref);
-     },
-     get numPages() {
-       var linearization = this.linearization;
-       var num = linearization ? linearization.numPages : this.catalog.numPages;
-       // shadow the prototype getter
-       return shadow(this, 'numPages', num);
-     },
-     getDocumentInfo: function PDFDocument_getDocumentInfo() {
-       var docInfo = {
-         PDFFormatVersion: this.pdfFormatVersion,
-         IsAcroFormPresent: !!this.acroForm
-       };
-       if (this.xref.trailer.has('Info')) {
-         var infoDict = this.xref.trailer.get('Info');
- 
-         var validEntries = DocumentInfoValidators.entries;
-         // Only fill the document info with valid entries from the spec.
-         for (var key in validEntries) {
-           if (infoDict.has(key)) {
-             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);
-             } else {
-               info('Bad value in document info for "' + key + '"');
-             }
-           }
-         }
-       }
-       return shadow(this, 'getDocumentInfo', docInfo);
-     },
-     getFingerprint: function PDFDocument_getFingerprint() {
-       var xref = this.xref, fileID;
-       if (xref.trailer.has('ID')) {
-         fileID = '';
-         var id = xref.trailer.get('ID')[0];
-         id.split('').forEach(function(el) {
-           fileID += Number(el.charCodeAt(0)).toString(16);
-         });
-       } else {
-         // If we got no fileID, then we generate one,
-         // from the first 100 bytes of PDF
-         var data = this.stream.bytes.subarray(0, 100);
-         var hash = calculateMD5(data, 0, data.length);
-         fileID = '';
-         for (var i = 0, length = hash.length; i < length; i++) {
-           fileID += Number(hash[i]).toString(16);
-         }
-       }
- 
-       return shadow(this, 'getFingerprint', fileID);
-     },
-     getPage: function PDFDocument_getPage(n) {
-       return this.catalog.getPage(n);
-     }
-   };
- 
-   return PDFDocument;
- })();
- 
- 
++PDFJS.VERBOSITY_LEVELS = {
++  errors: 0,
++  warnings: 1,
++  infos: 5
++};
 +
- // 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() {
-     };
-   }
- })();
++// All the possible operations for an operator list.
++var OPS = PDFJS.OPS = {
++  // Intentionally start from 1 so it is easy to spot bad operators that will be
++  // 0's.
++  dependency: 1,
++  setLineWidth: 2,
++  setLineCap: 3,
++  setLineJoin: 4,
++  setMiterLimit: 5,
++  setDash: 6,
++  setRenderingIntent: 7,
++  setFlatness: 8,
++  setGState: 9,
++  save: 10,
++  restore: 11,
++  transform: 12,
++  moveTo: 13,
++  lineTo: 14,
++  curveTo: 15,
++  curveTo2: 16,
++  curveTo3: 17,
++  closePath: 18,
++  rectangle: 19,
++  stroke: 20,
++  closeStroke: 21,
++  fill: 22,
++  eoFill: 23,
++  fillStroke: 24,
++  eoFillStroke: 25,
++  closeFillStroke: 26,
++  closeEOFillStroke: 27,
++  endPath: 28,
++  clip: 29,
++  eoClip: 30,
++  beginText: 31,
++  endText: 32,
++  setCharSpacing: 33,
++  setWordSpacing: 34,
++  setHScale: 35,
++  setLeading: 36,
++  setFont: 37,
++  setTextRenderingMode: 38,
++  setTextRise: 39,
++  moveText: 40,
++  setLeadingMoveText: 41,
++  setTextMatrix: 42,
++  nextLine: 43,
++  showText: 44,
++  showSpacedText: 45,
++  nextLineShowText: 46,
++  nextLineSetSpacingShowText: 47,
++  setCharWidth: 48,
++  setCharWidthAndBounds: 49,
++  setStrokeColorSpace: 50,
++  setFillColorSpace: 51,
++  setStrokeColor: 52,
++  setStrokeColorN: 53,
++  setFillColor: 54,
++  setFillColorN: 55,
++  setStrokeGray: 56,
++  setFillGray: 57,
++  setStrokeRGBColor: 58,
++  setFillRGBColor: 59,
++  setStrokeCMYKColor: 60,
++  setFillCMYKColor: 61,
++  shadingFill: 62,
++  beginInlineImage: 63,
++  beginImageData: 64,
++  endInlineImage: 65,
++  paintXObject: 66,
++  markPoint: 67,
++  markPointProps: 68,
++  beginMarkedContent: 69,
++  beginMarkedContentProps: 70,
++  endMarkedContent: 71,
++  beginCompat: 72,
++  endCompat: 73,
++  paintFormXObjectBegin: 74,
++  paintFormXObjectEnd: 75,
++  beginGroup: 76,
++  endGroup: 77,
++  beginAnnotations: 78,
++  endAnnotations: 79,
++  beginAnnotation: 80,
++  endAnnotation: 81,
++  paintJpegXObject: 82,
++  paintImageMaskXObject: 83,
++  paintImageMaskXObjectGroup: 84,
++  paintImageXObject: 85,
++  paintInlineImageXObject: 86,
++  paintInlineImageXObjectGroup: 87
++};
 +
- // A notice for devs that will not trigger the fallback UI.  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.
++// 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 (verbosity >= INFOS) {
-     log('Info: ' + msg);
-     PDFJS.LogManager.notify('info', msg);
++  if (PDFJS.verbosity >= PDFJS.VERBOSITY_LEVELS.infos) {
++    console.log('Info: ' + msg);
 +  }
 +}
 +
- // Non-fatal warnings that should trigger the fallback UI.
++// Non-fatal warnings.
 +function warn(msg) {
-   if (verbosity >= WARNINGS) {
-     log('Warning: ' + msg);
-     PDFJS.LogManager.notify('warn', msg);
++  if (PDFJS.verbosity >= PDFJS.VERBOSITY_LEVELS.warnings) {
++    console.log('Warning: ' + msg);
 +  }
 +}
 +
 +// Fatal errors that should trigger the fallback UI and halt execution by
 +// throwing an exception.
 +function error(msg) {
 +  // If multiple arguments were passed, pass them all to the log function.
 +  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());
-   PDFJS.LogManager.notify('error', msg);
++  console.log(backtrace());
++  UnsupportedManager.notify(UNSUPPORTED_FEATURES.unknown);
 +  throw new Error(msg);
 +}
 +
- // Missing features that should trigger the fallback UI.
- function TODO(what) {
-   warn('TODO: ' + what);
- }
- 
 +function backtrace() {
 +  try {
 +    throw new Error();
 +  } catch (e) {
 +    return e.stack ? e.stack.split('\n').slice(2).join('\n') : '';
 +  }
 +}
 +
 +function assert(cond, msg) {
-   if (!cond)
++  if (!cond) {
 +    error(msg);
++  }
 +}
 +
++var UNSUPPORTED_FEATURES = PDFJS.UNSUPPORTED_FEATURES = {
++  unknown: 'unknown',
++  forms: 'forms',
++  javaScript: 'javaScript',
++  smask: 'smask',
++  shadingPattern: 'shadingPattern',
++  font: 'font'
++};
++
++var UnsupportedManager = PDFJS.UnsupportedManager =
++  (function UnsupportedManagerClosure() {
++  var listeners = [];
++  return {
++    listen: function (cb) {
++      listeners.push(cb);
++    },
++    notify: function (featureId) {
++      warn('Unsupported feature "' + featureId + '"');
++      for (var i = 0, ii = listeners.length; i < ii; i++) {
++        listeners[i](featureId);
++      }
++    }
++  };
++})();
++
 +// 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) == '/') {
 +    // absolute path
 +    var i = baseUrl.indexOf('://');
-     i = baseUrl.indexOf('/', i + 3);
++    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;
 +    i = baseUrl.lastIndexOf('#');
 +    pathLength = i >= 0 ? i : pathLength;
 +    i = baseUrl.lastIndexOf('?', pathLength);
 +    pathLength = i >= 0 ? i : pathLength;
 +    var prefixLength = baseUrl.lastIndexOf('/', pathLength);
 +    return baseUrl.substring(0, prefixLength + 1) + url;
 +  }
 +}
 +
++// Validates if URL is safe and allowed, e.g. to avoid XSS.
++function isValidUrl(url, allowRelative) {
++  if (!url) {
++    return false;
++  }
++  // 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;
++  }
++  protocol = protocol[0].toLowerCase();
++  switch (protocol) {
++    case 'http':
++    case 'https':
++    case 'ftp':
++    case 'mailto':
++      return true;
++    default:
++      return false;
++  }
++}
++PDFJS.isValidUrl = isValidUrl;
++
 +// In a well-formed PDF, |cond| holds.  If it doesn't, subsequent
 +// behavior is undefined.
 +function assertWellFormed(cond, msg) {
-   if (!cond)
++  if (!cond) {
 +    error(msg);
++  }
 +}
 +
- var LogManager = PDFJS.LogManager = (function LogManagerClosure() {
-   var loggers = [];
-   return {
-     addLogger: function logManager_addLogger(logger) {
-       loggers.push(logger);
-     },
-     notify: function(type, message) {
-       for (var i = 0, ii = loggers.length; i < ii; i++) {
-         var logger = loggers[i];
-         if (logger[type])
-           logger[type](message);
-       }
-     }
-   };
- })();
- 
 +function shadow(obj, prop, value) {
 +  Object.defineProperty(obj, prop, { value: value,
 +                                     enumerable: true,
 +                                     configurable: true,
 +                                     writable: false });
 +  return value;
 +}
 +
++var PasswordResponses = PDFJS.PasswordResponses = {
++  NEED_PASSWORD: 1,
++  INCORRECT_PASSWORD: 2
++};
++
 +var PasswordException = (function PasswordExceptionClosure() {
 +  function PasswordException(msg, code) {
 +    this.name = 'PasswordException';
 +    this.message = msg;
 +    this.code = code;
 +  }
 +
 +  PasswordException.prototype = new Error();
 +  PasswordException.constructor = PasswordException;
 +
 +  return PasswordException;
 +})();
 +
 +var UnknownErrorException = (function UnknownErrorExceptionClosure() {
 +  function UnknownErrorException(msg, details) {
 +    this.name = 'UnknownErrorException';
 +    this.message = msg;
 +    this.details = details;
 +  }
 +
 +  UnknownErrorException.prototype = new Error();
 +  UnknownErrorException.constructor = UnknownErrorException;
 +
 +  return UnknownErrorException;
 +})();
 +
 +var InvalidPDFException = (function InvalidPDFExceptionClosure() {
 +  function InvalidPDFException(msg) {
 +    this.name = 'InvalidPDFException';
 +    this.message = msg;
 +  }
 +
 +  InvalidPDFException.prototype = new Error();
 +  InvalidPDFException.constructor = InvalidPDFException;
 +
 +  return InvalidPDFException;
 +})();
 +
 +var MissingPDFException = (function MissingPDFExceptionClosure() {
 +  function MissingPDFException(msg) {
 +    this.name = 'MissingPDFException';
 +    this.message = msg;
 +  }
 +
 +  MissingPDFException.prototype = new Error();
 +  MissingPDFException.constructor = MissingPDFException;
 +
 +  return MissingPDFException;
 +})();
 +
++var NotImplementedException = (function NotImplementedExceptionClosure() {
++  function NotImplementedException(msg) {
++    this.message = msg;
++  }
++
++  NotImplementedException.prototype = new Error();
++  NotImplementedException.prototype.name = 'NotImplementedException';
++  NotImplementedException.constructor = NotImplementedException;
++
++  return NotImplementedException;
++})();
++
++var MissingDataException = (function MissingDataExceptionClosure() {
++  function MissingDataException(begin, end) {
++    this.begin = begin;
++    this.end = end;
++    this.message = 'Missing data [' + begin + ', ' + end + ')';
++  }
++
++  MissingDataException.prototype = new Error();
++  MissingDataException.prototype.name = 'MissingDataException';
++  MissingDataException.constructor = MissingDataException;
++
++  return MissingDataException;
++})();
++
++var XRefParseException = (function XRefParseExceptionClosure() {
++  function XRefParseException(msg) {
++    this.message = msg;
++  }
++
++  XRefParseException.prototype = new Error();
++  XRefParseException.prototype.name = 'XRefParseException';
++  XRefParseException.constructor = XRefParseException;
++
++  return XRefParseException;
++})();
++
++
 +function bytesToString(bytes) {
-   var str = '';
++  var strBuf = [];
 +  var length = bytes.length;
-   for (var n = 0; n < length; ++n)
-     str += String.fromCharCode(bytes[n]);
-   return str;
++  for (var n = 0; n < length; ++n) {
++    strBuf.push(String.fromCharCode(bytes[n]));
++  }
++  return strBuf.join('');
 +}
 +
 +function stringToBytes(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) & 0xFF;
++  }
 +  return bytes;
 +}
 +
 +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] + ')';
 +  };
 +
 +  Util.makeCssCmyk = function Util_makeCssCmyk(cmyk) {
-     var cs = new DeviceCmykCS();
-     Util.makeCssCmyk = function makeCssCmyk(cmyk) {
-       var rgb = cs.getRgb(cmyk, 0);
-       return Util.makeCssRgb(rgb);
-     };
-     return Util.makeCssCmyk(cmyk);
++    var rgb = ColorSpace.singletons.cmyk.getRgb(cmyk, 0);
++    return Util.makeCssRgb(rgb);
++  };
++
++  // Concatenates two transformation matrices together and returns the result.
++  Util.transform = function Util_transform(m1, m2) {
++    return [
++      m1[0] * m2[0] + m1[2] * m2[1],
++      m1[1] * m2[0] + m1[3] * m2[1],
++      m1[0] * m2[2] + m1[2] * m2[3],
++      m1[1] * m2[2] + m1[3] * m2[3],
++      m1[0] * m2[4] + m1[2] * m2[5] + m1[4],
++      m1[1] * m2[4] + m1[3] * m2[5] + m1[5]
++    ];
 +  };
 +
 +  // For 2d affine transforms
 +  Util.applyTransform = function Util_applyTransform(p, m) {
 +    var xt = p[0] * m[0] + p[1] * m[2] + m[4];
 +    var yt = p[0] * m[1] + p[1] * m[3] + m[5];
 +    return [xt, yt];
 +  };
 +
 +  Util.applyInverseTransform = function Util_applyInverseTransform(p, m) {
 +    var d = m[0] * m[3] - m[1] * m[2];
 +    var xt = (p[0] * m[3] - p[1] * m[2] + m[2] * m[5] - m[4] * m[3]) / d;
 +    var yt = (-p[0] * m[1] + p[1] * m[0] + m[4] * m[1] - m[5] * m[0]) / d;
 +    return [xt, yt];
 +  };
 +
 +  // Applies the transform to the rectangle and finds the minimum axially
 +  // aligned bounding box.
 +  Util.getAxialAlignedBoundingBox =
 +    function Util_getAxialAlignedBoundingBox(r, m) {
 +
 +    var p1 = Util.applyTransform(r, m);
 +    var p2 = Util.applyTransform(r.slice(2, 4), m);
 +    var p3 = Util.applyTransform([r[0], r[3]], m);
 +    var p4 = Util.applyTransform([r[2], r[1]], m);
 +    return [
 +      Math.min(p1[0], p2[0], p3[0], p4[0]),
 +      Math.min(p1[1], p2[1], p3[1], p4[1]),
 +      Math.max(p1[0], p2[0], p3[0], p4[0]),
 +      Math.max(p1[1], p2[1], p3[1], p4[1])
 +    ];
 +  };
 +
 +  Util.inverseTransform = function Util_inverseTransform(m) {
 +    var d = m[0] * m[3] - m[1] * m[2];
 +    return [m[3] / d, -m[1] / d, -m[2] / d, m[0] / d,
 +      (m[2] * m[5] - m[4] * m[3]) / d, (m[4] * m[1] - m[5] * m[0]) / d];
 +  };
 +
 +  // Apply a generic 3d matrix M on a 3-vector v:
 +  //   | a b c |   | X |
 +  //   | d e f | x | Y |
 +  //   | g h i |   | Z |
 +  // M is assumed to be serialized as [a,b,c,d,e,f,g,h,i],
 +  // with v as [X,Y,Z]
 +  Util.apply3dTransform = function Util_apply3dTransform(m, v) {
 +    return [
 +      m[0] * v[0] + m[1] * v[1] + m[2] * v[2],
 +      m[3] * v[0] + m[4] * v[1] + m[5] * v[2],
 +      m[6] * v[0] + m[7] * v[1] + m[8] * v[2]
 +    ];
 +  };
 +
 +  // This calculation uses Singular Value Decomposition.
 +  // The SVD can be represented with formula A = USV. We are interested in the
 +  // matrix S here because it represents the scale values.
 +  Util.singularValueDecompose2dScale =
 +    function Util_singularValueDecompose2dScale(m) {
 +
 +    var transpose = [m[0], m[2], m[1], m[3]];
 +
 +    // Multiply matrix m with its transpose.
 +    var a = m[0] * transpose[0] + m[1] * transpose[2];
 +    var b = m[0] * transpose[1] + m[1] * transpose[3];
 +    var c = m[2] * transpose[0] + m[3] * transpose[2];
 +    var d = m[2] * transpose[1] + m[3] * transpose[3];
 +
 +    // Solve the second degree polynomial to get roots.
 +    var first = (a + d) / 2;
 +    var second = Math.sqrt((a + d) * (a + d) - 4 * (a * d - c * b)) / 2;
 +    var sx = first + second || 1;
 +    var sy = first - second || 1;
 +
 +    // Scale values are the square roots of the eigenvalues.
 +    return [Math.sqrt(sx), Math.sqrt(sy)];
 +  };
 +
 +  // Normalize rectangle rect=[x1, y1, x2, y2] so that (x1,y1) < (x2,y2)
 +  // For coordinate systems whose origin lies in the bottom-left, this
 +  // means normalization to (BL,TR) ordering. For systems with origin in the
 +  // top-left, this means (TL,BR) ordering.
 +  Util.normalizeRect = function Util_normalizeRect(rect) {
 +    var r = rect.slice(0); // clone rect
 +    if (rect[0] > rect[2]) {
 +      r[0] = rect[2];
 +      r[2] = rect[0];
 +    }
 +    if (rect[1] > rect[3]) {
 +      r[1] = rect[3];
 +      r[3] = rect[1];
 +    }
 +    return r;
 +  };
 +
 +  // Returns a rectangle [x1, y1, x2, y2] corresponding to the
 +  // intersection of rect1 and rect2. If no intersection, returns 'false'
 +  // The rectangle coordinates of rect1, rect2 should be [x1, y1, x2, y2]
 +  Util.intersect = function Util_intersect(rect1, rect2) {
 +    function compare(a, b) {
 +      return a - b;
 +    }
 +
 +    // Order points along the axes
 +    var orderedX = [rect1[0], rect1[2], rect2[0], rect2[2]].sort(compare),
 +        orderedY = [rect1[1], rect1[3], rect2[1], rect2[3]].sort(compare),
 +        result = [];
 +
 +    rect1 = Util.normalizeRect(rect1);
 +    rect2 = Util.normalizeRect(rect2);
 +
 +    // X: first and second points belong to different rectangles?
 +    if ((orderedX[0] === rect1[0] && orderedX[1] === rect2[0]) ||
 +        (orderedX[0] === rect2[0] && orderedX[1] === rect1[0])) {
 +      // Intersection must be between second and third points
 +      result[0] = orderedX[1];
 +      result[2] = orderedX[2];
 +    } else {
 +      return false;
 +    }
 +
 +    // Y: first and second points belong to different rectangles?
 +    if ((orderedY[0] === rect1[1] && orderedY[1] === rect2[1]) ||
 +        (orderedY[0] === rect2[1] && orderedY[1] === rect1[1])) {
 +      // Intersection must be between second and third points
 +      result[1] = orderedY[1];
 +      result[3] = orderedY[2];
 +    } else {
 +      return false;
 +    }
 +
 +    return result;
 +  };
 +
 +  Util.sign = function Util_sign(num) {
 +    return num < 0 ? -1 : 1;
 +  };
 +
++  // TODO(mack): Rename appendToArray
++  Util.concatenateToArray = function concatenateToArray(arr1, arr2) {
++    Array.prototype.push.apply(arr1, arr2);
++  };
++
++  Util.prependToArray = function concatenateToArray(arr1, arr2) {
++    Array.prototype.unshift.apply(arr1, arr2);
++  };
++
++  Util.extendObj = function extendObj(obj1, obj2) {
++    for (var key in obj2) {
++      obj1[key] = obj2[key];
++    }
++  };
++
++  Util.getInheritableProperty = function Util_getInheritableProperty(dict,
++                                                                     name) {
++    while (dict && !dict.has(name)) {
++      dict = dict.get('Parent');
++    }
++    if (!dict) {
++      return null;
++    }
++    return dict.get(name);
++  };
++
++  Util.inherit = function Util_inherit(sub, base, prototype) {
++    sub.prototype = Object.create(base.prototype);
++    sub.prototype.constructor = sub;
++    for (var prop in prototype) {
++      sub.prototype[prop] = prototype[prop];
++    }
++  };
++
++  Util.loadScript = function Util_loadScript(src, callback) {
++    var script = document.createElement('script');
++    var loaded = false;
++    script.setAttribute('src', src);
++    if (callback) {
++      script.onload = function() {
++        if (!loaded) {
++          callback();
++        }
++        loaded = true;
++      };
++    }
++    document.getElementsByTagName('head')[0].appendChild(script);
++  };
++
 +  return Util;
 +})();
 +
 +var PageViewport = PDFJS.PageViewport = (function PageViewportClosure() {
-   function PageViewport(viewBox, scale, rotation, offsetX, offsetY) {
++  function PageViewport(viewBox, scale, rotation, offsetX, offsetY, dontFlip) {
 +    this.viewBox = viewBox;
 +    this.scale = scale;
 +    this.rotation = rotation;
 +    this.offsetX = offsetX;
 +    this.offsetY = offsetY;
 +
 +    // creating transform to convert pdf coordinate system to the normal
 +    // canvas like coordinates taking in account scale and rotation
 +    var centerX = (viewBox[2] + viewBox[0]) / 2;
 +    var centerY = (viewBox[3] + viewBox[1]) / 2;
 +    var rotateA, rotateB, rotateC, rotateD;
-     switch (rotation % 360) {
-       case -180:
++    rotation = rotation % 360;
++    rotation = rotation < 0 ? rotation + 360 : rotation;
++    switch (rotation) {
 +      case 180:
 +        rotateA = -1; rotateB = 0; rotateC = 0; rotateD = 1;
 +        break;
-       case -270:
 +      case 90:
 +        rotateA = 0; rotateB = 1; rotateC = 1; rotateD = 0;
 +        break;
-       case -90:
 +      case 270:
 +        rotateA = 0; rotateB = -1; rotateC = -1; rotateD = 0;
 +        break;
-       //case 360:
 +      //case 0:
 +      default:
 +        rotateA = 1; rotateB = 0; rotateC = 0; rotateD = -1;
 +        break;
 +    }
++
++    if (dontFlip) {
++      rotateC = -rotateC; rotateD = -rotateD;
++    }
++
 +    var offsetCanvasX, offsetCanvasY;
 +    var width, height;
 +    if (rotateA === 0) {
 +      offsetCanvasX = Math.abs(centerY - viewBox[1]) * scale + offsetX;
 +      offsetCanvasY = Math.abs(centerX - viewBox[0]) * scale + offsetY;
 +      width = Math.abs(viewBox[3] - viewBox[1]) * scale;
 +      height = Math.abs(viewBox[2] - viewBox[0]) * scale;
 +    } else {
 +      offsetCanvasX = Math.abs(centerX - viewBox[0]) * scale + offsetX;
 +      offsetCanvasY = Math.abs(centerY - viewBox[1]) * scale + offsetY;
 +      width = Math.abs(viewBox[2] - viewBox[0]) * scale;
 +      height = Math.abs(viewBox[3] - viewBox[1]) * scale;
 +    }
 +    // creating transform for the following operations:
 +    // translate(-centerX, -centerY), rotate and flip vertically,
 +    // scale, and translate(offsetCanvasX, offsetCanvasY)
 +    this.transform = [
 +      rotateA * scale,
 +      rotateB * scale,
 +      rotateC * scale,
 +      rotateD * scale,
 +      offsetCanvasX - rotateA * scale * centerX - rotateC * scale * centerY,
 +      offsetCanvasY - rotateB * scale * centerX - rotateD * scale * centerY
 +    ];
 +
 +    this.width = width;
 +    this.height = height;
 +    this.fontScale = scale;
 +  }
 +  PageViewport.prototype = {
 +    clone: function PageViewPort_clone(args) {
 +      args = args || {};
 +      var scale = 'scale' in args ? args.scale : this.scale;
 +      var rotation = 'rotation' in args ? args.rotation : this.rotation;
 +      return new PageViewport(this.viewBox.slice(), scale, rotation,
-                               this.offsetX, this.offsetY);
++                              this.offsetX, this.offsetY, args.dontFlip);
 +    },
 +    convertToViewportPoint: function PageViewport_convertToViewportPoint(x, y) {
 +      return Util.applyTransform([x, y], this.transform);
 +    },
 +    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]];
 +    },
 +    convertToPdfPoint: function PageViewport_convertToPdfPoint(x, y) {
 +      return Util.applyInverseTransform([x, y], this.transform);
 +    }
 +  };
 +  return PageViewport;
 +})();
 +
 +var PDFStringTranslateTable = [
 +  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 +  0x2D8, 0x2C7, 0x2C6, 0x2D9, 0x2DD, 0x2DB, 0x2DA, 0x2DC, 0, 0, 0, 0, 0, 0, 0,
 +  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 +  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 +  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 +  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2022, 0x2020, 0x2021, 0x2026, 0x2014,
 +  0x2013, 0x192, 0x2044, 0x2039, 0x203A, 0x2212, 0x2030, 0x201E, 0x201C,
 +  0x201D, 0x2018, 0x2019, 0x201A, 0x2122, 0xFB01, 0xFB02, 0x141, 0x152, 0x160,
 +  0x178, 0x17D, 0x131, 0x142, 0x153, 0x161, 0x17E, 0, 0x20AC
 +];
 +
 +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) {
 +  return decodeURIComponent(escape(str));
 +}
 +
++function isEmptyObj(obj) {
++  for (var key in obj) {
++    return false;
++  }
++  return true;
++}
++
 +function isBool(v) {
 +  return typeof v == 'boolean';
 +}
 +
 +function isInt(v) {
 +  return typeof v == 'number' && ((v | 0) == v);
 +}
 +
 +function isNum(v) {
 +  return typeof v == 'number';
 +}
 +
 +function isString(v) {
 +  return typeof v == 'string';
 +}
 +
 +function isNull(v) {
 +  return v === null;
 +}
 +
 +function isName(v) {
 +  return v instanceof Name;
 +}
 +
 +function isCmd(v, cmd) {
 +  return v instanceof Cmd && (!cmd || v.cmd == cmd);
 +}
 +
 +function isDict(v, type) {
 +  if (!(v instanceof Dict)) {
 +    return false;
 +  }
 +  if (!type) {
 +    return true;
 +  }
 +  var dictType = v.get('Type');
 +  return isName(dictType) && dictType.name == type;
 +}
 +
 +function isArray(v) {
 +  return v instanceof Array;
 +}
 +
 +function isStream(v) {
 +  return typeof v == 'object' && v !== null && v !== undefined &&
-          ('getChar' in v);
++         ('getBytes' in v);
 +}
 +
 +function isArrayBuffer(v) {
 +  return typeof v == 'object' && v !== null && v !== undefined &&
 +         ('byteLength' in v);
 +}
 +
 +function isRef(v) {
 +  return v instanceof Ref;
 +}
 +
 +function isPDFFunction(v) {
 +  var fnDict;
-   if (typeof v != 'object')
++  if (typeof v != 'object') {
 +    return false;
-   else if (isDict(v))
++  } else if (isDict(v)) {
 +    fnDict = v;
-   else if (isStream(v))
++  } else if (isStream(v)) {
 +    fnDict = v.dict;
-   else
++  } else {
 +    return false;
++  }
 +  return fnDict.has('FunctionType');
 +}
 +
 +/**
-  * 'Promise' object.
-  * Each object that is stored in PDFObjects is based on a Promise object that
-  * contains the status of the object and the data. There migth be situations,
-  * where a function want to use the value of an object, but it isn't ready at
-  * that time. To get a notification, once the object is ready to be used, s.o.
-  * can add a callback using the `then` method on the promise that then calls
-  * the callback once the object gets resolved.
-  * A promise can get resolved only once and only once the data of the promise
-  * can be set. If any of these happens twice or the data is required before
-  * it was set, an exception is throw.
++ * Legacy support for PDFJS Promise implementation.
++ * TODO remove eventually
 + */
- var Promise = PDFJS.Promise = (function PromiseClosure() {
-   var EMPTY_PROMISE = {};
++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;
++  };
++})();
 +
-   /**
-    * If `data` is passed in this constructor, the promise is created resolved.
-    * If there isn't data, it isn't resolved at the beginning.
-    */
-   function Promise(name, data) {
-     this.name = name;
-     this.isRejected = false;
-     this.error = null;
-     this.exception = null;
-     // If you build a promise and pass in some data it's already resolved.
-     if (data !== null && data !== undefined) {
-       this.isResolved = true;
-       this._data = data;
-       this.hasData = true;
-     } else {
-       this.isResolved = false;
-       this._data = EMPTY_PROMISE;
++/**
++ * Polyfill for Promises:
++ * The following promise implementation tries to generally implment 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.
++ *
++ * Based off of the work in:
++ * https://bugzilla.mozilla.org/show_bug.cgi?id=810490
++ */
++(function PromiseClosure() {
++  if (globalScope.Promise) {
++    // Promises existing in the DOM/Worker, checking presence of all/resolve
++    if (typeof globalScope.Promise.all !== 'function') {
++      globalScope.Promise.all = function (iterable) {
++        var count = 0, results = [], resolve, reject;
++        var promise = new globalScope.Promise(function (resolve_, reject_) {
++          resolve = resolve_;
++          reject = reject_;
++        });
++        iterable.forEach(function (p, i) {
++          count++;
++          p.then(function (result) {
++            results[i] = result;
++            count--;
++            if (count === 0) {
++              resolve(results);
++            }
++          }, reject);
++        });
++        if (count === 0) {
++          resolve(results);
++        }
++        return promise;
++      };
++    }
++    if (typeof globalScope.Promise.resolve !== 'function') {
++      globalScope.Promise.resolve = function (x) {
++        return new globalScope.Promise(function (resolve) { resolve(x); });
++      };
 +    }
-     this.callbacks = [];
-     this.errbacks = [];
-     this.progressbacks = [];
++    return;
 +  }
-   /**
-    * Builds a promise that is resolved when all the passed in promises are
-    * resolved.
-    * @param {Promise[]} promises Array of promises to wait for.
++  var STATUS_PENDING = 0;
++  var STATUS_RESOLVED = 1;
++  var STATUS_REJECTED = 2;
++
++  // In an attempt to avoid silent exceptions, unhandled rejections are
++  // tracked and if they aren't handled in a certain amount of time an
++  // error is logged.
++  var REJECTION_TIMEOUT = 500;
++
++  var HandlerManager = {
++    handlers: [],
++    running: false,
++    unhandledRejections: [],
++    pendingRejectionCheck: false,
++
++    scheduleHandlers: function scheduleHandlers(promise) {
++      if (promise._status == STATUS_PENDING) {
++        return;
++      }
++
++      this.handlers = this.handlers.concat(promise._handlers);
++      promise._handlers = [];
++
++      if (this.running) {
++        return;
++      }
++      this.running = true;
++
++      setTimeout(this.runHandlers.bind(this), 0);
++    },
++
++    runHandlers: function runHandlers() {
++      var RUN_TIMEOUT = 1; // ms
++      var timeoutAt = Date.now() + RUN_TIMEOUT;
++      while (this.handlers.length > 0) {
++        var handler = this.handlers.shift();
++
++        var nextStatus = handler.thisPromise._status;
++        var nextValue = handler.thisPromise._value;
++
++        try {
++          if (nextStatus === STATUS_RESOLVED) {
++            if (typeof(handler.onResolve) == 'function') {
++              nextValue = handler.onResolve(nextValue);
++            }
++          } else if (typeof(handler.onReject) === 'function') {
++              nextValue = handler.onReject(nextValue);
++              nextStatus = STATUS_RESOLVED;
++
++              if (handler.thisPromise._unhandledRejection) {
++                this.removeUnhandeledRejection(handler.thisPromise);
++              }
++          }
++        } catch (ex) {
++          nextStatus = STATUS_REJECTED;
++          nextValue = ex;
++        }
++
++        handler.nextPromise._updateStatus(nextStatus, nextValue);
++        if (Date.now() >= timeoutAt) {
++          break;
++        }
++      }
++
++      if (this.handlers.length > 0) {
++        setTimeout(this.runHandlers.bind(this), 0);
++        return;
++      }
++
++      this.running = false;
++    },
++
++    addUnhandledRejection: function addUnhandledRejection(promise) {
++      this.unhandledRejections.push({
++        promise: promise,
++        time: Date.now()
++      });
++      this.scheduleRejectionCheck();
++    },
++
++    removeUnhandeledRejection: function removeUnhandeledRejection(promise) {
++      promise._unhandledRejection = false;
++      for (var i = 0; i < this.unhandledRejections.length; i++) {
++        if (this.unhandledRejections[i].promise === promise) {
++          this.unhandledRejections.splice(i);
++          i--;
++        }
++      }
++    },
++
++    scheduleRejectionCheck: function scheduleRejectionCheck() {
++      if (this.pendingRejectionCheck) {
++        return;
++      }
++      this.pendingRejectionCheck = true;
++      setTimeout(function rejectionCheck() {
++        this.pendingRejectionCheck = false;
++        var now = Date.now();
++        for (var i = 0; i < this.unhandledRejections.length; i++) {
++          if (now - this.unhandledRejections[i].time > REJECTION_TIMEOUT) {
++            var unhandled = this.unhandledRejections[i].promise._value;
++            var msg = 'Unhandled rejection: ' + unhandled;
++            if (unhandled.stack) {
++              msg += '\n' + unhandled.stack;
++            }
++            warn(msg);
++            this.unhandledRejections.splice(i);
++            i--;
++          }
++        }
++        if (this.unhandledRejections.length) {
++          this.scheduleRejectionCheck();
++        }
++      }.bind(this), REJECTION_TIMEOUT);
++    }
++  };
++
++  function Promise(resolver) {
++    this._status = STATUS_PENDING;
++    this._handlers = [];
++    resolver.call(this, this._resolve.bind(this), this._reject.bind(this));
++  }
++  /**
++   * Builds a promise that is resolved when all the passed in promises are
++   * resolved.
++   * @param {array} array of data and/or promises to wait for.
 +   * @return {Promise} New dependant promise.
 +   */
 +  Promise.all = function Promise_all(promises) {
-     var deferred = new Promise();
++    var resolveAll, rejectAll;
++    var deferred = new Promise(function (resolve, reject) {
++      resolveAll = resolve;
++      rejectAll = reject;
++    });
 +    var unresolved = promises.length;
 +    var results = [];
 +    if (unresolved === 0) {
-       deferred.resolve(results);
++      resolveAll(results);
 +      return deferred;
 +    }
++    function reject(reason) {
++      if (deferred._status === STATUS_REJECTED) {
++        return;
++      }
++      results = [];
++      rejectAll(reason);
++    }
 +    for (var i = 0, ii = promises.length; i < ii; ++i) {
 +      var promise = promises[i];
-       promise.then((function(i) {
++      var resolve = (function(i) {
 +        return function(value) {
++          if (deferred._status === STATUS_REJECTED) {
++            return;
++          }
 +          results[i] = value;
 +          unresolved--;
-           if (unresolved === 0)
-             deferred.resolve(results);
++          if (unresolved === 0) {
++            resolveAll(results);
++          }
 +        };
-       })(i));
++      })(i);
++      if (Promise.isPromise(promise)) {
++        promise.then(resolve, reject);
++      } else {
++        resolve(promise);
++      }
 +    }
 +    return deferred;
 +  };
-   Promise.prototype = {
-     hasData: false,
 +
-     set data(value) {
-       if (value === undefined) {
-         return;
-       }
-       if (this._data !== EMPTY_PROMISE) {
-         error('Promise ' + this.name +
-               ': Cannot set the data of a promise twice');
-       }
-       this._data = value;
-       this.hasData = true;
++  /**
++   * Checks if the value is likely a promise (has a 'then' function).
++   * @return {boolean} true if x is thenable
++   */
++  Promise.isPromise = function Promise_isPromise(value) {
++    return value && typeof value.then === 'function';
++  };
++  /**
++   * Creates resolved promise
++   * @param x resolve value
++   * @returns {Promise}
++   */
++  Promise.resolve = function Promise_resolve(x) {
++    return new Promise(function (resolve) { resolve(x); });
++  };
 +
-       if (this.onDataCallback) {
-         this.onDataCallback(value);
++  Promise.prototype = {
++    _status: null,
++    _value: null,
++    _handlers: null,
++    _unhandledRejection: null,
++
++    _updateStatus: function Promise__updateStatus(status, value) {
++      if (this._status === STATUS_RESOLVED ||
++          this._status === STATUS_REJECTED) {
++        return;
 +      }
-     },
 +
-     get data() {
-       if (this._data === EMPTY_PROMISE) {
-         error('Promise ' + this.name + ': Cannot get data that isn\'t set');
++      if (status == STATUS_RESOLVED &&
++          Promise.isPromise(value)) {
++        value.then(this._updateStatus.bind(this, STATUS_RESOLVED),
++                   this._updateStatus.bind(this, STATUS_REJECTED));
++        return;
 +      }
-       return this._data;
-     },
 +
-     onData: function Promise_onData(callback) {
-       if (this._data !== EMPTY_PROMISE) {
-         callback(this._data);
-       } else {
-         this.onDataCallback = callback;
-       }
-     },
++      this._status = status;
++      this._value = value;
 +
-     resolve: function Promise_resolve(data) {
-       if (this.isResolved) {
-         error('A Promise can be resolved only once ' + this.name);
-       }
-       if (this.isRejected) {
-         error('The Promise was already rejected ' + this.name);
++      if (status === STATUS_REJECTED && this._handlers.length === 0) {
++        this._unhandledRejection = true;
++        HandlerManager.addUnhandledRejection(this);
 +      }
 +
-       this.isResolved = true;
-       this.data = (typeof data !== 'undefined') ? data : null;
-       var callbacks = this.callbacks;
- 
-       for (var i = 0, ii = callbacks.length; i < ii; i++) {
-         callbacks[i].call(null, data);
-       }
++      HandlerManager.scheduleHandlers(this);
 +    },
 +
-     progress: function Promise_progress(data) {
-       var callbacks = this.progressbacks;
-       for (var i = 0, ii = callbacks.length; i < ii; i++) {
-         callbacks[i].call(null, data);
-       }
++    _resolve: function Promise_resolve(value) {
++      this._updateStatus(STATUS_RESOLVED, value);
 +    },
 +
-     reject: function Promise_reject(reason, exception) {
-       if (this.isRejected) {
-         error('A Promise can be rejected only once ' + this.name);
-       }
-       if (this.isResolved) {
-         error('The Promise was already resolved ' + this.name);
-       }
- 
-       this.isRejected = true;
-       this.error = reason || null;
-       this.exception = exception || null;
-       var errbacks = this.errbacks;
- 
-       for (var i = 0, ii = errbacks.length; i < ii; i++) {
-         errbacks[i].call(null, reason, exception);
-       }
++    _reject: function Promise_reject(reason) {
++      this._updateStatus(STATUS_REJECTED, reason);
 +    },
 +
-     then: function Promise_then(callback, errback, progressback) {
-       if (!callback) {
-         error('Requiring callback' + this.name);
-       }
- 
-       // If the promise is already resolved, call the callback directly.
-       if (this.isResolved) {
-         var data = this.data;
-         callback.call(null, data);
-       } else if (this.isRejected && errback) {
-         var error = this.error;
-         var exception = this.exception;
-         errback.call(null, error, exception);
-       } else {
-         this.callbacks.push(callback);
-         if (errback)
-           this.errbacks.push(errback);
-       }
- 
-       if (progressback)
-         this.progressbacks.push(progressback);
++    then: function Promise_then(onResolve, onReject) {
++      var nextPromise = new Promise(function (resolve, reject) {
++        this.resolve = reject;
++        this.reject = reject;
++      });
++      this._handlers.push({
++        thisPromise: this,
++        onResolve: onResolve,
++        onReject: onReject,
++        nextPromise: nextPromise
++      });
++      HandlerManager.scheduleHandlers(this);
++      return nextPromise;
 +    }
 +  };
 +
-   return Promise;
++  globalScope.Promise = Promise;
 +})();
 +
 +var StatTimer = (function StatTimerClosure() {
 +  function rpad(str, pad, length) {
-     while (str.length < length)
++    while (str.length < length) {
 +      str += pad;
++    }
 +    return str;
 +  }
 +  function StatTimer() {
 +    this.started = {};
 +    this.times = [];
 +    this.enabled = true;
 +  }
 +  StatTimer.prototype = {
 +    time: function StatTimer_time(name) {
-       if (!this.enabled)
++      if (!this.enabled) {
 +        return;
-       if (name in this.started)
-         throw 'Timer is already running for ' + name;
++      }
++      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))
-         throw 'Timer has not been started for ' + name;
++      }
++      if (!(name in this.started)) {
++        warn('Timer has not been started for ' + name);
++      }
 +      this.times.push({
 +        'name': name,
 +        'start': this.started[name],
 +        'end': Date.now()
 +      });
 +      // Remove timer from started so it can be called again.
 +      delete this.started[name];
 +    },
 +    toString: function StatTimer_toString() {
 +      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) {
 +        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) {
 +        var span = times[i];
 +        var duration = span.end - span.start;
 +        out += rpad(span['name'], ' ', longest) + ' ' + duration + 'ms\n';
 +      }
 +      return out;
 +    }
 +  };
 +  return StatTimer;
 +})();
 +
 +PDFJS.createBlob = function createBlob(data, contentType) {
-   if (typeof Blob === 'function')
++  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);
 +  return bb.getBlob(contentType);
 +};
 +
++PDFJS.createObjectURL = (function createObjectURLClosure() {
++  // Blob/createObjectURL is not available, falling back to data schema.
++  var digits =
++    'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
 +
- /**
-  * This is the main entry point for loading a PDF and interacting with it.
-  * NOTE: If a URL is used to fetch the PDF data a standard XMLHttpRequest(XHR)
-  * 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.
-  *
-  * @return {Promise} A promise that is resolved with {PDFDocumentProxy} object.
-  */
- PDFJS.getDocument = function getDocument(source) {
-   var workerInitializedPromise, workerReadyPromise, transport;
++  return function createObjectURL(data, contentType) {
++    if (!PDFJS.disableCreateObjectURL &&
++        typeof URL !== 'undefined' && URL.createObjectURL) {
++      var blob = PDFJS.createBlob(data, contentType);
++      return URL.createObjectURL(blob);
++    }
 +
-   if (typeof source === 'string') {
-     source = { url: source };
-   } else if (isArrayBuffer(source)) {
-     source = { data: source };
-   } else if (typeof source !== 'object') {
-     error('Invalid parameter in getDocument, need either Uint8Array, ' +
-           'string or a parameter object');
-   }
++    var buffer = 'data:' + contentType + ';base64,';
++    for (var i = 0, ii = data.length; i < ii; i += 3) {
++      var b1 = data[i] & 0xFF;
++      var b2 = data[i + 1] & 0xFF;
++      var b3 = data[i + 2] & 0xFF;
++      var d1 = b1 >> 2, d2 = ((b1 & 3) << 4) | (b2 >> 4);
++      var d3 = i + 1 < ii ? ((b2 & 0xF) << 2) | (b3 >> 6) : 64;
++      var d4 = i + 2 < ii ? (b3 & 0x3F) : 64;
++      buffer += digits[d1] + digits[d2] + digits[d3] + digits[d4];
++    }
++    return buffer;
++  };
++})();
 +
-   if (!source.url && !source.data)
-     error('Invalid parameter array, need either .data or .url');
++function MessageHandler(name, comObj) {
++  this.name = name;
++  this.comObj = comObj;
++  this.callbackIndex = 1;
++  this.postMessageTransfers = true;
++  var callbacks = this.callbacks = {};
++  var ah = this.actionHandler = {};
 +
-   // copy/use all keys as is except 'url' -- full path is required
-   var params = {};
-   for (var key in source) {
-     if (key === 'url' && typeof window !== 'undefined') {
-       params[key] = combineUrl(window.location.href, source[key]);
-       continue;
++  ah['console_log'] = [function ahConsoleLog(data) {
++    console.log.apply(console, data);
++  }];
++  ah['console_error'] = [function ahConsoleError(data) {
++    console.error.apply(console, data);
++  }];
++  ah['_unsupported_feature'] = [function ah_unsupportedFeature(data) {
++    UnsupportedManager.notify(data);
++  }];
++
++  comObj.onmessage = function messageHandlerComObjOnMessage(event) {
++    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);
++      } 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) {
++          comObj.postMessage({
++            isReply: true,
++            callbackId: data.callbackId,
++            data: resolvedData
++          });
++        });
++        action[0].call(action[1], data.data, deferred);
++      } else {
++        action[0].call(action[1], data.data);
++      }
++    } else {
++      error('Unkown action from worker: ' + data.action);
++    }
++  };
++}
++
++MessageHandler.prototype = {
++  on: function messageHandlerOn(actionName, handler, scope) {
++    var ah = this.actionHandler;
++    if (ah[actionName]) {
++      error('There is already an actionName called "' + actionName + '"');
++    }
++    ah[actionName] = [handler, scope];
++  },
++  /**
++   * 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) {
++    var message = {
++      action: actionName,
++      data: data
++    };
++    if (callback) {
++      var callbackId = this.callbackIndex++;
++      this.callbacks[callbackId] = callback;
++      message.callbackId = callbackId;
++    }
++    if (transfers && this.postMessageTransfers) {
++      this.comObj.postMessage(message, transfers);
++    } else {
++      this.comObj.postMessage(message);
 +    }
-     params[key] = source[key];
 +  }
++};
 +
-   workerInitializedPromise = new PDFJS.Promise();
-   workerReadyPromise = new PDFJS.Promise();
-   transport = new WorkerTransport(workerInitializedPromise, workerReadyPromise);
-   workerInitializedPromise.then(function transportInitialized() {
-     transport.fetchDocument(params);
++function loadJpegStream(id, imageUrl, objs) {
++  var img = new Image();
++  img.onload = (function loadJpegStream_onloadClosure() {
++    objs.resolve(id, img);
 +  });
-   return workerReadyPromise;
- };
++  img.src = imageUrl;
++}
 +
- /**
-  * Proxy to a PDFDocument in the worker thread. Also, contains commonly used
-  * properties that can be read synchronously.
-  */
- var PDFDocumentProxy = (function PDFDocumentProxyClosure() {
-   function PDFDocumentProxy(pdfInfo, transport) {
-     this.pdfInfo = pdfInfo;
-     this.transport = transport;
++
++var ColorSpace = (function ColorSpaceClosure() {
++  // Constructor should define this.numComps, this.defaultColor, this.name
++  function ColorSpace() {
++    error('should not call ColorSpace constructor');
 +  }
-   PDFDocumentProxy.prototype = {
++
++  ColorSpace.prototype = {
 +    /**
-      * @return {number} Total number of pages the PDF contains.
++     * 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].
 +     */
-     get numPages() {
-       return this.pdfInfo.numPages;
++    getRgb: function ColorSpace_getRgb(src, srcOffset) {
++      var rgb = new Uint8Array(3);
++      this.getRgbItem(src, srcOffset, rgb, 0);
++      return rgb;
 +    },
 +    /**
-      * @return {string} A unique ID to identify a PDF. Not guaranteed to be
-      * unique.
++     * Converts the color value to the RGB color, similar to the getRgb method.
++     * The result placed into the dest array starting from the destOffset.
 +     */
-     get fingerprint() {
-       return this.pdfInfo.fingerprint;
++    getRgbItem: function ColorSpace_getRgbItem(src, srcOffset,
++                                               dest, destOffset) {
++      error('Should not call ColorSpace.getRgbItem');
 +    },
 +    /**
-      * @return {boolean} true if embedded document fonts are in use. Will be
-      * set during rendering of the pages.
++     * 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).
 +     */
-     get embeddedFontsUsed() {
-       return this.transport.embeddedFontsUsed;
++    getRgbBuffer: function ColorSpace_getRgbBuffer(src, srcOffset, count,
++                                                   dest, destOffset, bits,
++                                                   alpha01) {
++      error('Should not call ColorSpace.getRgbBuffer');
 +    },
 +    /**
-      * @param {number} The page number to get. The first page is 1.
-      * @return {Promise} A promise that is resolved with a {PDFPageProxy}
-      * object.
++     * 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).
 +     */
-     getPage: function PDFDocumentProxy_getPage(number) {
-       return this.transport.getPage(number);
++    getOutputLength: function ColorSpace_getOutputLength(inputLength,
++                                                         alpha01) {
++      error('Should not call ColorSpace.getOutputLength');
 +    },
 +    /**
-      * @return {Promise} A promise that is resolved with a lookup table for
-      * mapping named destinations to reference numbers.
++     * Returns true if source data will be equal the result/output data.
 +     */
-     getDestinations: function PDFDocumentProxy_getDestinations() {
-       var promise = new PDFJS.Promise();
-       var destinations = this.pdfInfo.destinations;
-       promise.resolve(destinations);
-       return promise;
++    isPassthrough: function ColorSpace_isPassthrough(bits) {
++      return false;
 +    },
 +    /**
-      * @return {Promise} A promise that is resolved with an array of all the
-      * JavaScript strings in the name tree.
++     * 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).
 +     */
-     getJavaScript: function PDFDocumentProxy_getDestinations() {
-       var promise = new PDFJS.Promise();
-       var js = this.pdfInfo.javaScript;
-       promise.resolve(js);
-       return promise;
-     },
-     /**
-      * @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:
-      * [
-      *  {
-      *   title: string,
-      *   bold: boolean,
-      *   italic: boolean,
-      *   color: rgb array,
-      *   dest: dest obj,
-      *   items: array of more items like this
-      *  },
-      *  ...
-      * ].
-      */
-     getOutline: function PDFDocumentProxy_getOutline() {
-       var promise = new PDFJS.Promise();
-       var outline = this.pdfInfo.outline;
-       promise.resolve(outline);
-       return promise;
-     },
-     /**
-      * @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.Promise();
-       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.Promise();
-       promise.resolve(this.pdfInfo.encrypted);
-       return promise;
-     },
-     /**
-      * @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.Promise();
-       this.transport.getData(promise);
-       return promise;
-     },
-     destroy: function PDFDocumentProxy_destroy() {
-       this.transport.destroy();
-     }
-   };
-   return PDFDocumentProxy;
- })();
- 
- var PDFPageProxy = (function PDFPageProxyClosure() {
-   function PDFPageProxy(pageInfo, transport) {
-     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.renderInProgress = false;
-     this.cleanupAfterRender = false;
-   }
-   PDFPageProxy.prototype = {
-     /**
-      * @return {number} Page number of the page. First page is 1.
-      */
-     get pageNumber() {
-       return this.pageInfo.pageIndex + 1;
-     },
-     /**
-      * @return {number} The number of degrees the page is rotated clockwise.
-      */
-     get rotate() {
-       return this.pageInfo.rotate;
-     },
-     /**
-      * @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
-      * user space units - [x1, y1, x2, y2].
-      */
-     get view() {
-       return this.pageInfo.view;
-     },
-     /**
-      * @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.
-      */
-     getViewport: function PDFPageProxy_getViewport(scale, rotate) {
-       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
-      * annotation objects.
-      */
-     getAnnotations: function PDFPageProxy_getAnnotations() {
-       if (this.annotationsPromise)
-         return this.annotationsPromise;
- 
-       var promise = new PDFJS.Promise();
-       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 {Promise} A promise that is resolved when the page finishes
-      * rendering.
-      */
-     render: function PDFPageProxy_render(params) {
-       this.renderInProgress = true;
- 
-       var promise = new Promise();
-       var stats = this.stats;
-       stats.time('Overall');
-       // If there is no displayReadyPromise yet, then the operatorList was never
-       // requested before. Make the request and create the promise.
-       if (!this.displayReadyPromise) {
-         this.displayReadyPromise = new Promise();
-         this.destroyed = false;
- 
-         this.stats.time('Page Request');
-         this.transport.messageHandler.send('RenderPageRequest', {
-           pageIndex: this.pageNumber - 1
-         });
-       }
- 
-       var self = this;
-       function complete(error) {
-         self.renderInProgress = false;
-         if (self.destroyed || self.cleanupAfterRender) {
-           delete self.displayReadyPromise;
-           delete self.operatorList;
-           self.objs.clear();
++    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;
++
++      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);
++        for (var i = 0; i < numComponentColors; i++) {
++          allColors[i] = i;
 +        }
- 
-         if (error)
-           promise.reject(error);
-         else
-           promise.resolve();
-       }
-       var continueCallback = params.continueCallback;
- 
-       // Once the operatorList and fonts are loaded, do the actual rendering.
-       this.displayReadyPromise.then(
-         function pageDisplayReadyPromise() {
-           if (self.destroyed) {
-             complete();
-             return;
++        var colorMap = new Uint8Array(numComponentColors * 3);
++        this.getRgbBuffer(allColors, 0, numComponentColors, colorMap, 0, bpc,
++                          /* alpha01 = */ 0);
++
++        if (!needsResizing) {
++          // Fill in the RGB values directly into |dest|.
++          var destPos = 0;
++          for (var i = 0; i < count; ++i) {
++            var key = comps[i] * 3;
++            dest[destPos++] = colorMap[key];
++            dest[destPos++] = colorMap[key + 1];
++            dest[destPos++] = colorMap[key + 2];
++            destPos += alpha01;
 +          }
- 
-           var gfx = new CanvasGraphics(params.canvasContext, this.commonObjs,
-             this.objs, params.textLayer, params.imageLayer);
-           try {
-             this.display(gfx, params.viewport, complete, continueCallback);
-           } catch (e) {
-             complete(e);
++        } else {
++          rgbBuf = new Uint8Array(count * 3);
++          var rgbPos = 0;
++          for (var i = 0; i < count; ++i) {
++            var key = comps[i] * 3;
++            rgbBuf[rgbPos++] = colorMap[key];
++            rgbBuf[rgbPos++] = colorMap[key + 1];
++            rgbBuf[rgbPos++] = colorMap[key + 2];
 +          }
-         }.bind(this),
-         function pageDisplayReadPromiseError(reason) {
-           complete(reason);
 +        }
-       );
- 
-       return promise;
-     },
-     /**
-      * For internal use only.
-      */
-     startRenderingFromOperatorList:
-       function PDFPageProxy_startRenderingFromOperatorList(operatorList,
-                                                            fonts) {
-       var self = this;
-       this.operatorList = operatorList;
- 
-       var displayContinuation = function pageDisplayContinuation() {
-         // Always defer call to display() to work around bug in
-         // Firefox error reporting from XHR callbacks.
-         setTimeout(function pageSetTimeout() {
-           self.displayReadyPromise.resolve();
-         });
-       };
- 
-       this.ensureFonts(fonts,
-         function pageStartRenderingFromOperatorListEnsureFonts() {
-           displayContinuation();
++      } 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);
 +        }
-       );
-     },
-     /**
-      * For internal use only.
-      */
-     ensureFonts: function PDFPageProxy_ensureFonts(fonts, callback) {
-       this.stats.time('Font Loading');
-       // Convert the font names to the corresponding font obj.
-       var fontObjs = [];
-       for (var i = 0, ii = fonts.length; i < ii; i++) {
-         var obj = this.commonObjs.getData(fonts[i]);
-         if (obj.error) {
-           warn('Error during font loading: ' + obj.error);
-           continue;
++      }
++
++      if (rgbBuf) {
++        if (needsResizing) {
++          rgbBuf = PDFImage.resize(rgbBuf, bpc, 3, originalWidth,
++                                   originalHeight, width, height);
 +        }
-         if (!obj.coded) {
-           this.transport.embeddedFontsUsed = true;
++        var rgbPos = 0;
++        var destPos = 0;
++        for (var i = 0, ii = width * actualHeight; i < ii; i++) {
++          dest[destPos++] = rgbBuf[rgbPos++];
++          dest[destPos++] = rgbBuf[rgbPos++];
++          dest[destPos++] = rgbBuf[rgbPos++];
++          destPos += alpha01;
 +        }
-         fontObjs.push(obj);
 +      }
- 
-       // Load all the fonts
-       FontLoader.bind(
-         fontObjs,
-         function pageEnsureFontsFontObjs(fontObjs) {
-           this.stats.timeEnd('Font Loading');
- 
-           callback.call(this);
-         }.bind(this)
-       );
 +    },
 +    /**
-      * For internal use only.
++     * 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].
 +     */
-     display: function PDFPageProxy_display(gfx, viewport, callback,
-                                            continueCallback) {
-       var stats = this.stats;
-       stats.time('Rendering');
- 
-       gfx.beginDrawing(viewport);
++    usesZeroToOneRange: true
++  };
 +
-       var startIdx = 0;
-       var length = this.operatorList.fnArray.length;
-       var operatorList = this.operatorList;
-       var stepper = null;
-       if (PDFJS.pdfBug && 'StepperManager' in globalScope &&
-           globalScope['StepperManager'].enabled) {
-         stepper = globalScope['StepperManager'].create(this.pageNumber - 1);
-         stepper.init(operatorList);
-         stepper.nextBreakPoint = stepper.getNextBreakPoint();
-       }
++  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);
++  };
 +
-       var continueWrapper;
-       if (continueCallback)
-         continueWrapper = function() { continueCallback(next); };
-       else
-         continueWrapper = next;
++  ColorSpace.fromIR = function ColorSpace_fromIR(IR) {
++    var name = isArray(IR) ? IR[0] : IR;
 +
-       var self = this;
-       function next() {
-         startIdx = gfx.executeOperatorList(operatorList, startIdx,
-                                            continueWrapper, stepper);
-         if (startIdx == length) {
-           gfx.endDrawing();
-           stats.timeEnd('Rendering');
-           stats.timeEnd('Overall');
-           if (callback) callback();
-         }
-       }
-       continueWrapper();
-     },
-     /**
-      * @return {Promise} That is resolved with the a {string} that is the text
-      * content from the page.
-      */
-     getTextContent: function PDFPageProxy_getTextContent() {
-       var promise = new PDFJS.Promise();
-       this.transport.messageHandler.send('GetTextContent', {
-           pageIndex: this.pageNumber - 1
-         },
-         function textContentCallback(textContent) {
-           promise.resolve(textContent);
++    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 promise;
-     },
-     /**
-      * Stub for future feature.
-      */
-     getOperationList: function PDFPageProxy_getOperationList() {
-       var promise = new PDFJS.Promise();
-       var operationList = { // not implemented
-         dependencyFontsID: null,
-         operatorList: null
-       };
-       promise.resolve(operationList);
-       return promise;
-     },
-     /**
-      * Destroys resources allocated by the page.
-      */
-     destroy: function PDFPageProxy_destroy() {
-       this.destroyed = true;
++        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];
 +
-       if (!this.renderInProgress) {
-         delete this.operatorList;
-         delete this.displayReadyPromise;
-         this.objs.clear();
-       }
++        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;
 +  };
-   return PDFPageProxy;
- })();
- /**
-  * For internal use only.
-  */
- var WorkerTransport = (function WorkerTransportClosure() {
-   function WorkerTransport(workerInitializedPromise, workerReadyPromise) {
-     this.workerReadyPromise = workerReadyPromise;
-     this.commonObjs = new PDFObjects();
- 
-     this.pageCache = [];
-     this.pagePromises = [];
-     this.embeddedFontsUsed = false;
 +
-     // If worker support isn't disabled explicit and the browser has worker
-     // support, create a new web worker and test if it/the browser fullfills
-     // all requirements to run parts of pdf.js in a web worker.
-     // Right now, the requirement is, that an Uint8Array is still an Uint8Array
-     // as it arrives on the worker. Chrome added this with version 15.
-     if (!globalScope.PDFJS.disableWorker && typeof Worker !== 'undefined') {
-       var workerSrc = PDFJS.workerSrc;
-       if (typeof workerSrc === 'undefined') {
-         error('No PDFJS.workerSrc specified');
++  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;
++        }
 +      }
++    }
 +
-       try {
-         // Some versions of FF can't create a worker on localhost, see:
-         // https://bugzilla.mozilla.org/show_bug.cgi?id=683280
-         var worker = new Worker(workerSrc);
-         var messageHandler = new MessageHandler('main', worker);
-         this.messageHandler = messageHandler;
++    cs = xref.fetchIfRef(cs);
++    var mode;
 +
-         messageHandler.on('test', function transportTest(supportTypedArray) {
-           if (supportTypedArray) {
-             this.worker = worker;
-             this.setupMessageHandler(messageHandler);
-           } else {
-             globalScope.PDFJS.disableWorker = true;
-             this.setupFakeWorker();
++    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';
++          } else if (numComps == 3) {
++            return 'DeviceRgbCS';
++          } else if (numComps == 4) {
++            return 'DeviceCmykCS';
 +          }
-           workerInitializedPromise.resolve();
-         }.bind(this));
++          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;
++    }
 +
-         var testObj = new Uint8Array(1);
-         // Some versions of Opera throw a DATA_CLONE_ERR on
-         // serializing the typed array.
-         messageHandler.send('test', testObj);
-         return;
-       } catch (e) {
-         info('The worker has been disabled.');
++    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;
 +      }
 +    }
-     // Either workers are disabled, not supported or have thrown an exception.
-     // Thus, we fallback to a faked worker.
-     globalScope.PDFJS.disableWorker = true;
-     this.setupFakeWorker();
-     workerInitializedPromise.resolve();
-   }
-   WorkerTransport.prototype = {
-     destroy: function WorkerTransport_destroy() {
-       if (this.worker)
-         this.worker.terminate();
++    return true;
++  };
 +
-       this.pageCache = [];
-       this.pagePromises = [];
++  ColorSpace.singletons = {
++    get gray() {
++      return shadow(this, 'gray', new DeviceGrayCS());
 +    },
-     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);
- 
-       // If the main thread is our worker, setup the handling for the messages
-       // the main thread sends to it self.
-       WorkerMessageHandler.setup(messageHandler);
++    get rgb() {
++      return shadow(this, 'rgb', new DeviceRgbCS());
 +    },
++    get cmyk() {
++      return shadow(this, 'cmyk', new DeviceCmykCS());
++    }
++  };
 +
-     setupMessageHandler:
-       function WorkerTransport_setupMessageHandler(messageHandler) {
-       this.messageHandler = messageHandler;
++  return ColorSpace;
++})();
 +
-       messageHandler.on('GetDoc', function transportDoc(data) {
-         var pdfInfo = data.pdfInfo;
-         var pdfDocument = new PDFDocumentProxy(pdfInfo, this);
-         this.pdfDocument = pdfDocument;
-         this.workerReadyPromise.resolve(pdfDocument);
-       }, this);
++/**
++ * 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;
++  }
 +
-       messageHandler.on('NeedPassword', function transportPassword(data) {
-         this.workerReadyPromise.reject(data.exception.message, data.exception);
-       }, this);
++  AlternateCS.prototype = {
++    getRgb: ColorSpace.prototype.getRgb,
++    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,
++                                                    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;
 +
-       messageHandler.on('IncorrectPassword', function transportBadPass(data) {
-         this.workerReadyPromise.reject(data.exception.message, data.exception);
-       }, this);
++      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, 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
++  };
 +
-       messageHandler.on('InvalidPDF', function transportInvalidPDF(data) {
-         this.workerReadyPromise.reject(data.exception.name, data.exception);
-       }, this);
++  return AlternateCS;
++})();
 +
-       messageHandler.on('MissingPDF', function transportMissingPDF(data) {
-         this.workerReadyPromise.reject(data.exception.message, data.exception);
-       }, this);
++var PatternCS = (function PatternCSClosure() {
++  function PatternCS(baseCS) {
++    this.name = 'Pattern';
++    this.base = baseCS;
++  }
++  PatternCS.prototype = {};
 +
-       messageHandler.on('UnknownError', function transportUnknownError(data) {
-         this.workerReadyPromise.reject(data.exception.message, data.exception);
-       }, this);
++  return PatternCS;
++})();
 +
-       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);
-       }, this);
++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;
 +
-       messageHandler.on('GetAnnotations', function transportAnnotations(data) {
-         var annotations = data.annotations;
-         var promise = this.pageCache[data.pageIndex].annotationsPromise;
-         promise.resolve(annotations);
-       }, this);
++    var baseNumComps = base.numComps;
++    var length = baseNumComps * highVal;
++    var lookupArray;
 +
-       messageHandler.on('RenderPage', function transportRender(data) {
-         var page = this.pageCache[data.pageIndex];
-         var depFonts = data.depFonts;
++    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;
++  }
 +
-         page.stats.timeEnd('Page Request');
-         page.startRenderingFromOperatorList(data.operatorList, depFonts);
-       }, this);
++  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;
 +
-       messageHandler.on('commonobj', function transportObj(data) {
-         var id = data[0];
-         var type = data[1];
-         if (this.commonObjs.hasData(id))
-           return;
++      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;
++})();
 +
-         switch (type) {
-           case 'Font':
-             var exportedData = data[2];
++var DeviceGrayCS = (function DeviceGrayCSClosure() {
++  function DeviceGrayCS() {
++    this.name = 'DeviceGray';
++    this.numComps = 1;
++    this.defaultColor = new Float32Array([0]);
++  }
 +
-             // At this point, only the font object is created but the font is
-             // not yet attached to the DOM. This is done in `FontLoader.bind`.
-             var font;
-             if ('error' in exportedData)
-               font = new ErrorFont(exportedData.error);
-             else
-               font = new Font(exportedData);
-             this.commonObjs.resolve(id, font);
-             break;
-           default:
-             error('Got unknown common object type ' + type);
-         }
-       }, this);
++  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;
++})();
 +
-       messageHandler.on('obj', function transportObj(data) {
-         var id = data[0];
-         var pageIndex = data[1];
-         var type = data[2];
-         var pageProxy = this.pageCache[pageIndex];
-         if (pageProxy.objs.hasData(id))
-           return;
++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;
++})();
 +
-         switch (type) {
-           case 'JpegStream':
-             var imageData = data[3];
-             loadJpegStream(id, imageData, pageProxy.objs);
-             break;
-           case 'Image':
-             var imageData = data[3];
-             pageProxy.objs.resolve(id, imageData);
++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;
++  }
 +
-             // heuristics that will allow not to store large data
-             var MAX_IMAGE_SIZE_TO_STORE = 8000000;
-             if ('data' in imageData &&
-                 imageData.data.length > MAX_IMAGE_SIZE_TO_STORE) {
-               pageProxy.cleanupAfterRender = true;
-             }
-             break;
-           default:
-             error('Got unknown object type ' + type);
-         }
-       }, this);
++  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
++  };
 +
-       messageHandler.on('DocProgress', function transportDocProgress(data) {
-         this.workerReadyPromise.progress({
-           loaded: data.loaded,
-           total: data.total
-         });
-       }, this);
++  return DeviceCmykCS;
++})();
 +
-       messageHandler.on('DocError', function transportDocError(data) {
-         this.workerReadyPromise.reject(data);
-       }, this);
++//
++// 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]);
 +
-       messageHandler.on('PageError', function transportError(data) {
-         var page = this.pageCache[data.pageNum - 1];
-         if (page.displayReadyPromise)
-           page.displayReadyPromise.reject(data.error);
-         else
-           error(data.error);
-       }, this);
++    if (!whitePoint) {
++      error('WhitePoint missing - required for color space CalGray');
++    }
++    blackPoint = blackPoint || [0, 0, 0];
++    gamma = gamma || 1;
 +
-       messageHandler.on('JpegDecode', function(data, promise) {
-         var imageData = data[0];
-         var components = data[1];
-         if (components != 3 && components != 1)
-           error('Only 3 component or 1 component can be returned');
++    // Translate arguments to spec variables.
++    this.XW = whitePoint[0];
++    this.YW = whitePoint[1];
++    this.ZW = whitePoint[2];
 +
-         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;
++    this.XB = blackPoint[0];
++    this.YB = blackPoint[1];
++    this.ZB = blackPoint[2];
 +
-           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];
-             }
-           } else if (components == 1) {
-             for (var i = 0, j = 0; i < rgbaLength; i += 4, j++) {
-               buf[j] = data[i];
-             }
-           }
-           promise.resolve({ data: buf, width: width, height: height});
-         }).bind(this);
-         var src = 'data:image/jpeg;base64,' + window.btoa(imageData);
-         img.src = src;
-       });
-     },
++    this.G = gamma;
 +
-     fetchDocument: function WorkerTransport_fetchDocument(source) {
-       this.messageHandler.send('GetDocRequest', {source: source});
-     },
++    // 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');
++    }
 +
-     getData: function WorkerTransport_getData(promise) {
-       this.messageHandler.send('GetData', null, function(data) {
-         promise.resolve(data);
-       });
-     },
++    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;
++    }
 +
-     getPage: function WorkerTransport_getPage(pageNumber, promise) {
-       var pageIndex = pageNumber - 1;
-       if (pageIndex in this.pagePromises)
-         return this.pagePromises[pageIndex];
-       var promise = new PDFJS.Promise('Page ' + pageNumber);
-       this.pagePromises[pageIndex] = promise;
-       this.messageHandler.send('GetPageRequest', { pageIndex: pageIndex });
-       return promise;
-     },
++    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.');
++    }
 +
-     getAnnotations: function WorkerTransport_getAnnotations(pageIndex) {
-       this.messageHandler.send('GetAnnotationsRequest',
-         { pageIndex: pageIndex });
++    if (this.G < 1) {
++      info('Invalid Gamma: ' + this.G + ' for ' + this.name +
++           ', falling back to default');
++      this.G = 1;
 +    }
-   };
-   return WorkerTransport;
++  }
 +
- })();
++  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;
 +
- // <canvas> contexts store most of the state we need natively.
- // However, PDF needs a bit more state, which we store here.
++    // Decode XYZ, as per spec.
++    var X = M;
++    var Y = L;
++    var Z = N;
 +
- var TextRenderingMode = {
-   FILL: 0,
-   STROKE: 1,
-   FILL_STROKE: 2,
-   INVISIBLE: 3,
-   FILL_ADD_TO_PATH: 4,
-   STROKE_ADD_TO_PATH: 5,
-   FILL_STROKE_ADD_TO_PATH: 6,
-   ADD_TO_PATH: 7,
-   ADD_TO_PATH_FLAG: 4
- };
++    // 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);
 +
- // Minimal font size that would be used during canvas fillText operations.
- var MIN_FONT_SIZE = 1;
++    // Convert values to rgb range [0, 255].
++    dest[destOffset] = Lstar * 255 / 100;
++    dest[destOffset + 1] = Lstar * 255 / 100;
++    dest[destOffset + 2] = Lstar * 255 / 100;
++  }
 +
- function createScratchCanvas(width, height) {
-   var canvas = document.createElement('canvas');
-   canvas.width = width;
-   canvas.height = height;
-   return canvas;
- }
++  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);
 +
- function addContextCurrentTransform(ctx) {
-   // If the context doesn't expose a `mozCurrentTransform`, add a JS based on.
-   if (!ctx.mozCurrentTransform) {
-     // Store the original context
-     ctx._scaleX = ctx._scaleX || 1.0;
-     ctx._scaleY = ctx._scaleY || 1.0;
-     ctx._originalSave = ctx.save;
-     ctx._originalRestore = ctx.restore;
-     ctx._originalRotate = ctx.rotate;
-     ctx._originalScale = ctx.scale;
-     ctx._originalTranslate = ctx.translate;
-     ctx._originalTransform = ctx.transform;
++      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;
++})();
 +
-     ctx._transformMatrix = [ctx._scaleX, 0, 0, ctx._scaleY, 0, 0];
-     ctx._transformStack = [];
++//
++// 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]);
 +
-     Object.defineProperty(ctx, 'mozCurrentTransform', {
-       get: function getCurrentTransform() {
-         return this._transformMatrix;
-       }
-     });
++    if (!whitePoint) {
++      error('WhitePoint missing - required for color space Lab');
++    }
++    blackPoint = blackPoint || [0, 0, 0];
++    range = range || [-100, 100, -100, 100];
 +
-     Object.defineProperty(ctx, 'mozCurrentTransformInverse', {
-       get: function getCurrentTransformInverse() {
-         // Calculation done using WolframAlpha:
-         // http://www.wolframalpha.com/input/?
-         //   i=Inverse+{{a%2C+c%2C+e}%2C+{b%2C+d%2C+f}%2C+{0%2C+0%2C+1}}
++    // 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];
 +
-         var m = this._transformMatrix;
-         var a = m[0], b = m[1], c = m[2], d = m[3], e = m[4], f = m[5];
++    // 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];
 +
-         var ad_bc = a * d - b * c;
-         var bc_ad = b * c - a * d;
++    // Validate vars as per spec
++    if (this.XW < 0 || this.ZW < 0 || this.YW !== 1) {
++      error('Invalid WhitePoint components, no fallback available');
++    }
 +
-         return [
-           d / ad_bc,
-           b / bc_ad,
-           c / bc_ad,
-           a / ad_bc,
-           (d * e - c * f) / bc_ad,
-           (b * e - a * f) / ad_bc
-         ];
-       }
-     });
++    if (this.XB < 0 || this.YB < 0 || this.ZB < 0) {
++      info('Invalid BlackPoint, falling back to default');
++      this.XB = this.YB = this.ZB = 0;
++    }
 +
-     ctx.save = function ctxSave() {
-       var old = this._transformMatrix;
-       this._transformStack.push(old);
-       this._transformMatrix = old.slice(0, 6);
++    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;
++    }
++  }
 +
-       this._originalSave();
-     };
++  // Function g(x) from spec
++  function fn_g(x) {
++    if (x >= 6 / 29) {
++      return x * x * x;
++    } else {
++      return (108 / 841) * (x - 4 / 29);
++    }
++  }
 +
-     ctx.restore = function ctxRestore() {
-       var prev = this._transformStack.pop();
-       if (prev) {
-         this._transformMatrix = prev;
-         this._originalRestore();
-       }
-     };
++  function decode(value, high1, low2, high2) {
++    return low2 + (value) * (high2 - low2) / (high1);
++  }
 +
-     ctx.translate = function ctxTranslate(x, y) {
-       var m = this._transformMatrix;
-       m[4] = m[0] * x + m[2] * y + m[4];
-       m[5] = m[1] * x + m[3] * y + m[5];
++  // 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);
++    }
 +
-       this._originalTranslate(x, y);
-     };
++    // 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;
 +
-     ctx.scale = function ctxScale(x, y) {
-       var m = this._transformMatrix;
-       m[0] = m[0] * x;
-       m[1] = m[1] * x;
-       m[2] = m[2] * y;
-       m[3] = m[3] * y;
++    // Computes intermediate variables X,Y,Z as per spec
++    var M = (Ls + 16) / 116;
++    var L = M + (as / 500);
++    var N = M - (bs / 200);
 +
-       this._originalScale(x, y);
-     };
++    var X = cs.XW * fn_g(L);
++    var Y = cs.YW * fn_g(M);
++    var Z = cs.ZW * fn_g(N);
 +
-     ctx.transform = function ctxTransform(a, b, c, d, e, f) {
-       var m = this._transformMatrix;
-       this._transformMatrix = [
-         m[0] * a + m[2] * b,
-         m[1] * a + m[3] * b,
-         m[0] * c + m[2] * d,
-         m[1] * c + m[3] * d,
-         m[0] * e + m[2] * f + m[4],
-         m[1] * e + m[3] * f + m[5]
-       ];
++    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;
++  }
 +
-       ctx._originalTransform(a, b, c, d, e, f);
-     };
++  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,
++    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;
++})();
 +
-     ctx.rotate = function ctxRotate(angle) {
-       var cosValue = Math.cos(angle);
-       var sinValue = Math.sin(angle);
 +
-       var m = this._transformMatrix;
-       this._transformMatrix = [
-         m[0] * cosValue + m[2] * sinValue,
-         m[1] * cosValue + m[3] * sinValue,
-         m[0] * (-sinValue) + m[2] * cosValue,
-         m[1] * (-sinValue) + m[3] * cosValue,
-         m[4],
-         m[5]
-       ];
 +
-       this._originalRotate(angle);
-     };
-   }
- }
++var PDFFunction = (function PDFFunctionClosure() {
++  var CONSTRUCT_SAMPLED = 0;
++  var CONSTRUCT_INTERPOLATED = 2;
++  var CONSTRUCT_STICHED = 3;
++  var CONSTRUCT_POSTSCRIPT = 4;
 +
- var CanvasExtraState = (function CanvasExtraStateClosure() {
-   function CanvasExtraState(old) {
-     // Are soft masks and alpha values shapes or opacities?
-     this.alphaIsShape = false;
-     this.fontSize = 0;
-     this.fontSizeScale = 1;
-     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.textRenderingMode = TextRenderingMode.FILL;
-     this.textRise = 0;
-     // Color spaces
-     this.fillColorSpace = new DeviceGrayCS();
-     this.fillColorSpaceObj = null;
-     this.strokeColorSpace = new DeviceGrayCS();
-     this.strokeColorSpaceObj = null;
-     this.fillColorObj = null;
-     this.strokeColorObj = null;
-     // Default fore and background colors
-     this.fillColor = '#000000';
-     this.strokeColor = '#000000';
-     // Note: fill alpha applies to all non-stroking operations
-     this.fillAlpha = 1;
-     this.strokeAlpha = 1;
-     this.lineWidth = 1;
-     this.paintFormXObjectDepth = 0;
++  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;
 +
-     this.old = old;
-   }
++      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);
 +
-   CanvasExtraState.prototype = {
-     clone: function CanvasExtraState_clone() {
-       return Object.create(this);
++      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;
 +    },
-     setCurrentPoint: function CanvasExtraState_setCurrentPoint(x, y) {
-       this.x = x;
-       this.y = y;
-     }
-   };
-   return CanvasExtraState;
- })();
 +
- 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;
++    getIR: function PDFFunction_getIR(xref, fn) {
++      var dict = fn.dict;
++      if (!dict) {
++        dict = fn;
++      }
 +
-   function CanvasGraphics(canvasCtx, commonObjs, objs, textLayer, imageLayer) {
-     this.ctx = canvasCtx;
-     this.current = new CanvasExtraState();
-     this.stateStack = [];
-     this.pendingClip = null;
-     this.res = null;
-     this.xobjs = null;
-     this.commonObjs = commonObjs;
-     this.objs = objs;
-     this.textLayer = textLayer;
-     this.imageLayer = imageLayer;
-     this.groupStack = [];
-     if (canvasCtx) {
-       addContextCurrentTransform(canvasCtx);
-     }
-   }
++      var types = [this.constructSampled,
++                   null,
++                   this.constructInterpolated,
++                   this.constructStiched,
++                   this.constructPostScript];
 +
-   function applyStencilMask(imgArray, width, height, inverseDecode, buffer) {
-     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] = 0;
-         }
-         bufferPos += 4;
-         mask >>= 1;
++      var typeNum = dict.get('FunctionType');
++      var typeFn = types[typeNum];
++      if (!typeFn) {
++        error('Unknown type of function');
 +      }
-     }
-   }
 +
-   function putBinaryImageData(ctx, data, w, h) {
-     var tmpImgData = 'createImageData' in ctx ? ctx.createImageData(w, h) :
-       ctx.getImageData(0, 0, w, h);
- 
-     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];
-     }
++      return typeFn.call(this, fn, dict, xref);
++    },
 +
-     ctx.putImageData(tmpImgData, 0, 0);
-   }
++    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);
++      }
++    },
 +
-   function prescaleImage(pixels, width, height, widthScale, heightScale) {
-     pixels = new Uint8Array(pixels); // creating a copy
-     while (widthScale > 2 || heightScale > 2) {
-       if (heightScale > 2) {
-         // scaling image twice vertically
-         var rowSize = width * 4;
-         var k = 0, l = 0;
-         for (var i = 0; i < height - 1; i += 2) {
-           for (var j = 0; j < width; j++) {
-             var alpha1 = pixels[k + 3], alpha2 = pixels[k + 3 + rowSize];
-             if (alpha1 === alpha2) {
-               pixels[l] = (pixels[k] + pixels[k + rowSize]) >> 1;
-               pixels[l + 1] = (pixels[k + 1] + pixels[k + 1 + rowSize]) >> 1;
-               pixels[l + 2] = (pixels[k + 2] + pixels[k + 2 + rowSize]) >> 1;
-               pixels[l + 3] = alpha1;
-             } else if (alpha1 < alpha2) {
-               var d = 256 - alpha2 + alpha1;
-               pixels[l] = (pixels[k] * d + (pixels[k + rowSize] << 8)) >> 9;
-               pixels[l + 1] = (pixels[k + 1] * d +
-                               (pixels[k + 1 + rowSize] << 8)) >> 9;
-               pixels[l + 2] = (pixels[k + 2] * d +
-                               (pixels[k + 2 + rowSize] << 8)) >> 9;
-               pixels[l + 3] = alpha2;
-             } else {
-               var d = 256 - alpha1 + alpha2;
-               pixels[l] = ((pixels[k] << 8) + pixels[k + rowSize] * d) >> 9;
-               pixels[l + 1] = ((pixels[k + 1] << 8) +
-                               pixels[k + 1 + rowSize] * d) >> 9;
-               pixels[l + 2] = ((pixels[k + 2] << 8) +
-                               pixels[k + 2 + rowSize] * d) >> 9;
-               pixels[l + 3] = alpha1;
-             }
-             k += 4; l += 4;
-           }
-           k += rowSize;
-         }
-         if (height & 1) {
-           for (var i = 0; i < rowSize; i++) {
-             pixels[l++] = pixels[k++];
-           }
++    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;
 +        }
-         height = (height + 1) >> 1;
-         heightScale /= 2;
++        return out;
 +      }
-       if (widthScale > 2) {
-         // scaling image twice horizontally
-         var k = 0, l = 0;
-         for (var i = 0; i < height; i++) {
-           for (var j = 0; j < width - 1; j += 2) {
-             var alpha1 = pixels[k + 3], alpha2 = pixels[k + 7];
-             if (alpha1 === alpha2) {
-               pixels[l] = (pixels[k] + pixels[k + 4]) >> 1;
-               pixels[l + 1] = (pixels[k + 1] + pixels[k + 5]) >> 1;
-               pixels[l + 2] = (pixels[k + 2] + pixels[k + 6]) >> 1;
-               pixels[l + 3] = alpha1;
-             } else if (alpha1 < alpha2) {
-               var d = 256 - alpha2 + alpha1;
-               pixels[l] = (pixels[k] * d + (pixels[k + 4] << 8)) >> 9;
-               pixels[l + 1] = (pixels[k + 1] * d + (pixels[k + 5] << 8)) >> 9;
-               pixels[l + 2] = (pixels[k + 2] * d + (pixels[k + 6] << 8)) >> 9;
-               pixels[l + 3] = alpha2;
-             } else {
-               var d = 256 - alpha1 + alpha2;
-               pixels[l] = ((pixels[k] << 8) + pixels[k + 4] * d) >> 9;
-               pixels[l + 1] = ((pixels[k + 1] << 8) + pixels[k + 5] * d) >> 9;
-               pixels[l + 2] = ((pixels[k + 2] << 8) + pixels[k + 6] * d) >> 9;
-               pixels[l + 3] = alpha1;
-             }
-             k += 8; l += 4;
-           }
-           if (width & 1) {
-             pixels[l++] = pixels[k++];
-             pixels[l++] = pixels[k++];
-             pixels[l++] = pixels[k++];
-             pixels[l++] = pixels[k++];
-           }
-         }
-         width = (width + 1) >> 1;
-         widthScale /= 2;
++      var domain = dict.get('Domain');
++      var range = dict.get('Range');
++
++      if (!domain || !range) {
++        error('No domain or range');
 +      }
-     }
 +
-     var tmpCanvas = createScratchCanvas(width, height);
-     var tmpCtx = tmpCanvas.getContext('2d');
-     putBinaryImageData(tmpCtx, pixels.subarray(0, width * height * 4),
-                                width, height);
++      var inputSize = domain.length / 2;
++      var outputSize = range.length / 2;
 +
-     return tmpCanvas;
-   }
++      domain = toMultiArray(domain);
++      range = toMultiArray(range);
 +
-   function copyCtxState(sourceCtx, destCtx) {
-     var properties = ['strokeStyle', 'fillStyle', 'fillRule', 'globalAlpha',
-                       'lineWidth', 'lineCap', 'lineJoin', 'miterLimit',
-                       'globalCompositeOperation', 'font'];
-     for (var i = 0, ii = properties.length; i < ii; i++) {
-       var property = properties[i];
-       if (property in sourceCtx) {
-         destCtx[property] = sourceCtx[property];
++      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);
 +      }
-     }
-     if ('setLineDash' in sourceCtx) {
-       destCtx.setLineDash(sourceCtx.getLineDash());
-       destCtx.lineDashOffset =  sourceCtx.lineDashOffset;
-     } else if ('mozDash' in sourceCtx) {
-       destCtx.mozDash = sourceCtx.mozDash;
-       destCtx.mozDashOffset = sourceCtx.mozDashOffset;
-     }
-   }
 +
-   var LINE_CAP_STYLES = ['butt', 'round', 'square'];
-   var LINE_JOIN_STYLES = ['miter', 'round', 'bevel'];
-   var NORMAL_CLIP = {};
-   var EO_CLIP = {};
++      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);
 +
-   CanvasGraphics.prototype = {
-     slowCommands: {
-       'stroke': true,
-       'closeStroke': true,
-       'fill': true,
-       'eoFill': true,
-       'fillStroke': true,
-       'eoFillStroke': true,
-       'closeFillStroke': true,
-       'closeEOFillStroke': true,
-       'showText': true,
-       'showSpacedText': true,
-       'setStrokeColorSpace': true,
-       'setFillColorSpace': true,
-       'setStrokeColor': true,
-       'setStrokeColorN': true,
-       'setFillColor': true,
-       'setFillColorN': true,
-       'setStrokeGray': true,
-       'setFillGray': true,
-       'setStrokeRGBColor': true,
-       'setFillRGBColor': true,
-       'setStrokeCMYKColor': true,
-       'setFillCMYKColor': true,
-       'paintJpegXObject': true,
-       'paintImageXObject': true,
-       'paintInlineImageXObject': true,
-       'paintInlineImageXObjectGroup': true,
-       'paintImageMaskXObject': true,
-       'paintImageMaskXObjectGroup': true,
-       'shadingFill': true
-     },
++      var decode = dict.get('Decode');
++      if (!decode) {
++        decode = range;
++      } else {
++        decode = toMultiArray(decode);
++      }
 +
-     beginDrawing: function CanvasGraphics_beginDrawing(viewport) {
-       var transform = viewport.transform;
-       this.ctx.save();
-       this.ctx.transform.apply(this.ctx, transform);
++      var samples = this.getSampleArray(size, outputSize, bps, str);
 +
-       if (this.textLayer) {
-         this.textLayer.beginLayout();
-       }
-       if (this.imageLayer) {
-         this.imageLayer.beginLayout();
-       }
++      return [
++        CONSTRUCT_SAMPLED, inputSize, domain, encode, decode, samples, size,
++        outputSize, Math.pow(2, bps) - 1, range
++      ];
 +    },
 +
-     executeOperatorList: function CanvasGraphics_executeOperatorList(
-                                     operatorList,
-                                     executionStartIdx, continueCallback,
-                                     stepper) {
-       var argsArray = operatorList.argsArray;
-       var fnArray = operatorList.fnArray;
-       var i = executionStartIdx || 0;
-       var argsArrayLen = argsArray.length;
- 
-       // Sometimes the OperatorList to execute is empty.
-       if (argsArrayLen == i) {
-         return i;
++    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)));
 +      }
 +
-       var executionEndIdx;
-       var endTime = Date.now() + EXECUTION_TIME;
- 
-       var commonObjs = this.commonObjs;
-       var objs = this.objs;
-       var fnName;
-       var slowCommands = this.slowCommands;
++      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];
 +
-       while (true) {
-         if (stepper && i === stepper.nextBreakPoint) {
-           stepper.breakIt(i, continueCallback);
-           return i;
++        if (m != args.length) {
++          error('Incorrect number of arguments: ' + m + ' != ' +
++                args.length);
 +        }
 +
-         fnName = fnArray[i];
- 
-         if (fnName !== 'dependency') {
-           this[fnName].apply(this, argsArray[i]);
-         } else {
-           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 x = args;
 +
-             // 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);
-               return i;
++        // 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;
 +        }
 +
-         i++;
++        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];
++          }
 +
-         // If the entire operatorList was executed, stop as were done.
-         if (i == argsArrayLen) {
-           return 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]);
 +
-         // If the execution took longer then a certain amount of time, shedule
-         // to continue exeution after a short delay.
-         // However, this is only possible if a 'continueCallback' is passed in.
-         if (continueCallback && slowCommands[fnName] && Date.now() > endTime) {
-           setTimeout(continueCallback, 0);
-           return i;
++          // y_j = min(max(r_j, range_2j), range_2j+1)
++          y[j] = Math.min(Math.max(rj, range[j][0]), range[j][1]);
 +        }
 +
-         // If the operatorList isn't executed completely yet OR the execution
-         // time was short enough, do another execution round.
-       }
++        return y;
++      };
 +    },
 +
-     endDrawing: function CanvasGraphics_endDrawing() {
-       this.ctx.restore();
++    constructInterpolated: function PDFFunction_constructInterpolated(str,
++                                                                      dict) {
++      var c0 = dict.get('C0') || [0];
++      var c1 = dict.get('C1') || [1];
++      var n = dict.get('N');
 +
-       if (this.textLayer) {
-         this.textLayer.endLayout();
-       }
-       if (this.imageLayer) {
-         this.imageLayer.endLayout();
++      if (!isArray(c0) || !isArray(c1)) {
++        error('Illegal dictionary for interpolated function');
 +      }
-     },
 +
-     // Graphics state
-     setLineWidth: function CanvasGraphics_setLineWidth(width) {
-       this.current.lineWidth = width;
-       this.ctx.lineWidth = width;
-     },
-     setLineCap: function CanvasGraphics_setLineCap(style) {
-       this.ctx.lineCap = LINE_CAP_STYLES[style];
-     },
-     setLineJoin: function CanvasGraphics_setLineJoin(style) {
-       this.ctx.lineJoin = LINE_JOIN_STYLES[style];
-     },
-     setMiterLimit: function CanvasGraphics_setMiterLimit(limit) {
-       this.ctx.miterLimit = limit;
-     },
-     setDash: function CanvasGraphics_setDash(dashArray, dashPhase) {
-       var ctx = this.ctx;
-       if ('setLineDash' in ctx) {
-         ctx.setLineDash(dashArray);
-         ctx.lineDashOffset = dashPhase;
-       } else {
-         ctx.mozDash = dashArray;
-         ctx.mozDashOffset = dashPhase;
++      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];
 +    },
-     setRenderingIntent: function CanvasGraphics_setRenderingIntent(intent) {
-       // Maybe if we one day fully support color spaces this will be important
-       // for now we can ignore.
-       // TODO set rendering intent?
-     },
-     setFlatness: function CanvasGraphics_setFlatness(flatness) {
-       // There's no way to control this with canvas, but we can safely ignore.
-       // TODO set flatness?
-     },
-     setGState: function CanvasGraphics_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':
-             this.setRenderingIntent(value);
-             break;
-           case 'FL':
-             this.setFlatness(value);
-             break;
-           case 'Font':
-             this.setFont(state[1], state[2]);
-             break;
-           case 'CA':
-             this.current.strokeAlpha = state[1];
-             break;
-           case 'ca':
-             this.current.fillAlpha = state[1];
-             this.ctx.globalAlpha = state[1];
-             break;
-           case 'BM':
-             if (value && value.name && (value.name !== 'Normal')) {
-               var mode = value.name.replace(/([A-Z])/g,
-                 function(c) {
-                   return '-' + c.toLowerCase();
-                 }
-               ).substring(1);
-               this.ctx.globalCompositeOperation = mode;
-               if (this.ctx.globalCompositeOperation !== mode) {
-                 warn('globalCompositeOperation "' + mode +
-                      '" is not supported');
-               }
-             } else {
-               this.ctx.globalCompositeOperation = 'source-over';
-             }
-             break;
++    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]));
 +        }
-       }
-     },
-     save: function CanvasGraphics_save() {
-       this.ctx.save();
-       var old = this.current;
-       this.stateStack.push(old);
-       this.current = old.clone();
++
++        return out;
++
++      };
 +    },
-     restore: function CanvasGraphics_restore() {
-       if ('textClipLayers' in this) {
-         this.completeTextClipping();
++
++    constructStiched: function PDFFunction_constructStiched(fn, dict, xref) {
++      var domain = dict.get('Domain');
++
++      if (!domain) {
++        error('No domain');
 +      }
 +
-       var prev = this.stateStack.pop();
-       if (prev) {
-         this.current = prev;
-         this.ctx.restore();
++      var inputSize = domain.length / 2;
++      if (inputSize != 1) {
++        error('Bad domain for stiched function');
 +      }
-     },
-     transform: function CanvasGraphics_transform(a, b, c, d, e, f) {
-       this.ctx.transform(a, b, c, d, e, f);
-     },
 +
-     // 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) {
-       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);
-     },
-     closePath: function CanvasGraphics_closePath() {
-       this.ctx.closePath();
-     },
-     rectangle: function CanvasGraphics_rectangle(x, y, width, height) {
-       this.ctx.rect(x, y, width, height);
++      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];
 +    },
-     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)
-         ctx.lineWidth = this.getSinglePixelWidth();
-       // For stroke we want to temporarily change the global alpha to the
-       // stroking alpha.
-       ctx.globalAlpha = this.current.strokeAlpha;
-       if (strokeColor && strokeColor.hasOwnProperty('type') &&
-           strokeColor.type === 'Pattern') {
-         // for patterns, we transform to pattern space, calculate
-         // the pattern, call stroke, and restore to user space
-         ctx.save();
-         ctx.strokeStyle = strokeColor.getPattern(ctx);
-         ctx.stroke();
-         ctx.restore();
-       } else {
-         ctx.stroke();
-       }
-       if (consumePath)
-         this.consumePath();
-       // Restore the global alpha to the fill alpha
-       ctx.globalAlpha = this.current.fillAlpha;
-     },
-     closeStroke: function CanvasGraphics_closeStroke() {
-       this.closePath();
-       this.stroke();
-     },
-     fill: function CanvasGraphics_fill(consumePath) {
-       consumePath = typeof consumePath !== 'undefined' ? consumePath : true;
-       var ctx = this.ctx;
-       var fillColor = this.current.fillColor;
 +
-       if (fillColor && fillColor.hasOwnProperty('type') &&
-           fillColor.type === 'Pattern') {
-         ctx.save();
-         ctx.fillStyle = fillColor.getPattern(ctx);
-         ctx.fill();
-         ctx.restore();
-       } else {
-         ctx.fill();
++    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]));
 +      }
-       if (consumePath)
-         this.consumePath();
-     },
-     eoFill: function CanvasGraphics_eoFill() {
-       var savedFillRule = this.setEOFillRule();
-       this.fill();
-       this.restoreFillRule(savedFillRule);
-     },
-     fillStroke: function CanvasGraphics_fillStroke() {
-       this.fill(false);
-       this.stroke(false);
 +
-       this.consumePath();
-     },
-     eoFillStroke: function CanvasGraphics_eoFillStroke() {
-       var savedFillRule = this.setEOFillRule();
-       this.fillStroke();
-       this.restoreFillRule(savedFillRule);
-     },
-     closeFillStroke: function CanvasGraphics_closeFillStroke() {
-       this.closePath();
-       this.fillStroke();
-     },
-     closeEOFillStroke: function CanvasGraphics_closeEOFillStroke() {
-       var savedFillRule = this.setEOFillRule();
-       this.closePath();
-       this.fillStroke();
-       this.restoreFillRule(savedFillRule);
-     },
-     endPath: function CanvasGraphics_endPath() {
-       this.consumePath();
-     },
++      return function constructStichedFromIRResult(args) {
++        var clip = function constructStichedFromIRClip(v, min, max) {
++          if (v > max) {
++            v = max;
++          } else if (v < min) {
++            v = min;
++          }
++          return v;
++        };
 +
-     // Clipping
-     clip: function CanvasGraphics_clip() {
-       this.pendingClip = NORMAL_CLIP;
-     },
-     eoClip: function CanvasGraphics_eoClip() {
-       this.pendingClip = EO_CLIP;
-     },
++        // 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;
++          }
++        }
 +
-     // Text
-     beginText: function CanvasGraphics_beginText() {
-       this.current.textMatrix = IDENTITY_MATRIX;
-       this.current.x = this.current.lineX = 0;
-       this.current.y = this.current.lineY = 0;
-     },
-     endText: function CanvasGraphics_endText() {
-       if ('textClipLayers' in this) {
-         this.swapImageForTextClipping();
-       }
-     },
-     getCurrentTextClipping: function CanvasGraphics_getCurrentTextClipping() {
-       var ctx = this.ctx;
-       var transform = ctx.mozCurrentTransform;
-       if ('textClipLayers' in this) {
-         // we need to reset only font and transform
-         var maskCtx = this.textClipLayers.maskCtx;
-         maskCtx.setTransform.apply(maskCtx, transform);
-         maskCtx.font = ctx.font;
-         return maskCtx;
-       }
++        // 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 canvasWidth = ctx.canvas.width;
-       var canvasHeight = ctx.canvas.height;
-       // keeping track of the text clipping of the separate canvas
-       var maskCanvas = createScratchCanvas(canvasWidth, canvasHeight);
-       var maskCtx = maskCanvas.getContext('2d');
-       maskCtx.setTransform.apply(maskCtx, transform);
-       maskCtx.font = ctx.font;
-       var textClipLayers = {
-         maskCanvas: maskCanvas,
-         maskCtx: maskCtx
-       };
-       this.textClipLayers = textClipLayers;
-       return maskCtx;
-     },
-     swapImageForTextClipping:
-       function CanvasGraphics_swapImageForTextClipping() {
-       var ctx = this.ctx;
-       var canvasWidth = ctx.canvas.width;
-       var canvasHeight = ctx.canvas.height;
-       // saving current image content and clearing whole canvas
-       ctx.save();
-       ctx.setTransform(1, 0, 0, 1, 0, 0);
-       var data = ctx.getImageData(0, 0, canvasWidth, canvasHeight);
-       this.textClipLayers.imageData = data;
-       ctx.clearRect(0, 0, canvasWidth, canvasHeight);
-       ctx.restore();
-     },
-     completeTextClipping: function CanvasGraphics_completeTextClipping() {
-       var ctx = this.ctx;
-       // applying mask to the image (result is saved in maskCanvas)
-       var maskCtx = this.textClipLayers.maskCtx;
-       maskCtx.setTransform(1, 0, 0, 1, 0, 0);
-       maskCtx.globalCompositeOperation = 'source-in';
-       maskCtx.drawImage(ctx.canvas, 0, 0);
++        var rmin = encode[2 * i];
++        var rmax = encode[2 * i + 1];
 +
-       // restoring image data and applying the result of masked drawing
-       ctx.save();
-       ctx.setTransform(1, 0, 0, 1, 0, 0);
-       ctx.putImageData(this.textClipLayers.imageData, 0, 0);
-       ctx.drawImage(this.textClipLayers.maskCanvas, 0, 0);
-       ctx.restore();
++        var v2 = rmin + (v - dmin) * (rmax - rmin) / (dmax - dmin);
 +
-       delete this.textClipLayers;
-     },
-     setCharSpacing: function CanvasGraphics_setCharSpacing(spacing) {
-       this.current.charSpacing = spacing;
-     },
-     setWordSpacing: function CanvasGraphics_setWordSpacing(spacing) {
-       this.current.wordSpacing = spacing;
-     },
-     setHScale: function CanvasGraphics_setHScale(scale) {
-       this.current.textHScale = scale / 100;
-     },
-     setLeading: function CanvasGraphics_setLeading(leading) {
-       this.current.leading = -leading;
++        // call the appropriate function
++        return fns[i]([v2]);
++      };
 +    },
-     setFont: function CanvasGraphics_setFont(fontRefName, size) {
-       var fontObj = this.commonObjs.get(fontRefName);
-       var current = this.current;
- 
-       if (!fontObj)
-         error('Can\'t find font for ' + fontRefName);
 +
-       current.fontMatrix = fontObj.fontMatrix ? fontObj.fontMatrix :
-                                                 FONT_IDENTITY_MATRIX;
++    constructPostScript: function PDFFunction_constructPostScript(fn, dict,
++                                                                  xref) {
++      var domain = dict.get('Domain');
++      var range = dict.get('Range');
 +
-       // A valid matrix needs all main diagonal elements to be non-zero
-       // This also ensures we bypass FF bugzilla bug #719844.
-       if (current.fontMatrix[0] === 0 ||
-           current.fontMatrix[3] === 0) {
-         warn('Invalid font matrix for font ' + fontRefName);
++      if (!domain) {
++        error('No domain.');
 +      }
 +
-       // The spec for Tf (setFont) says that 'size' specifies the font 'scale',
-       // and in some docs this can be negative (inverted x-y axes).
-       if (size < 0) {
-         size = -size;
-         current.fontDirection = -1;
-       } else {
-         current.fontDirection = 1;
++      if (!range) {
++        error('No range.');
 +      }
 +
-       this.current.font = fontObj;
-       this.current.fontSize = size;
++      var lexer = new PostScriptLexer(fn);
++      var parser = new PostScriptParser(lexer);
++      var code = parser.parse();
 +
-       if (fontObj.coded)
-         return; // we don't need ctx.font for Type3 fonts
++      return [CONSTRUCT_POSTSCRIPT, domain, range, code];
++    },
 +
-       var name = fontObj.loadedName || 'sans-serif';
-       var bold = fontObj.black ? (fontObj.bold ? 'bolder' : 'bold') :
-                                  (fontObj.bold ? 'bold' : 'normal');
++    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 italic = fontObj.italic ? 'italic' : 'normal';
-       var typeface = '"' + name + '", ' + fontObj.fallbackName;
++        var key = initialStack.join('_');
++        if (cache.has(key)) {
++          return cache.get(key);
++        }
 +
-       // Some font backends cannot handle fonts below certain size.
-       // Keeping the font at minimal size and using the fontSizeScale to change
-       // 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 :
-                                    size / MIN_FONT_SIZE;
++        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 rule = italic + ' ' + bold + ' ' + browserFontSize + 'px ' + typeface;
-       this.ctx.font = rule;
-     },
-     setTextRenderingMode: function CanvasGraphics_setTextRenderingMode(mode) {
-       this.current.textRenderingMode = mode;
-     },
-     setTextRise: function CanvasGraphics_setTextRise(rise) {
-       this.current.textRise = rise;
-     },
-     moveText: function CanvasGraphics_moveText(x, y) {
-       this.current.x = this.current.lineX += x;
-       this.current.y = this.current.lineY += y;
++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;
 +    },
-     setLeadingMoveText: function CanvasGraphics_setLeadingMoveText(x, y) {
-       this.setLeading(-y);
-       this.moveText(x, y);
++    get: function FunctionCache_get(key) {
++      return this.cache[key];
 +    },
-     setTextMatrix: function CanvasGraphics_setTextMatrix(a, b, c, d, e, f) {
-       this.current.textMatrix = [a, b, c, d, e, f];
++    set: function FunctionCache_set(key, value) {
++      if (this.total < MAX_CACHE_SIZE) {
++        this.cache[key] = value;
++        this.total++;
++      }
++    }
++  };
++  return FunctionCache;
++})();
 +
-       this.current.x = this.current.lineX = 0;
-       this.current.y = this.current.lineY = 0;
-     },
-     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);
++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);
 +    },
-     createTextGeometry: function CanvasGraphics_createTextGeometry() {
-       var geometry = {};
-       var ctx = this.ctx;
-       var font = this.current.font;
-       var ctxMatrix = ctx.mozCurrentTransform;
-       if (ctxMatrix) {
-         var bl = Util.applyTransform([0, 0], ctxMatrix);
-         var tr = Util.applyTransform([1, 1], ctxMatrix);
-         geometry.x = bl[0];
-         geometry.y = bl[1];
-         geometry.hScale = tr[0] - bl[0];
-         geometry.vScale = tr[1] - bl[1];
++    pop: function PostScriptStack_pop() {
++      if (this.stack.length <= 0) {
++        error('PostScript function stack underflow.');
 +      }
-       geometry.spaceWidth = font.spaceWidth;
-       geometry.fontName = font.loadedName;
-       geometry.fontFamily = font.fallbackName;
-       geometry.fontSize = this.current.fontSize;
-       return geometry;
++      return this.stack.pop();
 +    },
- 
-     showText: function CanvasGraphics_showText(str, skipTextSelection) {
-       var ctx = this.ctx;
-       var current = this.current;
-       var font = current.font;
-       var glyphs = font.charsToGlyphs(str);
-       var fontSize = current.fontSize;
-       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 glyphsLength = glyphs.length;
-       var textLayer = this.textLayer;
-       var geom;
-       var textSelection = textLayer && !skipTextSelection ? true : false;
-       var textRenderingMode = current.textRenderingMode;
-       var canvasWidth = 0.0;
-       var vertical = font.vertical;
-       var defaultVMetrics = font.defaultVMetrics;
- 
-       // 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);
- 
-         ctx.scale(textHScale, 1);
- 
-         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.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();
-       } else {
-         ctx.save();
-         this.applyTextTransforms();
- 
-         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;
- 
-         if (textSelection)
-           geom = this.createTextGeometry();
- 
-         if (fontSizeScale != 1.0) {
-           ctx.scale(fontSizeScale, fontSizeScale);
-           lineWidth /= fontSizeScale;
-         }
- 
-         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 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 (accent) {
-               scaledAccentX = scaledX + accent.offset.x / fontSizeScale;
-               scaledAccentY = scaledY - accent.offset.y / fontSizeScale;
-             }
-             switch (textRenderingMode) {
-               default: // other unsupported rendering modes
-               case TextRenderingMode.FILL:
-               case TextRenderingMode.FILL_ADD_TO_PATH:
-                 ctx.fillText(character, scaledX, scaledY);
-                 if (accent) {
-                   ctx.fillText(accent.fontChar, scaledAccentX, scaledAccentY);
-                 }
-                 break;
-               case TextRenderingMode.STROKE:
-               case TextRenderingMode.STROKE_ADD_TO_PATH:
-                 ctx.strokeText(character, scaledX, scaledY);
-                 if (accent) {
-                   ctx.strokeText(accent.fontChar, scaledAccentX, scaledAccentY);
-                 }
-                 break;
-               case TextRenderingMode.FILL_STROKE:
-               case TextRenderingMode.FILL_STROKE_ADD_TO_PATH:
-                 ctx.fillText(character, scaledX, scaledY);
-                 ctx.strokeText(character, scaledX, scaledY);
-                 if (accent) {
-                   ctx.fillText(accent.fontChar, scaledAccentX, scaledAccentY);
-                   ctx.strokeText(accent.fontChar, scaledAccentX, scaledAccentY);
-                 }
-                 break;
-               case TextRenderingMode.INVISIBLE:
-               case TextRenderingMode.ADD_TO_PATH:
-                 break;
-             }
-             if (textRenderingMode & TextRenderingMode.ADD_TO_PATH_FLAG) {
-               var clipCtx = this.getCurrentTextClipping();
-               clipCtx.fillText(character, scaledX, scaledY);
-               if (accent) {
-                 clipCtx.fillText(accent.fontChar, scaledAccentX, scaledAccentY);
-               }
-             }
-           }
- 
-           x += charWidth;
- 
-           canvasWidth += charWidth;
-         }
-         if (vertical) {
-           current.y -= x * textHScale;
-         } else {
-           current.x += x * textHScale;
-         }
-         ctx.restore();
++    copy: function PostScriptStack_copy(n) {
++      if (this.stack.length + n >= MAX_STACK_SIZE) {
++        error('PostScript function stack overflow.');
 +      }
- 
-       if (textSelection) {
-         geom.canvasWidth = canvasWidth;
-         if (vertical) {
-           var vmetric = font.defaultVMetrics;
-           geom.x += vmetric[1] * fontSize * current.fontMatrix[0] /
-                     fontSizeScale * geom.hScale;
-           geom.y += vmetric[2] * fontSize * current.fontMatrix[0] /
-                     fontSizeScale * geom.vScale;
-         }
-         this.textLayer.appendText(geom);
++      var stack = this.stack;
++      for (var i = stack.length - n, j = n - 1; j >= 0; j--, i++) {
++        stack.push(stack[i]);
 +      }
- 
-       return canvasWidth;
 +    },
-     showSpacedText: function CanvasGraphics_showSpacedText(arr) {
-       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;
- 
-       if (textSelection) {
-         ctx.save();
-         this.applyTextTransforms();
-         geom = this.createTextGeometry();
-         ctx.restore();
++    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 (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;
-           }
- 
-           if (textSelection)
-             spacingAccumulator += spacingLength;
-         } else if (isString(e)) {
-           var shownCanvasWidth = this.showText(e, true);
- 
-           if (textSelection) {
-             canvasWidth += spacingAccumulator + shownCanvasWidth;
-             spacingAccumulator = 0;
-           }
-         } else {
-           error('TJ array element ' + e + ' is not string or num');
-         }
++      for (i = l, j = c - 1; i < j; i++, j--) {
++        t = stack[i]; stack[i] = stack[j]; stack[j] = t;
 +      }
- 
-       if (textSelection) {
-         geom.canvasWidth = canvasWidth;
-         if (vertical) {
-           var fontSizeScale = current.fontSizeScale;
-           var vmetric = font.defaultVMetrics;
-           geom.x += vmetric[1] * fontSize * current.fontMatrix[0] /
-                     fontSizeScale * geom.hScale;
-           geom.y += vmetric[2] * fontSize * current.fontMatrix[0] /
-                     fontSizeScale * geom.vScale;
-         }
-         this.textLayer.appendText(geom);
-       }
-     },
-     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);
-     },
- 
-     // Type3 fonts
-     setCharWidth: function CanvasGraphics_setCharWidth(xWidth, yWidth) {
-       // We can safely ignore this since the width should be the same
-       // as the width in the Widths array.
-     },
-     setCharWidthAndBounds: function CanvasGraphics_setCharWidthAndBounds(xWidth,
-                                                                         yWidth,
-                                                                         llx,
-                                                                         lly,
-                                                                         urx,
-                                                                         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.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);
-       } else if (IR[0] == 'RadialAxial' || IR[0] == 'Dummy') {
-         var pattern = Pattern.shadingFromIR(IR);
-       } else {
-         error('Unkown IR type ' + IR[0]);
-       }
-       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;
-     },
-     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) {
-       if (!(this.current.strokeColorSpace instanceof DeviceGrayCS))
-         this.current.strokeColorSpace = new DeviceGrayCS();
- 
-       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) {
-       if (!(this.current.fillColorSpace instanceof DeviceGrayCS))
-         this.current.fillColorSpace = new DeviceGrayCS();
- 
-       var rgbColor = this.current.fillColorSpace.getRgb(arguments, 0);
-       var color = Util.makeCssRgb(rgbColor);
-       this.ctx.fillStyle = color;
-       this.current.fillColor = color;
-     },
-     setStrokeRGBColor: function CanvasGraphics_setStrokeRGBColor(r, g, b) {
-       if (!(this.current.strokeColorSpace instanceof DeviceRgbCS))
-         this.current.strokeColorSpace = new DeviceRgbCS();
- 
-       var rgbColor = this.current.strokeColorSpace.getRgb(arguments, 0);
-       var color = Util.makeCssRgb(rgbColor);
-       this.ctx.strokeStyle = color;
-       this.current.strokeColor = color;
-     },
-     setFillRGBColor: function CanvasGraphics_setFillRGBColor(r, g, b) {
-       if (!(this.current.fillColorSpace instanceof DeviceRgbCS))
-         this.current.fillColorSpace = new DeviceRgbCS();
- 
-       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) {
-       if (!(this.current.strokeColorSpace instanceof DeviceCmykCS))
-         this.current.strokeColorSpace = new DeviceCmykCS();
- 
-       var color = Util.makeCssCmyk(arguments);
-       this.ctx.strokeStyle = color;
-       this.current.strokeColor = color;
-     },
-     setFillCMYKColor: function CanvasGraphics_setFillCMYKColor(c, m, y, k) {
-       if (!(this.current.fillColorSpace instanceof DeviceCmykCS))
-         this.current.fillColorSpace = new DeviceCmykCS();
- 
-       var color = Util.makeCssCmyk(arguments);
-       this.ctx.fillStyle = color;
-       this.current.fillColor = color;
-     },
- 
-     shadingFill: function CanvasGraphics_shadingFill(patternIR) {
-       var ctx = this.ctx;
- 
-       this.save();
-       var pattern = Pattern.shadingFromIR(patternIR);
-       ctx.fillStyle = pattern.getPattern(ctx);
- 
-       var inv = ctx.mozCurrentTransformInverse;
-       if (inv) {
-         var canvas = ctx.canvas;
-         var width = canvas.width;
-         var height = canvas.height;
- 
-         var bl = Util.applyTransform([0, 0], inv);
-         var br = Util.applyTransform([0, height], inv);
-         var ul = Util.applyTransform([width, 0], inv);
-         var ur = Util.applyTransform([width, height], inv);
- 
-         var x0 = Math.min(bl[0], br[0], ul[0], ur[0]);
-         var y0 = Math.min(bl[1], br[1], ul[1], ur[1]);
-         var x1 = Math.max(bl[0], br[0], ul[0], ur[0]);
-         var y1 = Math.max(bl[1], br[1], ul[1], ur[1]);
- 
-         this.ctx.fillRect(x0, y0, x1 - x0, y1 - y0);
-       } else {
-         // HACK to draw the gradient onto an infinite rectangle.
-         // PDF gradients are drawn across the entire image while
-         // Canvas only allows gradients to be drawn in a rectangle
-         // The following bug should allow us to remove this.
-         // https://bugzilla.mozilla.org/show_bug.cgi?id=664884
- 
-         this.ctx.fillRect(-1e10, -1e10, 2e10, 2e10);
-       }
- 
-       this.restore();
-     },
- 
-     // Images
-     beginInlineImage: function CanvasGraphics_beginInlineImage() {
-       error('Should not call beginInlineImage');
-     },
-     beginImageData: function CanvasGraphics_beginImageData() {
-       error('Should not call beginImageData');
-     },
- 
-     paintFormXObjectBegin: function CanvasGraphics_paintFormXObjectBegin(matrix,
-                                                                         bbox) {
-       this.save();
-       this.current.paintFormXObjectDepth++;
- 
-       if (matrix && isArray(matrix) && 6 == matrix.length)
-         this.transform.apply(this, matrix);
- 
-       if (bbox && 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.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);
-     },
- 
-     beginGroup: function CanvasGraphics_beginGroup(group) {
-       this.save();
-       var currentCtx = this.ctx;
-       // TODO non-isolated groups - according to Rik at adobe non-isolated
-       // group results aren't usually that different and they even have tools
-       // that ignore this setting. Notes from Rik on implmenting:
-       // - When you encounter an transparency group, create a new canvas with
-       // the dimensions of the bbox
-       // - copy the content from the previous canvas to the new canvas
-       // - draw as usual
-       // - remove the backdrop alpha:
-       // alphaNew = 1 - (1 - alpha)/(1 - alphaBackdrop) with 'alpha' the alpha
-       // value of your transparency group and 'alphaBackdrop' the alpha of the
-       // backdrop
-       // - remove background color:
-       // colorNew = color - alphaNew *colorBackdrop /(1 - alphaNew)
-       if (!group.isolated) {
-         TODO('Support non-isolated groups.');
-       }
- 
-       // TODO knockout - supposedly possible with the clever use of compositing
-       // modes.
-       if (group.knockout) {
-         TODO('Support knockout groups.');
-       }
- 
-       var currentTransform = currentCtx.mozCurrentTransform;
-       if (group.matrix) {
-         currentCtx.transform.apply(currentCtx, group.matrix);
-       }
-       assert(group.bbox, 'Bounding box is required.');
- 
-       // Based on the current transform figure out how big the bounding box
-       // will actually be.
-       var bounds = Util.getAxialAlignedBoundingBox(
-                     group.bbox,
-                     currentCtx.mozCurrentTransform);
-       // Use ceil in case we're between sizes so we don't create canvas that is
-       // too small.
-       var drawnWidth = Math.ceil(bounds[2] - bounds[0]);
-       var drawnHeight = Math.ceil(bounds[3] - bounds[1]);
-       var scratchCanvas = createScratchCanvas(drawnWidth, drawnHeight);
-       var groupCtx = scratchCanvas.getContext('2d');
-       addContextCurrentTransform(groupCtx);
-       // 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.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);
- 
-       // 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]
-       ]);
-       this.groupStack.push(currentCtx);
-     },
- 
-     endGroup: function CanvasGraphics_endGroup(group) {
-       var groupCtx = this.ctx;
-       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) {
-         this.ctx.imageSmoothingEnabled = false;
-       } else {
-         this.ctx.mozImageSmoothingEnabled = false;
-       }
-       this.ctx.drawImage(groupCtx.canvas, 0, 0);
-       this.restore();
-     },
- 
-     paintJpegXObject: function CanvasGraphics_paintJpegXObject(objId, w, h) {
-       var domImage = this.objs.get(objId);
-       if (!domImage) {
-         error('Dependent image isn\'t ready yet');
-       }
- 
-       this.save();
- 
-       var ctx = this.ctx;
-       // scale the image to the unit square
-       ctx.scale(1 / w, -1 / h);
- 
-       ctx.drawImage(domImage, 0, 0, domImage.width, domImage.height,
-                     0, -h, w, h);
-       if (this.imageLayer) {
-         var currentTransform = ctx.mozCurrentTransformInverse;
-         var position = this.getCanvasPosition(0, 0);
-         this.imageLayer.appendImage({
-           objId: objId,
-           left: position[0],
-           top: position[1],
-           width: w / currentTransform[0],
-           height: h / currentTransform[3]
-         });
-       }
-       this.restore();
-     },
- 
-     paintImageMaskXObject: function CanvasGraphics_paintImageMaskXObject(
-                              imgArray, inverseDecode, width, height) {
-       var ctx = this.ctx;
-       var tmpCanvas = createScratchCanvas(width, height);
-       var tmpCtx = tmpCanvas.getContext('2d');
- 
-       var fillColor = this.current.fillColor;
-       tmpCtx.fillStyle = (fillColor && fillColor.hasOwnProperty('type') &&
-                           fillColor.type === 'Pattern') ?
-                           fillColor.getPattern(tmpCtx) : fillColor;
-       tmpCtx.fillRect(0, 0, width, height);
- 
-       var imgData = tmpCtx.getImageData(0, 0, width, height);
-       var pixels = imgData.data;
- 
-       applyStencilMask(imgArray, width, height, inverseDecode, pixels);
- 
-       this.paintInlineImageXObject(imgData);
-     },
- 
-     paintImageMaskXObjectGroup:
-       function CanvasGraphics_paintImageMaskXObjectGroup(images) {
-       var ctx = this.ctx;
-       var tmpCanvasWidth = 0, tmpCanvasHeight = 0, tmpCanvas, tmpCtx;
-       for (var i = 0, ii = images.length; i < ii; i++) {
-         var image = images[i];
-         var w = image.width, h = image.height;
-         if (w > tmpCanvasWidth || h > tmpCanvasHeight) {
-           tmpCanvasWidth = Math.max(w, tmpCanvasWidth);
-           tmpCanvasHeight = Math.max(h, tmpCanvasHeight);
-           tmpCanvas = createScratchCanvas(tmpCanvasWidth, tmpCanvasHeight);
-           tmpCtx = tmpCanvas.getContext('2d');
- 
-           var fillColor = this.current.fillColor;
-           tmpCtx.fillStyle = (fillColor && fillColor.hasOwnProperty('type') &&
-                               fillColor.type === 'Pattern') ?
-                               fillColor.getPattern(tmpCtx) : fillColor;
-         }
-         tmpCtx.fillRect(0, 0, w, h);
- 
-         var imgData = tmpCtx.getImageData(0, 0, w, h);
-         var pixels = imgData.data;
- 
-         applyStencilMask(image.data, w, h, image.inverseDecode, pixels);
- 
-         tmpCtx.putImageData(imgData, 0, 0);
- 
-         ctx.save();
-         ctx.transform.apply(ctx, image.transform);
-         ctx.scale(1, -1);
-         ctx.drawImage(tmpCanvas, 0, 0, w, h,
-                       0, -1, 1, 1);
-         ctx.restore();
-       }
-     },
- 
-     paintImageXObject: function CanvasGraphics_paintImageXObject(objId) {
-       var imgData = this.objs.get(objId);
-       if (!imgData)
-         error('Dependent image isn\'t ready yet');
- 
-       this.paintInlineImageXObject(imgData);
-     },
- 
-     paintInlineImageXObject:
-       function CanvasGraphics_paintInlineImageXObject(imgData) {
-       var width = imgData.width;
-       var height = imgData.height;
-       var ctx = this.ctx;
-       this.save();
-       // scale the image to the unit square
-       ctx.scale(1 / width, -1 / height);
- 
-       var currentTransform = ctx.mozCurrentTransformInverse;
-       var widthScale = Math.max(Math.abs(currentTransform[0]), 1);
-       var heightScale = Math.max(Math.abs(currentTransform[3]), 1);
-       var tmpCanvas = createScratchCanvas(width, height);
-       var tmpCtx = tmpCanvas.getContext('2d');
- 
-       if (widthScale > 2 || heightScale > 2) {
-         // canvas does not resize well large images to small -- using simple
-         // algorithm to perform pre-scaling
-         tmpCanvas = prescaleImage(imgData.data,
-                                  width, height,
-                                  widthScale, heightScale);
-         ctx.drawImage(tmpCanvas, 0, 0, tmpCanvas.width, tmpCanvas.height,
-                                  0, -height, width, height);
-       } else {
-         if (typeof ImageData !== 'undefined' && imgData instanceof ImageData) {
-           tmpCtx.putImageData(imgData, 0, 0);
-         } else {
-           putBinaryImageData(tmpCtx, imgData.data, width, height);
-         }
-         ctx.drawImage(tmpCanvas, 0, -height);
-       }
- 
-       if (this.imageLayer) {
-         var position = this.getCanvasPosition(0, -height);
-         this.imageLayer.appendImage({
-           imgData: imgData,
-           left: position[0],
-           top: position[1],
-           width: width / currentTransform[0],
-           height: height / currentTransform[3]
-         });
-       }
-       this.restore();
-     },
- 
-     paintInlineImageXObjectGroup:
-       function CanvasGraphics_paintInlineImageXObjectGroup(imgData, map) {
-       var ctx = this.ctx;
-       var w = imgData.width;
-       var h = imgData.height;
- 
-       var tmpCanvas = createScratchCanvas(w, h);
-       var tmpCtx = tmpCanvas.getContext('2d');
-       putBinaryImageData(tmpCtx, imgData.data, w, h);
- 
-       for (var i = 0, ii = map.length; i < ii; i++) {
-         var entry = map[i];
-         ctx.save();
-         ctx.transform.apply(ctx, entry.transform);
-         ctx.scale(1, -1);
-         ctx.drawImage(tmpCanvas, entry.x, entry.y, entry.w, entry.h,
-                       0, -1, 1, 1);
-         if (this.imageLayer) {
-           var position = this.getCanvasPosition(entry.x, entry.y);
-           this.imageLayer.appendImage({
-             imgData: imgData,
-             left: position[0],
-             top: position[1],
-             width: w,
-             height: h
-           });
-         }
-         ctx.restore();
-       }
-     },
- 
-     // Marked content
- 
-     markPoint: function CanvasGraphics_markPoint(tag) {
-       // TODO Marked content.
-     },
-     markPointProps: function CanvasGraphics_markPointProps(tag, properties) {
-       // TODO Marked content.
-     },
-     beginMarkedContent: function CanvasGraphics_beginMarkedContent(tag) {
-       // TODO Marked content.
-     },
-     beginMarkedContentProps: function CanvasGraphics_beginMarkedContentProps(
-                                         tag, properties) {
-       // TODO Marked content.
-     },
-     endMarkedContent: function CanvasGraphics_endMarkedContent() {
-       // TODO Marked content.
-     },
- 
-     // Compatibility
- 
-     beginCompat: function CanvasGraphics_beginCompat() {
-       // TODO ignore undefined operators (should we do that anyway?)
-     },
-     endCompat: function CanvasGraphics_endCompat() {
-       // TODO stop ignoring undefined operators
-     },
- 
-     // Helper functions
- 
-     consumePath: function CanvasGraphics_consumePath() {
-       if (this.pendingClip) {
-         var savedFillRule = null;
-         if (this.pendingClip == EO_CLIP)
-           savedFillRule = this.setEOFillRule();
- 
-         this.ctx.clip();
- 
-         this.pendingClip = null;
-         if (savedFillRule !== null)
-           this.restoreFillRule(savedFillRule);
-       }
-       this.ctx.beginPath();
-     },
-     // We generally keep the canvas context set for
-     // nonzero-winding, and just set evenodd for the operations
-     // that need them.
-     setEOFillRule: function CanvasGraphics_setEOFillRule() {
-       var savedFillRule = this.ctx.mozFillRule;
-       this.ctx.mozFillRule = 'evenodd';
-       return savedFillRule;
-     },
-     restoreFillRule: function CanvasGraphics_restoreFillRule(rule) {
-       this.ctx.mozFillRule = rule;
-     },
-     getSinglePixelWidth: function CanvasGraphics_getSinglePixelWidth(scale) {
-       var inverse = this.ctx.mozCurrentTransformInverse;
-       // max of the current horizontal and vertical scale
-       return Math.sqrt(Math.max(
-         (inverse[0] * inverse[0] + inverse[1] * inverse[1]),
-         (inverse[2] * inverse[2] + inverse[3] * inverse[3])));
-     },
-     getCanvasPosition: function CanvasGraphics_getCanvasPosition(x, y) {
-         var transform = this.ctx.mozCurrentTransform;
-         return [
-           transform[0] * x + transform[2] * y + transform[4],
-           transform[1] * x + transform[3] * y + transform[5]
-         ];
-     }
-   };
- 
-   return CanvasGraphics;
- })();
- 
- 
- 
- var Name = (function NameClosure() {
-   function Name(name) {
-     this.name = name;
-   }
- 
-   Name.prototype = {};
- 
-   return Name;
- })();
- 
- var Cmd = (function CmdClosure() {
-   function Cmd(cmd) {
-     this.cmd = cmd;
-   }
- 
-   Cmd.prototype = {};
- 
-   var cmdCache = {};
- 
-   Cmd.get = function Cmd_get(cmd) {
-     var cmdValue = cmdCache[cmd];
-     if (cmdValue)
-       return cmdValue;
- 
-     return cmdCache[cmd] = new Cmd(cmd);
-   };
- 
-   return Cmd;
- })();
- 
- var Dict = (function DictClosure() {
-   // xref is optional
-   function Dict(xref) {
-     // Map should only be used internally, use functions below to access.
-     var map = Object.create(null);
- 
-     this.assignXref = function Dict_assignXref(newXref) {
-       xref = newXref;
-     };
- 
-     // automatically dereferences Ref objects
-     this.get = function Dict_get(key1, key2, key3) {
-       var value;
-       if (typeof (value = map[key1]) != 'undefined' || key1 in map ||
-           typeof key2 == 'undefined') {
-         return xref ? xref.fetchIfRef(value) : value;
-       }
-       if (typeof (value = map[key2]) != 'undefined' || key2 in map ||
-           typeof key3 == 'undefined') {
-         return xref ? xref.fetchIfRef(value) : value;
-       }
-       value = map[key3] || null;
-       return xref ? xref.fetchIfRef(value) : value;
-     };
- 
-     // no dereferencing
-     this.getRaw = function Dict_getRaw(key) {
-       return map[key];
-     };
- 
-     // creates new map and dereferences all Refs
-     this.getAll = function Dict_getAll() {
-       var all = {};
-       for (var key in map) {
-         var obj = this.get(key);
-         all[key] = obj instanceof Dict ? obj.getAll() : obj;
-       }
-       return all;
-     };
- 
-     this.set = function Dict_set(key, value) {
-       map[key] = value;
-     };
- 
-     this.has = function Dict_has(key) {
-       return key in map;
-     };
- 
-     this.forEach = function Dict_forEach(callback) {
-       for (var key in map) {
-         callback(key, this.get(key));
-       }
-     };
-   }
- 
-   return Dict;
- })();
- 
- var Ref = (function RefClosure() {
-   function Ref(num, gen) {
-     this.num = num;
-     this.gen = gen;
-   }
- 
-   Ref.prototype = {};
- 
-   return Ref;
- })();
- 
- // 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 = {};
-   }
- 
-   RefSet.prototype = {
-     has: function RefSet_has(ref) {
-       return !!this.dict['R' + ref.num + '.' + ref.gen];
-     },
- 
-     put: function RefSet_put(ref) {
-       this.dict['R' + ref.num + '.' + ref.gen] = ref;
-     }
-   };
- 
-   return RefSet;
- })();
- 
- var Catalog = (function CatalogClosure() {
-   function Catalog(xref) {
-     this.xref = xref;
-     var obj = xref.getCatalogObj();
-     assertWellFormed(isDict(obj), 'catalog object is not a dictionary');
-     this.catDict = obj;
-   }
- 
-   Catalog.prototype = {
-     get metadata() {
-       var streamRef = this.catDict.getRaw('Metadata');
-       if (!isRef(streamRef))
-         return shadow(this, 'metadata', null);
- 
-       var encryptMetadata = !this.xref.encrypt ? false :
-         this.xref.encrypt.encryptMetadata;
- 
-       var stream = this.xref.fetch(streamRef, !encryptMetadata);
-       var metadata;
-       if (stream && isDict(stream.dict)) {
-         var type = stream.dict.get('Type');
-         var subtype = stream.dict.get('Subtype');
- 
-         if (isName(type) && isName(subtype) &&
-             type.name === 'Metadata' && subtype.name === 'XML') {
-           // XXX: This should examine the charset the XML document defines,
-           // however since there are currently no real means to decode
-           // arbitrary charsets, let's just hope that the author of the PDF
-           // was reasonable enough to stick with the XML default charset,
-           // which is UTF-8.
-           try {
-             metadata = stringToUTF8String(bytesToString(stream.getBytes()));
-           } catch (e) {
-             info('Skipping invalid metadata.');
-           }
-         }
-       }
- 
-       return shadow(this, 'metadata', metadata);
-     },
-     get toplevelPagesDict() {
-       var pagesObj = this.catDict.get('Pages');
-       assertWellFormed(isDict(pagesObj), 'invalid top-level pages dictionary');
-       // shadow the prototype getter
-       return shadow(this, 'toplevelPagesDict', pagesObj);
-     },
-     get documentOutline() {
-       var xref = this.xref;
-       var obj = this.catDict.get('Outlines');
-       var root = { items: [] };
-       if (isDict(obj)) {
-         obj = obj.getRaw('First');
-         var processed = new RefSet();
-         if (isRef(obj)) {
-           var queue = [{obj: obj, parent: root}];
-           // to avoid recursion keeping track of the items
-           // in the processed dictionary
-           processed.put(obj);
-           while (queue.length > 0) {
-             var i = queue.shift();
-             var outlineDict = xref.fetchIfRef(i.obj);
-             if (outlineDict === null)
-               continue;
-             if (!outlineDict.has('Title'))
-               error('Invalid outline item');
-             var dest = outlineDict.get('A');
-             if (dest)
-               dest = dest.get('D');
-             else if (outlineDict.has('Dest')) {
-               dest = outlineDict.getRaw('Dest');
-               if (isName(dest))
-                 dest = dest.name;
-             }
-             var title = outlineDict.get('Title');
-             var outlineItem = {
-               dest: dest,
-               title: stringToPDFString(title),
-               color: outlineDict.get('C') || [0, 0, 0],
-               count: outlineDict.get('Count'),
-               bold: !!(outlineDict.get('F') & 2),
-               italic: !!(outlineDict.get('F') & 1),
-               items: []
-             };
-             i.parent.items.push(outlineItem);
-             obj = outlineDict.getRaw('First');
-             if (isRef(obj) && !processed.has(obj)) {
-               queue.push({obj: obj, parent: outlineItem});
-               processed.put(obj);
-             }
-             obj = outlineDict.getRaw('Next');
-             if (isRef(obj) && !processed.has(obj)) {
-               queue.push({obj: obj, parent: i.parent});
-               processed.put(obj);
-             }
-           }
-         }
-       }
-       obj = root.items.length > 0 ? root.items : null;
-       return shadow(this, 'documentOutline', obj);
-     },
-     get numPages() {
-       var obj = this.toplevelPagesDict.get('Count');
-       assertWellFormed(
-         isInt(obj),
-         'page count in top level pages object is not an integer'
-       );
-       // shadow the prototype getter
-       return shadow(this, 'num', obj);
-     },
-     traverseKids: function Catalog_traverseKids(pagesDict) {
-       var pageCache = this.pageCache;
-       var kids = pagesDict.get('Kids');
-       assertWellFormed(isArray(kids),
-                        'page dictionary kids object is not an array');
-       for (var i = 0, ii = kids.length; i < ii; ++i) {
-         var kid = kids[i];
-         assertWellFormed(isRef(kid),
-                         'page dictionary kid is not a reference');
-         var obj = this.xref.fetch(kid);
-         if (isDict(obj, 'Page') || (isDict(obj) && !obj.has('Kids'))) {
-           pageCache.push(new Page(this.xref, pageCache.length, obj, kid));
-         } else { // must be a child page dictionary
-           assertWellFormed(
-             isDict(obj),
-             'page dictionary kid reference points to wrong type of object'
-           );
-           this.traverseKids(obj);
-         }
-       }
-     },
-     get destinations() {
-       function fetchDestination(dest) {
-         return isDict(dest) ? dest.get('D') : dest;
-       }
- 
-       var xref = this.xref;
-       var dests = {}, nameTreeRef, nameDictionaryRef;
-       var obj = this.catDict.get('Names');
-       if (obj)
-         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;
-           dests[key] = fetchDestination(value);
-         });
-       }
-       if (nameTreeRef) {
-         var nameTree = new NameTree(nameTreeRef, xref);
-         var names = nameTree.getAll();
-         for (var name in names) {
-           if (!names.hasOwnProperty(name)) {
-             continue;
-           }
-           dests[name] = fetchDestination(names[name]);
-         }
-       }
-       return shadow(this, 'destinations', dests);
-     },
-     get javaScript() {
-       var xref = this.xref;
-       var obj = this.catDict.get('Names');
- 
-       var javaScript = [];
-       if (obj && obj.has('JavaScript')) {
-         var nameTree = new NameTree(obj.getRaw('JavaScript'), xref);
-         var names = nameTree.getAll();
-         for (var name in names) {
-           if (!names.hasOwnProperty(name)) {
-             continue;
-           }
-           // We don't really use the JavaScript right now so this code is
-           // defensive so we don't cause errors on document load.
-           var jsDict = names[name];
-           if (!isDict(jsDict)) {
-             continue;
-           }
-           var type = jsDict.get('S');
-           if (!isName(type) || type.name !== 'JavaScript') {
-             continue;
-           }
-           var js = jsDict.get('JS');
-           if (!isString(js) && !isStream(js)) {
-             continue;
-           }
-           if (isStream(js)) {
-             js = bytesToString(js.getBytes());
-           }
-           javaScript.push(stringToPDFString(js));
-         }
-       }
-       return shadow(this, 'javaScript', javaScript);
-     },
-     getPage: function Catalog_getPage(n) {
-       var pageCache = this.pageCache;
-       if (!pageCache) {
-         pageCache = this.pageCache = [];
-         this.traverseKids(this.toplevelPagesDict);
-       }
-       return this.pageCache[n - 1];
-     }
-   };
- 
-   return Catalog;
- })();
- 
- var XRef = (function XRefClosure() {
-   function XRef(stream, startXRef, mainXRefEntriesOffset, password) {
-     this.stream = stream;
-     this.entries = [];
-     this.xrefstms = {};
-     var trailerDict = this.readXRef(startXRef);
-     trailerDict.assignXref(this);
-     this.trailer = trailerDict;
-     // prepare the XRef cache
-     this.cache = [];
- 
-     var encrypt = trailerDict.get('Encrypt');
-     if (encrypt) {
-       var ids = trailerDict.get('ID');
-       var fileId = (ids && ids.length) ? ids[0] : '';
-       this.encrypt = new CipherTransformFactory(encrypt, fileId, password);
-     }
- 
-     // get the root dictionary (catalog) object
-     if (!(this.root = trailerDict.get('Root')))
-       error('Invalid root reference');
-   }
- 
-   XRef.prototype = {
-     readXRefTable: function XRef_readXRefTable(parser) {
-       // Example of cross-reference table:
-       // xref
-       // 0 1                    <-- subsection header (first obj #, obj count)
-       // 0000000000 65535 f     <-- actual object (offset, generation #, f/n)
-       // 23 2                   <-- subsection header ... and so on ...
-       // 0000025518 00002 n
-       // 0000025635 00000 n
-       // trailer
-       // ...
- 
-       // Outer loop is over subsection headers
-       var obj;
-       while (!isCmd(obj = parser.getObj(), 'trailer')) {
-         var first = obj,
-             count = parser.getObj();
- 
-         if (!isInt(first) || !isInt(count))
-           error('Invalid XRef table: wrong types in subsection header');
- 
-         // Inner loop is over objects themselves
-         for (var i = 0; i < count; i++) {
-           var entry = {};
-           entry.offset = parser.getObj();
-           entry.gen = parser.getObj();
-           var type = parser.getObj();
- 
-           if (isCmd(type, 'f'))
-             entry.free = true;
-           else if (isCmd(type, 'n'))
-             entry.uncompressed = true;
- 
-           // Validate entry obj
-           if (!isInt(entry.offset) || !isInt(entry.gen) ||
-               !(entry.free || entry.uncompressed)) {
-             error('Invalid entry in XRef subsection: ' + first + ', ' + count);
-           }
- 
-           if (!this.entries[i + first])
-             this.entries[i + first] = entry;
-         }
-       }
- 
-       // Sanity check: as per spec, first object must be free
-       if (this.entries[0] && !this.entries[0].free)
-         error('Invalid XRef table: unexpected first object');
- 
-       // Sanity check
-       if (!isCmd(obj, 'trailer'))
-         error('Invalid XRef table: could not find trailer dictionary');
- 
-       // Read trailer dictionary, e.g.
-       // trailer
-       //    << /Size 22
-       //      /Root 20R
-       //      /Info 10R
-       //      /ID [ <81b14aafa313db63dbd6f981e49f94f4> ]
-       //    >>
-       // 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');
- 
-       return dict;
-     },
-     readXRefStream: function XRef_readXRefStream(stream) {
-       var streamParameters = stream.parameters;
-       var byteWidths = streamParameters.get('W');
-       var range = streamParameters.get('Index');
-       if (!range)
-         range = [0, streamParameters.get('Size')];
-       var i, j;
-       while (range.length > 0) {
-         var first = range[0], n = range[1];
-         if (!isInt(first) || !isInt(n))
-           error('Invalid XRef range fields: ' + first + ', ' + n);
-         var typeFieldWidth = byteWidths[0];
-         var offsetFieldWidth = byteWidths[1];
-         var generationFieldWidth = byteWidths[2];
-         if (!isInt(typeFieldWidth) || !isInt(offsetFieldWidth) ||
-             !isInt(generationFieldWidth)) {
-           error('Invalid XRef entry fields length: ' + first + ', ' + n);
-         }
-         for (i = 0; i < n; ++i) {
-           var type = 0, offset = 0, generation = 0;
-           for (j = 0; j < typeFieldWidth; ++j)
-             type = (type << 8) | stream.getByte();
-           // if type field is absent, its default value = 1
-           if (typeFieldWidth === 0)
-             type = 1;
-           for (j = 0; j < offsetFieldWidth; ++j)
-             offset = (offset << 8) | stream.getByte();
-           for (j = 0; j < generationFieldWidth; ++j)
-             generation = (generation << 8) | stream.getByte();
-           var entry = {};
-           entry.offset = offset;
-           entry.gen = generation;
-           switch (type) {
-             case 0:
-               entry.free = true;
-               break;
-             case 1:
-               entry.uncompressed = true;
-               break;
-             case 2:
-               break;
-             default:
-               error('Invalid XRef entry type: ' + type);
-           }
-           if (!this.entries[first + i])
-             this.entries[first + i] = entry;
-         }
-         range.splice(0, 2);
-       }
-       return streamParameters;
-     },
-     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)
-             break;
-           token += String.fromCharCode(ch);
-           ch = data[offset];
-         }
-         return token;
-       }
-       function skipUntil(data, offset, what) {
-         var length = what.length, dataLength = data.length;
-         var skipped = 0;
-         // finding byte sequence
-         while (offset < dataLength) {
-           var i = 0;
-           while (i < length && data[offset + i] == what[i])
-             ++i;
-           if (i >= length)
-             break; // sequence found
- 
-           offset++;
-           skipped++;
-         }
-         return skipped;
-       }
-       var trailerBytes = new Uint8Array([116, 114, 97, 105, 108, 101, 114]);
-       var startxrefBytes = new Uint8Array([115, 116, 97, 114, 116, 120, 114,
-                                           101, 102]);
-       var endobjBytes = new Uint8Array([101, 110, 100, 111, 98, 106]);
-       var xrefBytes = new Uint8Array([47, 88, 82, 101, 102]);
- 
-       var stream = this.stream;
-       stream.pos = 0;
-       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) {
-           ++position;
-           continue;
-         }
-         if (ch === 37) { // %-comment
-           do {
-             ++position;
-             ch = buffer[position];
-           } while (ch !== 13 && ch !== 10);
-           continue;
-         }
-         var token = readToken(buffer, position);
-         var m;
-         if (token === 'xref') {
-           position += skipUntil(buffer, position, trailerBytes);
-           trailers.push(position);
-           position += skipUntil(buffer, position, startxrefBytes);
-         } else if ((m = /^(\d+)\s+(\d+)\s+obj\b/.exec(token))) {
-           this.entries[m[1]] = {
-             offset: position,
-             gen: m[2] | 0,
-             uncompressed: true
-           };
- 
-           var contentLength = skipUntil(buffer, position, endobjBytes) + 7;
-           var content = buffer.subarray(position, position + contentLength);
- 
-           // checking XRef stream suspect
-           // (it shall have '/XRef' and next char is not a letter)
-           var xrefTagOffset = skipUntil(content, 0, xrefBytes);
-           if (xrefTagOffset < contentLength &&
-               content[xrefTagOffset + 5] < 64) {
-             xrefStms.push(position);
-             this.xrefstms[position] = 1; // don't read it recursively
-           }
- 
-           position += contentLength;
-         } else
-           position += token.length + 1;
-       }
-       // reading XRef streams
-       for (var i = 0, ii = xrefStms.length; i < ii; ++i) {
-           this.readXRef(xrefStms[i], true);
-       }
-       // finding main trailer
-       var dict;
-       for (var i = 0, ii = trailers.length; i < ii; ++i) {
-         stream.pos = trailers[i];
-         var parser = new Parser(new Lexer(stream), true, null);
-         var obj = parser.getObj();
-         if (!isCmd(obj, 'trailer'))
-           continue;
-         // read the trailer dictionary
-         if (!isDict(dict = parser.getObj()))
-           continue;
-         // taking the first one with 'ID'
-         if (dict.has('ID'))
-           return dict;
-       }
-       // no tailer with 'ID', taking last one (if exists)
-       if (dict)
-         return dict;
-       // nothing helps
-       // calling error() would reject worker with an UnknownErrorException.
-       throw new InvalidPDFException('Invalid PDF structure');
-     },
-     readXRef: function XRef_readXRef(startXRef, recoveryMode) {
-       var stream = this.stream;
-       stream.pos = startXRef;
- 
-       try {
-         var parser = new Parser(new Lexer(stream), true, null);
-         var obj = parser.getObj();
-         var dict;
- 
-         // Get dictionary
-         if (isCmd(obj, 'xref')) {
-           // Parse end-of-file XRef
-           dict = this.readXRefTable(parser);
- 
-           // Recursively get other XRefs 'XRefStm', if any
-           obj = dict.get('XRefStm');
-           if (isInt(obj)) {
-             var pos = obj;
-             // ignore previously loaded xref streams
-             // (possible infinite recursion)
-             if (!(pos in this.xrefstms)) {
-               this.xrefstms[pos] = 1;
-               this.readXRef(pos);
-             }
-           }
-         } else if (isInt(obj)) {
-           // Parse in-stream XRef
-           if (!isInt(parser.getObj()) ||
-               !isCmd(parser.getObj(), 'obj') ||
-               !isStream(obj = parser.getObj())) {
-             error('Invalid XRef stream');
-           }
-           dict = this.readXRefStream(obj);
-           if (!dict)
-             error('Failed to read XRef stream');
-         }
- 
-         // Recursively get previous dictionary, if any
-         obj = dict.get('Prev');
-         if (isInt(obj))
-           this.readXRef(obj, recoveryMode);
-         else if (isRef(obj)) {
-           // The spec says Prev must not be a reference, i.e. "/Prev NNN"
-           // This is a fallback for non-compliant PDFs, i.e. "/Prev NNN 0 R"
-           this.readXRef(obj.num, recoveryMode);
-         }
- 
-         return dict;
-       } catch (e) {
-         log('(while reading XRef): ' + e);
-       }
- 
-       if (recoveryMode)
-         return;
- 
-       warn('Indexing all PDF objects');
-       return this.indexObjects();
-     },
-     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
-     },
-     fetchIfRef: function XRef_fetchIfRef(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');
-       var num = ref.num;
-       if (num in this.cache)
-         return this.cache[num];
- 
-       var e = 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();
-         }
-         // Don't cache streams since they are mutable (except images).
-         if (!isStream(e) || e instanceof JpegStream)
-           this.cache[num] = e;
-         return e;
-       }
- 
-       // compressed entry
-       var tableOffset = e.offset;
-       stream = this.fetch(new Ref(tableOffset, 0));
-       if (!isStream(stream))
-         error('bad ObjStm stream');
-       var first = stream.parameters.get('First');
-       var n = stream.parameters.get('N');
-       if (!isInt(first) || !isInt(n)) {
-         error('invalid first and n parameters for ObjStm stream');
-       }
-       parser = new Parser(new Lexer(stream), false, this);
-       parser.allowStreams = true;
-       var i, entries = [], nums = [];
-       // read the object numbers to populate cache
-       for (i = 0; i < n; ++i) {
-         num = parser.getObj();
-         if (!isInt(num)) {
-           error('invalid object number in the ObjStm stream: ' + num);
-         }
-         nums.push(num);
-         var offset = parser.getObj();
-         if (!isInt(offset)) {
-           error('invalid object offset in the ObjStm stream: ' + offset);
-         }
-       }
-       // read stream objects for cache
-       for (i = 0; i < n; ++i) {
-         entries.push(parser.getObj());
-         num = nums[i];
-         var entry = this.entries[num];
-         if (entry && entry.offset === tableOffset && entry.gen === i) {
-           this.cache[num] = entries[i];
-         }
-       }
-       e = entries[e.gen];
-       if (!e) {
-         error('bad XRef entry for compressed object');
-       }
-       return e;
-     },
-     getCatalogObj: function XRef_getCatalogObj() {
-       return this.root;
-     }
-   };
- 
-   return XRef;
- })();
- 
- /**
-  * A NameTree is like a Dict but has some adventagous 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() {
-   function NameTree(root, xref) {
-     this.root = root;
-     this.xref = xref;
-   }
- 
-   NameTree.prototype = {
-     getAll: function NameTree_getAll() {
-       var dict = {};
-       if (!this.root) {
-         return dict;
-       }
-       var xref = this.xref;
-       // reading name tree
-       var processed = new RefSet();
-       processed.put(this.root);
-       var queue = [this.root];
-       while (queue.length > 0) {
-         var i, n;
-         var obj = xref.fetchIfRef(queue.shift());
-         if (!isDict(obj)) {
-           continue;
-         }
-         if (obj.has('Kids')) {
-           var kids = obj.get('Kids');
-           for (i = 0, n = kids.length; i < n; i++) {
-             var kid = kids[i];
-             if (processed.has(kid))
-               error('invalid destinations');
-             queue.push(kid);
-             processed.put(kid);
-           }
-           continue;
-         }
-         var names = obj.get('Names');
-         if (names) {
-           for (i = 0, n = names.length; i < n; i += 2) {
-             dict[names[i]] = xref.fetchIfRef(names[i + 1]);
-           }
-         }
-       }
-       return dict;
-     }
-   };
-   return NameTree;
- })();
- 
- /**
-  * A PDF document and page is built of many objects. E.g. there are objects
-  * 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.
-  */
- var PDFObjects = (function PDFObjectsClosure() {
-   function PDFObjects() {
-     this.objs = {};
-   }
- 
-   PDFObjects.prototype = {
-     /**
-      * Internal function.
-      * Ensures there is an object defined for `objId`. Stores `data` on the
-      * object *if* it is created.
-      */
-     ensureObj: function PDFObjects_ensureObj(objId, data) {
-       if (this.objs[objId])
-         return this.objs[objId];
-       return this.objs[objId] = new Promise(objId, data);
-     },
- 
-     /**
-      * If called *without* callback, this returns the data of `objId` but the
-      * object needs to be resolved. If it isn't, this function throws.
-      *
-      * If called *with* a callback, the callback is called with the data of the
-      * object once the object is resolved. That means, if you call this
-      * function and the object is already resolved, the callback gets called
-      * right away.
-      */
-     get: function PDFObjects_get(objId, callback) {
-       // 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).then(callback);
-         return null;
-       }
- 
-       // If there isn't a callback, the user expects to get the resolved data
-       // directly.
-       var obj = this.objs[objId];
- 
-       // If there isn't an object yet or the object isn't resolved, then the
-       // data isn't ready yet!
-       if (!obj || !obj.isResolved)
-         error('Requesting object that isn\'t resolved yet ' + objId);
- 
-       return obj.data;
-     },
- 
-     /**
-      * Resolves the object `objId` with optional `data`.
-      */
-     resolve: function PDFObjects_resolve(objId, data) {
-       var objs = this.objs;
- 
-       // In case there is a promise already on this object, just resolve it.
-       if (objs[objId]) {
-         objs[objId].resolve(data);
-       } else {
-         this.ensureObj(objId, data);
-       }
-     },
- 
-     onData: function PDFObjects_onData(objId, callback) {
-       this.ensureObj(objId).onData(callback);
-     },
- 
-     isResolved: function PDFObjects_isResolved(objId) {
-       var objs = this.objs;
-       if (!objs[objId]) {
-         return false;
-       } else {
-         return objs[objId].isResolved;
-       }
-     },
- 
-     hasData: function PDFObjects_hasData(objId) {
-       var objs = this.objs;
-       if (!objs[objId]) {
-         return false;
-       } else {
-         return objs[objId].hasData;
-       }
-     },
- 
-     /**
-      * Returns the data of `objId` if object exists, null otherwise.
-      */
-     getData: function PDFObjects_getData(objId) {
-       var objs = this.objs;
-       if (!objs[objId] || !objs[objId].hasData) {
-         return null;
-       } else {
-         return objs[objId].data;
-       }
-     },
- 
-     /**
-      * Sets the data of an object but *doesn't* resolve it.
-      */
-     setData: function PDFObjects_setData(objId, data) {
-       // Watchout! If you call `this.ensureObj(objId, data)` you're going to
-       // create a *resolved* promise which shouldn't be the case!
-       this.ensureObj(objId).data = data;
-     },
- 
-     clear: function PDFObjects_clear() {
-       this.objs = {};
-     }
-   };
-   return PDFObjects;
- })();
- 
- 
- 
- 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
-         TODO('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;
-   }
-   PostScriptLexer.prototype = {
-     getToken: function PostScriptLexer_getToken() {
-       var s = '';
-       var ch;
-       var comment = false;
-       var stream = this.stream;
- 
-       // skip comments
-       while (true) {
-         if (!(ch = stream.getChar()))
-           return EOF;
- 
-         if (comment) {
-           if (ch == '\x0a' || ch == '\x0d')
-             comment = false;
-         } else if (ch == '%') {
-           comment = true;
-         } else if (!Lexer.isSpace(ch)) {
-           break;
-         }
-       }
-       switch (ch) {
-         case '0': case '1': case '2': case '3': case '4':
-         case '5': case '6': case '7': case '8': case '9':
-         case '+': case '-': case '.':
-           return new PostScriptToken(PostScriptTokenTypes.NUMBER,
-                                       this.getNumber(ch));
-         case '{':
-           return PostScriptToken.LBRACE;
-         case '}':
-           return PostScriptToken.RBRACE;
-       }
-       // operator
-       var str = ch.toLowerCase();
-       while (true) {
-         ch = stream.lookChar();
-         if (ch === null)
-           break;
-         ch = ch.toLowerCase();
-         if (ch >= 'a' && ch <= 'z')
-           str += ch;
-         else
-           break;
-         stream.skip();
-       }
-       switch (str) {
-         case 'if':
-           return PostScriptToken.IF;
-         case 'ifelse':
-           return PostScriptToken.IFELSE;
-         default:
-           return PostScriptToken.getOperator(str);
-       }
-     },
-     getNumber: function PostScriptLexer_getNumber(ch) {
-       var str = ch;
-       var stream = this.stream;
-       while (true) {
-         ch = stream.lookChar();
-         if ((ch >= '0' && ch <= '9') || ch == '-' || ch == '.')
-           str += ch;
-         else
-           break;
-         stream.skip();
-       }
-       var value = parseFloat(str);
-       if (isNaN(value))
-         error('Invalid floating point number: ' + value);
-       return value;
-     }
-   };
-   return PostScriptLexer;
- })();
- 
- 
- 
- var ISOAdobeCharset = [
-   '.notdef', 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar',
-   'percent', 'ampersand', 'quoteright', 'parenleft', 'parenright',
-   'asterisk', 'plus', 'comma', 'hyphen', 'period', 'slash', 'zero',
-   'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight',
-   'nine', 'colon', 'semicolon', 'less', 'equal', 'greater', 'question',
-   'at', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
-   'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
-   'bracketleft', 'backslash', 'bracketright', 'asciicircum', 'underscore',
-   'quoteleft', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
-   'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
-   'braceleft', 'bar', 'braceright', 'asciitilde', 'exclamdown', 'cent',
-   'sterling', 'fraction', 'yen', 'florin', 'section', 'currency',
-   'quotesingle', 'quotedblleft', 'guillemotleft', 'guilsinglleft',
-   'guilsinglright', 'fi', 'fl', 'endash', 'dagger', 'daggerdbl',
-   'periodcentered', 'paragraph', 'bullet', 'quotesinglbase',
-   'quotedblbase', 'quotedblright', 'guillemotright', 'ellipsis',
-   'perthousand', 'questiondown', 'grave', 'acute', 'circumflex', 'tilde',
-   'macron', 'breve', 'dotaccent', 'dieresis', 'ring', 'cedilla',
-   'hungarumlaut', 'ogonek', 'caron', 'emdash', 'AE', 'ordfeminine',
-   'Lslash', 'Oslash', 'OE', 'ordmasculine', 'ae', 'dotlessi', 'lslash',
-   'oslash', 'oe', 'germandbls', 'onesuperior', 'logicalnot', 'mu',
-   'trademark', 'Eth', 'onehalf', 'plusminus', 'Thorn', 'onequarter',
-   'divide', 'brokenbar', 'degree', 'thorn', 'threequarters', 'twosuperior',
-   'registered', 'minus', 'eth', 'multiply', 'threesuperior', 'copyright',
-   'Aacute', 'Acircumflex', 'Adieresis', 'Agrave', 'Aring', 'Atilde',
-   'Ccedilla', 'Eacute', 'Ecircumflex', 'Edieresis', 'Egrave', 'Iacute',
-   'Icircumflex', 'Idieresis', 'Igrave', 'Ntilde', 'Oacute', 'Ocircumflex',
-   'Odieresis', 'Ograve', 'Otilde', 'Scaron', 'Uacute', 'Ucircumflex',
-   'Udieresis', 'Ugrave', 'Yacute', 'Ydieresis', 'Zcaron', 'aacute',
-   'acircumflex', 'adieresis', 'agrave', 'aring', 'atilde', 'ccedilla',
-   'eacute', 'ecircumflex', 'edieresis', 'egrave', 'iacute', 'icircumflex',
-   'idieresis', 'igrave', 'ntilde', 'oacute', 'ocircumflex', 'odieresis',
-   'ograve', 'otilde', 'scaron', 'uacute', 'ucircumflex', 'udieresis',
-   'ugrave', 'yacute', 'ydieresis', 'zcaron'
- ];
- 
- var ExpertCharset = [
-   '.notdef', 'space', 'exclamsmall', 'Hungarumlautsmall', 'dollaroldstyle',
-   'dollarsuperior', 'ampersandsmall', 'Acutesmall', 'parenleftsuperior',
-   'parenrightsuperior', 'twodotenleader', 'onedotenleader', 'comma',
-   'hyphen', 'period', 'fraction', 'zerooldstyle', 'oneoldstyle',
-   'twooldstyle', 'threeoldstyle', 'fouroldstyle', 'fiveoldstyle',
-   'sixoldstyle', 'sevenoldstyle', 'eightoldstyle', 'nineoldstyle',
-   'colon', 'semicolon', 'commasuperior', 'threequartersemdash',
-   'periodsuperior', 'questionsmall', 'asuperior', 'bsuperior',
-   'centsuperior', 'dsuperior', 'esuperior', 'isuperior', 'lsuperior',
-   'msuperior', 'nsuperior', 'osuperior', 'rsuperior', 'ssuperior',
-   'tsuperior', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'parenleftinferior',
-   'parenrightinferior', 'Circumflexsmall', 'hyphensuperior', 'Gravesmall',
-   'Asmall', 'Bsmall', 'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall',
-   'Hsmall', 'Ismall', 'Jsmall', 'Ksmall', 'Lsmall', 'Msmall', 'Nsmall',
-   'Osmall', 'Psmall', 'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall',
-   'Vsmall', 'Wsmall', 'Xsmall', 'Ysmall', 'Zsmall', 'colonmonetary',
-   'onefitted', 'rupiah', 'Tildesmall', 'exclamdownsmall', 'centoldstyle',
-   'Lslashsmall', 'Scaronsmall', 'Zcaronsmall', 'Dieresissmall',
-   'Brevesmall', 'Caronsmall', 'Dotaccentsmall', 'Macronsmall',
-   'figuredash', 'hypheninferior', 'Ogoneksmall', 'Ringsmall',
-   'Cedillasmall', 'onequarter', 'onehalf', 'threequarters',
-   'questiondownsmall', 'oneeighth', 'threeeighths', 'fiveeighths',
-   'seveneighths', 'onethird', 'twothirds', 'zerosuperior', 'onesuperior',
-   'twosuperior', 'threesuperior', 'foursuperior', 'fivesuperior',
-   'sixsuperior', 'sevensuperior', 'eightsuperior', 'ninesuperior',
-   'zeroinferior', 'oneinferior', 'twoinferior', 'threeinferior',
-   'fourinferior', 'fiveinferior', 'sixinferior', 'seveninferior',
-   'eightinferior', 'nineinferior', 'centinferior', 'dollarinferior',
-   'periodinferior', 'commainferior', 'Agravesmall', 'Aacutesmall',
-   'Acircumflexsmall', 'Atildesmall', 'Adieresissmall', 'Aringsmall',
-   'AEsmall', 'Ccedillasmall', 'Egravesmall', 'Eacutesmall',
-   'Ecircumflexsmall', 'Edieresissmall', 'Igravesmall', 'Iacutesmall',
-   'Icircumflexsmall', 'Idieresissmall', 'Ethsmall', 'Ntildesmall',
-   'Ogravesmall', 'Oacutesmall', 'Ocircumflexsmall', 'Otildesmall',
-   'Odieresissmall', 'OEsmall', 'Oslashsmall', 'Ugravesmall', 'Uacutesmall',
-   'Ucircumflexsmall', 'Udieresissmall', 'Yacutesmall', 'Thornsmall',
-   'Ydieresissmall'
- ];
- 
- var ExpertSubsetCharset = [
-   '.notdef', 'space', 'dollaroldstyle', 'dollarsuperior',
-   'parenleftsuperior', 'parenrightsuperior', 'twodotenleader',
-   'onedotenleader', 'comma', 'hyphen', 'period', 'fraction',
-   'zerooldstyle', 'oneoldstyle', 'twooldstyle', 'threeoldstyle',
-   'fouroldstyle', 'fiveoldstyle', 'sixoldstyle', 'sevenoldstyle',
-   'eightoldstyle', 'nineoldstyle', 'colon', 'semicolon', 'commasuperior',
-   'threequartersemdash', 'periodsuperior', 'asuperior', 'bsuperior',
-   'centsuperior', 'dsuperior', 'esuperior', 'isuperior', 'lsuperior',
-   'msuperior', 'nsuperior', 'osuperior', 'rsuperior', 'ssuperior',
-   'tsuperior', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'parenleftinferior',
-   'parenrightinferior', 'hyphensuperior', 'colonmonetary', 'onefitted',
-   'rupiah', 'centoldstyle', 'figuredash', 'hypheninferior', 'onequarter',
-   'onehalf', 'threequarters', 'oneeighth', 'threeeighths', 'fiveeighths',
-   'seveneighths', 'onethird', 'twothirds', 'zerosuperior', 'onesuperior',
-   'twosuperior', 'threesuperior', 'foursuperior', 'fivesuperior',
-   'sixsuperior', 'sevensuperior', 'eightsuperior', 'ninesuperior',
-   'zeroinferior', 'oneinferior', 'twoinferior', 'threeinferior',
-   'fourinferior', 'fiveinferior', 'sixinferior', 'seveninferior',
-   'eightinferior', 'nineinferior', 'centinferior', 'dollarinferior',
-   'periodinferior', 'commainferior'
- ];
- 
- 
- 
- 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 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;
-     }
-   };
- 
-   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 new DeviceGrayCS();
-       case 'DeviceRgbCS':
-         return new DeviceRgbCS();
-       case 'DeviceCmykCS':
-         return new DeviceCmykCS();
-       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':
-           return 'DeviceGrayCS';
-         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;
-   };
- 
-   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 isGetRgbBufferSupported = 'getRgbBuffer' in base;
-       var isPassthrough = base.isPassthrough(8) || !isGetRgbBufferSupported;
-       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 (isGetRgbBufferSupported) {
-           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);
-     }
-   };
- 
-   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) {
-       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;
-     }
-   };
-   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);
-     }
-   };
-   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);
-     }
-   };
-   return DeviceRgbCS;
- })();
- 
- var DeviceCmykCS = (function DeviceCmykCSClosure() {
-   // Sampled RGB colors from CMYK US Web Coated (SWOP) colorspace
-   var lut = new Uint8Array([
-     255, 255, 254, 221, 222, 223, 191, 193, 195, 161, 163, 166, 133, 136, 138,
-     105, 107, 109, 75, 75, 77, 35, 31, 32, 255, 252, 224, 226, 220, 198, 195,
-     191, 173, 164, 162, 147, 136, 134, 122, 107, 106, 96, 75, 74, 66, 33, 29,
-     24, 255, 249, 197, 229, 218, 174, 198, 190, 153, 166, 160, 129, 138, 133,
-     107, 108, 104, 83, 76, 73, 56, 33, 28, 15, 255, 247, 168, 232, 216, 149,
-     200, 188, 130, 168, 158, 110, 139, 131, 90, 110, 103, 70, 77, 72, 45, 32,
-     27, 4, 255, 245, 140, 234, 214, 124, 202, 186, 108, 170, 157, 91, 140, 130,
-     74, 110, 102, 56, 77, 71, 33, 31, 27, 0, 255, 243, 107, 235, 212, 95, 203,
-     184, 83, 171, 155, 69, 141, 129, 55, 111, 101, 40, 77, 70, 19, 29, 26, 0,
-     255, 241, 64, 237, 211, 59, 204, 183, 52, 171, 154, 42, 142, 128, 31, 111,
-     100, 16, 77, 69, 0, 27, 26, 0, 255, 240, 0, 238, 209, 0, 205, 182, 3, 172,
-     153, 0, 142, 127, 0, 112, 100, 0, 77, 69, 0, 26, 25, 0, 251, 225, 236, 218,
-     196, 207, 189, 171, 181, 160, 144, 154, 133, 120, 128, 105, 94, 101, 74, 64,
-     70, 35, 21, 25, 255, 222, 208, 222, 195, 184, 192, 169, 161, 162, 143, 136,
-     135, 118, 113, 106, 92, 88, 75, 63, 60, 34, 20, 17, 255, 220, 184, 225, 193,
-     162, 195, 168, 142, 164, 142, 120, 136, 117, 99, 107, 91, 77, 75, 62, 50,
-     33, 20, 8, 255, 218, 157, 227, 191, 139, 197, 166, 121, 165, 140, 102, 137,
-     116, 84, 108, 90, 64, 76, 61, 40, 32, 19, 0, 255, 216, 132, 229, 189, 116,
-     198, 165, 101, 167, 139, 85, 138, 115, 69, 109, 89, 51, 76, 61, 28, 31, 18,
-     0, 255, 214, 102, 230, 188, 90, 199, 163, 78, 167, 138, 65, 139, 114, 51,
-     109, 89, 35, 76, 60, 14, 29, 18, 0, 255, 213, 65, 232, 186, 58, 200, 162,
-     50, 168, 136, 39, 139, 113, 28, 110, 88, 12, 76, 60, 0, 27, 18, 0, 255, 212,
-     8, 232, 185, 13, 201, 161, 11, 169, 136, 3, 139, 112, 0, 110, 87, 0, 76, 59,
-     0, 26, 18, 0, 248, 197, 219, 216, 172, 192, 187, 150, 168, 158, 126, 143,
-     132, 104, 119, 104, 81, 93, 74, 54, 64, 35, 10, 19, 251, 195, 193, 219, 171,
-     171, 190, 149, 150, 161, 125, 127, 133, 103, 105, 106, 80, 81, 75, 53, 54,
-     34, 10, 10, 254, 193, 171, 221, 169, 151, 192, 148, 132, 162, 124, 112, 134,
-     102, 92, 106, 79, 70, 75, 52, 45, 34, 9, 1, 255, 191, 147, 223, 168, 130,
-     193, 146, 113, 163, 123, 95, 135, 101, 77, 107, 78, 58, 75, 52, 35, 32, 9,
-     0, 255, 190, 124, 225, 166, 109, 195, 145, 95, 164, 122, 79, 136, 100, 63,
-     107, 77, 46, 76, 51, 24, 31, 9, 0, 255, 188, 97, 226, 165, 85, 196, 143, 74,
-     165, 121, 60, 137, 99, 47, 108, 77, 31, 75, 51, 10, 29, 9, 0, 255, 187, 64,
-     227, 164, 56, 196, 142, 48, 165, 120, 37, 137, 98, 25, 108, 76, 9, 75, 50,
-     0, 28, 9, 0, 255, 186, 23, 228, 163, 21, 197, 142, 15, 166, 119, 5, 137, 98,
-     0, 108, 76, 0, 75, 50, 0, 27, 8, 0, 245, 168, 201, 214, 147, 177, 186, 128,
-     155, 157, 107, 131, 131, 88, 109, 104, 67, 85, 74, 42, 57, 35, 0, 12, 248,
-     166, 178, 216, 146, 157, 188, 127, 138, 159, 107, 116, 132, 87, 96, 105, 66,
-     74, 74, 41, 48, 35, 0, 3, 250, 165, 158, 218, 145, 139, 189, 126, 122, 160,
-     106, 103, 133, 86, 84, 105, 66, 64, 75, 41, 39, 33, 0, 0, 252, 164, 136,
-     220, 144, 120, 190, 125, 104, 161, 105, 87, 134, 86, 71, 106, 65, 52, 75,
-     41, 29, 32, 0, 0, 253, 162, 115, 221, 142, 101, 191, 124, 88, 161, 104, 72,
-     134, 85, 58, 106, 64, 41, 75, 40, 19, 31, 0, 0, 254, 161, 91, 222, 141, 80,
-     192, 123, 68, 162, 103, 55, 134, 84, 42, 106, 64, 26, 75, 40, 6, 29, 0, 0,
-     255, 160, 62, 223, 140, 54, 193, 122, 45, 162, 102, 34, 135, 83, 22, 106,
-     63, 5, 74, 40, 0, 28, 0, 0, 255, 159, 29, 223, 140, 25, 193, 121, 18, 163,
-     101, 7, 135, 83, 0, 107, 63, 0, 74, 40, 0, 28, 0, 0, 243, 142, 185, 212,
-     123, 163, 184, 107, 142, 156, 89, 120, 130, 72, 100, 104, 53, 77, 74, 29,
-     51, 35, 0, 4, 245, 140, 164, 214, 123, 145, 186, 106, 127, 157, 89, 107,
-     131, 72, 88, 104, 53, 67, 74, 29, 42, 34, 0, 0, 247, 139, 146, 215, 122,
-     129, 187, 106, 112, 158, 88, 94, 132, 71, 77, 104, 53, 57, 74, 29, 33, 33,
-     0, 0, 248, 138, 126, 217, 121, 111, 188, 105, 96, 159, 87, 80, 132, 70, 64,
-     105, 52, 47, 74, 29, 24, 31, 0, 0, 249, 137, 107, 218, 120, 94, 189, 104,
-     81, 159, 86, 66, 132, 70, 52, 105, 52, 36, 74, 29, 15, 30, 0, 0, 250, 136,
-     85, 218, 119, 74, 189, 103, 63, 160, 86, 51, 133, 69, 38, 105, 51, 22, 74,
-     29, 2, 29, 0, 0, 251, 135, 59, 219, 118, 51, 190, 102, 42, 160, 85, 31, 133,
-     69, 19, 105, 51, 3, 74, 29, 0, 29, 0, 0, 252, 134, 31, 219, 118, 26, 190,
-     102, 19, 160, 85, 7, 133, 69, 0, 105, 51, 0, 73, 29, 0, 28, 0, 0, 240, 113,
-     169, 210, 98, 149, 183, 84, 130, 155, 69, 110, 129, 54, 90, 103, 37, 70, 74,
-     11, 44, 32, 0, 1, 242, 111, 150, 212, 97, 132, 184, 84, 116, 156, 69, 97,
-     130, 54, 79, 103, 37, 60, 74, 12, 36, 31, 0, 0, 244, 111, 134, 213, 97, 118,
-     185, 83, 102, 157, 68, 86, 130, 54, 69, 104, 37, 51, 74, 13, 28, 30, 0, 0,
-     245, 110, 116, 214, 96, 102, 186, 83, 88, 157, 68, 73, 131, 53, 58, 104, 37,
-     41, 74, 14, 19, 29, 0, 0, 246, 110, 98, 215, 96, 86, 186, 82, 74, 157, 67,
-     60, 131, 53, 46, 104, 37, 30, 73, 14, 10, 28, 0, 0, 247, 109, 79, 215, 95,
-     69, 187, 82, 58, 158, 67, 46, 131, 53, 33, 104, 37, 18, 73, 15, 1, 28, 0, 0,
-     247, 108, 56, 216, 95, 48, 187, 82, 40, 158, 67, 29, 131, 53, 16, 104, 37,
-     0, 73, 15, 0, 27, 0, 0, 248, 108, 32, 216, 94, 27, 187, 81, 20, 158, 67, 8,
-     131, 53, 0, 104, 37, 0, 72, 16, 0, 27, 0, 0, 238, 78, 154, 208, 66, 135,
-     181, 55, 118, 154, 43, 99, 129, 30, 81, 103, 12, 62, 74, 0, 38, 27, 0, 0,
-     240, 77, 136, 210, 66, 120, 183, 56, 105, 155, 43, 88, 129, 30, 71, 103, 13,
-     53, 73, 0, 29, 26, 0, 0, 241, 77, 122, 211, 66, 107, 183, 56, 93, 155, 44,
-     77, 129, 31, 62, 103, 14, 44, 73, 0, 23, 26, 0, 0, 242, 77, 106, 211, 66,
-     92, 184, 56, 80, 155, 44, 65, 129, 31, 51, 103, 15, 35, 73, 0, 14, 25, 0, 0,
-     243, 77, 90, 212, 66, 79, 184, 56, 67, 156, 44, 54, 129, 32, 41, 103, 16,
-     25, 73, 0, 6, 25, 0, 0, 243, 77, 73, 213, 66, 63, 184, 56, 53, 156, 44, 41,
-     130, 32, 28, 103, 17, 13, 72, 0, 0, 25, 0, 0, 244, 77, 53, 213, 67, 45, 185,
-     56, 37, 156, 45, 26, 130, 33, 13, 103, 18, 0, 72, 0, 0, 25, 0, 0, 244, 77,
-     33, 213, 67, 28, 185, 57, 21, 156, 45, 9, 130, 33, 0, 103, 19, 0, 72, 0, 0,
-     24, 0, 0, 237, 13, 138, 207, 4, 122, 180, 0, 106, 153, 0, 89, 128, 0, 72,
-     102, 0, 54, 73, 0, 31, 21, 0, 0, 238, 16, 123, 208, 6, 108, 181, 0, 94, 154,
-     0, 78, 128, 0, 63, 102, 0, 46, 72, 0, 24, 21, 0, 0, 239, 20, 110, 209, 11,
-     96, 181, 1, 83, 154, 0, 69, 128, 0, 54, 102, 0, 38, 72, 0, 17, 22, 0, 0,
-     239, 23, 96, 209, 15, 84, 182, 5, 72, 154, 0, 58, 128, 0, 45, 102, 0, 29,
-     72, 0, 9, 22, 0, 0, 240, 26, 82, 210, 19, 71, 182, 10, 60, 154, 0, 48, 128,
-     0, 35, 102, 0, 20, 72, 0, 3, 22, 0, 0, 241, 27, 67, 210, 21, 58, 182, 14,
-     48, 154, 3, 37, 128, 0, 24, 102, 0, 8, 71, 0, 0, 22, 0, 0, 241, 29, 50, 210,
-     23, 42, 183, 17, 34, 154, 6, 23, 129, 0, 10, 102, 0, 0, 71, 0, 0, 22, 0, 0,
-     241, 30, 34, 211, 25, 28, 183, 19, 21, 155, 9, 10, 129, 0, 0, 102, 0, 0, 71,
-     0, 0, 22, 0, 0, 211, 239, 252, 184, 210, 221, 160, 183, 194, 135, 155, 164,
-     111, 128, 137, 87, 101, 109, 59, 70, 76, 22, 28, 32, 218, 237, 223, 190,
-     208, 196, 165, 181, 172, 139, 153, 146, 114, 127, 121, 89, 100, 95, 61, 69,
-     66, 21, 27, 25, 223, 235, 196, 195, 206, 174, 169, 179, 152, 142, 151, 129,
-     117, 126, 107, 91, 99, 83, 62, 68, 56, 20, 26, 17, 227, 232, 168, 198, 204,
-     149, 171, 177, 130, 144, 150, 110, 119, 124, 91, 93, 98, 70, 63, 68, 46, 20,
-     25, 6, 231, 230, 142, 201, 202, 125, 174, 176, 109, 146, 148, 92, 120, 123,
-     75, 94, 97, 57, 63, 67, 35, 19, 25, 0, 234, 229, 112, 203, 200, 98, 176,
-     174, 86, 147, 147, 71, 121, 122, 57, 94, 96, 42, 64, 66, 21, 17, 24, 0, 236,
-     227, 75, 205, 199, 66, 177, 173, 57, 148, 146, 47, 122, 121, 35, 95, 95, 21,
-     64, 65, 2, 14, 24, 0, 238, 226, 32, 207, 198, 30, 178, 172, 25, 149, 145,
-     17, 123, 120, 6, 95, 94, 0, 64, 65, 0, 11, 24, 0, 211, 211, 233, 184, 186,
-     206, 160, 162, 180, 135, 137, 153, 112, 113, 127, 88, 89, 100, 61, 60, 70,
-     23, 18, 26, 217, 209, 207, 190, 184, 183, 165, 161, 160, 139, 136, 136, 115,
-     112, 113, 90, 88, 88, 62, 59, 60, 23, 17, 19, 221, 208, 183, 193, 183, 162,
-     167, 159, 142, 141, 134, 120, 116, 111, 99, 91, 87, 77, 62, 59, 51, 22, 17,
-     10, 224, 206, 158, 196, 181, 139, 170, 157, 122, 143, 133, 103, 118, 110,
-     84, 92, 86, 64, 63, 58, 40, 22, 16, 0, 227, 204, 133, 198, 179, 118, 172,
-     156, 102, 144, 132, 86, 119, 109, 70, 93, 85, 52, 64, 57, 30, 20, 16, 0,
-     230, 203, 106, 200, 178, 93, 173, 155, 81, 145, 130, 67, 120, 108, 53, 94,
-     84, 37, 64, 57, 17, 17, 16, 0, 232, 201, 73, 202, 177, 64, 175, 154, 55,
-     146, 129, 44, 121, 107, 33, 94, 83, 18, 64, 56, 0, 15, 16, 0, 233, 201, 38,
-     203, 176, 32, 175, 153, 27, 147, 129, 18, 121, 106, 6, 94, 83, 0, 64, 56, 0,
-     13, 16, 0, 210, 186, 216, 184, 163, 191, 160, 143, 167, 136, 120, 142, 112,
-     99, 118, 88, 77, 93, 61, 50, 64, 24, 6, 21, 215, 184, 192, 189, 162, 170,
-     164, 141, 149, 138, 119, 126, 115, 98, 104, 90, 76, 81, 62, 50, 54, 24, 6,
-     12, 219, 183, 171, 192, 161, 151, 166, 140, 132, 140, 118, 112, 116, 97, 92,
-     91, 75, 71, 63, 49, 46, 23, 6, 3, 222, 181, 148, 194, 159, 130, 168, 139,
-     114, 142, 117, 95, 117, 96, 78, 92, 74, 59, 63, 49, 36, 22, 6, 0, 224, 180,
-     125, 196, 158, 110, 170, 138, 96, 143, 116, 80, 118, 95, 64, 92, 74, 47, 64,
-     48, 25, 20, 6, 0, 226, 178, 100, 197, 157, 88, 171, 136, 76, 144, 115, 62,
-     119, 94, 49, 93, 73, 33, 64, 48, 13, 18, 6, 0, 228, 177, 71, 199, 156, 62,
-     172, 135, 52, 144, 114, 41, 119, 94, 30, 93, 72, 14, 64, 47, 0, 16, 6, 0,
-     229, 177, 40, 200, 155, 34, 173, 135, 27, 145, 113, 18, 120, 93, 5, 93, 72,
-     0, 63, 47, 0, 15, 6, 0, 210, 159, 199, 184, 140, 176, 160, 122, 154, 136,
-     102, 131, 113, 84, 108, 89, 64, 85, 62, 39, 57, 25, 0, 14, 214, 158, 177,
-     188, 139, 157, 163, 121, 137, 138, 102, 116, 114, 83, 96, 90, 63, 74, 63,
-     38, 48, 25, 0, 5, 217, 157, 158, 190, 138, 139, 165, 120, 122, 139, 101,
-     103, 115, 82, 84, 91, 62, 64, 63, 38, 40, 23, 0, 0, 219, 156, 137, 192, 137,
-     120, 167, 119, 105, 140, 100, 88, 116, 82, 71, 91, 62, 53, 63, 38, 30, 22,
-     0, 0, 221, 155, 116, 193, 136, 102, 168, 118, 89, 141, 99, 73, 117, 81, 59,
-     92, 61, 42, 63, 38, 21, 20, 0, 0, 223, 153, 94, 195, 135, 82, 169, 117, 70,
-     142, 98, 57, 117, 80, 44, 92, 61, 29, 63, 37, 8, 18, 0, 0, 224, 153, 68,
-     196, 134, 58, 170, 116, 49, 143, 97, 38, 118, 80, 26, 92, 60, 11, 63, 37, 0,
-     17, 0, 0, 225, 152, 41, 197, 133, 34, 170, 116, 27, 143, 97, 17, 118, 79, 4,
-     92, 60, 0, 63, 37, 0, 16, 0, 0, 209, 134, 183, 183, 118, 162, 160, 102, 142,
-     136, 85, 120, 113, 69, 100, 89, 50, 77, 62, 26, 51, 23, 0, 6, 213, 133, 163,
-     187, 117, 144, 163, 102, 126, 137, 85, 107, 114, 68, 88, 90, 50, 67, 63, 26,
-     43, 22, 0, 1, 215, 133, 146, 188, 116, 129, 164, 101, 112, 139, 84, 94, 115,
-     68, 77, 91, 50, 58, 63, 27, 34, 20, 0, 0, 217, 132, 127, 190, 116, 111, 165,
-     100, 97, 139, 84, 81, 116, 67, 65, 91, 49, 48, 63, 27, 25, 19, 0, 0, 219,
-     131, 108, 191, 115, 95, 166, 100, 82, 140, 83, 68, 116, 67, 53, 91, 49, 37,
-     63, 27, 17, 17, 0, 0, 220, 130, 88, 192, 114, 76, 167, 99, 65, 141, 82, 53,
-     116, 66, 40, 91, 49, 24, 63, 27, 5, 16, 0, 0, 221, 129, 64, 193, 113, 55,
-     168, 98, 46, 141, 82, 35, 117, 66, 23, 91, 49, 7, 63, 27, 0, 14, 0, 0, 222,
-     129, 41, 194, 113, 34, 168, 98, 26, 141, 81, 16, 117, 66, 3, 92, 48, 0, 62,
-     27, 0, 13, 0, 0, 209, 108, 168, 183, 94, 148, 160, 81, 130, 135, 66, 110,
-     113, 51, 91, 89, 35, 70, 63, 8, 45, 18, 0, 1, 212, 107, 150, 186, 94, 132,
-     162, 81, 116, 137, 66, 97, 114, 52, 80, 90, 35, 60, 63, 9, 37, 16, 0, 0,
-     214, 107, 134, 187, 93, 118, 163, 80, 103, 138, 66, 86, 114, 51, 70, 90, 35,
-     52, 63, 10, 29, 15, 0, 0, 215, 106, 117, 188, 93, 103, 164, 80, 89, 138, 66,
-     74, 115, 51, 59, 90, 35, 42, 63, 11, 21, 13, 0, 0, 216, 106, 100, 189, 92,
-     88, 164, 79, 75, 139, 65, 62, 115, 51, 48, 91, 35, 32, 63, 12, 12, 12, 0, 0,
-     217, 105, 82, 190, 92, 71, 165, 79, 60, 139, 65, 48, 115, 51, 35, 91, 35,
-     20, 62, 13, 3, 11, 0, 0, 218, 105, 61, 191, 92, 52, 166, 79, 43, 140, 65,
-     32, 116, 51, 20, 91, 35, 3, 62, 14, 0, 10, 0, 0, 219, 104, 41, 192, 91, 34,
-     166, 78, 26, 140, 65, 15, 116, 51, 2, 91, 35, 0, 62, 14, 0, 10, 0, 0, 208,
-     76, 153, 183, 65, 135, 159, 54, 118, 135, 42, 99, 113, 29, 82, 89, 10, 62,
-     62, 0, 38, 10, 0, 0, 211, 76, 137, 185, 65, 121, 161, 55, 105, 136, 43, 88,
-     114, 30, 72, 90, 12, 54, 63, 0, 31, 9, 0, 0, 212, 76, 122, 186, 66, 108,
-     162, 55, 94, 137, 43, 78, 114, 30, 63, 90, 13, 45, 62, 0, 24, 9, 0, 0, 213,
-     76, 107, 187, 66, 94, 162, 55, 81, 137, 43, 67, 114, 31, 52, 90, 15, 36, 62,
-     0, 16, 8, 0, 0, 214, 76, 92, 188, 66, 80, 163, 55, 69, 138, 44, 56, 114, 31,
-     42, 90, 16, 27, 62, 0, 8, 8, 0, 0, 215, 76, 76, 188, 66, 65, 164, 55, 55,
-     138, 44, 43, 114, 32, 31, 90, 16, 16, 62, 0, 1, 7, 0, 0, 216, 76, 57, 189,
-     66, 49, 164, 56, 40, 138, 44, 29, 115, 32, 16, 90, 17, 1, 61, 0, 0, 7, 0, 0,
-     217, 76, 40, 190, 66, 33, 164, 56, 25, 138, 44, 14, 114, 33, 1, 90, 18, 0,
-     61, 0, 0, 7, 0, 0, 207, 26, 139, 182, 16, 122, 159, 3, 106, 135, 0, 89, 113,
-     0, 73, 89, 0, 55, 62, 0, 32, 4, 0, 0, 210, 27, 124, 184, 18, 109, 160, 7,
-     95, 136, 0, 79, 113, 0, 64, 90, 0, 47, 62, 0, 25, 4, 0, 0, 211, 30, 111,
-     185, 21, 98, 161, 11, 84, 136, 0, 70, 113, 0, 55, 90, 0, 39, 62, 0, 18, 4,
-     0, 0, 212, 32, 98, 185, 24, 85, 161, 15, 73, 136, 2, 60, 113, 0, 46, 90, 0,
-     30, 61, 0, 11, 4, 0, 0, 213, 34, 85, 186, 26, 73, 162, 17, 62, 137, 5, 50,
-     113, 0, 37, 89, 0, 22, 61, 0, 5, 4, 0, 0, 213, 35, 70, 187, 27, 60, 162, 19,
-     50, 137, 8, 39, 114, 0, 26, 89, 0, 11, 61, 0, 0, 4, 0, 0, 214, 35, 54, 187,
-     29, 45, 163, 21, 37, 137, 11, 26, 114, 0, 13, 89, 0, 0, 60, 0, 0, 4, 0, 0,
-     214, 35, 40, 188, 29, 32, 163, 22, 24, 137, 12, 13, 114, 0, 0, 89, 0, 0, 60,
-     0, 0, 4, 0, 0, 169, 226, 249, 148, 199, 219, 129, 173, 192, 108, 147, 163,
-     88, 122, 136, 68, 96, 108, 43, 66, 76, 4, 25, 33, 178, 224, 221, 156, 197,
-     195, 136, 172, 171, 114, 145, 145, 93, 121, 120, 71, 95, 95, 46, 65, 66, 4,
-     24, 25, 185, 222, 196, 162, 195, 173, 140, 170, 151, 117, 144, 128, 96, 119,
-     106, 74, 94, 83, 47, 65, 57, 4, 24, 18, 190, 220, 169, 166, 193, 149, 144,
-     168, 130, 120, 142, 110, 99, 118, 91, 76, 93, 70, 49, 64, 46, 3, 23, 8, 195,
-     218, 143, 170, 191, 126, 147, 167, 110, 123, 141, 93, 100, 117, 76, 77, 92,
-     58, 50, 63, 36, 3, 23, 0, 199, 216, 115, 173, 190, 101, 149, 165, 88, 125,
-     140, 74, 102, 116, 59, 78, 91, 43, 51, 63, 23, 0, 23, 0, 202, 215, 83, 176,
-     189, 72, 152, 164, 62, 126, 138, 51, 103, 115, 39, 79, 90, 25, 51, 62, 6, 0,
-     22, 0, 204, 214, 50, 178, 188, 43, 153, 163, 37, 127, 138, 28, 104, 114, 18,
-     80, 89, 3, 51, 62, 0, 0, 22, 0, 172, 200, 231, 152, 176, 204, 132, 154, 178,
-     111, 130, 152, 91, 108, 126, 70, 84, 100, 46, 57, 70, 9, 15, 27, 180, 198,
-     205, 158, 175, 182, 138, 153, 159, 116, 129, 135, 95, 107, 112, 73, 83, 88,
-     48, 56, 60, 8, 15, 20, 186, 197, 182, 163, 173, 161, 141, 151, 141, 119,
-     128, 119, 97, 106, 99, 75, 82, 77, 49, 55, 51, 8, 14, 11, 190, 195, 158,
-     166, 172, 139, 144, 150, 122, 121, 127, 103, 99, 105, 84, 77, 81, 65, 50,
-     55, 41, 8, 14, 2, 194, 193, 135, 169, 170, 119, 147, 148, 103, 123, 125, 87,
-     101, 104, 70, 78, 81, 53, 51, 54, 31, 5, 14, 0, 197, 192, 109, 172, 169, 96,
-     149, 147, 83, 124, 124, 69, 102, 103, 55, 79, 80, 39, 51, 54, 19, 2, 14, 0,
-     200, 191, 80, 174, 168, 69, 150, 146, 59, 126, 123, 48, 103, 102, 36, 79,
-     79, 22, 52, 53, 2, 0, 14, 0, 202, 190, 51, 176, 167, 43, 152, 145, 36, 127,
-     123, 27, 103, 101, 16, 80, 79, 1, 52, 53, 0, 0, 14, 0, 175, 176, 215, 154,
-     156, 190, 134, 136, 166, 113, 115, 141, 93, 94, 118, 72, 73, 93, 48, 47, 64,
-     12, 2, 22, 182, 175, 191, 160, 154, 169, 139, 135, 148, 117, 114, 126, 96,
-     94, 104, 75, 72, 81, 50, 47, 55, 12, 3, 14, 186, 174, 170, 163, 153, 151,
-     142, 134, 132, 119, 113, 111, 98, 93, 92, 76, 71, 71, 51, 46, 46, 11, 3, 5,
-     190, 172, 148, 166, 152, 130, 144, 132, 114, 121, 112, 96, 100, 92, 78, 77,
-     71, 59, 51, 46, 36, 9, 4, 0, 192, 171, 127, 169, 151, 111, 146, 131, 97,
-     123, 111, 81, 101, 91, 65, 78, 70, 48, 52, 45, 26, 6, 4, 0, 195, 170, 103,
-     171, 150, 90, 148, 130, 78, 124, 110, 64, 102, 90, 51, 79, 70, 35, 52, 45,
-     15, 3, 5, 0, 198, 169, 76, 173, 149, 66, 149, 129, 56, 125, 109, 45, 103,
-     89, 33, 79, 69, 18, 52, 45, 0, 1, 5, 0, 199, 168, 51, 174, 148, 43, 150,
-     129, 35, 126, 108, 26, 103, 89, 14, 80, 69, 0, 52, 45, 0, 0, 5, 0, 177, 151,
-     198, 156, 134, 175, 136, 117, 153, 115, 98, 130, 95, 80, 108, 74, 60, 85,
-     50, 36, 58, 11, 0, 15, 183, 150, 176, 161, 133, 156, 140, 116, 137, 118, 97,
-     116, 97, 79, 96, 76, 60, 74, 51, 36, 49, 11, 0, 6, 186, 150, 158, 163, 132,
-     139, 142, 115, 122, 120, 97, 103, 99, 79, 84, 77, 59, 64, 52, 36, 41, 9, 0,
-     1, 189, 148, 137, 166, 131, 121, 144, 114, 105, 121, 96, 88, 100, 78, 72,
-     78, 59, 54, 52, 36, 31, 7, 0, 0, 191, 147, 118, 168, 130, 103, 145, 113, 90,
-     122, 95, 75, 101, 77, 60, 78, 59, 43, 52, 35, 22, 5, 0, 0, 193, 147, 97,
-     169, 129, 84, 147, 112, 72, 123, 94, 59, 101, 77, 46, 79, 58, 31, 52, 35,
-     11, 4, 0, 0, 195, 146, 73, 171, 128, 62, 148, 111, 53, 124, 93, 41, 102, 76,
-     30, 79, 58, 15, 52, 35, 0, 3, 0, 0, 197, 145, 50, 172, 128, 42, 149, 111,
-     34, 125, 93, 24, 102, 76, 12, 79, 57, 0, 52, 35, 0, 2, 0, 0, 179, 128, 183,
-     157, 113, 162, 137, 98, 142, 116, 82, 120, 96, 66, 100, 75, 48, 78, 51, 24,
-     52, 5, 0, 8, 183, 128, 163, 161, 113, 144, 140, 98, 126, 119, 81, 107, 98,
-     65, 88, 76, 48, 68, 52, 24, 43, 6, 0, 1, 186, 127, 146, 163, 112, 129, 142,
-     97, 112, 120, 81, 95, 99, 65, 77, 77, 47, 58, 52, 24, 35, 4, 0, 0, 188, 126,
-     128, 165, 111, 112, 144, 96, 97, 121, 80, 81, 100, 65, 66, 78, 47, 48, 53,
-     24, 26, 3, 0, 0, 190, 126, 110, 167, 110, 96, 145, 96, 83, 122, 80, 69, 101,
-     64, 54, 78, 47, 38, 52, 25, 18, 2, 0, 0, 192, 125, 90, 168, 110, 79, 146,
-     95, 67, 123, 79, 54, 101, 64, 42, 79, 47, 26, 52, 25, 7, 2, 0, 0, 194, 124,
-     69, 170, 109, 59, 147, 95, 49, 123, 79, 38, 101, 63, 26, 79, 47, 11, 52, 25,
-     0, 1, 0, 0, 195, 124, 49, 171, 109, 40, 148, 94, 32, 124, 78, 22, 102, 63,
-     9, 79, 46, 0, 52, 25, 0, 1, 0, 0, 180, 104, 168, 158, 91, 148, 138, 78, 130,
-     117, 64, 110, 97, 49, 91, 76, 33, 70, 52, 7, 46, 2, 0, 1, 184, 103, 150,
-     162, 91, 133, 141, 78, 116, 119, 64, 98, 99, 50, 80, 77, 33, 61, 52, 8, 37,
-     2, 0, 0, 186, 103, 135, 163, 90, 119, 142, 78, 103, 120, 64, 87, 99, 50, 70,
-     78, 33, 52, 52, 10, 30, 1, 0, 0, 188, 103, 118, 165, 90, 103, 143, 77, 90,
-     121, 63, 75, 100, 49, 60, 78, 33, 43, 52, 11, 22, 1, 0, 0, 189, 102, 102,
-     166, 89, 89, 144, 77, 76, 121, 63, 63, 100, 49, 49, 78, 34, 33, 52, 12, 14,
-     0, 0, 0, 191, 102, 84, 167, 89, 73, 145, 77, 62, 122, 63, 50, 101, 49, 37,
-     78, 34, 22, 52, 13, 4, 0, 0, 0, 192, 101, 65, 168, 89, 55, 146, 76, 46, 123,
-     63, 35, 101, 49, 23, 78, 34, 7, 51, 13, 0, 0, 0, 0, 193, 101, 48, 169, 88,
-     39, 146, 76, 31, 123, 63, 20, 101, 49, 8, 78, 34, 0, 51, 14, 0, 0, 0, 0,
-     181, 75, 154, 159, 64, 136, 139, 54, 118, 118, 41, 100, 98, 28, 82, 77, 8,
-     63, 51, 0, 39, 0, 0, 0, 184, 75, 137, 162, 65, 121, 141, 54, 106, 119, 42,
-     89, 99, 29, 72, 77, 11, 54, 52, 0, 32, 0, 0, 0, 186, 75, 123, 163, 65, 109,
-     142, 54, 94, 120, 43, 79, 99, 30, 63, 78, 12, 46, 52, 0, 25, 0, 0, 0, 187,
-     76, 108, 164, 65, 95, 143, 55, 82, 121, 43, 68, 100, 31, 54, 78, 14, 37, 52,
-     0, 17, 0, 0, 0, 188, 76, 94, 165, 65, 82, 144, 55, 70, 121, 43, 57, 100, 31,
-     44, 78, 15, 28, 51, 0, 9, 0, 0, 0, 189, 75, 78, 166, 65, 68, 144, 55, 57,
-     121, 43, 45, 100, 31, 33, 78, 16, 18, 51, 0, 2, 0, 0, 0, 190, 75, 61, 167,
-     65, 52, 145, 55, 42, 122, 44, 31, 100, 32, 19, 78, 16, 4, 51, 0, 0, 0, 0, 0,
-     191, 75, 46, 168, 65, 37, 145, 55, 29, 122, 44, 18, 100, 32, 5, 78, 17, 0,
-     50, 0, 0, 0, 0, 0, 181, 35, 140, 160, 24, 123, 140, 12, 107, 118, 0, 90, 98,
-     0, 74, 77, 0, 56, 51, 0, 33, 0, 0, 0, 184, 34, 125, 162, 26, 110, 141, 15,
-     96, 120, 1, 80, 99, 0, 65, 78, 0, 48, 51, 0, 26, 0, 0, 0, 186, 36, 113, 163,
-     27, 99, 142, 18, 86, 120, 5, 71, 99, 0, 57, 78, 0, 40, 51, 0, 20, 0, 0, 0,
-     187, 38, 99, 164, 30, 87, 142, 21, 74, 120, 8, 61, 99, 0, 48, 78, 0, 32, 51,
-     0, 12, 0, 0, 0, 187, 39, 87, 164, 31, 75, 143, 22, 64, 120, 11, 51, 100, 0,
-     39, 78, 0, 24, 51, 0, 6, 0, 0, 0, 188, 40, 73, 165, 32, 62, 143, 24, 52,
-     121, 13, 40, 100, 0, 28, 78, 0, 14, 51, 0, 0, 0, 0, 0, 189, 40, 58, 166, 33,
-     48, 144, 25, 39, 121, 15, 28, 100, 1, 16, 78, 0, 2, 50, 0, 0, 0, 0, 0, 190,
-     40, 45, 166, 34, 36, 144, 26, 27, 121, 16, 17, 100, 3, 3, 77, 0, 0, 49, 0,
-     0, 0, 0, 0, 120, 213, 247, 106, 188, 217, 92, 164, 190, 76, 139, 162, 60,
-     115, 135, 43, 91, 107, 21, 62, 76, 0, 22, 34, 134, 211, 219, 118, 186, 193,
-     102, 162, 169, 84, 138, 144, 67, 114, 120, 49, 90, 95, 26, 62, 66, 0, 22,
-     26, 143, 209, 195, 125, 184, 172, 108, 161, 151, 90, 136, 128, 72, 113, 106,
-     53, 89, 83, 29, 61, 57, 0, 22, 19, 150, 207, 169, 131, 182, 149, 113, 159,
-     130, 94, 135, 110, 76, 112, 91, 56, 88, 71, 31, 60, 47, 0, 21, 9, 156, 205,
-     145, 136, 181, 127, 117, 158, 111, 97, 133, 94, 78, 111, 77, 58, 87, 59, 33,
-     60, 37, 0, 21, 0, 161, 204, 118, 141, 179, 104, 121, 156, 90, 100, 132, 75,
-     81, 110, 61, 60, 86, 45, 35, 59, 25, 0, 21, 0, 165, 203, 89, 144, 178, 77,
-     124, 155, 67, 102, 131, 55, 82, 109, 43, 62, 85, 29, 36, 59, 10, 0, 21, 0,
-     169, 202, 62, 147, 178, 53, 126, 155, 45, 104, 131, 36, 84, 108, 25, 62, 85,
-     11, 36, 58, 0, 0, 21, 0, 129, 189, 229, 114, 167, 202, 99, 146, 177, 83,
-     124, 151, 67, 102, 126, 49, 79, 99, 28, 53, 70, 0, 12, 28, 140, 188, 204,
-     124, 166, 180, 107, 145, 158, 89, 123, 134, 72, 101, 111, 54, 79, 88, 31,
-     53, 60, 0, 12, 21, 148, 186, 182, 130, 164, 161, 112, 144, 141, 93, 121,
-     119, 76, 100, 99, 56, 78, 77, 33, 52, 51, 0, 12, 13, 153, 184, 158, 134,
-     163, 140, 116, 142, 122, 97, 120, 103, 78, 99, 85, 59, 77, 65, 35, 52, 42,
-     0, 12, 3, 158, 183, 136, 138, 161, 120, 119, 141, 104, 99, 119, 87, 80, 98,
-     71, 60, 77, 54, 36, 51, 32, 0, 12, 0, 162, 182, 112, 142, 160, 98, 122, 140,
-     85, 102, 118, 70, 82, 97, 56, 62, 76, 41, 37, 51, 21, 0, 11, 0, 166, 181,
-     85, 145, 159, 74, 125, 139, 63, 103, 117, 51, 84, 97, 39, 63, 75, 25, 37,
-     51, 6, 0, 11, 0, 168, 180, 60, 147, 158, 51, 126, 138, 43, 105, 116, 34, 85,
-     96, 23, 64, 75, 8, 38, 50, 0, 0, 11, 0, 136, 167, 213, 120, 148, 188, 105,
-     129, 165, 88, 109, 140, 71, 90, 117, 54, 69, 92, 32, 44, 64, 0, 2, 23, 145,
-     166, 190, 128, 147, 168, 111, 128, 147, 93, 108, 125, 75, 89, 104, 57, 68,
-     81, 34, 44, 55, 0, 2, 15, 151, 165, 170, 133, 146, 150, 115, 127, 131, 96,
-     107, 111, 78, 88, 92, 59, 68, 71, 36, 43, 46, 0, 2, 6, 155, 163, 148, 136,
-     144, 131, 118, 126, 114, 99, 106, 96, 80, 87, 79, 61, 67, 60, 37, 43, 37, 0,
-     2, 0, 159, 162, 128, 140, 143, 112, 121, 125, 97, 101, 105, 82, 82, 87, 66,
-     62, 67, 49, 38, 43, 27, 0, 2, 0, 163, 161, 105, 142, 142, 92, 123, 124, 80,
-     103, 104, 66, 83, 86, 52, 63, 66, 37, 39, 43, 17, 0, 2, 0, 166, 160, 81,
-     145, 141, 70, 125, 123, 59, 104, 104, 48, 84, 85, 36, 64, 66, 21, 39, 42, 2,
-     0, 1, 0, 168, 160, 59, 147, 141, 50, 126, 122, 41, 105, 103, 32, 85, 85, 20,
-     64, 65, 6, 39, 42, 0, 0, 1, 0, 142, 144, 197, 125, 128, 174, 109, 111, 153,
-     92, 93, 130, 75, 76, 108, 57, 57, 85, 36, 33, 58, 0, 0, 16, 149, 143, 176,
-     131, 127, 156, 114, 110, 136, 96, 93, 116, 78, 75, 96, 60, 57, 74, 37, 33,
-     49, 0, 0, 7, 153, 142, 157, 135, 126, 139, 117, 110, 122, 98, 92, 103, 80,
-     75, 84, 61, 56, 65, 38, 33, 41, 0, 0, 1, 157, 142, 138, 138, 125, 121, 120,
-     109, 106, 100, 91, 89, 82, 74, 72, 62, 56, 54, 39, 33, 32, 0, 0, 0, 160,
-     141, 119, 140, 124, 105, 122, 108, 91, 102, 91, 76, 83, 74, 61, 63, 56, 44,
-     40, 33, 23, 0, 0, 0, 163, 140, 99, 143, 123, 86, 124, 107, 74, 103, 90, 61,
-     84, 73, 48, 64, 55, 32, 40, 33, 13, 0, 0, 0, 165, 139, 77, 145, 122, 66,
-     125, 107, 56, 104, 89, 44, 85, 73, 33, 65, 55, 18, 40, 33, 1, 0, 0, 0, 167,
-     139, 57, 146, 122, 48, 126, 106, 39, 105, 89, 29, 86, 72, 18, 65, 55, 3, 40,
-     33, 0, 0, 0, 0, 146, 123, 182, 129, 108, 161, 113, 94, 141, 95, 78, 120, 78,
-     62, 99, 60, 45, 78, 38, 21, 52, 0, 0, 9, 152, 122, 163, 134, 108, 144, 117,
-     94, 126, 98, 78, 107, 80, 62, 88, 61, 45, 68, 39, 22, 44, 0, 0, 1, 156, 122,
-     146, 137, 107, 129, 119, 93, 113, 100, 77, 95, 82, 62, 78, 63, 45, 59, 40,
-     22, 36, 0, 0, 0, 158, 121, 128, 139, 107, 113, 121, 92, 98, 101, 77, 82, 83,
-     62, 66, 64, 45, 49, 40, 23, 27, 0, 0, 0, 161, 120, 111, 141, 106, 97, 122,
-     92, 84, 103, 77, 70, 84, 62, 56, 64, 45, 40, 40, 23, 19, 0, 0, 0, 163, 120,
-     93, 143, 105, 81, 124, 91, 69, 104, 76, 56, 85, 61, 43, 65, 45, 28, 40, 24,
-     9, 0, 0, 0, 165, 119, 73, 145, 105, 62, 125, 91, 52, 105, 76, 41, 85, 61,
-     29, 65, 44, 15, 40, 24, 0, 0, 0, 0, 166, 119, 55, 146, 104, 46, 126, 90, 37,
-     105, 75, 27, 86, 61, 15, 65, 44, 0, 40, 24, 0, 0, 0, 0, 150, 100, 168, 132,
-     88, 148, 115, 75, 130, 97, 61, 110, 80, 47, 91, 62, 30, 71, 39, 7, 46, 0, 0,
-     2, 154, 100, 150, 136, 88, 133, 119, 75, 116, 100, 61, 98, 82, 47, 81, 63,
-     31, 62, 40, 9, 38, 0, 0, 0, 157, 100, 135, 138, 87, 119, 120, 75, 104, 101,
-     61, 87, 83, 48, 71, 64, 31, 53, 40, 10, 31, 0, 0, 0, 159, 99, 119, 140, 87,
-     104, 122, 75, 91, 102, 61, 75, 84, 48, 61, 64, 32, 44, 40, 11, 23, 0, 0, 0,
-     161, 99, 104, 141, 87, 90, 123, 74, 78, 103, 61, 64, 84, 48, 50, 65, 32, 35,
-     40, 12, 15, 0, 0, 0, 163, 99, 87, 143, 86, 75, 124, 74, 64, 104, 61, 52, 85,
-     47, 39, 65, 32, 24, 40, 13, 6, 0, 0, 0, 164, 98, 69, 144, 86, 58, 125, 74,
-     49, 104, 61, 38, 85, 47, 26, 65, 32, 11, 40, 13, 0, 0, 0, 0, 166, 98, 53,
-     145, 86, 44, 126, 74, 35, 105, 60, 25, 86, 47, 13, 65, 32, 0, 40, 14, 0, 0,
-     0, 0, 152, 75, 154, 134, 64, 136, 117, 53, 119, 99, 41, 101, 82, 27, 83, 63,
-     7, 64, 39, 0, 40, 0, 0, 0, 156, 74, 138, 138, 64, 122, 120, 53, 106, 101,
-     41, 90, 83, 28, 73, 64, 10, 55, 40, 0, 33, 0, 0, 0, 158, 74, 124, 139, 64,
-     110, 121, 54, 95, 102, 42, 80, 84, 29, 64, 65, 12, 47, 41, 0, 26, 0, 0, 0,
-     160, 75, 110, 140, 64, 96, 122, 54, 83, 103, 42, 69, 84, 30, 55, 65, 13, 39,
-     41, 0, 18, 0, 0, 0, 161, 75, 96, 142, 64, 83, 123, 54, 71, 103, 43, 58, 85,
-     30, 45, 65, 14, 30, 41, 0, 11, 0, 0, 0, 163, 75, 81, 143, 64, 70, 124, 54,
-     59, 104, 43, 47, 85, 31, 35, 65, 15, 20, 41, 0, 3, 0, 0, 0, 164, 74, 65,
-     144, 64, 55, 125, 54, 45, 104, 43, 34, 85, 31, 22, 66, 16, 7, 41, 0, 0, 0,
-     0, 0, 165, 74, 51, 145, 64, 42, 125, 54, 33, 105, 43, 22, 86, 32, 10, 65,
-     17, 0, 40, 0, 0, 0, 0, 0, 154, 41, 142, 136, 30, 124, 119, 19, 108, 101, 3,
-     91, 83, 0, 75, 64, 0, 57, 39, 0, 34, 0, 0, 0, 158, 40, 127, 139, 31, 112,
-     121, 21, 97, 102, 7, 81, 84, 0, 66, 65, 0, 49, 40, 0, 27, 0, 0, 0, 159, 41,
-     114, 140, 32, 100, 122, 23, 87, 103, 10, 72, 85, 0, 58, 65, 0, 42, 40, 0,
-     21, 0, 0, 0, 160, 43, 101, 141, 34, 88, 123, 25, 76, 103, 13, 62, 85, 0, 49,
-     65, 0, 33, 41, 0, 14, 0, 0, 0, 161, 44, 89, 142, 35, 77, 123, 26, 65, 103,
-     15, 53, 85, 1, 40, 65, 0, 25, 41, 0, 7, 0, 0, 0, 162, 44, 75, 143, 36, 64,
-     124, 28, 54, 104, 17, 42, 85, 3, 30, 65, 0, 16, 40, 0, 1, 0, 0, 0, 164, 45,
-     61, 144, 37, 51, 124, 29, 42, 104, 18, 31, 85, 4, 19, 65, 0, 4, 40, 0, 0, 0,
-     0, 0, 164, 45, 49, 144, 37, 40, 125, 29, 31, 105, 19, 20, 86, 6, 7, 65, 0,
-     0, 39, 0, 0, 0, 0, 0, 49, 202, 244, 45, 178, 215, 38, 156, 188, 28, 132,
-     160, 14, 110, 134, 0, 86, 107, 0, 59, 76, 0, 20, 34, 80, 200, 217, 70, 176,
-     192, 60, 154, 168, 47, 131, 143, 34, 109, 119, 16, 85, 94, 0, 58, 66, 0, 20,
-     27, 95, 198, 194, 84, 175, 171, 71, 153, 150, 57, 130, 127, 42, 108, 106,
-     25, 84, 83, 0, 58, 57, 0, 20, 19, 107, 196, 169, 93, 173, 149, 79, 151, 130,
-     64, 128, 110, 49, 106, 91, 32, 84, 71, 3, 57, 47, 0, 19, 10, 115, 195, 145,
-     100, 171, 128, 86, 150, 112, 69, 127, 94, 53, 105, 78, 36, 83, 59, 8, 57,
-     37, 0, 19, 1, 122, 193, 120, 107, 170, 106, 91, 149, 92, 74, 126, 77, 57,
-     104, 62, 39, 82, 46, 13, 56, 26, 0, 18, 0, 128, 192, 93, 112, 169, 81, 95,
-     148, 70, 77, 125, 58, 60, 104, 46, 42, 81, 31, 15, 56, 13, 0, 17, 0, 132,
-     191, 69, 115, 168, 60, 98, 147, 51, 79, 124, 41, 62, 103, 30, 43, 81, 17,
-     16, 56, 0, 0, 17, 0, 77, 180, 227, 69, 159, 200, 60, 139, 176, 48, 118, 150,
-     35, 97, 125, 20, 75, 99, 0, 50, 70, 0, 9, 29, 96, 178, 203, 85, 158, 179,
-     73, 138, 157, 59, 117, 133, 45, 96, 111, 29, 75, 87, 3, 50, 60, 0, 9, 21,
-     107, 177, 181, 94, 156, 160, 80, 137, 140, 65, 116, 119, 51, 96, 98, 34, 74,
-     77, 9, 49, 52, 0, 8, 14, 115, 175, 158, 101, 155, 140, 86, 135, 122, 71,
-     114, 103, 55, 95, 85, 38, 73, 65, 14, 49, 42, 0, 7, 4, 121, 174, 137, 106,
-     153, 120, 91, 134, 105, 74, 113, 88, 58, 94, 72, 41, 73, 54, 17, 49, 33, 0,
-     6, 0, 127, 173, 114, 111, 152, 100, 95, 133, 86, 78, 112, 72, 61, 93, 58,
-     43, 72, 42, 19, 48, 22, 0, 6, 0, 132, 172, 88, 115, 151, 77, 98, 132, 66,
-     80, 112, 54, 63, 92, 42, 45, 72, 28, 20, 48, 9, 0, 5, 0, 135, 171, 67, 118,
-     151, 57, 100, 131, 49, 82, 111, 39, 65, 92, 28, 46, 71, 13, 21, 48, 0, 0, 5,
-     0, 93, 159, 211, 83, 141, 187, 72, 123, 164, 59, 104, 140, 46, 85, 116, 31,
-     65, 92, 8, 41, 64, 0, 1, 23, 106, 158, 189, 94, 140, 167, 81, 122, 147, 67,
-     103, 124, 52, 85, 103, 36, 65, 81, 14, 41, 55, 0, 0, 15, 114, 157, 169, 100,
-     139, 150, 87, 121, 131, 71, 102, 111, 56, 84, 92, 40, 64, 71, 17, 41, 47, 0,
-     0, 7, 121, 156, 148, 106, 138, 131, 91, 120, 114, 75, 101, 96, 60, 83, 79,
-     43, 64, 60, 20, 40, 37, 0, 0, 1, 126, 155, 129, 110, 136, 113, 95, 119, 98,
-     78, 101, 82, 62, 83, 67, 45, 63, 50, 22, 40, 28, 0, 0, 0, 130, 154, 107,
-     114, 135, 94, 98, 118, 81, 81, 100, 67, 64, 82, 54, 46, 63, 38, 23, 40, 18,
-     0, 0, 0, 134, 153, 84, 117, 135, 73, 101, 117, 62, 83, 99, 51, 66, 81, 39,
-     48, 62, 24, 24, 40, 5, 0, 0, 0, 137, 152, 65, 119, 134, 55, 102, 117, 46,
-     84, 99, 36, 67, 81, 25, 48, 62, 11, 24, 40, 0, 0, 0, 0, 105, 138, 196, 93,
-     122, 173, 81, 106, 152, 67, 89, 129, 53, 72, 107, 38, 54, 84, 17, 30, 58, 0,
-     0, 17, 115, 137, 175, 101, 121, 155, 88, 106, 136, 73, 89, 115, 58, 72, 95,
-     42, 54, 74, 21, 31, 49, 0, 0, 8, 120, 136, 157, 106, 120, 139, 92, 105, 121,
-     76, 88, 103, 61, 71, 84, 44, 53, 65, 23, 31, 41, 0, 0, 1, 125, 135, 138,
-     110, 119, 122, 95, 104, 106, 79, 87, 89, 63, 71, 73, 46, 53, 55, 25, 31, 33,
-     0, 0, 0, 129, 134, 120, 113, 119, 105, 98, 103, 91, 81, 87, 76, 65, 71, 61,
-     48, 53, 45, 26, 31, 24, 0, 0, 0, 133, 134, 101, 116, 118, 88, 100, 103, 76,
-     83, 86, 62, 67, 70, 49, 49, 53, 34, 27, 31, 14, 0, 0, 0, 136, 133, 80, 119,
-     117, 69, 102, 102, 58, 85, 86, 47, 68, 70, 35, 50, 52, 20, 27, 31, 3, 0, 0,
-     0, 138, 133, 62, 121, 117, 52, 104, 102, 43, 86, 85, 33, 69, 69, 22, 50, 52,
-     7, 27, 31, 0, 0, 0, 0, 114, 118, 182, 100, 104, 161, 87, 90, 141, 73, 75,
-     120, 59, 59, 99, 43, 42, 78, 22, 20, 52, 0, 0, 10, 121, 117, 163, 106, 104,
-     144, 92, 90, 126, 77, 75, 107, 62, 59, 88, 46, 42, 68, 24, 21, 44, 0, 0, 2,
-     125, 117, 146, 110, 103, 129, 95, 89, 113, 79, 74, 95, 64, 59, 78, 47, 42,
-     59, 26, 21, 36, 0, 0, 0, 129, 116, 129, 113, 102, 113, 98, 89, 99, 82, 74,
-     83, 66, 59, 67, 49, 42, 50, 27, 22, 28, 0, 0, 0, 132, 116, 112, 116, 102,
-     98, 100, 88, 85, 83, 73, 71, 67, 59, 57, 50, 43, 41, 28, 22, 20, 0, 0, 0,
-     134, 115, 95, 118, 101, 82, 102, 88, 71, 85, 73, 58, 68, 59, 45, 51, 43, 30,
-     29, 22, 11, 0, 0, 0, 137, 115, 76, 120, 101, 65, 104, 87, 55, 86, 73, 44,
-     69, 58, 32, 51, 42, 18, 29, 22, 1, 0, 0, 0, 139, 114, 60, 122, 100, 50, 105,
-     87, 41, 87, 72, 31, 70, 58, 19, 51, 42, 4, 29, 22, 0, 0, 0, 0, 120, 97, 168,
-     106, 85, 149, 92, 73, 130, 77, 59, 110, 63, 45, 91, 47, 28, 71, 25, 6, 47,
-     0, 0, 3, 126, 97, 151, 111, 85, 133, 96, 73, 117, 80, 59, 98, 65, 46, 81,
-     48, 29, 62, 27, 7, 39, 0, 0, 0, 129, 97, 136, 113, 85, 120, 98, 73, 104, 82,
-     59, 88, 67, 46, 72, 50, 30, 54, 29, 8, 32, 0, 0, 0, 132, 96, 120, 116, 84,
-     105, 100, 72, 91, 84, 59, 76, 68, 46, 61, 51, 30, 45, 29, 9, 24, 0, 0, 0,
-     134, 96, 105, 117, 84, 92, 102, 72, 79, 85, 59, 65, 69, 46, 52, 51, 30, 36,
-     30, 10, 16, 0, 0, 0, 136, 96, 89, 119, 84, 77, 103, 72, 66, 86, 59, 53, 69,
-     46, 41, 52, 31, 26, 30, 11, 7, 0, 0, 0, 138, 95, 71, 121, 83, 61, 105, 72,
-     51, 87, 59, 40, 70, 46, 28, 52, 31, 14, 30, 11, 0, 0, 0, 0, 139, 95, 57,
-     122, 83, 47, 106, 71, 38, 88, 59, 28, 71, 46, 17, 52, 31, 2, 29, 12, 0, 0,
-     0, 0, 125, 74, 155, 110, 63, 137, 96, 52, 120, 81, 40, 101, 66, 27, 83, 49,
-     7, 64, 27, 0, 41, 0, 0, 0, 129, 73, 139, 114, 63, 123, 99, 53, 107, 83, 41,
-     90, 68, 28, 74, 51, 10, 56, 29, 0, 33, 0, 0, 0, 132, 74, 125, 116, 63, 110,
-     101, 53, 96, 84, 41, 80, 69, 29, 65, 51, 12, 48, 30, 0, 27, 0, 0, 0, 134,
-     74, 111, 118, 64, 97, 102, 53, 84, 85, 42, 70, 69, 29, 56, 52, 13, 40, 30,
-     0, 19, 0, 0, 0, 136, 74, 97, 119, 64, 85, 103, 53, 73, 86, 42, 60, 70, 30,
-     47, 52, 14, 31, 30, 0, 12, 0, 0, 0, 137, 74, 83, 121, 64, 71, 104, 54, 61,
-     87, 42, 49, 71, 30, 36, 53, 15, 22, 30, 0, 5, 0, 0, 0, 139, 74, 67, 122, 64,
-     57, 105, 54, 47, 88, 42, 36, 71, 31, 25, 53, 16, 9, 30, 0, 0, 0, 0, 0, 140,
-     73, 54, 123, 64, 45, 106, 54, 36, 88, 43, 26, 71, 31, 14, 53, 17, 1, 29, 0,
-     0, 0, 0, 0, 129, 44, 143, 114, 34, 126, 99, 24, 110, 84, 9, 92, 68, 0, 76,
-     51, 0, 58, 28, 0, 35, 0, 0, 0, 132, 44, 128, 117, 35, 113, 102, 25, 98, 85,
-     12, 82, 69, 0, 67, 52, 0, 50, 29, 0, 28, 0, 0, 0, 134, 45, 116, 118, 36,
-     102, 103, 27, 88, 86, 14, 73, 70, 0, 59, 52, 0, 43, 29, 0, 22, 0, 0, 0, 136,
-     46, 103, 119, 37, 90, 103, 28, 77, 87, 17, 64, 71, 1, 50, 53, 0, 35, 30, 0,
-     15, 0, 0, 0, 137, 47, 90, 120, 38, 78, 104, 29, 67, 87, 18, 54, 71, 3, 42,
-     53, 0, 27, 29, 0, 8, 0, 0, 0, 138, 47, 77, 121, 39, 66, 105, 30, 56, 88, 19,
-     44, 71, 5, 32, 53, 0, 18, 29, 0, 2, 0, 0, 0, 139, 48, 63, 122, 39, 53, 106,
-     31, 44, 88, 20, 33, 71, 7, 21, 53, 0, 6, 28, 0, 0, 0, 0, 0, 140, 48, 52,
-     123, 40, 42, 107, 31, 33, 89, 21, 23, 72, 8, 10, 53, 0, 0, 27, 0, 0, 0, 0,
-     0, 0, 192, 242, 0, 169, 213, 0, 148, 187, 0, 125, 159, 0, 104, 133, 0, 82,
-     106, 0, 56, 76, 0, 18, 34, 0, 189, 216, 0, 167, 190, 0, 147, 167, 0, 124,
-     142, 0, 103, 119, 0, 81, 94, 0, 55, 66, 0, 16, 27, 0, 188, 193, 0, 166, 170,
-     0, 145, 149, 0, 123, 127, 0, 102, 105, 0, 80, 83, 0, 55, 57, 0, 15, 20, 32,
-     186, 168, 27, 164, 149, 17, 144, 130, 0, 122, 110, 0, 101, 91, 0, 79, 71, 0,
-     55, 47, 0, 14, 11, 56, 184, 146, 47, 163, 129, 37, 142, 113, 23, 121, 95, 5,
-     100, 78, 0, 79, 60, 0, 54, 38, 0, 14, 2, 70, 183, 122, 60, 161, 107, 49,
-     141, 94, 35, 120, 79, 20, 100, 64, 0, 78, 48, 0, 54, 27, 0, 13, 0, 80, 182,
-     96, 69, 160, 84, 57, 140, 73, 43, 119, 61, 28, 99, 48, 6, 78, 34, 0, 53, 15,
-     0, 13, 0, 87, 181, 74, 75, 160, 65, 62, 140, 56, 47, 119, 46, 32, 98, 35,
-     12, 77, 21, 0, 53, 2, 0, 13, 0, 0, 171, 225, 0, 151, 199, 0, 132, 174, 0,
-     112, 149, 0, 92, 124, 0, 71, 98, 0, 47, 69, 0, 4, 29, 0, 169, 201, 0, 150,
-     178, 0, 131, 156, 0, 111, 133, 0, 92, 111, 0, 71, 87, 0, 47, 60, 0, 3, 22,
-     41, 168, 180, 36, 148, 159, 28, 130, 140, 15, 110, 118, 0, 91, 98, 0, 70,
-     77, 0, 46, 52, 0, 2, 14, 61, 166, 158, 53, 147, 139, 43, 129, 122, 31, 109,
-     103, 17, 90, 85, 0, 70, 66, 0, 46, 43, 0, 2, 5, 73, 165, 137, 64, 146, 121,
-     53, 128, 106, 40, 108, 89, 26, 89, 73, 6, 69, 55, 0, 46, 33, 0, 1, 0, 83,
-     164, 115, 72, 145, 101, 60, 127, 88, 46, 107, 73, 32, 89, 59, 14, 69, 43, 0,
-     46, 23, 0, 1, 0, 90, 163, 91, 78, 144, 80, 65, 126, 69, 51, 106, 57, 37, 88,
-     44, 19, 68, 30, 0, 45, 11, 0, 1, 0, 95, 163, 72, 82, 143, 62, 69, 125, 53,
-     54, 106, 43, 39, 88, 32, 22, 68, 18, 0, 45, 0, 0, 1, 0, 0, 152, 210, 0, 134,
-     186, 0, 117, 163, 0, 99, 139, 0, 81, 116, 0, 62, 92, 0, 38, 64, 0, 1, 24,
-     47, 151, 188, 42, 133, 167, 35, 117, 146, 24, 98, 124, 10, 81, 103, 0, 61,
-     81, 0, 38, 55, 0, 0, 16, 65, 150, 169, 57, 132, 149, 47, 116, 131, 36, 98,
-     111, 23, 80, 92, 4, 61, 71, 0, 38, 47, 0, 0, 7, 76, 148, 148, 67, 131, 131,
-     56, 115, 114, 44, 97, 96, 31, 79, 79, 14, 61, 61, 0, 38, 38, 0, 0, 1, 84,
-     147, 129, 74, 130, 114, 62, 114, 99, 49, 96, 83, 35, 79, 68, 19, 60, 50, 0,
-     37, 29, 0, 0, 0, 91, 146, 109, 80, 129, 95, 67, 113, 83, 53, 95, 69, 39, 78,
-     55, 23, 60, 39, 1, 37, 20, 0, 0, 0, 97, 146, 87, 84, 128, 76, 71, 112, 65,
-     57, 95, 53, 42, 78, 41, 26, 60, 26, 4, 37, 7, 0, 0, 0, 101, 145, 69, 88,
-     128, 59, 74, 112, 50, 59, 94, 40, 44, 77, 29, 27, 59, 15, 4, 37, 0, 0, 0, 0,
-     52, 132, 195, 47, 117, 172, 40, 102, 151, 30, 85, 129, 19, 69, 107, 2, 51,
-     84, 0, 28, 58, 0, 0, 18, 70, 131, 175, 61, 116, 155, 52, 101, 135, 41, 85,
-     115, 29, 68, 95, 13, 51, 74, 0, 28, 49, 0, 0, 9, 80, 130, 157, 70, 115, 139,
-     59, 100, 121, 47, 84, 103, 35, 68, 85, 19, 51, 65, 0, 28, 42, 0, 0, 1, 87,
-     130, 138, 76, 114, 122, 65, 100, 106, 52, 84, 89, 39, 68, 73, 24, 50, 55, 4,
-     28, 33, 0, 0, 0, 93, 129, 121, 81, 114, 106, 69, 99, 92, 56, 83, 77, 42, 67,
-     62, 27, 50, 46, 7, 29, 25, 0, 0, 0, 98, 128, 102, 86, 113, 89, 73, 98, 77,
-     59, 82, 64, 45, 67, 50, 29, 50, 35, 9, 29, 16, 0, 0, 0, 102, 127, 82, 89,
-     112, 71, 76, 98, 61, 61, 82, 49, 47, 66, 37, 31, 50, 23, 11, 29, 4, 0, 0, 0,
-     105, 127, 66, 92, 112, 56, 78, 97, 47, 63, 82, 37, 48, 66, 25, 32, 50, 11,
-     10, 29, 0, 0, 0, 0, 72, 114, 181, 63, 100, 160, 54, 87, 140, 44, 72, 119,
-     32, 57, 99, 18, 39, 78, 0, 18, 52, 0, 0, 11, 83, 113, 163, 73, 100, 144, 62,
-     86, 126, 50, 71, 107, 38, 57, 88, 24, 40, 68, 3, 19, 44, 0, 0, 3, 89, 113,
-     147, 78, 99, 129, 67, 86, 113, 55, 71, 95, 42, 57, 78, 27, 40, 60, 8, 19,
-     37, 0, 0, 0, 95, 112, 129, 83, 98, 114, 71, 85, 99, 58, 71, 83, 45, 56, 67,
-     30, 40, 50, 11, 20, 29, 0, 0, 0, 99, 111, 113, 86, 98, 99, 74, 85, 86, 60,
-     70, 72, 47, 56, 57, 31, 40, 41, 12, 20, 21, 0, 0, 0, 103, 111, 96, 90, 97,
-     84, 77, 84, 72, 63, 70, 59, 49, 56, 46, 33, 40, 31, 13, 21, 12, 0, 0, 0,
-     106, 110, 78, 93, 97, 67, 79, 84, 57, 64, 70, 46, 50, 56, 34, 34, 40, 19,
-     13, 21, 2, 0, 0, 0, 108, 110, 63, 95, 97, 53, 81, 84, 44, 66, 69, 34, 51,
-     56, 22, 35, 40, 7, 13, 21, 0, 0, 0, 0, 85, 94, 168, 74, 82, 149, 64, 70,
-     130, 53, 57, 110, 41, 43, 91, 27, 26, 71, 5, 5, 47, 0, 0, 4, 92, 94, 151,
-     81, 82, 134, 70, 70, 117, 57, 57, 99, 45, 44, 81, 30, 27, 62, 10, 7, 39, 0,
-     0, 0, 97, 94, 136, 85, 82, 120, 73, 70, 105, 60, 57, 88, 47, 44, 72, 32, 28,
-     54, 13, 8, 32, 0, 0, 0, 101, 94, 121, 88, 82, 106, 76, 70, 92, 62, 57, 77,
-     49, 44, 62, 34, 28, 45, 14, 9, 25, 0, 0, 0, 104, 93, 106, 91, 81, 93, 78,
-     70, 80, 64, 57, 66, 50, 44, 52, 35, 29, 37, 14, 10, 17, 0, 0, 0, 106, 93,
-     90, 93, 81, 78, 80, 69, 67, 66, 57, 55, 52, 44, 42, 36, 29, 27, 15, 11, 8,
-     0, 0, 0, 109, 92, 74, 96, 81, 63, 82, 69, 53, 67, 57, 42, 53, 44, 30, 36,
-     29, 16, 15, 11, 1, 0, 0, 0, 111, 92, 60, 97, 80, 50, 83, 69, 41, 68, 57, 31,
-     53, 44, 20, 37, 30, 5, 15, 11, 0, 0, 0, 0, 94, 73, 155, 82, 63, 137, 72, 52,
-     120, 59, 40, 102, 47, 26, 84, 32, 8, 65, 9, 0, 42, 0, 0, 0, 99, 73, 140, 87,
-     63, 124, 76, 52, 108, 62, 40, 91, 49, 27, 75, 34, 11, 57, 12, 0, 34, 0, 0,
-     0, 103, 73, 126, 90, 63, 111, 78, 53, 97, 64, 41, 81, 51, 28, 66, 35, 13,
-     49, 13, 0, 27, 0, 0, 0, 105, 73, 112, 92, 63, 98, 80, 53, 85, 66, 41, 71,
-     52, 29, 57, 36, 14, 41, 15, 0, 20, 0, 0, 0, 107, 73, 99, 94, 63, 86, 81, 53,
-     74, 67, 41, 61, 53, 29, 48, 37, 15, 32, 16, 0, 13, 0, 0, 0, 110, 73, 85, 96,
-     63, 73, 83, 53, 62, 68, 42, 50, 54, 30, 38, 38, 16, 23, 16, 1, 5, 0, 0, 0,
-     112, 73, 69, 98, 63, 59, 84, 53, 49, 69, 42, 38, 55, 30, 27, 38, 16, 12, 17,
-     1, 0, 0, 0, 0, 113, 73, 57, 99, 63, 47, 85, 53, 38, 70, 42, 28, 55, 30, 17,
-     38, 17, 3, 16, 2, 0, 0, 0, 0, 101, 47, 144, 88, 38, 127, 77, 27, 111, 64,
-     14, 94, 51, 0, 77, 35, 0, 59, 9, 0, 36, 0, 0, 0, 105, 47, 129, 92, 38, 114,
-     80, 28, 99, 66, 16, 83, 53, 0, 68, 37, 0, 51, 13, 0, 29, 0, 0, 0, 107, 48,
-     117, 94, 39, 103, 81, 29, 89, 67, 18, 74, 54, 2, 60, 38, 0, 44, 15, 0, 23,
-     0, 0, 0, 109, 49, 104, 95, 40, 91, 82, 31, 79, 68, 19, 65, 54, 5, 51, 39, 0,
-     36, 17, 0, 16, 0, 0, 0, 110, 50, 92, 97, 40, 80, 84, 31, 68, 69, 20, 56, 55,
-     7, 43, 39, 0, 28, 17, 0, 9, 0, 0, 0, 112, 50, 79, 98, 41, 68, 85, 32, 57,
-     70, 21, 46, 56, 8, 34, 40, 0, 20, 18, 0, 3, 0, 0, 0, 113, 50, 65, 100, 41,
-     55, 86, 33, 46, 71, 22, 35, 56, 10, 23, 40, 0, 8, 17, 0, 0, 0, 0, 0, 115,
-     50, 54, 101, 41, 44, 87, 33, 36, 71, 23, 25, 56, 11, 14, 40, 0, 1, 16, 0, 0,
-     0, 0, 0, 0, 182, 240, 0, 161, 212, 0, 141, 185, 0, 120, 158, 0, 99, 132, 0,
-     78, 106, 0, 53, 75, 0, 12, 35, 0, 180, 214, 0, 159, 189, 0, 140, 166, 0,
-     119, 141, 0, 99, 118, 0, 77, 94, 0, 53, 66, 0, 11, 28, 0, 179, 192, 0, 158,
-     169, 0, 138, 149, 0, 118, 126, 0, 98, 105, 0, 77, 83, 0, 52, 57, 0, 10, 21,
-     0, 177, 168, 0, 156, 149, 0, 137, 130, 0, 116, 110, 0, 97, 91, 0, 76, 71, 0,
-     52, 48, 0, 9, 12, 0, 175, 146, 0, 155, 129, 0, 136, 113, 0, 115, 96, 0, 96,
-     79, 0, 75, 60, 0, 51, 39, 0, 9, 3, 0, 174, 123, 0, 154, 109, 0, 135, 95, 0,
-     115, 80, 0, 95, 65, 0, 75, 49, 0, 51, 28, 0, 8, 0, 0, 173, 98, 0, 153, 87,
-     0, 134, 76, 0, 114, 63, 0, 95, 50, 0, 74, 35, 0, 51, 17, 0, 8, 0, 0, 172,
-     78, 0, 152, 70, 0, 134, 60, 0, 114, 49, 0, 94, 38, 0, 74, 24, 0, 51, 5, 0,
-     8, 0, 0, 163, 224, 0, 144, 198, 0, 126, 173, 0, 107, 148, 0, 88, 123, 0, 68,
-     98, 0, 44, 69, 0, 1, 29, 0, 162, 200, 0, 143, 177, 0, 125, 155, 0, 106, 132,
-     0, 88, 110, 0, 68, 87, 0, 44, 60, 0, 1, 22, 0, 160, 180, 0, 142, 159, 0,
-     124, 139, 0, 105, 118, 0, 87, 98, 0, 67, 77, 0, 44, 52, 0, 0, 15, 0, 159,
-     158, 0, 140, 139, 0, 123, 122, 0, 104, 103, 0, 86, 85, 0, 67, 66, 0, 43, 43,
-     0, 0, 5, 0, 157, 138, 0, 139, 121, 0, 122, 106, 0, 103, 89, 0, 85, 73, 0,
-     66, 56, 0, 43, 34, 0, 0, 0, 0, 156, 116, 0, 138, 102, 0, 121, 89, 0, 103,
-     75, 0, 85, 60, 0, 66, 44, 0, 43, 24, 0, 0, 0, 6, 155, 94, 2, 137, 82, 0,
-     120, 71, 0, 102, 59, 0, 84, 46, 0, 65, 32, 0, 43, 13, 0, 0, 0, 30, 155, 75,
-     23, 137, 66, 11, 120, 57, 0, 102, 46, 0, 84, 35, 0, 65, 20, 0, 43, 2, 0, 0,
-     0, 0, 145, 209, 0, 129, 185, 0, 112, 162, 0, 95, 138, 0, 77, 115, 0, 59, 91,
-     0, 35, 64, 0, 1, 24, 0, 144, 188, 0, 128, 166, 0, 112, 145, 0, 94, 124, 0,
-     77, 103, 0, 58, 81, 0, 35, 55, 0, 0, 16, 0, 143, 168, 0, 127, 149, 0, 111,
-     130, 0, 93, 111, 0, 77, 92, 0, 58, 71, 0, 35, 47, 0, 0, 8, 0, 142, 148, 0,
-     126, 131, 0, 110, 114, 0, 93, 97, 0, 76, 79, 0, 58, 61, 0, 35, 38, 0, 0, 1,
-     0, 141, 130, 0, 125, 114, 0, 109, 100, 0, 92, 84, 0, 75, 68, 0, 58, 51, 0,
-     35, 30, 0, 0, 0, 27, 140, 110, 22, 124, 97, 12, 108, 84, 0, 91, 70, 0, 75,
-     56, 0, 57, 40, 0, 35, 21, 0, 0, 0, 43, 139, 89, 36, 123, 78, 26, 108, 67,
-     12, 91, 55, 0, 74, 43, 0, 57, 28, 0, 35, 9, 0, 0, 0, 51, 139, 72, 43, 123,
-     63, 33, 107, 53, 20, 90, 43, 3, 74, 31, 0, 57, 18, 0, 35, 1, 0, 0, 0, 0,
-     127, 194, 0, 112, 172, 0, 98, 151, 0, 81, 128, 0, 66, 107, 0, 48, 84, 0, 26,
-     58, 0, 0, 18, 0, 126, 174, 0, 111, 154, 0, 97, 135, 0, 81, 115, 0, 65, 95,
-     0, 48, 74, 0, 26, 50, 0, 0, 9, 0, 125, 157, 0, 111, 139, 0, 96, 121, 0, 81,
-     103, 0, 65, 85, 0, 48, 65, 0, 27, 42, 0, 0, 2, 20, 125, 139, 17, 110, 122,
-     9, 96, 107, 0, 80, 90, 0, 65, 73, 0, 48, 56, 0, 27, 34, 0, 0, 0, 39, 124,
-     122, 33, 109, 107, 25, 95, 93, 13, 80, 78, 0, 65, 63, 0, 48, 46, 0, 27, 26,
-     0, 0, 0, 51, 123, 103, 43, 108, 90, 34, 94, 78, 23, 79, 65, 8, 64, 51, 0,
-     48, 36, 0, 27, 17, 0, 0, 0, 59, 122, 84, 51, 108, 73, 41, 94, 63, 29, 79,
-     51, 15, 64, 39, 0, 47, 24, 0, 27, 6, 0, 0, 0, 64, 122, 69, 55, 107, 59, 45,
-     94, 50, 32, 78, 39, 19, 64, 28, 0, 47, 14, 0, 27, 0, 0, 0, 0, 0, 110, 181,
-     0, 97, 160, 0, 83, 140, 0, 69, 119, 0, 54, 99, 0, 37, 78, 0, 16, 53, 0, 0,
-     12, 7, 109, 163, 8, 96, 144, 3, 83, 126, 0, 69, 107, 0, 54, 88, 0, 38, 68,
-     0, 17, 45, 0, 0, 3, 34, 109, 147, 30, 96, 129, 23, 83, 113, 13, 69, 95, 0,
-     54, 78, 0, 38, 60, 0, 18, 37, 0, 0, 0, 48, 108, 130, 41, 95, 114, 33, 82,
-     99, 23, 68, 84, 10, 54, 68, 0, 38, 51, 0, 18, 29, 0, 0, 0, 56, 108, 114, 49,
-     94, 100, 40, 82, 87, 29, 68, 72, 16, 54, 58, 0, 38, 42, 0, 18, 22, 0, 0, 0,
-     63, 107, 97, 55, 94, 85, 45, 81, 73, 34, 68, 60, 21, 54, 47, 5, 38, 32, 0,
-     18, 13, 0, 0, 0, 68, 106, 80, 59, 93, 69, 49, 81, 59, 37, 67, 47, 25, 54,
-     35, 9, 38, 21, 0, 18, 4, 0, 0, 0, 72, 106, 66, 63, 93, 56, 52, 81, 47, 40,
-     67, 36, 27, 53, 25, 11, 38, 11, 0, 18, 0, 0, 0, 0, 28, 92, 168, 24, 80, 149,
-     19, 68, 130, 11, 55, 111, 0, 41, 92, 0, 25, 71, 0, 6, 47, 0, 0, 5, 46, 92,
-     151, 40, 80, 134, 33, 68, 117, 24, 55, 99, 12, 42, 81, 0, 26, 63, 0, 7, 40,
-     0, 0, 0, 55, 91, 137, 48, 80, 121, 40, 68, 105, 30, 55, 89, 18, 42, 72, 2,
-     27, 55, 0, 8, 32, 0, 0, 0, 62, 91, 121, 54, 79, 107, 45, 68, 93, 34, 55, 77,
-     23, 42, 62, 7, 27, 46, 0, 8, 25, 0, 0, 0, 67, 91, 107, 58, 79, 93, 49, 68,
-     81, 38, 55, 67, 26, 42, 53, 12, 27, 37, 0, 8, 18, 0, 0, 0, 72, 90, 91, 62,
-     79, 79, 52, 67, 68, 41, 55, 56, 29, 42, 43, 15, 28, 28, 1, 9, 9, 0, 0, 0,
-     76, 90, 75, 66, 78, 65, 56, 67, 55, 43, 55, 44, 31, 42, 32, 17, 28, 18, 2,
-     9, 2, 0, 0, 0, 78, 90, 62, 68, 78, 52, 58, 67, 43, 45, 55, 33, 32, 42, 22,
-     19, 28, 7, 2, 9, 0, 0, 0, 0, 53, 72, 156, 46, 62, 138, 39, 51, 121, 30, 39,
-     102, 20, 25, 84, 2, 9, 65, 0, 0, 42, 0, 0, 0, 62, 72, 140, 55, 62, 124, 46,
-     52, 108, 36, 40, 91, 25, 27, 75, 9, 11, 57, 0, 0, 34, 0, 0, 0, 68, 72, 127,
-     59, 62, 112, 50, 52, 97, 39, 40, 82, 28, 27, 66, 13, 12, 49, 0, 0, 28, 0, 0,
-     0, 72, 73, 113, 63, 62, 99, 53, 52, 86, 42, 40, 71, 30, 28, 57, 17, 13, 41,
-     0, 0, 21, 0, 0, 0, 76, 72, 100, 66, 62, 87, 56, 52, 75, 44, 41, 62, 32, 29,
-     48, 19, 14, 33, 3, 0, 13, 0, 0, 0, 79, 72, 86, 69, 62, 74, 58, 52, 63, 46,
-     41, 51, 34, 29, 39, 21, 15, 24, 4, 1, 6, 0, 0, 0, 81, 72, 71, 71, 62, 61,
-     60, 52, 51, 48, 41, 40, 35, 29, 28, 22, 15, 13, 5, 1, 0, 0, 0, 0, 83, 72,
-     59, 73, 62, 49, 62, 52, 41, 49, 41, 31, 36, 30, 20, 22, 16, 5, 4, 2, 0, 0,
-     0, 0, 67, 49, 144, 59, 40, 128, 50, 30, 112, 40, 18, 95, 29, 2, 78, 13, 0,
-     60, 0, 0, 37, 0, 0, 0, 73, 50, 130, 64, 40, 115, 55, 31, 100, 44, 19, 84,
-     32, 4, 69, 18, 0, 52, 0, 0, 30, 0, 0, 0, 76, 50, 118, 67, 41, 104, 57, 32,
-     90, 46, 20, 75, 34, 7, 61, 20, 0, 45, 0, 0, 24, 0, 0, 0, 79, 51, 105, 69,
-     42, 92, 59, 33, 80, 47, 21, 66, 35, 9, 52, 22, 0, 37, 1, 0, 16, 0, 0, 0, 81,
-     52, 93, 71, 42, 81, 61, 33, 70, 49, 22, 57, 36, 11, 44, 23, 0, 29, 2, 0, 9,
-     0, 0, 0, 83, 52, 80, 73, 43, 69, 62, 34, 59, 50, 23, 47, 37, 12, 35, 23, 0,
-     21, 3, 0, 3, 0, 0, 0, 85, 52, 67, 75, 43, 57, 64, 34, 47, 51, 24, 36, 38,
-     13, 25, 24, 0, 10, 3, 0, 0, 0, 0, 0, 87, 52, 56, 76, 43, 46, 65, 34, 37, 52,
-     24, 27, 39, 14, 16, 24, 0, 2, 2, 0, 0, 0, 0, 0, 0, 174, 238, 0, 154, 210, 0,
-     135, 184, 0, 115, 157, 0, 95, 132, 0, 75, 105, 0, 50, 75, 0, 6, 35, 0, 172,
-     213, 0, 153, 188, 0, 134, 165, 0, 114, 141, 0, 94, 118, 0, 74, 93, 0, 50,
-     66, 0, 5, 28, 0, 171, 191, 0, 151, 169, 0, 133, 148, 0, 113, 126, 0, 94,
-     105, 0, 73, 83, 0, 50, 57, 0, 5, 21, 0, 169, 168, 0, 150, 148, 0, 131, 130,
-     0, 112, 110, 0, 93, 92, 0, 73, 71, 0, 49, 48, 0, 5, 13, 0, 167, 146, 0, 148,
-     130, 0, 130, 113, 0, 111, 96, 0, 92, 79, 0, 72, 61, 0, 49, 39, 0, 4, 3, 0,
-     166, 124, 0, 147, 110, 0, 129, 96, 0, 110, 81, 0, 92, 66, 0, 72, 49, 0, 49,
-     29, 0, 4, 0, 0, 165, 100, 0, 146, 89, 0, 129, 78, 0, 110, 65, 0, 91, 52, 0,
-     72, 37, 0, 49, 18, 0, 4, 0, 0, 164, 82, 0, 146, 73, 0, 128, 64, 0, 109, 52,
-     0, 91, 41, 0, 72, 26, 0, 49, 8, 0, 4, 0, 0, 157, 223, 0, 138, 197, 0, 121,
-     172, 0, 102, 147, 0, 84, 123, 0, 65, 98, 0, 41, 69, 0, 1, 30, 0, 155, 199,
-     0, 137, 176, 0, 120, 155, 0, 102, 132, 0, 84, 110, 0, 65, 87, 0, 41, 60, 0,
-     1, 22, 0, 154, 179, 0, 136, 158, 0, 119, 139, 0, 101, 118, 0, 83, 98, 0, 64,
-     77, 0, 41, 52, 0, 0, 15, 0, 152, 158, 0, 135, 139, 0, 118, 122, 0, 100, 103,
-     0, 83, 85, 0, 64, 66, 0, 41, 43, 0, 0, 6, 0, 151, 138, 0, 133, 122, 0, 117,
-     106, 0, 99, 90, 0, 82, 74, 0, 64, 56, 0, 41, 35, 0, 0, 0, 0, 150, 117, 0,
-     133, 103, 0, 116, 90, 0, 99, 76, 0, 82, 61, 0, 63, 45, 0, 41, 25, 0, 0, 0,
-     0, 149, 95, 0, 132, 84, 0, 116, 73, 0, 98, 61, 0, 81, 48, 0, 63, 33, 0, 41,
-     15, 0, 0, 0, 0, 148, 78, 0, 131, 69, 0, 115, 59, 0, 98, 49, 0, 81, 37, 0,
-     63, 23, 0, 40, 4, 0, 0, 0, 0, 140, 208, 0, 124, 184, 0, 108, 161, 0, 91,
-     137, 0, 74, 115, 0, 56, 91, 0, 33, 64, 0, 1, 24, 0, 139, 187, 0, 123, 165,
-     0, 107, 145, 0, 90, 123, 0, 74, 102, 0, 56, 80, 0, 33, 55, 0, 0, 17, 0, 138,
-     168, 0, 122, 149, 0, 106, 130, 0, 90, 110, 0, 73, 91, 0, 56, 71, 0, 33, 47,
-     0, 0, 8, 0, 136, 148, 0, 121, 131, 0, 105, 115, 0, 89, 97, 0, 73, 80, 0, 55,
-     61, 0, 33, 39, 0, 0, 1, 0, 135, 130, 0, 120, 115, 0, 105, 100, 0, 88, 84, 0,
-     72, 69, 0, 55, 52, 0, 33, 30, 0, 0, 0, 0, 135, 111, 0, 119, 98, 0, 104, 85,
-     0, 88, 71, 0, 72, 57, 0, 55, 41, 0, 33, 22, 0, 0, 0, 0, 134, 91, 0, 118, 80,
-     0, 103, 69, 0, 87, 57, 0, 72, 44, 0, 54, 30, 0, 33, 11, 0, 0, 0, 0, 133, 75,
-     0, 118, 65, 0, 103, 56, 0, 87, 45, 0, 71, 34, 0, 54, 20, 0, 33, 2, 0, 0, 0,
-     0, 123, 194, 0, 108, 171, 0, 94, 150, 0, 78, 128, 0, 63, 106, 0, 46, 84, 0,
-     24, 58, 0, 0, 19, 0, 122, 174, 0, 107, 154, 0, 93, 135, 0, 78, 114, 0, 63,
-     95, 0, 46, 74, 0, 25, 50, 0, 0, 10, 0, 121, 157, 0, 107, 139, 0, 93, 121, 0,
-     78, 103, 0, 63, 85, 0, 46, 65, 0, 25, 42, 0, 0, 2, 0, 120, 139, 0, 106, 122,
-     0, 92, 107, 0, 77, 90, 0, 62, 74, 0, 46, 56, 0, 25, 34, 0, 0, 0, 0, 119,
-     122, 0, 105, 107, 0, 91, 93, 0, 77, 78, 0, 62, 63, 0, 45, 47, 0, 25, 26, 0,
-     0, 0, 0, 119, 104, 0, 104, 91, 0, 91, 79, 0, 76, 66, 0, 62, 52, 0, 45, 37,
-     0, 25, 18, 0, 0, 0, 0, 118, 86, 0, 104, 75, 0, 90, 64, 0, 76, 52, 0, 61, 40,
-     0, 45, 26, 0, 25, 7, 0, 0, 0, 0, 118, 71, 0, 104, 61, 0, 90, 52, 0, 75, 42,
-     0, 61, 30, 0, 45, 17, 0, 24, 1, 0, 0, 0, 0, 107, 181, 0, 94, 160, 0, 81,
-     140, 0, 66, 119, 0, 52, 99, 0, 35, 78, 0, 15, 53, 0, 0, 13, 0, 106, 163, 0,
-     93, 144, 0, 80, 126, 0, 66, 107, 0, 52, 88, 0, 36, 68, 0, 15, 45, 0, 0, 4,
-     0, 106, 147, 0, 93, 130, 0, 80, 113, 0, 66, 96, 0, 52, 79, 0, 36, 60, 0, 16,
-     37, 0, 0, 0, 0, 105, 130, 0, 92, 115, 0, 79, 100, 0, 66, 84, 0, 52, 68, 0,
-     36, 51, 0, 16, 30, 0, 0, 0, 0, 104, 115, 0, 91, 101, 0, 79, 87, 0, 65, 73,
-     0, 52, 59, 0, 36, 43, 0, 16, 22, 0, 0, 0, 0, 104, 98, 0, 91, 86, 0, 79, 74,
-     0, 65, 61, 0, 52, 48, 0, 36, 33, 0, 16, 14, 0, 0, 0, 0, 103, 81, 0, 90, 70,
-     0, 78, 60, 0, 65, 49, 0, 52, 37, 0, 36, 22, 0, 16, 5, 0, 0, 0, 0, 103, 68,
-     0, 90, 58, 0, 78, 49, 0, 65, 38, 0, 51, 27, 0, 36, 13, 0, 16, 0, 0, 0, 0, 0,
-     90, 168, 0, 78, 149, 0, 67, 130, 0, 54, 111, 0, 40, 92, 0, 24, 72, 0, 6, 47,
-     0, 0, 6, 0, 90, 152, 0, 78, 134, 0, 67, 117, 0, 54, 99, 0, 40, 82, 0, 25,
-     63, 0, 6, 40, 0, 0, 0, 0, 89, 137, 0, 78, 121, 0, 66, 106, 0, 54, 89, 0, 41,
-     73, 0, 26, 55, 0, 7, 33, 0, 0, 0, 0, 89, 122, 0, 77, 107, 0, 66, 93, 0, 54,
-     78, 0, 41, 63, 0, 26, 46, 0, 7, 25, 0, 0, 0, 0, 89, 108, 0, 77, 94, 0, 66,
-     81, 0, 53, 68, 0, 41, 54, 0, 26, 38, 0, 8, 18, 0, 0, 0, 7, 88, 92, 4, 77,
-     80, 0, 66, 69, 0, 53, 57, 0, 41, 44, 0, 27, 29, 0, 8, 10, 0, 0, 0, 23, 88,
-     77, 19, 76, 66, 11, 65, 56, 0, 53, 45, 0, 41, 33, 0, 27, 19, 0, 8, 3, 0, 0,
-     0, 30, 88, 64, 26, 76, 54, 18, 65, 45, 4, 53, 35, 0, 41, 24, 0, 27, 9, 0, 8,
-     0, 0, 0, 0, 0, 72, 156, 0, 62, 138, 0, 51, 121, 0, 39, 103, 0, 26, 85, 0, 9,
-     66, 0, 0, 42, 0, 0, 0, 0, 72, 141, 0, 62, 125, 0, 51, 109, 0, 39, 92, 0, 27,
-     75, 0, 11, 57, 0, 0, 35, 0, 0, 0, 0, 72, 128, 0, 62, 113, 0, 51, 98, 0, 40,
-     82, 0, 27, 67, 0, 12, 50, 0, 1, 28, 0, 0, 0, 17, 72, 114, 13, 62, 100, 6,
-     51, 87, 0, 40, 72, 0, 28, 58, 0, 13, 42, 0, 1, 21, 0, 0, 0, 28, 72, 101, 23,
-     61, 88, 16, 51, 76, 4, 40, 62, 0, 28, 49, 0, 14, 34, 0, 1, 14, 0, 0, 0, 36,
-     72, 87, 30, 61, 75, 23, 51, 64, 12, 40, 52, 1, 28, 40, 0, 14, 25, 0, 1, 7,
-     0, 0, 0, 41, 71, 72, 35, 61, 62, 28, 51, 52, 17, 40, 41, 5, 28, 29, 0, 14,
-     15, 0, 0, 0, 0, 0, 0, 45, 71, 60, 39, 61, 51, 31, 51, 42, 20, 40, 32, 8, 29,
-     21, 0, 15, 6, 0, 0, 0, 0, 0, 0, 0, 51, 145, 0, 42, 129, 0, 33, 113, 0, 20,
-     96, 0, 5, 79, 0, 0, 60, 0, 0, 37, 0, 0, 0, 24, 52, 131, 21, 42, 116, 15, 33,
-     101, 5, 21, 85, 0, 7, 69, 0, 0, 52, 0, 1, 30, 0, 0, 0, 34, 52, 119, 29, 43,
-     105, 22, 33, 91, 12, 22, 76, 0, 8, 61, 0, 0, 45, 0, 1, 24, 0, 0, 0, 40, 53,
-     106, 34, 43, 93, 27, 34, 80, 17, 23, 67, 5, 9, 53, 0, 0, 37, 0, 0, 16, 0, 0,
-     0, 45, 53, 94, 38, 44, 82, 31, 34, 70, 20, 24, 58, 10, 11, 45, 0, 0, 29, 0,
-     0, 9, 0, 0, 0, 48, 53, 81, 42, 44, 70, 34, 35, 60, 24, 24, 48, 13, 12, 36,
-     0, 0, 21, 0, 0, 3, 0, 0, 0, 51, 53, 68, 45, 44, 58, 37, 35, 48, 26, 25, 37,
-     15, 13, 26, 2, 1, 11, 0, 0, 0, 0, 0, 0, 54, 54, 57, 47, 44, 47, 39, 35, 39,
-     28, 25, 29, 17, 13, 17, 4, 1, 3, 0, 0, 0, 0, 0, 0]);
- 
-   function convertToRgb(src, srcOffset, srcScale, dest, destOffset) {
-     // using lut as in spline interpolation (see function.js)
-     var cubeVertices = 16; // 1 << number of colors
-     var cubeN = new Float32Array(cubeVertices);
-     var cubeVertex = new Uint32Array(cubeVertices);
-     for (var j = 0; j < cubeVertices; j++)
-       cubeN[j] = 1;
- 
-     var k = 3, pos = 1;
-     var lutDomain = 7, lutStep = 8;
-     for (var i = 3; i >= 0; i--) {
-       var e = src[srcOffset + i] * srcScale * lutDomain;
- 
-       var e0 = e < lutDomain ? 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 *= lutStep;
-       pos <<= 1;
-     }
-     var y0 = 0, y1 = 0, y2 = 0;
-     for (var i = 0; i < cubeVertices; i++)
-       y0 += lut[cubeVertex[i]] * cubeN[i];
-     for (var i = 0; i < cubeVertices; i++)
-       y1 += lut[cubeVertex[i] + 1] * cubeN[i];
-     for (var i = 0; i < cubeVertices; i++)
-       y2 += lut[cubeVertex[i] + 2] * cubeN[i];
-     dest[destOffset] = y0 > 255 ? 255 : y0;
-     dest[destOffset + 1] = y1 > 255 ? 255 : y1;
-     dest[destOffset + 2] = y2 > 255 ? 255 : y2;
-   }
- 
-   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);
-     }
-   };
- 
-   return DeviceCmykCS;
- })();
- 
- //
- // 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 convertToRgb(cs, src, srcOffset, dest, destOffset) {
-     // Ls,as,bs <---> L*,a*,b* in the spec
-     var Ls = src[srcOffset];
-     var as = src[srcOffset + 1];
-     var bs = src[srcOffset + 2];
- 
-     // 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,255] range
-     dest[destOffset] = r < 0 ? 0 : r > 1 ? 255 : r * 255;
-     dest[destOffset + 1] = g < 0 ? 0 : g > 1 ? 255 : g * 255;
-     dest[destOffset + 2] = b < 0 ? 0 : b > 1 ? 255 : b * 255;
-   }
- 
-   LabCS.prototype = {
-     getRgb: function LabCS_getRgb(src, srcOffset) {
-       var rgb = new Uint8Array(3);
-       convertToRgb(this, src, srcOffset, rgb, 0);
-       return rgb;
-     },
-     getRgbItem: function LabCS_getRgbItem(src, srcOffset, dest, destOffset) {
-       convertToRgb(this, src, srcOffset, dest, destOffset);
-     },
-     getOutputLength: function LabCS_getOutputLength(inputLength) {
-       return inputLength;
-     },
-     isPassthrough: ColorSpace.prototype.isPassthrough,
-     isDefaultDecode: function LabCS_isDefaultDecode(decodeMap) {
-       // From Table 90 in Adobe's:
-       // "Document management - Portable document format", 1st ed, 2008
-       if (decodeMap[0] === 0 && decodeMap[1] === 100 &&
-           decodeMap[2] === this.amin && decodeMap[3] === this.amax &&
-           decodeMap[4] === this.bmin && decodeMap[5] === this.bmax)
-         return true;
-       else
-         return false;
-     }
-   };
-   return LabCS;
- })();
- 
- 
- var ARCFourCipher = (function ARCFourCipherClosure() {
-   function ARCFourCipher(key) {
-     this.a = 0;
-     this.b = 0;
-     var s = new Uint8Array(256);
-     var i, j = 0, tmp, keyLength = key.length;
-     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;
-       s[i] = s[j];
-       s[j] = tmp;
-     }
-     this.s = s;
-   }
- 
-   ARCFourCipher.prototype = {
-     encryptBlock: function ARCFourCipher_encryptBlock(data) {
-       var i, n = data.length, tmp, tmp2;
-       var a = this.a, b = this.b, s = this.s;
-       var output = new Uint8Array(n);
-       for (i = 0; i < n; ++i) {
-         a = (a + 1) & 0xFF;
-         tmp = s[a];
-         b = (b + tmp) & 0xFF;
-         tmp2 = s[b];
-         s[a] = tmp2;
-         s[b] = tmp;
-         output[i] = data[i] ^ s[(tmp + tmp2) & 0xFF];
-       }
-       this.a = a;
-       this.b = b;
-       return output;
-     }
-   };
-   ARCFourCipher.prototype.decryptBlock = ARCFourCipher.prototype.encryptBlock;
- 
-   return ARCFourCipher;
- })();
- 
- var calculateMD5 = (function calculateMD5Closure() {
-   var r = new Uint8Array([
-     7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
-     5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
-     4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
-     6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21]);
- 
-   var k = new Int32Array([
-     -680876936, -389564586, 606105819, -1044525330, -176418897, 1200080426,
-     -1473231341, -45705983, 1770035416, -1958414417, -42063, -1990404162,
-     1804603682, -40341101, -1502002290, 1236535329, -165796510, -1069501632,
-     643717713, -373897302, -701558691, 38016083, -660478335, -405537848,
-     568446438, -1019803690, -187363961, 1163531501, -1444681467, -51403784,
-     1735328473, -1926607734, -378558, -2022574463, 1839030562, -35309556,
-     -1530992060, 1272893353, -155497632, -1094730640, 681279174, -358537222,
-     -722521979, 76029189, -640364487, -421815835, 530742520, -995338651,
-     -198630844, 1126891415, -1416354905, -57434055, 1700485571, -1894986606,
-     -1051523, -2054922799, 1873313359, -30611744, -1560198380, 1309151649,
-     -145523070, -1120210379, 718787259, -343485551]);
- 
-   function hash(data, offset, length) {
-     var h0 = 1732584193, h1 = -271733879, h2 = -1732584194, h3 = 271733878;
-     // pre-processing
-     var paddedLength = (length + 72) & ~63; // data + 9 extra bytes
-     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++] = (length << 3) & 0xFF;
-     padded[i++] = (length >> 5) & 0xFF;
-     padded[i++] = (length >> 13) & 0xFF;
-     padded[i++] = (length >> 21) & 0xFF;
-     padded[i++] = (length >>> 29) & 0xFF;
-     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));
-       }
-       var a = h0, b = h1, c = h2, d = h3, f, g;
-       for (j = 0; j < 64; ++j) {
-         if (j < 16) {
-           f = (b & c) | ((~b) & d);
-           g = j;
-         } else if (j < 32) {
-           f = (d & b) | ((~d) & c);
-           g = (5 * j + 1) & 15;
-         } else if (j < 48) {
-           f = b ^ c ^ d;
-           g = (3 * j + 5) & 15;
-         } else {
-           f = c ^ (b | (~d));
-           g = (7 * j) & 15;
-         }
-         var tmp = d, rotateArg = (a + f + k[j] + w[g]) | 0, rotate = r[j];
-         d = c;
-         c = b;
-         b = (b + ((rotateArg << rotate) | (rotateArg >>> (32 - rotate)))) | 0;
-         a = tmp;
-       }
-       h0 = (h0 + a) | 0;
-       h1 = (h1 + b) | 0;
-       h2 = (h2 + c) | 0;
-       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
-     ]);
-   }
-   return hash;
- })();
- 
- var NullCipher = (function NullCipherClosure() {
-   function NullCipher() {
-   }
- 
-   NullCipher.prototype = {
-     decryptBlock: function NullCipher_decryptBlock(data) {
-       return data;
-     }
-   };
- 
-   return NullCipher;
- })();
- 
- var AES128Cipher = (function AES128CipherClosure() {
-   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 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 expandKey128(cipherKey) {
-     var b = 176, result = new Uint8Array(b);
-     result.set(cipherKey);
-     for (var j = 16, i = 1; j < b; ++i) {
-       // 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 ^ 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++;
-       }
-     }
-     return result;
-   }
- 
-   function decrypt128(input, key) {
-     var state = new Uint8Array(16);
-     state.set(input);
-     var i, j, k;
-     var t, u, v;
-     // AddRoundKey
-     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;
-       // 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 AES128Cipher(key) {
-     this.key = expandKey128(key);
-     this.buffer = new Uint8Array(16);
-     this.bufferPosition = 0;
-   }
- 
-   function decryptBlock2(data) {
-     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 = decrypt128(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([]);
-     if (result.length == 1)
-       return result[0];
-     // combining plain text blocks into one
-     var output = new Uint8Array(16 * result.length);
-     for (i = 0, j = 0, ii = result.length; i < ii; ++i, j += 16)
-       output.set(result[i], j);
-     return output;
-   }
- 
-   AES128Cipher.prototype = {
-     decryptBlock: function AES128Cipher_decryptBlock(data) {
-       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)
-         buffer[bufferLength] = data[i];
-       if (bufferLength < 16) {
-         // need more data
-         this.bufferLength = bufferLength;
-         return new Uint8Array([]);
-       }
-       this.iv = buffer;
-       this.buffer = new Uint8Array(16);
-       this.bufferLength = 0;
-       // starting decryption
-       this.decryptBlock = decryptBlock2;
-       return this.decryptBlock(data.subarray(16));
-     }
-   };
- 
-   return AES128Cipher;
- })();
- 
- var CipherTransform = (function CipherTransformClosure() {
-   function CipherTransform(stringCipherConstructor, streamCipherConstructor) {
-     this.stringCipherConstructor = stringCipherConstructor;
-     this.streamCipherConstructor = streamCipherConstructor;
-   }
-   CipherTransform.prototype = {
-     createStream: function CipherTransform_createStream(stream) {
-       var cipher = new this.streamCipherConstructor();
-       return new DecryptStream(stream,
-         function cipherTransformDecryptStream(data) {
-           return cipher.decryptBlock(data);
-         }
-       );
-     },
-     decryptString: function CipherTransform_decryptString(s) {
-       var cipher = new this.stringCipherConstructor();
-       var data = stringToBytes(s);
-       data = cipher.decryptBlock(data);
-       return bytesToString(data);
-     }
-   };
-   return CipherTransform;
- })();
- 
- var CipherTransformFactory = (function CipherTransformFactoryClosure() {
-   var defaultPasswordBytes = new Uint8Array([
-     0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41,
-     0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA, 0x01, 0x08,
-     0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80,
-     0x2F, 0x0C, 0xA9, 0xFE, 0x64, 0x53, 0x69, 0x7A]);
- 
-   function prepareKeyData(fileId, password, ownerPassword, userPassword,
-                           flags, revision, keyLength, encryptMetadata) {
-     var hashData = new Uint8Array(100), i = 0, j, n;
-     if (password) {
-       n = Math.min(32, password.length);
-       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)
-       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)
-       hashData[i++] = fileId[j];
-     if (revision >= 4 && !encryptMetadata) {
-       hashData[i++] = 0xFF;
-       hashData[i++] = 0xFF;
-       hashData[i++] = 0xFF;
-       hashData[i++] = 0xFF;
-     }
-     var hash = calculateMD5(hashData, 0, i);
-     var keyLengthInBytes = keyLength >> 3;
-     if (revision >= 3) {
-       for (j = 0; j < 50; ++j) {
-          hash = calculateMD5(hash, 0, keyLengthInBytes);
-       }
-     }
-     var encryptionKey = hash.subarray(0, keyLengthInBytes);
-     var cipher, checkData;
- 
-     if (revision >= 3) {
-       for (i = 0; i < 32; ++i)
-         hashData[i] = defaultPasswordBytes[i];
-       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));
-       n = encryptionKey.length;
-       var derivedKey = new Uint8Array(n), k;
-       for (j = 1; j <= 19; ++j) {
-         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])
-           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])
-           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)
-       hashData[i] = password[i];
-     j = 0;
-     while (i < 32) {
-       hashData[i++] = defaultPasswordBytes[j++];
-     }
-     var hash = calculateMD5(hashData, 0, i);
-     var keyLengthInBytes = keyLength >> 3;
-     if (revision >= 3) {
-       for (j = 0; j < 50; ++j) {
-          hash = calculateMD5(hash, 0, hash.length);
-       }
-     }
- 
-     var cipher, userPassword;
-     if (revision >= 3) {
-       userPassword = ownerPassword;
-       var derivedKey = new Uint8Array(keyLengthInBytes), k;
-       for (j = 19; j >= 0; j--) {
-         for (k = 0; k < keyLengthInBytes; ++k)
-           derivedKey[k] = hash[k] ^ j;
-         cipher = new ARCFourCipher(derivedKey);
-         userPassword = cipher.encryptBlock(userPassword);
-       }
-     } else {
-       cipher = new ARCFourCipher(hash.subarray(0, keyLengthInBytes));
-       userPassword = cipher.encryptBlock(ownerPassword);
-     }
-     return userPassword;
-   }
- 
-   var identityName = new Name('Identity');
- 
-   function CipherTransformFactory(dict, fileId, password) {
-     var filter = dict.get('Filter');
-     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))
-       error('unsupported encryption algorithm');
-     this.algorithm = algorithm;
-     var keyLength = dict.get('Length') || 40;
-     if (!isInt(keyLength) ||
-       keyLength < 40 || (keyLength % 8) !== 0)
-       error('invalid key length');
-     // prepare keys
-     var ownerPassword = stringToBytes(dict.get('O'));
-     var userPassword = stringToBytes(dict.get('U'));
-     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
-     this.encryptMetadata = encryptMetadata;
- 
-     var fileIdBytes = stringToBytes(fileId);
-     var passwordBytes;
-     if (password)
-       passwordBytes = stringToBytes(password);
- 
-     var encryptionKey = prepareKeyData(fileIdBytes, passwordBytes,
-                                        ownerPassword, userPassword, flags,
-                                        revision, keyLength, encryptMetadata);
-     if (!encryptionKey && !password) {
-       throw new PasswordException('No password given', 'needpassword');
-     } else if (!encryptionKey && password) {
-       // Attempting use the password as an owner password
-       var decodedPassword = decodeUserPassword(passwordBytes, ownerPassword,
-                                                revision, keyLength);
-       encryptionKey = prepareKeyData(fileIdBytes, decodedPassword,
-                                      ownerPassword, userPassword, flags,
-                                      revision, keyLength, encryptMetadata);
-     }
- 
-     if (!encryptionKey)
-       throw new PasswordException('Incorrect Password', 'incorrectpassword');
- 
-     this.encryptionKey = encryptionKey;
- 
-     if (algorithm == 4) {
-       this.cf = dict.get('CF');
-       this.stmf = dict.get('StmF') || identityName;
-       this.strf = dict.get('StrF') || identityName;
-       this.eff = dict.get('EFF') || this.strf;
-     }
-   }
- 
-   function buildObjectKey(num, gen, encryptionKey, isAes) {
-     var key = new Uint8Array(encryptionKey.length + 9), i, n;
-     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;
-     key[i++] = gen & 0xFF;
-     key[i++] = (gen >> 8) & 0xFF;
-     if (isAes) {
-       key[i++] = 0x73;
-       key[i++] = 0x41;
-       key[i++] = 0x6C;
-       key[i++] = 0x54;
-     }
-     var hash = calculateMD5(key, 0, i);
-     return hash.subarray(0, Math.min(encryptionKey.length + 5, 16));
-   }
- 
-   function buildCipherConstructor(cf, name, num, gen, key) {
-     var cryptFilter = cf.get(name.name);
-     var cfm;
-     if (cryptFilter !== null && cryptFilter !== undefined)
-       cfm = cryptFilter.get('CFM');
-     if (!cfm || cfm.name == 'None') {
-       return function cipherTransformFactoryBuildCipherConstructorNone() {
-         return new NullCipher();
-       };
-     }
-     if ('V2' == cfm.name) {
-       return function cipherTransformFactoryBuildCipherConstructorV2() {
-         return new ARCFourCipher(
-           buildObjectKey(num, gen, key, false));
-       };
-     }
-     if ('AESV2' == cfm.name) {
-       return function cipherTransformFactoryBuildCipherConstructorAESV2() {
-         return new AES128Cipher(
-           buildObjectKey(num, gen, key, true));
-       };
-     }
-     error('Unknown crypto method');
-   }
- 
-   CipherTransformFactory.prototype = {
-     createCipherTransform:
-       function CipherTransformFactory_createCipherTransform(num, gen) {
-       if (this.algorithm == 4) {
-         return new CipherTransform(
-           buildCipherConstructor(this.cf, this.stmf,
-             num, gen, this.encryptionKey),
-           buildCipherConstructor(this.cf, this.strf,
-             num, gen, this.encryptionKey));
-       }
-       // algorithms 1 and 2
-       var key = buildObjectKey(num, gen, this.encryptionKey, false);
-       var cipherConstructor = function buildCipherCipherConstructor() {
-         return new ARCFourCipher(key);
-       };
-       return new CipherTransform(cipherConstructor, cipherConstructor);
-     }
-   };
- 
-   return CipherTransformFactory;
- })();
- 
- 
- 
- var PartialEvaluator = (function PartialEvaluatorClosure() {
-   function PartialEvaluator(xref, handler, pageIndex, uniquePrefix) {
-     this.state = new EvalState();
-     this.stateStack = [];
- 
-     this.xref = xref;
-     this.handler = handler;
-     this.pageIndex = pageIndex;
-     this.uniquePrefix = uniquePrefix;
-     this.objIdCounter = 0;
-     this.fontIdCounter = 0;
-   }
- 
-   // Specifies properties for each command
-   //
-   // If variableArgs === true: [0, `numArgs`] expected
-   // If variableArgs === false: exactly `numArgs` expected
-   var OP_MAP = {
-     // Graphic state
-     w: { fnName: 'setLineWidth', numArgs: 1, variableArgs: false },
-     J: { fnName: 'setLineCap', numArgs: 1, variableArgs: false },
-     j: { fnName: 'setLineJoin', numArgs: 1, variableArgs: false },
-     M: { fnName: 'setMiterLimit', numArgs: 1, variableArgs: false },
-     d: { fnName: 'setDash', numArgs: 2, variableArgs: false },
-     ri: { fnName: 'setRenderingIntent', numArgs: 1, variableArgs: false },
-     i: { fnName: 'setFlatness', numArgs: 1, variableArgs: false },
-     gs: { fnName: 'setGState', numArgs: 1, variableArgs: false },
-     q: { fnName: 'save', numArgs: 0, variableArgs: false },
-     Q: { fnName: 'restore', numArgs: 0, variableArgs: false },
-     cm: { fnName: 'transform', numArgs: 6, variableArgs: false },
- 
-     // Path
-     m: { fnName: 'moveTo', numArgs: 2, variableArgs: false },
-     l: { fnName: 'lineTo', numArgs: 2, variableArgs: false },
-     c: { fnName: 'curveTo', numArgs: 6, variableArgs: false },
-     v: { fnName: 'curveTo2', numArgs: 4, variableArgs: false },
-     y: { fnName: 'curveTo3', numArgs: 4, variableArgs: false },
-     h: { fnName: 'closePath', numArgs: 0, variableArgs: false },
-     re: { fnName: 'rectangle', numArgs: 4, variableArgs: false },
-     S: { fnName: 'stroke', numArgs: 0, variableArgs: false },
-     s: { fnName: 'closeStroke', numArgs: 0, variableArgs: false },
-     f: { fnName: 'fill', numArgs: 0, variableArgs: false },
-     F: { fnName: 'fill', numArgs: 0, variableArgs: false },
-     'f*': { fnName: 'eoFill', numArgs: 0, variableArgs: false },
-     B: { fnName: 'fillStroke', numArgs: 0, variableArgs: false },
-     'B*': { fnName: 'eoFillStroke', numArgs: 0, variableArgs: false },
-     b: { fnName: 'closeFillStroke', numArgs: 0, variableArgs: false },
-     'b*': { fnName: 'closeEOFillStroke', numArgs: 0, variableArgs: false },
-     n: { fnName: 'endPath', numArgs: 0, variableArgs: false },
- 
-     // Clipping
-     W: { fnName: 'clip', numArgs: 0, variableArgs: false },
-     'W*': { fnName: 'eoClip', numArgs: 0, variableArgs: false },
- 
-     // Text
-     BT: { fnName: 'beginText', numArgs: 0, variableArgs: false },
-     ET: { fnName: 'endText', numArgs: 0, variableArgs: false },
-     Tc: { fnName: 'setCharSpacing', numArgs: 1, variableArgs: false },
-     Tw: { fnName: 'setWordSpacing', numArgs: 1, variableArgs: false },
-     Tz: { fnName: 'setHScale', numArgs: 1, variableArgs: false },
-     TL: { fnName: 'setLeading', numArgs: 1, variableArgs: false },
-     Tf: { fnName: 'setFont', numArgs: 2, variableArgs: false },
-     Tr: { fnName: 'setTextRenderingMode', numArgs: 1, variableArgs: false },
-     Ts: { fnName: 'setTextRise', numArgs: 1, variableArgs: false },
-     Td: { fnName: 'moveText', numArgs: 2, variableArgs: false },
-     TD: { fnName: 'setLeadingMoveText', numArgs: 2, variableArgs: false },
-     Tm: { fnName: 'setTextMatrix', numArgs: 6, variableArgs: false },
-     'T*': { fnName: 'nextLine', numArgs: 0, variableArgs: false },
-     Tj: { fnName: 'showText', numArgs: 1, variableArgs: false },
-     TJ: { fnName: 'showSpacedText', numArgs: 1, variableArgs: false },
-     '\'': { fnName: 'nextLineShowText', numArgs: 1, variableArgs: false },
-     '"': { fnName: 'nextLineSetSpacingShowText', numArgs: 3,
-       variableArgs: false },
- 
-     // Type3 fonts
-     d0: { fnName: 'setCharWidth', numArgs: 2, variableArgs: false },
-     d1: { fnName: 'setCharWidthAndBounds', numArgs: 6, variableArgs: false },
- 
-     // Color
-     CS: { fnName: 'setStrokeColorSpace', numArgs: 1, variableArgs: false },
-     cs: { fnName: 'setFillColorSpace', numArgs: 1, variableArgs: false },
-     SC: { fnName: 'setStrokeColor', numArgs: 4, variableArgs: true },
-     SCN: { fnName: 'setStrokeColorN', numArgs: 33, variableArgs: true },
-     sc: { fnName: 'setFillColor', numArgs: 4, variableArgs: true },
-     scn: { fnName: 'setFillColorN', numArgs: 33, variableArgs: true },
-     G: { fnName: 'setStrokeGray', numArgs: 1, variableArgs: false },
-     g: { fnName: 'setFillGray', numArgs: 1, variableArgs: false },
-     RG: { fnName: 'setStrokeRGBColor', numArgs: 3, variableArgs: false },
-     rg: { fnName: 'setFillRGBColor', numArgs: 3, variableArgs: false },
-     K: { fnName: 'setStrokeCMYKColor', numArgs: 4, variableArgs: false },
-     k: { fnName: 'setFillCMYKColor', numArgs: 4, variableArgs: false },
- 
-     // Shading
-     sh: { fnName: 'shadingFill', numArgs: 1, variableArgs: false },
- 
-     // Images
-     BI: { fnName: 'beginInlineImage', numArgs: 0, variableArgs: false },
-     ID: { fnName: 'beginImageData', numArgs: 0, variableArgs: false },
-     EI: { fnName: 'endInlineImage', numArgs: 0, variableArgs: false },
- 
-     // XObjects
-     Do: { fnName: 'paintXObject', numArgs: 1, variableArgs: false },
-     MP: { fnName: 'markPoint', numArgs: 1, variableArgs: false },
-     DP: { fnName: 'markPointProps', numArgs: 2, variableArgs: false },
-     BMC: { fnName: 'beginMarkedContent', numArgs: 1, variableArgs: false },
-     BDC: { fnName: 'beginMarkedContentProps', numArgs: 2, variableArgs: false },
-     EMC: { fnName: 'endMarkedContent', numArgs: 0, variableArgs: false },
- 
-     // Compatibility
-     BX: { fnName: 'beginCompat', numArgs: 0, variableArgs: false },
-     EX: { fnName: 'endCompat', numArgs: 0, variableArgs: false },
- 
-     // (reserved partial commands for the lexer)
-     BM: null,
-     BD: null,
-     'true': null,
-     fa: null,
-     fal: null,
-     fals: null,
-     'false': null,
-     nu: null,
-     nul: null,
-     'null': null
-   };
- 
-   PartialEvaluator.prototype = {
-     loadFont: function PartialEvaluator_loadFont(fontName, font, xref,
-                                                  resources, dependency) {
-       var fontRes = resources.get('Font');
- 
-       assert(fontRes, 'fontRes not available');
- 
-       ++this.fontIdCounter;
- 
-       font = xref.fetchIfRef(font) || fontRes.get(fontName);
-       if (!isDict(font)) {
-         return {
-           translated: new ErrorFont('Font ' + fontName + ' is not available'),
-           loadedName: 'g_font_' + this.uniquePrefix + this.fontIdCounter
-         };
-       }
- 
-       var loadedName = font.loadedName;
-       if (!loadedName) {
-         // keep track of each font we translated so the caller can
-         // load them asynchronously before calling display on a page
-         loadedName = 'g_font_' + this.uniquePrefix + this.fontIdCounter;
-         font.loadedName = loadedName;
- 
-         var translated;
-         try {
-           translated = this.translateFont(font, xref, resources,
-                                           dependency);
-         } catch (e) {
-           translated = new ErrorFont(e instanceof Error ? e.message : e);
-         }
-         font.translated = translated;
- 
-         var data = translated;
-         if (data.loadCharProcs) {
-           delete data.loadCharProcs;
- 
-           var charProcs = font.get('CharProcs').getAll();
-           var fontResources = font.get('Resources') || resources;
-           var charProcOperatorList = {};
-           for (var key in charProcs) {
-             var glyphStream = charProcs[key];
-             charProcOperatorList[key] =
-               this.getOperatorList(glyphStream, fontResources, dependency);
-           }
-           data.charProcOperatorList = charProcOperatorList;
-         }
-       }
-       return font;
-     },
- 
-     getOperatorList: function PartialEvaluator_getOperatorList(stream,
-                                                                resources,
-                                                                dependency,
-                                                                queue) {
- 
-       var self = this;
-       var xref = this.xref;
-       var handler = this.handler;
-       var pageIndex = this.pageIndex;
-       var uniquePrefix = this.uniquePrefix || '';
- 
-       function insertDependency(depList) {
-         fnArray.push('dependency');
-         argsArray.push(depList);
-         for (var i = 0, ii = depList.length; i < ii; i++) {
-           var dep = depList[i];
-           if (dependency.indexOf(dep) == -1) {
-             dependency.push(depList[i]);
-           }
-         }
-       }
- 
-       function handleSetFont(fontName, font) {
-         font = self.loadFont(fontName, font, xref, resources, dependency);
- 
-         var loadedName = font.loadedName;
-         if (!font.sent) {
-           var data = font.translated.exportData();
- 
-           handler.send('commonobj', [
-               loadedName,
-               'Font',
-               data
-           ]);
-           font.sent = true;
-         }
- 
-         // Ensure the font is ready before the font is set
-         // and later on used for drawing.
-         // OPTIMIZE: This should get insert to the operatorList only once per
-         // page.
-         insertDependency([loadedName]);
-         return loadedName;
-       }
- 
-       function buildFormXObject(xobj, smask) {
-         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.
-           }
-           fnArray.push('beginGroup');
-           argsArray.push([groupOptions]);
-         }
- 
-         fnArray.push('paintFormXObjectBegin');
-         argsArray.push([matrix, bbox]);
- 
-         // This adds the operatorList of the xObj to the current queue.
-         var depIdx = dependencyArray.length;
- 
-         // Pass in the current `queue` object. That means the `fnArray`
-         // and the `argsArray` in this scope is reused and new commands
-         // are added to them.
-         self.getOperatorList(xobj,
-             xobj.dict.get('Resources') || resources,
-             dependencyArray, queue);
- 
-         self.getOperatorList(xobj,
-                              xobj.dict.get('Resources') || resources,
-                              dependencyArray, queue);
- 
-         // Add the dependencies that are required to execute the
-         // operatorList.
-         insertDependency(dependencyArray.slice(depIdx));
- 
-         fnArray.push('paintFormXObjectEnd');
-         argsArray.push([]);
- 
-         if (group) {
-           fnArray.push('endGroup');
-           argsArray.push([groupOptions]);
-         }
-       }
- 
-       function buildPaintImageXObject(image, inline) {
-         var dict = image.dict;
-         var w = dict.get('Width', 'W');
-         var h = dict.get('Height', 'H');
- 
-         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;
- 
-           fn = 'paintImageMaskXObject';
-           args = [imgArray, inverseDecode, width, height];
-           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(xref, resources, image,
-                                       inline, null, null);
-           var imgData = imageObj.getImageData();
-           fn = 'paintInlineImageXObject';
-           args = [imgData];
-           return;
-         }
- 
-         // If there is no imageMask, create the PDFImage and a lot
-         // of image processing can be done here.
-         var objId = 'img_' + uniquePrefix + (++self.objIdCounter);
-         insertDependency([objId]);
-         args = [objId, w, h];
- 
-         if (!softMask && !mask && image instanceof JpegStream &&
-             image.isNativelySupported(xref, resources)) {
-           // These JPEGs don't need any more processing so we can just send it.
-           fn = 'paintJpegXObject';
-           handler.send('obj', [objId, pageIndex, 'JpegStream', image.getIR()]);
-           return;
-         }
- 
-         fn = 'paintImageXObject';
- 
-         PDFImage.buildImage(function(imageObj) {
-             var imgData = imageObj.getImageData();
-             handler.send('obj', [objId, pageIndex, 'Image', imgData]);
-           }, handler, xref, resources, image, inline);
-       }
- 
-       if (!queue)
-         queue = {};
- 
-       if (!queue.argsArray) {
-         queue.argsArray = [];
-       }
-       if (!queue.fnArray) {
-         queue.fnArray = [];
-       }
- 
-       var fnArray = queue.fnArray, argsArray = queue.argsArray;
-       var dependencyArray = dependency || [];
- 
-       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 res = resources;
-       var args = [], obj;
-       var TILING_PATTERN = 1, SHADING_PATTERN = 2;
- 
-       while (true) {
-         obj = parser.getObj();
-         if (isEOF(obj)) {
-           break;
-         }
- 
-         if (isCmd(obj)) {
-           var cmd = obj.cmd;
- 
-           // Check that the command is valid
-           var opSpec = OP_MAP[cmd];
-           if (!opSpec) {
-             warn('Unknown command "' + cmd + '"');
-             continue;
-           }
- 
-           var fn = opSpec.fnName;
- 
-           // 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');
-             }
-           } else {
-             if (args.length < opSpec.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 + ' args; skipping');
-               args = [];
-               continue;
-             } else if (args.length > opSpec.numArgs) {
-               info('Command ' + fn + ': expected ' + opSpec.numArgs +
-                   ' args, but received ' + args.length + ' args');
-             }
-           }
- 
-           // TODO figure out how to type-check vararg functions
- 
-           if ((cmd == 'SCN' || cmd == 'scn') && !args[args.length - 1].code) {
-             // compile tiling patterns
-             var patternName = args[args.length - 1];
-             // SCN/scn applies patterns along with normal colors
-             if (isName(patternName)) {
-               var pattern = patterns.get(patternName.name);
-               if (pattern) {
-                 var dict = isStream(pattern) ? pattern.dict : pattern;
-                 var typeNum = dict.get('PatternType');
- 
-                 if (typeNum == TILING_PATTERN) {
-                   // Create an IR of the pattern code.
-                   var depIdx = dependencyArray.length;
-                   var operatorList = this.getOperatorList(pattern,
-                       dict.get('Resources') || resources, dependencyArray);
- 
-                   // Add the dependencies that are required to execute the
-                   // operatorList.
-                   insertDependency(dependencyArray.slice(depIdx));
- 
-                   args = TilingPattern.getIR(operatorList, dict, args);
-                 }
-                 else if (typeNum == SHADING_PATTERN) {
-                   var shading = dict.get('Shading');
-                   var matrix = dict.get('Matrix');
-                   var pattern = Pattern.parseShading(shading, matrix, xref,
-                                                      res);
-                   args = pattern.getIR();
-                 } else {
-                   error('Unkown PatternType ' + typeNum);
-                 }
-               }
-             }
-           } else if (cmd == 'Do' && !args[0].code) {
-             // 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) {
-                 buildFormXObject(xobj);
-                 args = [];
-                 continue;
-               } else if ('Image' == type.name) {
-                 buildPaintImageXObject(xobj, false);
-               } else {
-                 error('Unhandled XObject subtype ' + type.name);
-               }
-             }
-           } else if (cmd == 'Tf') { // eagerly collect all fonts
-             args[0] = handleSetFont(args[0].name);
-           } else if (cmd == 'EI') {
-             buildPaintImageXObject(args[0], true);
-           }
- 
-           switch (fn) {
-             // Parse the ColorSpace data to a raw format.
-             case 'setFillColorSpace':
-             case 'setStrokeColorSpace':
-               args = [ColorSpace.parseToIR(args[0], xref, resources)];
-               break;
-             case 'shadingFill':
-               var shadingRes = res.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, res);
-               var patternIR = shadingFill.getIR();
-               args = [patternIR];
-               fn = 'shadingFill';
-               break;
-             case 'setGState':
-               var dictName = args[0];
-               var extGState = resources.get('ExtGState');
- 
-               if (!isDict(extGState) || !extGState.has(dictName.name))
-                 break;
- 
-               var gsState = extGState.get(dictName.name);
- 
-               // This array holds the converted/processed state data.
-               var gsStateObj = [];
- 
-               gsState.forEach(
-                 function canvasGraphicsSetGStateForEach(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':
-                     case 'BM':
-                       gsStateObj.push([key, value]);
-                       break;
-                     case 'Font':
-                       gsStateObj.push([
-                         'Font',
-                         handleSetFont(null, value[0]),
-                         value[1]
-                       ]);
-                       break;
-                     case 'SMask':
-                       // We support the default so don't trigger the TODO.
-                       if (!isName(value) || value.name != 'None')
-                         TODO('graphic state operator ' + key);
-                       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;
-                   }
-                 }
-               );
-               args = [gsStateObj];
-               break;
-           } // switch
- 
-           fnArray.push(fn);
-           argsArray.push(args);
-           args = [];
-         } else if (obj !== null && obj !== undefined) {
-           args.push(obj instanceof Dict ? obj.getAll() : obj);
-           assertWellFormed(args.length <= 33, 'Too many arguments');
-         }
-       }
- 
-       return queue;
-     },
- 
-     optimizeQueue: function PartialEvaluator_optimizeQueue(queue) {
-       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 = fnArray.length; i < ii; i++) {
-         if (fnArray[i] === 'paintInlineImageXObject' &&
-             fnArray[i - 2] === 'save' && fnArray[i - 1] === 'transform' &&
-             fnArray[i + 1] === '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
-           fnArray.splice(j, count * 4, ['paintInlineImageXObjectGroup']);
-           argsArray.splice(j, count * 4,
-             [{width: imgWidth, height: imgHeight, data: imgData}, map]);
-           i = j;
-           ii = fnArray.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 = fnArray.length; i < ii; i++) {
-         if (fnArray[i] === 'paintImageMaskXObject' &&
-             fnArray[i - 2] === 'save' && fnArray[i - 1] === 'transform' &&
-             fnArray[i + 1] === '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];
-             images.push({data: maskParams[0], width: maskParams[2],
-               height: maskParams[3], transform: transform,
-               inverseDecode: maskParams[1]});
-           }
-           // replacing queue items
-           fnArray.splice(j, count * 4, ['paintImageMaskXObjectGroup']);
-           argsArray.splice(j, count * 4, [images]);
-           i = j;
-           ii = fnArray.length;
-         }
-       }
-     },
- 
-     getTextContent: function PartialEvaluator_getTextContent(
-                                                     stream, resources, state) {
-       var bidiTexts;
-       var SPACE_FACTOR = 0.35;
-       var MULTI_SPACE_FACTOR = 1.5;
- 
-       if (!state) {
-         bidiTexts = [];
-         state = {
-           bidiTexts: bidiTexts
-         };
-       } else {
-         bidiTexts = state.bidiTexts;
-       }
- 
-       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;
-       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;
-               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);
-             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);
-       }
- 
-       var flags = properties.flags;
-       var differences = [];
-       var baseEncoding = 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 (!!(flags & FontFlags.Symbolic)) {
-         baseEncoding = !properties.file ? Encodings.symbolsEncoding :
-                                           Encodings.MacRomanEncoding;
-       }
-       var hasEncoding = dict.has('Encoding');
-       if (hasEncoding) {
-         var encoding = dict.get('Encoding');
-         if (isDict(encoding)) {
-           var baseName = encoding.get('BaseEncoding');
-           if (baseName)
-             baseEncoding = Encodings[baseName.name];
-           else
-             hasEncoding = false; // base encoding was not provided
- 
-           // 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)) {
-           baseEncoding = Encodings[encoding.name];
-         } else {
-           error('Encoding is not a Name nor a Dict');
-         }
-       }
- 
-       properties.differences = differences;
-       properties.baseEncoding = baseEncoding;
-       properties.hasEncoding = hasEncoding;
-     },
- 
-     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 tokens = [];
-         var token = '';
-         var beginArrayToken = {};
- 
-         var cmap = cmapObj.getBytes(cmapObj.length);
-         for (var i = 0, ii = cmap.length; i < ii; i++) {
-           var octet = cmap[i];
-           if (octet == 0x20 || octet == 0x0D || octet == 0x0A ||
-               octet == 0x3C || octet == 0x5B || octet == 0x5D) {
-             switch (token) {
-               case 'usecmap':
-                 error('usecmap is not implemented');
-                 break;
- 
-               case 'beginbfchar':
-               case 'beginbfrange':
-               case 'begincidchar':
-               case 'begincidrange':
-                 token = '';
-                 tokens = [];
-                 break;
- 
-               case 'endcidrange':
-               case 'endbfrange':
-                 for (var j = 0, jj = tokens.length; j < jj; j += 3) {
-                   var startRange = tokens[j];
-                   var endRange = tokens[j + 1];
-                   var code = tokens[j + 2];
-                   if (code == 0xFFFF) {
-                     // CMap is broken, assuming code == startRange
-                     code = startRange;
-                   }
-                   if (isArray(code)) {
-                     var codeindex = 0;
-                     while (startRange <= endRange) {
-                       charToUnicode[startRange] = code[codeindex++];
-                       ++startRange;
-                     }
-                   } else {
-                     while (startRange <= endRange) {
-                       charToUnicode[startRange] = code++;
-                       ++startRange;
-                     }
-                   }
-                 }
-                 break;
- 
-               case 'endcidchar':
-               case 'endbfchar':
-                 for (var j = 0, jj = tokens.length; j < jj; j += 2) {
-                   var index = tokens[j];
-                   var code = tokens[j + 1];
-                   charToUnicode[index] = code;
-                 }
-                 break;
- 
-               case '':
-                 break;
- 
-               default:
-                 if (token[0] >= '0' && token[0] <= '9')
-                   token = parseInt(token, 10); // a number
-                 tokens.push(token);
-                 token = '';
-             }
-             switch (octet) {
-               case 0x5B:
-                 // begin list parsing
-                 tokens.push(beginArrayToken);
-                 break;
-               case 0x5D:
-                 // collect array items
-                 var items = [], item;
-                 while (tokens.length &&
-                        (item = tokens.pop()) != beginArrayToken)
-                   items.unshift(item);
-                 tokens.push(items);
-                 break;
-             }
-           } else if (octet == 0x3E) {
-             if (token.length) {
-               // Heuristic: guessing chars size by checking numbers sizes
-               // in the CMap entries.
-               if (token.length == 2 && properties.composite)
-                 properties.wideChars = false;
- 
-               if (token.length <= 4) {
-                 // parsing hex number
-                 tokens.push(parseInt(token, 16));
-                 token = '';
-               } else {
-                 // parsing hex UTF-16BE numbers
-                 var str = [];
-                 for (var k = 0, kk = token.length; k < kk; k += 4) {
-                   var b = parseInt(token.substr(k, 4), 16);
-                   if (b <= 0x10) {
-                     k += 4;
-                     b = (b << 16) | parseInt(token.substr(k, 4), 16);
-                     b -= 0x10000;
-                     str.push(0xD800 | (b >> 10));
-                     str.push(0xDC00 | (b & 0x3FF));
-                     break;
-                   }
-                   str.push(b);
-                 }
-                 tokens.push(String.fromCharCode.apply(String, str));
-                 token = '';
-               }
-             }
-           } else {
-             token += String.fromCharCode(octet);
-           }
-         }
-       }
-       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;
-           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,
-                                                            resources,
-                                                            dependency) {
-       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) {
-           warn('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);
-         }
-       }
-       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);
-     }
-   };
- 
-   return PartialEvaluator;
- })();
- 
- var EvalState = (function EvalStateClosure() {
-   function EvalState() {
-     // Are soft masks and alpha values shapes or opacities?
-     this.alphaIsShape = false;
-     this.fontSize = 0;
-     this.textMatrix = IDENTITY_MATRIX;
-     this.leading = 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;
-     // Color spaces
-     this.fillColorSpace = null;
-     this.strokeColorSpace = null;
-   }
-   EvalState.prototype = {
-   };
-   return EvalState;
- })();
- 
- 
- 
- // Unicode Private Use Area
- var CMAP_GLYPH_OFFSET = 0xE000;
- var GLYPH_AREA_SIZE = 0x1900;
- var SYMBOLIC_FONT_GLYPH_OFFSET = 0xF000;
- 
- // PDF Glyph Space Units are one Thousandth of a TextSpace Unit
- // except for Type 3 fonts
- var PDF_GLYPH_SPACE_UNITS = 1000;
- 
- // Hinting is currently disabled due to unknown problems on windows
- // in tracemonkey and various other pdfs with type1 fonts.
- var HINTING_ENABLED = false;
- 
- // Accented charactars are not displayed properly on windows, using this flag
- // to control analysis of seac charstrings.
- var SEAC_ANALYSIS_ENABLED = false;
- 
- var FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0];
- 
- var FontFlags = {
-   FixedPitch: 1,
-   Serif: 2,
-   Symbolic: 4,
-   Script: 8,
-   Nonsymbolic: 32,
-   Italic: 64,
-   AllCap: 65536,
-   SmallCap: 131072,
-   ForceBold: 262144
- };
- 
- var Encodings = {
-   ExpertEncoding: ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
-     '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
-     'space', 'exclamsmall', 'Hungarumlautsmall', '', 'dollaroldstyle',
-     'dollarsuperior', 'ampersandsmall', 'Acutesmall', 'parenleftsuperior',
-     'parenrightsuperior', 'twodotenleader', 'onedotenleader', 'comma',
-     'hyphen', 'period', 'fraction', 'zerooldstyle', 'oneoldstyle',
-     'twooldstyle', 'threeoldstyle', 'fouroldstyle', 'fiveoldstyle',
-     'sixoldstyle', 'sevenoldstyle', 'eightoldstyle', 'nineoldstyle', 'colon',
-     'semicolon', 'commasuperior', 'threequartersemdash', 'periodsuperior',
-     'questionsmall', '', 'asuperior', 'bsuperior', 'centsuperior', 'dsuperior',
-     'esuperior', '', '', 'isuperior', '', '', 'lsuperior', 'msuperior',
-     'nsuperior', 'osuperior', '', '', 'rsuperior', 'ssuperior', 'tsuperior',
-     '', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'parenleftinferior', '',
-     'parenrightinferior', 'Circumflexsmall', 'hyphensuperior', 'Gravesmall',
-     'Asmall', 'Bsmall', 'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall',
-     'Hsmall', 'Ismall', 'Jsmall', 'Ksmall', 'Lsmall', 'Msmall', 'Nsmall',
-     'Osmall', 'Psmall', 'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall',
-     'Vsmall', 'Wsmall', 'Xsmall', 'Ysmall', 'Zsmall', 'colonmonetary',
-     'onefitted', 'rupiah', 'Tildesmall', '', '', '', '', '', '', '', '', '',
-     '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
-     '', '', '', '', '', '', 'exclamdownsmall', 'centoldstyle', 'Lslashsmall',
-     '', '', 'Scaronsmall', 'Zcaronsmall', 'Dieresissmall', 'Brevesmall',
-     'Caronsmall', '', 'Dotaccentsmall', '', '', 'Macronsmall', '', '',
-     'figuredash', 'hypheninferior', '', '', 'Ogoneksmall', 'Ringsmall',
-     'Cedillasmall', '', '', '', 'onequarter', 'onehalf', 'threequarters',
-     'questiondownsmall', 'oneeighth', 'threeeighths', 'fiveeighths',
-     'seveneighths', 'onethird', 'twothirds', '', '', 'zerosuperior',
-     'onesuperior', 'twosuperior', 'threesuperior', 'foursuperior',
-     'fivesuperior', 'sixsuperior', 'sevensuperior', 'eightsuperior',
-     'ninesuperior', 'zeroinferior', 'oneinferior', 'twoinferior',
-     'threeinferior', 'fourinferior', 'fiveinferior', 'sixinferior',
-     'seveninferior', 'eightinferior', 'nineinferior', 'centinferior',
-     'dollarinferior', 'periodinferior', 'commainferior', 'Agravesmall',
-     'Aacutesmall', 'Acircumflexsmall', 'Atildesmall', 'Adieresissmall',
-     'Aringsmall', 'AEsmall', 'Ccedillasmall', 'Egravesmall', 'Eacutesmall',
-     'Ecircumflexsmall', 'Edieresissmall', 'Igravesmall', 'Iacutesmall',
-     'Icircumflexsmall', 'Idieresissmall', 'Ethsmall', 'Ntildesmall',
-     'Ogravesmall', 'Oacutesmall', 'Ocircumflexsmall', 'Otildesmall',
-     'Odieresissmall', 'OEsmall', 'Oslashsmall', 'Ugravesmall', 'Uacutesmall',
-     'Ucircumflexsmall', 'Udieresissmall', 'Yacutesmall', 'Thornsmall',
-     'Ydieresissmall'],
-   MacExpertEncoding: ['', '', '', '', '', '', '', '', '', '', '', '', '', '',
-     '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
-     'space', 'exclamsmall', 'Hungarumlautsmall', 'centoldstyle',
-     'dollaroldstyle', 'dollarsuperior', 'ampersandsmall', 'Acutesmall',
-     'parenleftsuperior', 'parenrightsuperior', 'twodotenleader',
-     'onedotenleader', 'comma', 'hyphen', 'period', 'fraction', 'zerooldstyle',
-     'oneoldstyle', 'twooldstyle', 'threeoldstyle', 'fouroldstyle',
-     'fiveoldstyle', 'sixoldstyle', 'sevenoldstyle', 'eightoldstyle',
-     'nineoldstyle', 'colon', 'semicolon', '', 'threequartersemdash', '',
-     'questionsmall', '', '', '', '', 'Ethsmall', '', '', 'onequarter',
-     'onehalf', 'threequarters', 'oneeighth', 'threeeighths', 'fiveeighths',
-     'seveneighths', 'onethird', 'twothirds', '', '', '', '', '', '', 'ff',
-     'fi', 'fl', 'ffi', 'ffl', 'parenleftinferior', '', 'parenrightinferior',
-     'Circumflexsmall', 'hypheninferior', 'Gravesmall', 'Asmall', 'Bsmall',
-     'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall', 'Hsmall', 'Ismall',
-     'Jsmall', 'Ksmall', 'Lsmall', 'Msmall', 'Nsmall', 'Osmall', 'Psmall',
-     'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall', 'Vsmall', 'Wsmall',
-     'Xsmall', 'Ysmall', 'Zsmall', 'colonmonetary', 'onefitted', 'rupiah',
-     'Tildesmall', '', '', 'asuperior', 'centsuperior', '', '', '', '',
-     'Aacutesmall', 'Agravesmall', 'Acircumflexsmall', 'Adieresissmall',
-     'Atildesmall', 'Aringsmall', 'Ccedillasmall', 'Eacutesmall', 'Egravesmall',
-     'Ecircumflexsmall', 'Edieresissmall', 'Iacutesmall', 'Igravesmall',
-     'Icircumflexsmall', 'Idieresissmall', 'Ntildesmall', 'Oacutesmall',
-     'Ogravesmall', 'Ocircumflexsmall', 'Odieresissmall', 'Otildesmall',
-     'Uacutesmall', 'Ugravesmall', 'Ucircumflexsmall', 'Udieresissmall', '',
-     'eightsuperior', 'fourinferior', 'threeinferior', 'sixinferior',
-     'eightinferior', 'seveninferior', 'Scaronsmall', '', 'centinferior',
-     'twoinferior', '', 'Dieresissmall', '', 'Caronsmall', 'osuperior',
-     'fiveinferior', '', 'commainferior', 'periodinferior', 'Yacutesmall', '',
-     'dollarinferior', '', 'Thornsmall', '', 'nineinferior', 'zeroinferior',
-     'Zcaronsmall', 'AEsmall', 'Oslashsmall', 'questiondownsmall',
-     'oneinferior', 'Lslashsmall', '', '', '', '', '', '', 'Cedillasmall', '',
-     '', '', '', '', 'OEsmall', 'figuredash', 'hyphensuperior', '', '', '', '',
-     'exclamdownsmall', '', 'Ydieresissmall', '', 'onesuperior', 'twosuperior',
-     'threesuperior', 'foursuperior', 'fivesuperior', 'sixsuperior',
-     'sevensuperior', 'ninesuperior', 'zerosuperior', '', 'esuperior',
-     'rsuperior', 'tsuperior', '', '', 'isuperior', 'ssuperior', 'dsuperior',
-     '', '', '', '', '', 'lsuperior', 'Ogoneksmall', 'Brevesmall',
-     'Macronsmall', 'bsuperior', 'nsuperior', 'msuperior', 'commasuperior',
-     'periodsuperior', 'Dotaccentsmall', 'Ringsmall'],
-   MacRomanEncoding: ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
-     '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
-     'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent',
-     'ampersand', 'quotesingle', 'parenleft', 'parenright', 'asterisk', 'plus',
-     'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 'two', 'three',
-     'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon',
-     'less', 'equal', 'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F',
-     'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U',
-     'V', 'W', 'X', 'Y', 'Z', 'bracketleft', 'backslash', 'bracketright',
-     'asciicircum', 'underscore', 'grave', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
-     'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
-     'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright', 'asciitilde', '',
-     'Adieresis', 'Aring', 'Ccedilla', 'Eacute', 'Ntilde', 'Odieresis',
-     'Udieresis', 'aacute', 'agrave', 'acircumflex', 'adieresis', 'atilde',
-     'aring', 'ccedilla', 'eacute', 'egrave', 'ecircumflex', 'edieresis',
-     'iacute', 'igrave', 'icircumflex', 'idieresis', 'ntilde', 'oacute',
-     'ograve', 'ocircumflex', 'odieresis', 'otilde', 'uacute', 'ugrave',
-     'ucircumflex', 'udieresis', 'dagger', 'degree', 'cent', 'sterling',
-     'section', 'bullet', 'paragraph', 'germandbls', 'registered', 'copyright',
-     'trademark', 'acute', 'dieresis', 'notequal', 'AE', 'Oslash', 'infinity',
-     'plusminus', 'lessequal', 'greaterequal', 'yen', 'mu', 'partialdiff',
-     'summation', 'product', 'pi', 'integral', 'ordfeminine', 'ordmasculine',
-     'Omega', 'ae', 'oslash', 'questiondown', 'exclamdown', 'logicalnot',
-     'radical', 'florin', 'approxequal', 'Delta', 'guillemotleft',
-     'guillemotright', 'ellipsis', '', 'Agrave', 'Atilde', 'Otilde', 'OE',
-     'oe', 'endash', 'emdash', 'quotedblleft', 'quotedblright', 'quoteleft',
-     'quoteright', 'divide', 'lozenge', 'ydieresis', 'Ydieresis', 'fraction',
-     'currency', 'guilsinglleft', 'guilsinglright', 'fi', 'fl', 'daggerdbl',
-     'periodcentered', 'quotesinglbase', 'quotedblbase', 'perthousand',
-     'Acircumflex', 'Ecircumflex', 'Aacute', 'Edieresis', 'Egrave', 'Iacute',
-     'Icircumflex', 'Idieresis', 'Igrave', 'Oacute', 'Ocircumflex', 'apple',
-     'Ograve', 'Uacute', 'Ucircumflex', 'Ugrave', 'dotlessi', 'circumflex',
-     'tilde', 'macron', 'breve', 'dotaccent', 'ring', 'cedilla', 'hungarumlaut',
-     'ogonek', 'caron'],
-   StandardEncoding: ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
-     '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
-     'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent',
-     'ampersand', 'quoteright', 'parenleft', 'parenright', 'asterisk', 'plus',
-     'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 'two', 'three',
-     'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon',
-     'less', 'equal', 'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F',
-     'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U',
-     'V', 'W', 'X', 'Y', 'Z', 'bracketleft', 'backslash', 'bracketright',
-     'asciicircum', 'underscore', 'quoteleft', 'a', 'b', 'c', 'd', 'e', 'f',
-     'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u',
-     'v', 'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright', 'asciitilde',
-     '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
-     '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'exclamdown',
-     'cent', 'sterling', 'fraction', 'yen', 'florin', 'section', 'currency',
-     'quotesingle', 'quotedblleft', 'guillemotleft', 'guilsinglleft',
-     'guilsinglright', 'fi', 'fl', '', 'endash', 'dagger', 'daggerdbl',
-     'periodcentered', '', 'paragraph', 'bullet', 'quotesinglbase',
-     'quotedblbase', 'quotedblright', 'guillemotright', 'ellipsis',
-     'perthousand', '', 'questiondown', '', 'grave', 'acute', 'circumflex',
-     'tilde', 'macron', 'breve', 'dotaccent', 'dieresis', '', 'ring', 'cedilla',
-     '', 'hungarumlaut', 'ogonek', 'caron', 'emdash', '', '', '', '', '', '',
-     '', '', '', '', '', '', '', '', '', '', 'AE', '', 'ordfeminine', '', '',
-     '', '', 'Lslash', 'Oslash', 'OE', 'ordmasculine', '', '', '', '', '', 'ae',
-     '', '', '', 'dotlessi', '', '', 'lslash', 'oslash', 'oe', 'germandbls'],
-   WinAnsiEncoding: ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
-     '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
-     'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent',
-     'ampersand', 'quotesingle', 'parenleft', 'parenright', 'asterisk', 'plus',
-     'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 'two', 'three',
-     'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon',
-     'less', 'equal', 'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F',
-     'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U',
-     'V', 'W', 'X', 'Y', 'Z', 'bracketleft', 'backslash', 'bracketright',
-     'asciicircum', 'underscore', 'grave', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
-     'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
-     'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright', 'asciitilde',
-     'bullet', 'Euro', 'bullet', 'quotesinglbase', 'florin', 'quotedblbase',
-     'ellipsis', 'dagger', 'daggerdbl', 'circumflex', 'perthousand', 'Scaron',
-     'guilsinglleft', 'OE', 'bullet', 'Zcaron', 'bullet', 'bullet', 'quoteleft',
-     'quoteright', 'quotedblleft', 'quotedblright', 'bullet', 'endash',
-     'emdash', 'tilde', 'trademark', 'scaron', 'guilsinglright', 'oe', 'bullet',
-     'zcaron', 'Ydieresis', '', 'exclamdown', 'cent', 'sterling',
-     'currency', 'yen', 'brokenbar', 'section', 'dieresis', 'copyright',
-     'ordfeminine', 'guillemotleft', 'logicalnot', 'hyphen', 'registered',
-     'macron', 'degree', 'plusminus', 'twosuperior', 'threesuperior', 'acute',
-     'mu', 'paragraph', 'periodcentered', 'cedilla', 'onesuperior',
-     'ordmasculine', 'guillemotright', 'onequarter', 'onehalf', 'threequarters',
-     'questiondown', 'Agrave', 'Aacute', 'Acircumflex', 'Atilde', 'Adieresis',
-     'Aring', 'AE', 'Ccedilla', 'Egrave', 'Eacute', 'Ecircumflex', 'Edieresis',
-     'Igrave', 'Iacute', 'Icircumflex', 'Idieresis', 'Eth', 'Ntilde', 'Ograve',
-     'Oacute', 'Ocircumflex', 'Otilde', 'Odieresis', 'multiply', 'Oslash',
-     'Ugrave', 'Uacute', 'Ucircumflex', 'Udieresis', 'Yacute', 'Thorn',
-     'germandbls', 'agrave', 'aacute', 'acircumflex', 'atilde', 'adieresis',
-     'aring', 'ae', 'ccedilla', 'egrave', 'eacute', 'ecircumflex', 'edieresis',
-     'igrave', 'iacute', 'icircumflex', 'idieresis', 'eth', 'ntilde', 'ograve',
-     'oacute', 'ocircumflex', 'otilde', 'odieresis', 'divide', 'oslash',
-     'ugrave', 'uacute', 'ucircumflex', 'udieresis', 'yacute', 'thorn',
-     'ydieresis'],
-   symbolsEncoding: ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
-     '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
-     'space', 'exclam', 'universal', 'numbersign', 'existential', 'percent',
-     'ampersand', 'suchthat', 'parenleft', 'parenright', 'asteriskmath', 'plus',
-     'comma', 'minus', 'period', 'slash', 'zero', 'one', 'two', 'three', 'four',
-     'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon', 'less',
-     'equal', 'greater', 'question', 'congruent', 'Alpha', 'Beta', 'Chi',
-     'Delta', 'Epsilon', 'Phi', 'Gamma', 'Eta', 'Iota', 'theta1', 'Kappa',
-     'Lambda', 'Mu', 'Nu', 'Omicron', 'Pi', 'Theta', 'Rho', 'Sigma', 'Tau',
-     'Upsilon', 'sigma1', 'Omega', 'Xi', 'Psi', 'Zeta', 'bracketleft',
-     'therefore', 'bracketright', 'perpendicular', 'underscore', 'radicalex',
-     'alpha', 'beta', 'chi', 'delta', 'epsilon', 'phi', 'gamma', 'eta', 'iota',
-     'phi1', 'kappa', 'lambda', 'mu', 'nu', 'omicron', 'pi', 'theta', 'rho',
-     'sigma', 'tau', 'upsilon', 'omega1', 'omega', 'xi', 'psi', 'zeta',
-     'braceleft', 'bar', 'braceright', 'similar', '', '', '', '', '', '', '',
-     '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
-     '', '', '', '', '', '', '', 'Euro', 'Upsilon1', 'minute', 'lessequal',
-     'fraction', 'infinity', 'florin', 'club', 'diamond', 'heart', 'spade',
-     'arrowboth', 'arrowleft', 'arrowup', 'arrowright', 'arrowdown', 'degree',
-     'plusminus', 'second', 'greaterequal', 'multiply', 'proportional',
-     'partialdiff', 'bullet', 'divide', 'notequal', 'equivalence',
-     'approxequal', 'ellipsis', 'arrowvertex', 'arrowhorizex', 'carriagereturn',
-     'aleph', 'Ifraktur', 'Rfraktur', 'weierstrass', 'circlemultiply',
-     'circleplus', 'emptyset', 'intersection', 'union', 'propersuperset',
-     'reflexsuperset', 'notsubset', 'propersubset', 'reflexsubset', 'element',
-     'notelement', 'angle', 'gradient', 'registerserif', 'copyrightserif',
-     'trademarkserif', 'product', 'radical', 'dotmath', 'logicalnot',
-     'logicaland', 'logicalor', 'arrowdblboth', 'arrowdblleft', 'arrowdblup',
-     'arrowdblright', 'arrowdbldown', 'lozenge', 'angleleft', 'registersans',
-     'copyrightsans', 'trademarksans', 'summation', 'parenlefttp',
-     'parenleftex', 'parenleftbt', 'bracketlefttp', 'bracketleftex',
-     'bracketleftbt', 'bracelefttp', 'braceleftmid', 'braceleftbt', 'braceex',
-     '', 'angleright', 'integral', 'integraltp', 'integralex', 'integralbt',
-     'parenrighttp', 'parenrightex', 'parenrightbt', 'bracketrighttp',
-     'bracketrightex', 'bracketrightbt', 'bracerighttp', 'bracerightmid',
-     'bracerightbt'],
-   zapfDingbatsEncoding: ['', '', '', '', '', '', '', '', '', '', '', '', '', '',
-     '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
-     'space', 'a1', 'a2', 'a202', 'a3', 'a4', 'a5', 'a119', 'a118', 'a117',
-     'a11', 'a12', 'a13', 'a14', 'a15', 'a16', 'a105', 'a17', 'a18', 'a19',
-     'a20', 'a21', 'a22', 'a23', 'a24', 'a25', 'a26', 'a27', 'a28', 'a6', 'a7',
-     'a8', 'a9', 'a10', 'a29', 'a30', 'a31', 'a32', 'a33', 'a34', 'a35', 'a36',
-     'a37', 'a38', 'a39', 'a40', 'a41', 'a42', 'a43', 'a44', 'a45', 'a46',
-     'a47', 'a48', 'a49', 'a50', 'a51', 'a52', 'a53', 'a54', 'a55', 'a56',
-     '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']
- };
- 
- /**
-  * Hold a map of decoded fonts and of the standard fourteen Type1
-  * fonts and their acronyms.
-  */
- var stdFontMap = {
-   'ArialNarrow': 'Helvetica',
-   'ArialNarrow-Bold': 'Helvetica-Bold',
-   'ArialNarrow-BoldItalic': 'Helvetica-BoldOblique',
-   'ArialNarrow-Italic': 'Helvetica-Oblique',
-   'ArialBlack': 'Helvetica',
-   'ArialBlack-Bold': 'Helvetica-Bold',
-   'ArialBlack-BoldItalic': 'Helvetica-BoldOblique',
-   'ArialBlack-Italic': 'Helvetica-Oblique',
-   'Arial': 'Helvetica',
-   'Arial-Bold': 'Helvetica-Bold',
-   'Arial-BoldItalic': 'Helvetica-BoldOblique',
-   'Arial-Italic': 'Helvetica-Oblique',
-   'Arial-BoldItalicMT': 'Helvetica-BoldOblique',
-   'Arial-BoldMT': 'Helvetica-Bold',
-   'Arial-ItalicMT': 'Helvetica-Oblique',
-   'ArialMT': 'Helvetica',
-   'Courier-Bold': 'Courier-Bold',
-   'Courier-BoldItalic': 'Courier-BoldOblique',
-   'Courier-Italic': 'Courier-Oblique',
-   'CourierNew': 'Courier',
-   'CourierNew-Bold': 'Courier-Bold',
-   'CourierNew-BoldItalic': 'Courier-BoldOblique',
-   'CourierNew-Italic': 'Courier-Oblique',
-   'CourierNewPS-BoldItalicMT': 'Courier-BoldOblique',
-   'CourierNewPS-BoldMT': 'Courier-Bold',
-   'CourierNewPS-ItalicMT': 'Courier-Oblique',
-   'CourierNewPSMT': 'Courier',
-   'Helvetica-Bold': 'Helvetica-Bold',
-   'Helvetica-BoldItalic': 'Helvetica-BoldOblique',
-   'Helvetica-Italic': 'Helvetica-Oblique',
-   'Symbol-Bold': 'Symbol',
-   'Symbol-BoldItalic': 'Symbol',
-   'Symbol-Italic': 'Symbol',
-   'TimesNewRoman': 'Times-Roman',
-   'TimesNewRoman-Bold': 'Times-Bold',
-   'TimesNewRoman-BoldItalic': 'Times-BoldItalic',
-   'TimesNewRoman-Italic': 'Times-Italic',
-   'TimesNewRomanPS': 'Times-Roman',
-   'TimesNewRomanPS-Bold': 'Times-Bold',
-   'TimesNewRomanPS-BoldItalic': 'Times-BoldItalic',
-   'TimesNewRomanPS-BoldItalicMT': 'Times-BoldItalic',
-   'TimesNewRomanPS-BoldMT': 'Times-Bold',
-   'TimesNewRomanPS-Italic': 'Times-Italic',
-   'TimesNewRomanPS-ItalicMT': 'Times-Italic',
-   'TimesNewRomanPSMT': 'Times-Roman',
-   'TimesNewRomanPSMT-Bold': 'Times-Bold',
-   'TimesNewRomanPSMT-BoldItalic': 'Times-BoldItalic',
-   'TimesNewRomanPSMT-Italic': 'Times-Italic'
- };
- 
- /**
-  * Holds the map of the non-standard fonts that might be included as a standard
-  * fonts without glyph data.
-  */
- var nonStdFontMap = {
-   'ComicSansMS': 'Comic Sans MS',
-   'ComicSansMS-Bold': 'Comic Sans MS-Bold',
-   'ComicSansMS-BoldItalic': 'Comic Sans MS-BoldItalic',
-   'ComicSansMS-Italic': 'Comic Sans MS-Italic',
-   'LucidaConsole': 'Courier',
-   'LucidaConsole-Bold': 'Courier-Bold',
-   'LucidaConsole-BoldItalic': 'Courier-BoldOblique',
-   'LucidaConsole-Italic': 'Courier-Oblique',
-   'MS-Gothic': 'MS Gothic',
-   'MS-Gothic-Bold': 'MS Gothic-Bold',
-   'MS-Gothic-BoldItalic': 'MS Gothic-BoldItalic',
-   'MS-Gothic-Italic': 'MS Gothic-Italic',
-   'MS-Mincho': 'MS Mincho',
-   'MS-Mincho-Bold': 'MS Mincho-Bold',
-   'MS-Mincho-BoldItalic': 'MS Mincho-BoldItalic',
-   'MS-Mincho-Italic': 'MS Mincho-Italic',
-   'MS-PGothic': 'MS PGothic',
-   'MS-PGothic-Bold': 'MS PGothic-Bold',
-   'MS-PGothic-BoldItalic': 'MS PGothic-BoldItalic',
-   'MS-PGothic-Italic': 'MS PGothic-Italic',
-   'MS-PMincho': 'MS PMincho',
-   'MS-PMincho-Bold': 'MS PMincho-Bold',
-   'MS-PMincho-BoldItalic': 'MS PMincho-BoldItalic',
-   'MS-PMincho-Italic': 'MS PMincho-Italic',
- };
- 
- var serifFonts = {
-   'Adobe Jenson': true, 'Adobe Text': true, 'Albertus': true,
-   'Aldus': true, 'Alexandria': true, 'Algerian': true,
-   'American Typewriter': true, 'Antiqua': true, 'Apex': true,
-   'Arno': true, 'Aster': true, 'Aurora': true,
-   'Baskerville': true, 'Bell': true, 'Bembo': true,
-   'Bembo Schoolbook': true, 'Benguiat': true, 'Berkeley Old Style': true,
-   'Bernhard Modern': true, 'Berthold City': true, 'Bodoni': true,
-   'Bauer Bodoni': true, 'Book Antiqua': true, 'Bookman': true,
-   'Bordeaux Roman': true, 'Californian FB': true, 'Calisto': true,
-   'Calvert': true, 'Capitals': true, 'Cambria': true,
-   'Cartier': true, 'Caslon': true, 'Catull': true,
-   'Centaur': true, 'Century Old Style': true, 'Century Schoolbook': true,
-   'Chaparral': true, 'Charis SIL': true, 'Cheltenham': true,
-   'Cholla Slab': true, 'Clarendon': true, 'Clearface': true,
-   'Cochin': true, 'Colonna': true, 'Computer Modern': true,
-   'Concrete Roman': true, 'Constantia': true, 'Cooper Black': true,
-   'Corona': true, 'Ecotype': true, 'Egyptienne': true,
-   'Elephant': true, 'Excelsior': true, 'Fairfield': true,
-   'FF Scala': true, 'Folkard': true, 'Footlight': true,
-   'FreeSerif': true, 'Friz Quadrata': true, 'Garamond': true,
-   'Gentium': true, 'Georgia': true, 'Gloucester': true,
-   'Goudy Old Style': true, 'Goudy Schoolbook': true, 'Goudy Pro Font': true,
-   'Granjon': true, 'Guardian Egyptian': true, 'Heather': true,
-   'Hercules': true, 'High Tower Text': true, 'Hiroshige': true,
-   'Hoefler Text': true, 'Humana Serif': true, 'Imprint': true,
-   'Ionic No. 5': true, 'Janson': true, 'Joanna': true,
-   'Korinna': true, 'Lexicon': true, 'Liberation Serif': true,
-   'Linux Libertine': true, 'Literaturnaya': true, 'Lucida': true,
-   'Lucida Bright': true, 'Melior': true, 'Memphis': true,
-   'Miller': true, 'Minion': true, 'Modern': true,
-   'Mona Lisa': true, 'Mrs Eaves': true, 'MS Serif': true,
-   'Museo Slab': true, 'New York': true, 'Nimbus Roman': true,
-   'NPS Rawlinson Roadway': true, 'Palatino': true, 'Perpetua': true,
-   'Plantin': true, 'Plantin Schoolbook': true, 'Playbill': true,
-   'Poor Richard': true, 'Rawlinson Roadway': true, 'Renault': true,
-   'Requiem': true, 'Rockwell': true, 'Roman': true,
-   'Rotis Serif': true, 'Sabon': true, 'Scala': true,
-   'Seagull': true, 'Sistina': true, 'Souvenir': true,
-   'STIX': true, 'Stone Informal': true, 'Stone Serif': true,
-   'Sylfaen': true, 'Times': true, 'Trajan': true,
-   'Trinité': true, 'Trump Mediaeval': true, 'Utopia': true,
-   'Vale Type': true, 'Bitstream Vera': true, 'Vera Serif': true,
-   'Versailles': true, 'Wanted': true, 'Weiss': true,
-   'Wide Latin': true, 'Windsor': true, 'XITS': true
- };
- 
- 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,
-   '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
- };
- 
- 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) {
-     TODO('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) {
-     TODO('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
- // 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 FontLoader = {
-   loadingContext: {
-     requests: [],
-     nextRequestId: 0
-   },
- 
-   isSyncFontLoadingSupported: (function detectSyncFontLoadingSupport() {
-     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)
-       return true;
-     // TODO other browsers
-     return false;
-   })(),
- 
-   bind: function fontLoaderBind(fonts, callback) {
-     assert(!isWorker, 'bind() shall be called from main thread');
- 
-     var rules = [], fontsToLoad = [];
-     for (var i = 0, ii = fonts.length; i < ii; i++) {
-       var font = fonts[i];
- 
-       // Add the font to the DOM only once or skip if the font
-       // is already loaded.
-       if (font.attached || font.loading === false) {
-         continue;
-       }
-       font.attached = true;
- 
-       var rule = font.bindDOM();
-       if (rule) {
-         rules.push(rule);
-         fontsToLoad.push(font);
-       }
-     }
- 
-     var request = FontLoader.queueLoadingCallback(callback);
-     if (rules.length > 0 && !this.isSyncFontLoadingSupported) {
-       FontLoader.prepareFontLoadEvent(rules, fontsToLoad, request);
-     } else {
-       request.complete();
-     }
-   },
- 
-   queueLoadingCallback: function FontLoader_queueLoadingCallback(callback) {
-     function LoadLoader_completeRequest() {
-       assert(!request.end, 'completeRequest() cannot be called twice');
-       request.end = Date.now();
- 
-       // sending all completed requests in order how they were queued
-       while (context.requests.length > 0 && context.requests[0].end) {
-         var otherRequest = context.requests.shift();
-         setTimeout(otherRequest.callback, 0);
-       }
-     }
- 
-     var context = FontLoader.loadingContext;
-     var requestId = 'pdfjs-font-loading-' + (context.nextRequestId++);
-     var request = {
-       id: requestId,
-       complete: LoadLoader_completeRequest,
-       callback: callback,
-       started: Date.now()
-     };
-     context.requests.push(request);
-     return request;
-   },
- 
-   // Set things up so that at least one pdfjsFontLoad event is
-   // dispatched when all the @font-face |rules| for |fonts| have been
-   // loaded in a subdocument.  It's expected that the load of |rules|
-   // has already started in this (outer) document, so that they should
-   // be ordered before the load in the subdocument.
-   prepareFontLoadEvent: function fontLoaderPrepareFontLoadEvent(rules,
-                                                                 fonts,
-                                                                 request) {
-       /** Hack begin */
-       // There's no event when a font has finished downloading so the
-       // following code is a dirty hack to 'guess' when a font is
-       // ready.  This code will be obsoleted by Mozilla bug 471915.
-       //
-       // The only reliable way to know if a font is loaded in Gecko
-       // (at the moment) is document.onload in a document with
-       // a @font-face rule defined in a "static" stylesheet.  We use a
-       // subdocument in an <iframe>, set up properly, to know when
-       // our @font-face rule was loaded.  However, the subdocument and
-       // outer document can't share CSS rules, so the inner document
-       // is only part of the puzzle.  The second piece is an invisible
-       // div created in order to force loading of the @font-face in
-       // the *outer* document.  (The font still needs to be loaded for
-       // its metrics, for reflow).  We create the div first for the
-       // outer document, then create the iframe.  Unless something
-       // goes really wonkily, we expect the @font-face for the outer
-       // document to be processed before the inner.  That's still
-       // fragile, but seems to work in practice.
-       //
-       // The postMessage() hackery was added to work around chrome bug
-       // 82402.
- 
-       var requestId = request.id;
-       // Validate the requestId parameter -- the value used to construct HTML.
-       if (!/^[\w\-]+$/.test(requestId)) {
-         error('Invalid request id: ' + requestId);
- 
-         // Normally the error-function throws. But if a malicious code
-         // intercepts the function call then the return is needed.
-         return;
-       }
- 
-       var names = [];
-       for (var i = 0, ii = fonts.length; i < ii; i++)
-         names.push(fonts[i].loadedName);
- 
-       // Validate the names parameter -- the values can used to construct HTML.
-       if (!/^\w+$/.test(names.join(''))) {
-         error('Invalid font name(s): ' + names.join());
- 
-         // Normally the error-function throws. But if a malicious code
-         // intercepts the function call then the return is needed.
-         return;
-       }
- 
-       var div = document.createElement('div');
-       div.setAttribute('style',
-                        'visibility: hidden;' +
-                        'width: 10px; height: 10px;' +
-                        'position: absolute; top: 0px; left: 0px;');
-       var html = '';
-       for (var i = 0, ii = names.length; i < ii; ++i) {
-         html += '<span style="font-family:' + names[i] + '">Hi</span>';
-       }
-       div.innerHTML = html;
-       document.body.appendChild(div);
- 
-       window.addEventListener(
-         'message',
-         function fontLoaderMessage(e) {
-           if (e.data !== requestId)
-             return;
-           for (var i = 0, ii = fonts.length; i < ii; ++i) {
-             var font = fonts[i];
-             font.loading = false;
-           }
-           request.complete();
-           // cleanup
-           if (frame) {
-             document.body.removeChild(frame);
-           }
-           window.removeEventListener('message', fontLoaderMessage, false);
-         },
-         false);
- 
-       // XXX we should have a time-out here too, and maybe fire
-       // pdfjsFontLoadFailed?
-       var src = '<!DOCTYPE HTML><html><head><meta charset="utf-8">';
-       src += '<style type="text/css">';
-       for (var i = 0, ii = rules.length; i < ii; ++i) {
-         src += rules[i];
-       }
-       src += '</style>';
-       src += '<script type="application/javascript">';
-       src += '  window.onload = function fontLoaderOnload() {\n';
-       src += '    parent.postMessage("' + requestId + '", "*");\n';
-       // Chrome stuck on loading (see chrome issue 145227) - resetting url
-       src += '    window.location = "about:blank";\n';
-       src += '  }';
-       // Hack so the end script tag isn't counted if this is inline JS.
-       src += '</scr' + 'ipt></head><body>';
-       for (var i = 0, ii = names.length; i < ii; ++i) {
-         src += '<p style="font-family:\'' + names[i] + '\'">Hi</p>';
-       }
-       src += '</body></html>';
- 
-       var MAX_IFRAME_SRC_LENGTH = 1000000, IFRAME_TIMEOUT = 2000;
-       // Chrome fails for long src attributes (see issue 174023)
-       if (src.length > MAX_IFRAME_SRC_LENGTH) {
-         // ... waiting for some fixed period of time instead
-         window.setTimeout(function() {
-           window.postMessage(requestId, '*');
-         }, IFRAME_TIMEOUT);
-         return;
-       }
- 
-       var frame = document.createElement('iframe');
-       frame.src = 'data:text/html,' + src;
-       frame.setAttribute('style',
-                          'visibility: hidden;' +
-                          'width: 10px; height: 10px;' +
-                          'position: absolute; top: 0px; left: 0px;');
-       document.body.appendChild(frame);
-       /** Hack end */
-   }
- };
- 
- var UnicodeRanges = [
-   { 'begin': 0x0000, 'end': 0x007F }, // Basic Latin
-   { 'begin': 0x0080, 'end': 0x00FF }, // Latin-1 Supplement
-   { 'begin': 0x0100, 'end': 0x017F }, // Latin Extended-A
-   { 'begin': 0x0180, 'end': 0x024F }, // Latin Extended-B
-   { 'begin': 0x0250, 'end': 0x02AF }, // IPA Extensions
-   { 'begin': 0x02B0, 'end': 0x02FF }, // Spacing Modifier Letters
-   { 'begin': 0x0300, 'end': 0x036F }, // Combining Diacritical Marks
-   { 'begin': 0x0370, 'end': 0x03FF }, // Greek and Coptic
-   { 'begin': 0x2C80, 'end': 0x2CFF }, // Coptic
-   { 'begin': 0x0400, 'end': 0x04FF }, // Cyrillic
-   { 'begin': 0x0530, 'end': 0x058F }, // Armenian
-   { 'begin': 0x0590, 'end': 0x05FF }, // Hebrew
-   { 'begin': 0xA500, 'end': 0xA63F }, // Vai
-   { 'begin': 0x0600, 'end': 0x06FF }, // Arabic
-   { 'begin': 0x07C0, 'end': 0x07FF }, // NKo
-   { 'begin': 0x0900, 'end': 0x097F }, // Devanagari
-   { 'begin': 0x0980, 'end': 0x09FF }, // Bengali
-   { 'begin': 0x0A00, 'end': 0x0A7F }, // Gurmukhi
-   { 'begin': 0x0A80, 'end': 0x0AFF }, // Gujarati
-   { 'begin': 0x0B00, 'end': 0x0B7F }, // Oriya
-   { 'begin': 0x0B80, 'end': 0x0BFF }, // Tamil
-   { 'begin': 0x0C00, 'end': 0x0C7F }, // Telugu
-   { 'begin': 0x0C80, 'end': 0x0CFF }, // Kannada
-   { 'begin': 0x0D00, 'end': 0x0D7F }, // Malayalam
-   { 'begin': 0x0E00, 'end': 0x0E7F }, // Thai
-   { 'begin': 0x0E80, 'end': 0x0EFF }, // Lao
-   { 'begin': 0x10A0, 'end': 0x10FF }, // Georgian
-   { 'begin': 0x1B00, 'end': 0x1B7F }, // Balinese
-   { 'begin': 0x1100, 'end': 0x11FF }, // Hangul Jamo
-   { 'begin': 0x1E00, 'end': 0x1EFF }, // Latin Extended Additional
-   { 'begin': 0x1F00, 'end': 0x1FFF }, // Greek Extended
-   { 'begin': 0x2000, 'end': 0x206F }, // General Punctuation
-   { 'begin': 0x2070, 'end': 0x209F }, // Superscripts And Subscripts
-   { 'begin': 0x20A0, 'end': 0x20CF }, // Currency Symbol
-   { 'begin': 0x20D0, 'end': 0x20FF }, // Combining Diacritical Marks For Symbols
-   { 'begin': 0x2100, 'end': 0x214F }, // Letterlike Symbols
-   { 'begin': 0x2150, 'end': 0x218F }, // Number Forms
-   { 'begin': 0x2190, 'end': 0x21FF }, // Arrows
-   { 'begin': 0x2200, 'end': 0x22FF }, // Mathematical Operators
-   { 'begin': 0x2300, 'end': 0x23FF }, // Miscellaneous Technical
-   { 'begin': 0x2400, 'end': 0x243F }, // Control Pictures
-   { 'begin': 0x2440, 'end': 0x245F }, // Optical Character Recognition
-   { 'begin': 0x2460, 'end': 0x24FF }, // Enclosed Alphanumerics
-   { 'begin': 0x2500, 'end': 0x257F }, // Box Drawing
-   { 'begin': 0x2580, 'end': 0x259F }, // Block Elements
-   { 'begin': 0x25A0, 'end': 0x25FF }, // Geometric Shapes
-   { 'begin': 0x2600, 'end': 0x26FF }, // Miscellaneous Symbols
-   { 'begin': 0x2700, 'end': 0x27BF }, // Dingbats
-   { 'begin': 0x3000, 'end': 0x303F }, // CJK Symbols And Punctuation
-   { 'begin': 0x3040, 'end': 0x309F }, // Hiragana
-   { 'begin': 0x30A0, 'end': 0x30FF }, // Katakana
-   { 'begin': 0x3100, 'end': 0x312F }, // Bopomofo
-   { 'begin': 0x3130, 'end': 0x318F }, // Hangul Compatibility Jamo
-   { 'begin': 0xA840, 'end': 0xA87F }, // Phags-pa
-   { 'begin': 0x3200, 'end': 0x32FF }, // Enclosed CJK Letters And Months
-   { 'begin': 0x3300, 'end': 0x33FF }, // CJK Compatibility
-   { 'begin': 0xAC00, 'end': 0xD7AF }, // Hangul Syllables
-   { 'begin': 0xD800, 'end': 0xDFFF }, // Non-Plane 0 *
-   { 'begin': 0x10900, 'end': 0x1091F }, // Phoenicia
-   { 'begin': 0x4E00, 'end': 0x9FFF }, // CJK Unified Ideographs
-   { 'begin': 0xE000, 'end': 0xF8FF }, // Private Use Area (plane 0)
-   { 'begin': 0x31C0, 'end': 0x31EF }, // CJK Strokes
-   { 'begin': 0xFB00, 'end': 0xFB4F }, // Alphabetic Presentation Forms
-   { 'begin': 0xFB50, 'end': 0xFDFF }, // Arabic Presentation Forms-A
-   { 'begin': 0xFE20, 'end': 0xFE2F }, // Combining Half Marks
-   { 'begin': 0xFE10, 'end': 0xFE1F }, // Vertical Forms
-   { 'begin': 0xFE50, 'end': 0xFE6F }, // Small Form Variants
-   { 'begin': 0xFE70, 'end': 0xFEFF }, // Arabic Presentation Forms-B
-   { 'begin': 0xFF00, 'end': 0xFFEF }, // Halfwidth And Fullwidth Forms
-   { 'begin': 0xFFF0, 'end': 0xFFFF }, // Specials
-   { 'begin': 0x0F00, 'end': 0x0FFF }, // Tibetan
-   { 'begin': 0x0700, 'end': 0x074F }, // Syriac
-   { 'begin': 0x0780, 'end': 0x07BF }, // Thaana
-   { 'begin': 0x0D80, 'end': 0x0DFF }, // Sinhala
-   { 'begin': 0x1000, 'end': 0x109F }, // Myanmar
-   { 'begin': 0x1200, 'end': 0x137F }, // Ethiopic
-   { 'begin': 0x13A0, 'end': 0x13FF }, // Cherokee
-   { 'begin': 0x1400, 'end': 0x167F }, // Unified Canadian Aboriginal Syllabics
-   { 'begin': 0x1680, 'end': 0x169F }, // Ogham
-   { 'begin': 0x16A0, 'end': 0x16FF }, // Runic
-   { 'begin': 0x1780, 'end': 0x17FF }, // Khmer
-   { 'begin': 0x1800, 'end': 0x18AF }, // Mongolian
-   { 'begin': 0x2800, 'end': 0x28FF }, // Braille Patterns
-   { 'begin': 0xA000, 'end': 0xA48F }, // Yi Syllables
-   { 'begin': 0x1700, 'end': 0x171F }, // Tagalog
-   { 'begin': 0x10300, 'end': 0x1032F }, // Old Italic
-   { 'begin': 0x10330, 'end': 0x1034F }, // Gothic
-   { 'begin': 0x10400, 'end': 0x1044F }, // Deseret
-   { 'begin': 0x1D000, 'end': 0x1D0FF }, // Byzantine Musical Symbols
-   { 'begin': 0x1D400, 'end': 0x1D7FF }, // Mathematical Alphanumeric Symbols
-   { 'begin': 0xFF000, 'end': 0xFFFFD }, // Private Use (plane 15)
-   { 'begin': 0xFE00, 'end': 0xFE0F }, // Variation Selectors
-   { 'begin': 0xE0000, 'end': 0xE007F }, // Tags
-   { 'begin': 0x1900, 'end': 0x194F }, // Limbu
-   { 'begin': 0x1950, 'end': 0x197F }, // Tai Le
-   { 'begin': 0x1980, 'end': 0x19DF }, // New Tai Lue
-   { 'begin': 0x1A00, 'end': 0x1A1F }, // Buginese
-   { 'begin': 0x2C00, 'end': 0x2C5F }, // Glagolitic
-   { 'begin': 0x2D30, 'end': 0x2D7F }, // Tifinagh
-   { 'begin': 0x4DC0, 'end': 0x4DFF }, // Yijing Hexagram Symbols
-   { 'begin': 0xA800, 'end': 0xA82F }, // Syloti Nagri
-   { 'begin': 0x10000, 'end': 0x1007F }, // Linear B Syllabary
-   { 'begin': 0x10140, 'end': 0x1018F }, // Ancient Greek Numbers
-   { 'begin': 0x10380, 'end': 0x1039F }, // Ugaritic
-   { 'begin': 0x103A0, 'end': 0x103DF }, // Old Persian
-   { 'begin': 0x10450, 'end': 0x1047F }, // Shavian
-   { 'begin': 0x10480, 'end': 0x104AF }, // Osmanya
-   { 'begin': 0x10800, 'end': 0x1083F }, // Cypriot Syllabary
-   { 'begin': 0x10A00, 'end': 0x10A5F }, // Kharoshthi
-   { 'begin': 0x1D300, 'end': 0x1D35F }, // Tai Xuan Jing Symbols
-   { 'begin': 0x12000, 'end': 0x123FF }, // Cuneiform
-   { 'begin': 0x1D360, 'end': 0x1D37F }, // Counting Rod Numerals
-   { 'begin': 0x1B80, 'end': 0x1BBF }, // Sundanese
-   { 'begin': 0x1C00, 'end': 0x1C4F }, // Lepcha
-   { 'begin': 0x1C50, 'end': 0x1C7F }, // Ol Chiki
-   { 'begin': 0xA880, 'end': 0xA8DF }, // Saurashtra
-   { 'begin': 0xA900, 'end': 0xA92F }, // Kayah Li
-   { 'begin': 0xA930, 'end': 0xA95F }, // Rejang
-   { 'begin': 0xAA00, 'end': 0xAA5F }, // Cham
-   { 'begin': 0x10190, 'end': 0x101CF }, // Ancient Symbols
-   { 'begin': 0x101D0, 'end': 0x101FF }, // Phaistos Disc
-   { 'begin': 0x102A0, 'end': 0x102DF }, // Carian
-   { 'begin': 0x1F030, 'end': 0x1F09F }  // Domino Tiles
- ];
- 
- var MacStandardGlyphOrdering = [
-   '.notdef', '.null', 'nonmarkingreturn', 'space', 'exclam', 'quotedbl',
-   'numbersign', 'dollar', 'percent', 'ampersand', 'quotesingle', 'parenleft',
-   'parenright', 'asterisk', 'plus', 'comma', 'hyphen', 'period', 'slash',
-   'zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight',
-   'nine', 'colon', 'semicolon', 'less', 'equal', 'greater', 'question', 'at',
-   'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
-   'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'bracketleft',
-   'backslash', 'bracketright', 'asciicircum', 'underscore', 'grave', 'a', 'b',
-   'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
-   'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright',
-   'asciitilde', 'Adieresis', 'Aring', 'Ccedilla', 'Eacute', 'Ntilde',
-   'Odieresis', 'Udieresis', 'aacute', 'agrave', 'acircumflex', 'adieresis',
-   'atilde', 'aring', 'ccedilla', 'eacute', 'egrave', 'ecircumflex', 'edieresis',
-   'iacute', 'igrave', 'icircumflex', 'idieresis', 'ntilde', 'oacute', 'ograve',
-   'ocircumflex', 'odieresis', 'otilde', 'uacute', 'ugrave', 'ucircumflex',
-   'udieresis', 'dagger', 'degree', 'cent', 'sterling', 'section', 'bullet',
-   'paragraph', 'germandbls', 'registered', 'copyright', 'trademark', 'acute',
-   'dieresis', 'notequal', 'AE', 'Oslash', 'infinity', 'plusminus', 'lessequal',
-   'greaterequal', 'yen', 'mu', 'partialdiff', 'summation', 'product', 'pi',
-   'integral', 'ordfeminine', 'ordmasculine', 'Omega', 'ae', 'oslash',
-   'questiondown', 'exclamdown', 'logicalnot', 'radical', 'florin',
-   'approxequal', 'Delta', 'guillemotleft', 'guillemotright', 'ellipsis',
-   'nonbreakingspace', 'Agrave', 'Atilde', 'Otilde', 'OE', 'oe', 'endash',
-   'emdash', 'quotedblleft', 'quotedblright', 'quoteleft', 'quoteright',
-   'divide', 'lozenge', 'ydieresis', 'Ydieresis', 'fraction', 'currency',
-   'guilsinglleft', 'guilsinglright', 'fi', 'fl', 'daggerdbl', 'periodcentered',
-   'quotesinglbase', 'quotedblbase', 'perthousand', 'Acircumflex',
-   'Ecircumflex', 'Aacute', 'Edieresis', 'Egrave', 'Iacute', 'Icircumflex',
-   'Idieresis', 'Igrave', 'Oacute', 'Ocircumflex', 'apple', 'Ograve', 'Uacute',
-   'Ucircumflex', 'Ugrave', 'dotlessi', 'circumflex', 'tilde', 'macron',
-   'breve', 'dotaccent', 'ring', 'cedilla', 'hungarumlaut', 'ogonek', 'caron',
-   'Lslash', 'lslash', 'Scaron', 'scaron', 'Zcaron', 'zcaron', 'brokenbar',
-   'Eth', 'eth', 'Yacute', 'yacute', 'Thorn', 'thorn', 'minus', 'multiply',
-   'onesuperior', 'twosuperior', 'threesuperior', 'onehalf', 'onequarter',
-   'threequarters', 'franc', 'Gbreve', 'gbreve', 'Idotaccent', 'Scedilla',
-   'scedilla', 'Cacute', 'cacute', 'Ccaron', 'ccaron', 'dcroat'];
- 
- function getUnicodeRangeFor(value) {
-   for (var i = 0, ii = UnicodeRanges.length; i < ii; i++) {
-     var range = UnicodeRanges[i];
-     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)
-     return true;
-   range = UnicodeRanges[11];
-   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 <compat> entries.
- var NormalizedUnicodes = {
-   '\u00A8': '\u0020\u0308',
-   '\u00AF': '\u0020\u0304',
-   '\u00B4': '\u0020\u0301',
-   '\u00B5': '\u03BC',
-   '\u00B8': '\u0020\u0327',
-   '\u0132': '\u0049\u004A',
-   '\u0133': '\u0069\u006A',
-   '\u013F': '\u004C\u00B7',
-   '\u0140': '\u006C\u00B7',
-   '\u0149': '\u02BC\u006E',
-   '\u017F': '\u0073',
-   '\u01C4': '\u0044\u017D',
-   '\u01C5': '\u0044\u017E',
-   '\u01C6': '\u0064\u017E',
-   '\u01C7': '\u004C\u004A',
-   '\u01C8': '\u004C\u006A',
-   '\u01C9': '\u006C\u006A',
-   '\u01CA': '\u004E\u004A',
-   '\u01CB': '\u004E\u006A',
-   '\u01CC': '\u006E\u006A',
-   '\u01F1': '\u0044\u005A',
-   '\u01F2': '\u0044\u007A',
-   '\u01F3': '\u0064\u007A',
-   '\u02D8': '\u0020\u0306',
-   '\u02D9': '\u0020\u0307',
-   '\u02DA': '\u0020\u030A',
-   '\u02DB': '\u0020\u0328',
-   '\u02DC': '\u0020\u0303',
-   '\u02DD': '\u0020\u030B',
-   '\u037A': '\u0020\u0345',
-   '\u0384': '\u0020\u0301',
-   '\u03D0': '\u03B2',
-   '\u03D1': '\u03B8',
-   '\u03D2': '\u03A5',
-   '\u03D5': '\u03C6',
-   '\u03D6': '\u03C0',
-   '\u03F0': '\u03BA',
-   '\u03F1': '\u03C1',
-   '\u03F2': '\u03C2',
-   '\u03F4': '\u0398',
-   '\u03F5': '\u03B5',
-   '\u03F9': '\u03A3',
-   '\u0587': '\u0565\u0582',
-   '\u0675': '\u0627\u0674',
-   '\u0676': '\u0648\u0674',
-   '\u0677': '\u06C7\u0674',
-   '\u0678': '\u064A\u0674',
-   '\u0E33': '\u0E4D\u0E32',
-   '\u0EB3': '\u0ECD\u0EB2',
-   '\u0EDC': '\u0EAB\u0E99',
-   '\u0EDD': '\u0EAB\u0EA1',
-   '\u0F77': '\u0FB2\u0F81',
-   '\u0F79': '\u0FB3\u0F81',
-   '\u1E9A': '\u0061\u02BE',
-   '\u1FBD': '\u0020\u0313',
-   '\u1FBF': '\u0020\u0313',
-   '\u1FC0': '\u0020\u0342',
-   '\u1FFE': '\u0020\u0314',
-   '\u2002': '\u0020',
-   '\u2003': '\u0020',
-   '\u2004': '\u0020',
-   '\u2005': '\u0020',
-   '\u2006': '\u0020',
-   '\u2008': '\u0020',
-   '\u2009': '\u0020',
-   '\u200A': '\u0020',
-   '\u2017': '\u0020\u0333',
-   '\u2024': '\u002E',
-   '\u2025': '\u002E\u002E',
-   '\u2026': '\u002E\u002E\u002E',
-   '\u2033': '\u2032\u2032',
-   '\u2034': '\u2032\u2032\u2032',
-   '\u2036': '\u2035\u2035',
-   '\u2037': '\u2035\u2035\u2035',
-   '\u203C': '\u0021\u0021',
-   '\u203E': '\u0020\u0305',
-   '\u2047': '\u003F\u003F',
-   '\u2048': '\u003F\u0021',
-   '\u2049': '\u0021\u003F',
-   '\u2057': '\u2032\u2032\u2032\u2032',
-   '\u205F': '\u0020',
-   '\u20A8': '\u0052\u0073',
-   '\u2100': '\u0061\u002F\u0063',
-   '\u2101': '\u0061\u002F\u0073',
-   '\u2103': '\u00B0\u0043',
-   '\u2105': '\u0063\u002F\u006F',
-   '\u2106': '\u0063\u002F\u0075',
-   '\u2107': '\u0190',
-   '\u2109': '\u00B0\u0046',
-   '\u2116': '\u004E\u006F',
-   '\u2121': '\u0054\u0045\u004C',
-   '\u2135': '\u05D0',
-   '\u2136': '\u05D1',
-   '\u2137': '\u05D2',
-   '\u2138': '\u05D3',
-   '\u213B': '\u0046\u0041\u0058',
-   '\u2160': '\u0049',
-   '\u2161': '\u0049\u0049',
-   '\u2162': '\u0049\u0049\u0049',
-   '\u2163': '\u0049\u0056',
-   '\u2164': '\u0056',
-   '\u2165': '\u0056\u0049',
-   '\u2166': '\u0056\u0049\u0049',
-   '\u2167': '\u0056\u0049\u0049\u0049',
-   '\u2168': '\u0049\u0058',
-   '\u2169': '\u0058',
-   '\u216A': '\u0058\u0049',
-   '\u216B': '\u0058\u0049\u0049',
-   '\u216C': '\u004C',
-   '\u216D': '\u0043',
-   '\u216E': '\u0044',
-   '\u216F': '\u004D',
-   '\u2170': '\u0069',
-   '\u2171': '\u0069\u0069',
-   '\u2172': '\u0069\u0069\u0069',
-   '\u2173': '\u0069\u0076',
-   '\u2174': '\u0076',
-   '\u2175': '\u0076\u0069',
-   '\u2176': '\u0076\u0069\u0069',
-   '\u2177': '\u0076\u0069\u0069\u0069',
-   '\u2178': '\u0069\u0078',
-   '\u2179': '\u0078',
-   '\u217A': '\u0078\u0069',
-   '\u217B': '\u0078\u0069\u0069',
-   '\u217C': '\u006C',
-   '\u217D': '\u0063',
-   '\u217E': '\u0064',
-   '\u217F': '\u006D',
-   '\u222C': '\u222B\u222B',
-   '\u222D': '\u222B\u222B\u222B',
-   '\u222F': '\u222E\u222E',
-   '\u2230': '\u222E\u222E\u222E',
-   '\u2474': '\u0028\u0031\u0029',
-   '\u2475': '\u0028\u0032\u0029',
-   '\u2476': '\u0028\u0033\u0029',
-   '\u2477': '\u0028\u0034\u0029',
-   '\u2478': '\u0028\u0035\u0029',
-   '\u2479': '\u0028\u0036\u0029',
-   '\u247A': '\u0028\u0037\u0029',
-   '\u247B': '\u0028\u0038\u0029',
-   '\u247C': '\u0028\u0039\u0029',
-   '\u247D': '\u0028\u0031\u0030\u0029',
-   '\u247E': '\u0028\u0031\u0031\u0029',
-   '\u247F': '\u0028\u0031\u0032\u0029',
-   '\u2480': '\u0028\u0031\u0033\u0029',
-   '\u2481': '\u0028\u0031\u0034\u0029',
-   '\u2482': '\u0028\u0031\u0035\u0029',
-   '\u2483': '\u0028\u0031\u0036\u0029',
-   '\u2484': '\u0028\u0031\u0037\u0029',
-   '\u2485': '\u0028\u0031\u0038\u0029',
-   '\u2486': '\u0028\u0031\u0039\u0029',
-   '\u2487': '\u0028\u0032\u0030\u0029',
-   '\u2488': '\u0031\u002E',
-   '\u2489': '\u0032\u002E',
-   '\u248A': '\u0033\u002E',
-   '\u248B': '\u0034\u002E',
-   '\u248C': '\u0035\u002E',
-   '\u248D': '\u0036\u002E',
-   '\u248E': '\u0037\u002E',
-   '\u248F': '\u0038\u002E',
-   '\u2490': '\u0039\u002E',
-   '\u2491': '\u0031\u0030\u002E',
-   '\u2492': '\u0031\u0031\u002E',
-   '\u2493': '\u0031\u0032\u002E',
-   '\u2494': '\u0031\u0033\u002E',
-   '\u2495': '\u0031\u0034\u002E',
-   '\u2496': '\u0031\u0035\u002E',
-   '\u2497': '\u0031\u0036\u002E',
-   '\u2498': '\u0031\u0037\u002E',
-   '\u2499': '\u0031\u0038\u002E',
-   '\u249A': '\u0031\u0039\u002E',
-   '\u249B': '\u0032\u0030\u002E',
-   '\u249C': '\u0028\u0061\u0029',
-   '\u249D': '\u0028\u0062\u0029',
-   '\u249E': '\u0028\u0063\u0029',
-   '\u249F': '\u0028\u0064\u0029',
-   '\u24A0': '\u0028\u0065\u0029',
-   '\u24A1': '\u0028\u0066\u0029',
-   '\u24A2': '\u0028\u0067\u0029',
-   '\u24A3': '\u0028\u0068\u0029',
-   '\u24A4': '\u0028\u0069\u0029',
-   '\u24A5': '\u0028\u006A\u0029',
-   '\u24A6': '\u0028\u006B\u0029',
-   '\u24A7': '\u0028\u006C\u0029',
-   '\u24A8': '\u0028\u006D\u0029',
-   '\u24A9': '\u0028\u006E\u0029',
-   '\u24AA': '\u0028\u006F\u0029',
-   '\u24AB': '\u0028\u0070\u0029',
-   '\u24AC': '\u0028\u0071\u0029',
-   '\u24AD': '\u0028\u0072\u0029',
-   '\u24AE': '\u0028\u0073\u0029',
-   '\u24AF': '\u0028\u0074\u0029',
-   '\u24B0': '\u0028\u0075\u0029',
-   '\u24B1': '\u0028\u0076\u0029',
-   '\u24B2': '\u0028\u0077\u0029',
-   '\u24B3': '\u0028\u0078\u0029',
-   '\u24B4': '\u0028\u0079\u0029',
-   '\u24B5': '\u0028\u007A\u0029',
-   '\u2A0C': '\u222B\u222B\u222B\u222B',
-   '\u2A74': '\u003A\u003A\u003D',
-   '\u2A75': '\u003D\u003D',
-   '\u2A76': '\u003D\u003D\u003D',
-   '\u2E9F': '\u6BCD',
-   '\u2EF3': '\u9F9F',
-   '\u2F00': '\u4E00',
-   '\u2F01': '\u4E28',
-   '\u2F02': '\u4E36',
-   '\u2F03': '\u4E3F',
-   '\u2F04': '\u4E59',
-   '\u2F05': '\u4E85',
-   '\u2F06': '\u4E8C',
-   '\u2F07': '\u4EA0',
-   '\u2F08': '\u4EBA',
-   '\u2F09': '\u513F',
-   '\u2F0A': '\u5165',
-   '\u2F0B': '\u516B',
-   '\u2F0C': '\u5182',
-   '\u2F0D': '\u5196',
-   '\u2F0E': '\u51AB',
-   '\u2F0F': '\u51E0',
-   '\u2F10': '\u51F5',
-   '\u2F11': '\u5200',
-   '\u2F12': '\u529B',
-   '\u2F13': '\u52F9',
-   '\u2F14': '\u5315',
-   '\u2F15': '\u531A',
-   '\u2F16': '\u5338',
-   '\u2F17': '\u5341',
-   '\u2F18': '\u535C',
-   '\u2F19': '\u5369',
-   '\u2F1A': '\u5382',
-   '\u2F1B': '\u53B6',
-   '\u2F1C': '\u53C8',
-   '\u2F1D': '\u53E3',
-   '\u2F1E': '\u56D7',
-   '\u2F1F': '\u571F',
-   '\u2F20': '\u58EB',
-   '\u2F21': '\u5902',
-   '\u2F22': '\u590A',
-   '\u2F23': '\u5915',
-   '\u2F24': '\u5927',
-   '\u2F25': '\u5973',
-   '\u2F26': '\u5B50',
-   '\u2F27': '\u5B80',
-   '\u2F28': '\u5BF8',
-   '\u2F29': '\u5C0F',
-   '\u2F2A': '\u5C22',
-   '\u2F2B': '\u5C38',
-   '\u2F2C': '\u5C6E',
-   '\u2F2D': '\u5C71',
-   '\u2F2E': '\u5DDB',
-   '\u2F2F': '\u5DE5',
-   '\u2F30': '\u5DF1',
-   '\u2F31': '\u5DFE',
-   '\u2F32': '\u5E72',
-   '\u2F33': '\u5E7A',
-   '\u2F34': '\u5E7F',
-   '\u2F35': '\u5EF4',
-   '\u2F36': '\u5EFE',
-   '\u2F37': '\u5F0B',
-   '\u2F38': '\u5F13',
-   '\u2F39': '\u5F50',
-   '\u2F3A': '\u5F61',
-   '\u2F3B': '\u5F73',
-   '\u2F3C': '\u5FC3',
-   '\u2F3D': '\u6208',
-   '\u2F3E': '\u6236',
-   '\u2F3F': '\u624B',
-   '\u2F40': '\u652F',
-   '\u2F41': '\u6534',
-   '\u2F42': '\u6587',
-   '\u2F43': '\u6597',
-   '\u2F44': '\u65A4',
-   '\u2F45': '\u65B9',
-   '\u2F46': '\u65E0',
-   '\u2F47': '\u65E5',
-   '\u2F48': '\u66F0',
-   '\u2F49': '\u6708',
-   '\u2F4A': '\u6728',
-   '\u2F4B': '\u6B20',
-   '\u2F4C': '\u6B62',
-   '\u2F4D': '\u6B79',
-   '\u2F4E': '\u6BB3',
-   '\u2F4F': '\u6BCB',
-   '\u2F50': '\u6BD4',
-   '\u2F51': '\u6BDB',
-   '\u2F52': '\u6C0F',
-   '\u2F53': '\u6C14',
-   '\u2F54': '\u6C34',
-   '\u2F55': '\u706B',
-   '\u2F56': '\u722A',
-   '\u2F57': '\u7236',
-   '\u2F58': '\u723B',
-   '\u2F59': '\u723F',
-   '\u2F5A': '\u7247',
-   '\u2F5B': '\u7259',
-   '\u2F5C': '\u725B',
-   '\u2F5D': '\u72AC',
-   '\u2F5E': '\u7384',
-   '\u2F5F': '\u7389',
-   '\u2F60': '\u74DC',
-   '\u2F61': '\u74E6',
-   '\u2F62': '\u7518',
-   '\u2F63': '\u751F',
-   '\u2F64': '\u7528',
-   '\u2F65': '\u7530',
-   '\u2F66': '\u758B',
-   '\u2F67': '\u7592',
-   '\u2F68': '\u7676',
-   '\u2F69': '\u767D',
-   '\u2F6A': '\u76AE',
-   '\u2F6B': '\u76BF',
-   '\u2F6C': '\u76EE',
-   '\u2F6D': '\u77DB',
-   '\u2F6E': '\u77E2',
-   '\u2F6F': '\u77F3',
-   '\u2F70': '\u793A',
-   '\u2F71': '\u79B8',
-   '\u2F72': '\u79BE',
-   '\u2F73': '\u7A74',
-   '\u2F74': '\u7ACB',
-   '\u2F75': '\u7AF9',
-   '\u2F76': '\u7C73',
-   '\u2F77': '\u7CF8',
-   '\u2F78': '\u7F36',
-   '\u2F79': '\u7F51',
-   '\u2F7A': '\u7F8A',
-   '\u2F7B': '\u7FBD',
-   '\u2F7C': '\u8001',
-   '\u2F7D': '\u800C',
-   '\u2F7E': '\u8012',
-   '\u2F7F': '\u8033',
-   '\u2F80': '\u807F',
-   '\u2F81': '\u8089',
-   '\u2F82': '\u81E3',
-   '\u2F83': '\u81EA',
-   '\u2F84': '\u81F3',
-   '\u2F85': '\u81FC',
-   '\u2F86': '\u820C',
-   '\u2F87': '\u821B',
-   '\u2F88': '\u821F',
-   '\u2F89': '\u826E',
-   '\u2F8A': '\u8272',
-   '\u2F8B': '\u8278',
-   '\u2F8C': '\u864D',
-   '\u2F8D': '\u866B',
-   '\u2F8E': '\u8840',
-   '\u2F8F': '\u884C',
-   '\u2F90': '\u8863',
-   '\u2F91': '\u897E',
-   '\u2F92': '\u898B',
-   '\u2F93': '\u89D2',
-   '\u2F94': '\u8A00',
-   '\u2F95': '\u8C37',
-   '\u2F96': '\u8C46',
-   '\u2F97': '\u8C55',
-   '\u2F98': '\u8C78',
-   '\u2F99': '\u8C9D',
-   '\u2F9A': '\u8D64',
-   '\u2F9B': '\u8D70',
-   '\u2F9C': '\u8DB3',
-   '\u2F9D': '\u8EAB',
-   '\u2F9E': '\u8ECA',
-   '\u2F9F': '\u8F9B',
-   '\u2FA0': '\u8FB0',
-   '\u2FA1': '\u8FB5',
-   '\u2FA2': '\u9091',
-   '\u2FA3': '\u9149',
-   '\u2FA4': '\u91C6',
-   '\u2FA5': '\u91CC',
-   '\u2FA6': '\u91D1',
-   '\u2FA7': '\u9577',
-   '\u2FA8': '\u9580',
-   '\u2FA9': '\u961C',
-   '\u2FAA': '\u96B6',
-   '\u2FAB': '\u96B9',
-   '\u2FAC': '\u96E8',
-   '\u2FAD': '\u9751',
-   '\u2FAE': '\u975E',
-   '\u2FAF': '\u9762',
-   '\u2FB0': '\u9769',
-   '\u2FB1': '\u97CB',
-   '\u2FB2': '\u97ED',
-   '\u2FB3': '\u97F3',
-   '\u2FB4': '\u9801',
-   '\u2FB5': '\u98A8',
-   '\u2FB6': '\u98DB',
-   '\u2FB7': '\u98DF',
-   '\u2FB8': '\u9996',
-   '\u2FB9': '\u9999',
-   '\u2FBA': '\u99AC',
-   '\u2FBB': '\u9AA8',
-   '\u2FBC': '\u9AD8',
-   '\u2FBD': '\u9ADF',
-   '\u2FBE': '\u9B25',
-   '\u2FBF': '\u9B2F',
-   '\u2FC0': '\u9B32',
-   '\u2FC1': '\u9B3C',
-   '\u2FC2': '\u9B5A',
-   '\u2FC3': '\u9CE5',
-   '\u2FC4': '\u9E75',
-   '\u2FC5': '\u9E7F',
-   '\u2FC6': '\u9EA5',
-   '\u2FC7': '\u9EBB',
-   '\u2FC8': '\u9EC3',
-   '\u2FC9': '\u9ECD',
-   '\u2FCA': '\u9ED1',
-   '\u2FCB': '\u9EF9',
-   '\u2FCC': '\u9EFD',
-   '\u2FCD': '\u9F0E',
-   '\u2FCE': '\u9F13',
-   '\u2FCF': '\u9F20',
-   '\u2FD0': '\u9F3B',
-   '\u2FD1': '\u9F4A',
-   '\u2FD2': '\u9F52',
-   '\u2FD3': '\u9F8D',
-   '\u2FD4': '\u9F9C',
-   '\u2FD5': '\u9FA0',
-   '\u3036': '\u3012',
-   '\u3038': '\u5341',
-   '\u3039': '\u5344',
-   '\u303A': '\u5345',
-   '\u309B': '\u0020\u3099',
-   '\u309C': '\u0020\u309A',
-   '\u3131': '\u1100',
-   '\u3132': '\u1101',
-   '\u3133': '\u11AA',
-   '\u3134': '\u1102',
-   '\u3135': '\u11AC',
-   '\u3136': '\u11AD',
-   '\u3137': '\u1103',
-   '\u3138': '\u1104',
-   '\u3139': '\u1105',
-   '\u313A': '\u11B0',
-   '\u313B': '\u11B1',
-   '\u313C': '\u11B2',
-   '\u313D': '\u11B3',
-   '\u313E': '\u11B4',
-   '\u313F': '\u11B5',
-   '\u3140': '\u111A',
-   '\u3141': '\u1106',
-   '\u3142': '\u1107',
-   '\u3143': '\u1108',
-   '\u3144': '\u1121',
-   '\u3145': '\u1109',
-   '\u3146': '\u110A',
-   '\u3147': '\u110B',
-   '\u3148': '\u110C',
-   '\u3149': '\u110D',
-   '\u314A': '\u110E',
-   '\u314B': '\u110F',
-   '\u314C': '\u1110',
-   '\u314D': '\u1111',
-   '\u314E': '\u1112',
-   '\u314F': '\u1161',
-   '\u3150': '\u1162',
-   '\u3151': '\u1163',
-   '\u3152': '\u1164',
-   '\u3153': '\u1165',
-   '\u3154': '\u1166',
-   '\u3155': '\u1167',
-   '\u3156': '\u1168',
-   '\u3157': '\u1169',
-   '\u3158': '\u116A',
-   '\u3159': '\u116B',
-   '\u315A': '\u116C',
-   '\u315B': '\u116D',
-   '\u315C': '\u116E',
-   '\u315D': '\u116F',
-   '\u315E': '\u1170',
-   '\u315F': '\u1171',
-   '\u3160': '\u1172',
-   '\u3161': '\u1173',
-   '\u3162': '\u1174',
-   '\u3163': '\u1175',
-   '\u3164': '\u1160',
-   '\u3165': '\u1114',
-   '\u3166': '\u1115',
-   '\u3167': '\u11C7',
-   '\u3168': '\u11C8',
-   '\u3169': '\u11CC',
-   '\u316A': '\u11CE',
-   '\u316B': '\u11D3',
-   '\u316C': '\u11D7',
-   '\u316D': '\u11D9',
-   '\u316E': '\u111C',
-   '\u316F': '\u11DD',
-   '\u3170': '\u11DF',
-   '\u3171': '\u111D',
-   '\u3172': '\u111E',
-   '\u3173': '\u1120',
-   '\u3174': '\u1122',
-   '\u3175': '\u1123',
-   '\u3176': '\u1127',
-   '\u3177': '\u1129',
-   '\u3178': '\u112B',
-   '\u3179': '\u112C',
-   '\u317A': '\u112D',
-   '\u317B': '\u112E',
-   '\u317C': '\u112F',
-   '\u317D': '\u1132',
-   '\u317E': '\u1136',
-   '\u317F': '\u1140',
-   '\u3180': '\u1147',
-   '\u3181': '\u114C',
-   '\u3182': '\u11F1',
-   '\u3183': '\u11F2',
-   '\u3184': '\u1157',
-   '\u3185': '\u1158',
-   '\u3186': '\u1159',
-   '\u3187': '\u1184',
-   '\u3188': '\u1185',
-   '\u3189': '\u1188',
-   '\u318A': '\u1191',
-   '\u318B': '\u1192',
-   '\u318C': '\u1194',
-   '\u318D': '\u119E',
-   '\u318E': '\u11A1',
-   '\u3200': '\u0028\u1100\u0029',
-   '\u3201': '\u0028\u1102\u0029',
-   '\u3202': '\u0028\u1103\u0029',
-   '\u3203': '\u0028\u1105\u0029',
-   '\u3204': '\u0028\u1106\u0029',
-   '\u3205': '\u0028\u1107\u0029',
-   '\u3206': '\u0028\u1109\u0029',
-   '\u3207': '\u0028\u110B\u0029',
-   '\u3208': '\u0028\u110C\u0029',
-   '\u3209': '\u0028\u110E\u0029',
-   '\u320A': '\u0028\u110F\u0029',
-   '\u320B': '\u0028\u1110\u0029',
-   '\u320C': '\u0028\u1111\u0029',
-   '\u320D': '\u0028\u1112\u0029',
-   '\u320E': '\u0028\u1100\u1161\u0029',
-   '\u320F': '\u0028\u1102\u1161\u0029',
-   '\u3210': '\u0028\u1103\u1161\u0029',
-   '\u3211': '\u0028\u1105\u1161\u0029',
-   '\u3212': '\u0028\u1106\u1161\u0029',
-   '\u3213': '\u0028\u1107\u1161\u0029',
-   '\u3214': '\u0028\u1109\u1161\u0029',
-   '\u3215': '\u0028\u110B\u1161\u0029',
-   '\u3216': '\u0028\u110C\u1161\u0029',
-   '\u3217': '\u0028\u110E\u1161\u0029',
-   '\u3218': '\u0028\u110F\u1161\u0029',
-   '\u3219': '\u0028\u1110\u1161\u0029',
-   '\u321A': '\u0028\u1111\u1161\u0029',
-   '\u321B': '\u0028\u1112\u1161\u0029',
-   '\u321C': '\u0028\u110C\u116E\u0029',
-   '\u321D': '\u0028\u110B\u1169\u110C\u1165\u11AB\u0029',
-   '\u321E': '\u0028\u110B\u1169\u1112\u116E\u0029',
-   '\u3220': '\u0028\u4E00\u0029',
-   '\u3221': '\u0028\u4E8C\u0029',
-   '\u3222': '\u0028\u4E09\u0029',
-   '\u3223': '\u0028\u56DB\u0029',
-   '\u3224': '\u0028\u4E94\u0029',
-   '\u3225': '\u0028\u516D\u0029',
-   '\u3226': '\u0028\u4E03\u0029',
-   '\u3227': '\u0028\u516B\u0029',
-   '\u3228': '\u0028\u4E5D\u0029',
-   '\u3229': '\u0028\u5341\u0029',
-   '\u322A': '\u0028\u6708\u0029',
-   '\u322B': '\u0028\u706B\u0029',
-   '\u322C': '\u0028\u6C34\u0029',
-   '\u322D': '\u0028\u6728\u0029',
-   '\u322E': '\u0028\u91D1\u0029',
-   '\u322F': '\u0028\u571F\u0029',
-   '\u3230': '\u0028\u65E5\u0029',
-   '\u3231': '\u0028\u682A\u0029',
-   '\u3232': '\u0028\u6709\u0029',
-   '\u3233': '\u0028\u793E\u0029',
-   '\u3234': '\u0028\u540D\u0029',
-   '\u3235': '\u0028\u7279\u0029',
-   '\u3236': '\u0028\u8CA1\u0029',
-   '\u3237': '\u0028\u795D\u0029',
-   '\u3238': '\u0028\u52B4\u0029',
-   '\u3239': '\u0028\u4EE3\u0029',
-   '\u323A': '\u0028\u547C\u0029',
-   '\u323B': '\u0028\u5B66\u0029',
-   '\u323C': '\u0028\u76E3\u0029',
-   '\u323D': '\u0028\u4F01\u0029',
-   '\u323E': '\u0028\u8CC7\u0029',
-   '\u323F': '\u0028\u5354\u0029',
-   '\u3240': '\u0028\u796D\u0029',
-   '\u3241': '\u0028\u4F11\u0029',
-   '\u3242': '\u0028\u81EA\u0029',
-   '\u3243': '\u0028\u81F3\u0029',
-   '\u32C0': '\u0031\u6708',
-   '\u32C1': '\u0032\u6708',
-   '\u32C2': '\u0033\u6708',
-   '\u32C3': '\u0034\u6708',
-   '\u32C4': '\u0035\u6708',
-   '\u32C5': '\u0036\u6708',
-   '\u32C6': '\u0037\u6708',
-   '\u32C7': '\u0038\u6708',
-   '\u32C8': '\u0039\u6708',
-   '\u32C9': '\u0031\u0030\u6708',
-   '\u32CA': '\u0031\u0031\u6708',
-   '\u32CB': '\u0031\u0032\u6708',
-   '\u3358': '\u0030\u70B9',
-   '\u3359': '\u0031\u70B9',
-   '\u335A': '\u0032\u70B9',
-   '\u335B': '\u0033\u70B9',
-   '\u335C': '\u0034\u70B9',
-   '\u335D': '\u0035\u70B9',
-   '\u335E': '\u0036\u70B9',
-   '\u335F': '\u0037\u70B9',
-   '\u3360': '\u0038\u70B9',
-   '\u3361': '\u0039\u70B9',
-   '\u3362': '\u0031\u0030\u70B9',
-   '\u3363': '\u0031\u0031\u70B9',
-   '\u3364': '\u0031\u0032\u70B9',
-   '\u3365': '\u0031\u0033\u70B9',
-   '\u3366': '\u0031\u0034\u70B9',
-   '\u3367': '\u0031\u0035\u70B9',
-   '\u3368': '\u0031\u0036\u70B9',
-   '\u3369': '\u0031\u0037\u70B9',
-   '\u336A': '\u0031\u0038\u70B9',
-   '\u336B': '\u0031\u0039\u70B9',
-   '\u336C': '\u0032\u0030\u70B9',
-   '\u336D': '\u0032\u0031\u70B9',
-   '\u336E': '\u0032\u0032\u70B9',
-   '\u336F': '\u0032\u0033\u70B9',
-   '\u3370': '\u0032\u0034\u70B9',
-   '\u33E0': '\u0031\u65E5',
-   '\u33E1': '\u0032\u65E5',
-   '\u33E2': '\u0033\u65E5',
-   '\u33E3': '\u0034\u65E5',
-   '\u33E4': '\u0035\u65E5',
-   '\u33E5': '\u0036\u65E5',
-   '\u33E6': '\u0037\u65E5',
-   '\u33E7': '\u0038\u65E5',
-   '\u33E8': '\u0039\u65E5',
-   '\u33E9': '\u0031\u0030\u65E5',
-   '\u33EA': '\u0031\u0031\u65E5',
-   '\u33EB': '\u0031\u0032\u65E5',
-   '\u33EC': '\u0031\u0033\u65E5',
-   '\u33ED': '\u0031\u0034\u65E5',
-   '\u33EE': '\u0031\u0035\u65E5',
-   '\u33EF': '\u0031\u0036\u65E5',
-   '\u33F0': '\u0031\u0037\u65E5',
-   '\u33F1': '\u0031\u0038\u65E5',
-   '\u33F2': '\u0031\u0039\u65E5',
-   '\u33F3': '\u0032\u0030\u65E5',
-   '\u33F4': '\u0032\u0031\u65E5',
-   '\u33F5': '\u0032\u0032\u65E5',
-   '\u33F6': '\u0032\u0033\u65E5',
-   '\u33F7': '\u0032\u0034\u65E5',
-   '\u33F8': '\u0032\u0035\u65E5',
-   '\u33F9': '\u0032\u0036\u65E5',
-   '\u33FA': '\u0032\u0037\u65E5',
-   '\u33FB': '\u0032\u0038\u65E5',
-   '\u33FC': '\u0032\u0039\u65E5',
-   '\u33FD': '\u0033\u0030\u65E5',
-   '\u33FE': '\u0033\u0031\u65E5',
-   '\uFB00': '\u0066\u0066',
-   '\uFB01': '\u0066\u0069',
-   '\uFB02': '\u0066\u006C',
-   '\uFB03': '\u0066\u0066\u0069',
-   '\uFB04': '\u0066\u0066\u006C',
-   '\uFB05': '\u017F\u0074',
-   '\uFB06': '\u0073\u0074',
-   '\uFB13': '\u0574\u0576',
-   '\uFB14': '\u0574\u0565',
-   '\uFB15': '\u0574\u056B',
-   '\uFB16': '\u057E\u0576',
-   '\uFB17': '\u0574\u056D',
-   '\uFB4F': '\u05D0\u05DC',
-   '\uFB50': '\u0671',
-   '\uFB51': '\u0671',
-   '\uFB52': '\u067B',
-   '\uFB53': '\u067B',
-   '\uFB54': '\u067B',
-   '\uFB55': '\u067B',
-   '\uFB56': '\u067E',
-   '\uFB57': '\u067E',
-   '\uFB58': '\u067E',
-   '\uFB59': '\u067E',
-   '\uFB5A': '\u0680',
-   '\uFB5B': '\u0680',
-   '\uFB5C': '\u0680',
-   '\uFB5D': '\u0680',
-   '\uFB5E': '\u067A',
-   '\uFB5F': '\u067A',
-   '\uFB60': '\u067A',
-   '\uFB61': '\u067A',
-   '\uFB62': '\u067F',
-   '\uFB63': '\u067F',
-   '\uFB64': '\u067F',
-   '\uFB65': '\u067F',
-   '\uFB66': '\u0679',
-   '\uFB67': '\u0679',
-   '\uFB68': '\u0679',
-   '\uFB69': '\u0679',
-   '\uFB6A': '\u06A4',
-   '\uFB6B': '\u06A4',
-   '\uFB6C': '\u06A4',
-   '\uFB6D': '\u06A4',
-   '\uFB6E': '\u06A6',
-   '\uFB6F': '\u06A6',
-   '\uFB70': '\u06A6',
-   '\uFB71': '\u06A6',
-   '\uFB72': '\u0684',
-   '\uFB73': '\u0684',
-   '\uFB74': '\u0684',
-   '\uFB75': '\u0684',
-   '\uFB76': '\u0683',
-   '\uFB77': '\u0683',
-   '\uFB78': '\u0683',
-   '\uFB79': '\u0683',
-   '\uFB7A': '\u0686',
-   '\uFB7B': '\u0686',
-   '\uFB7C': '\u0686',
-   '\uFB7D': '\u0686',
-   '\uFB7E': '\u0687',
-   '\uFB7F': '\u0687',
-   '\uFB80': '\u0687',
-   '\uFB81': '\u0687',
-   '\uFB82': '\u068D',
-   '\uFB83': '\u068D',
-   '\uFB84': '\u068C',
-   '\uFB85': '\u068C',
-   '\uFB86': '\u068E',
-   '\uFB87': '\u068E',
-   '\uFB88': '\u0688',
-   '\uFB89': '\u0688',
-   '\uFB8A': '\u0698',
-   '\uFB8B': '\u0698',
-   '\uFB8C': '\u0691',
-   '\uFB8D': '\u0691',
-   '\uFB8E': '\u06A9',
-   '\uFB8F': '\u06A9',
-   '\uFB90': '\u06A9',
-   '\uFB91': '\u06A9',
-   '\uFB92': '\u06AF',
-   '\uFB93': '\u06AF',
-   '\uFB94': '\u06AF',
-   '\uFB95': '\u06AF',
-   '\uFB96': '\u06B3',
-   '\uFB97': '\u06B3',
-   '\uFB98': '\u06B3',
-   '\uFB99': '\u06B3',
-   '\uFB9A': '\u06B1',
-   '\uFB9B': '\u06B1',
-   '\uFB9C': '\u06B1',
-   '\uFB9D': '\u06B1',
-   '\uFB9E': '\u06BA',
-   '\uFB9F': '\u06BA',
-   '\uFBA0': '\u06BB',
-   '\uFBA1': '\u06BB',
-   '\uFBA2': '\u06BB',
-   '\uFBA3': '\u06BB',
-   '\uFBA4': '\u06C0',
-   '\uFBA5': '\u06C0',
-   '\uFBA6': '\u06C1',
-   '\uFBA7': '\u06C1',
-   '\uFBA8': '\u06C1',
-   '\uFBA9': '\u06C1',
-   '\uFBAA': '\u06BE',
-   '\uFBAB': '\u06BE',
-   '\uFBAC': '\u06BE',
-   '\uFBAD': '\u06BE',
-   '\uFBAE': '\u06D2',
-   '\uFBAF': '\u06D2',
-   '\uFBB0': '\u06D3',
-   '\uFBB1': '\u06D3',
-   '\uFBD3': '\u06AD',
-   '\uFBD4': '\u06AD',
-   '\uFBD5': '\u06AD',
-   '\uFBD6': '\u06AD',
-   '\uFBD7': '\u06C7',
-   '\uFBD8': '\u06C7',
-   '\uFBD9': '\u06C6',
-   '\uFBDA': '\u06C6',
-   '\uFBDB': '\u06C8',
-   '\uFBDC': '\u06C8',
-   '\uFBDD': '\u0677',
-   '\uFBDE': '\u06CB',
-   '\uFBDF': '\u06CB',
-   '\uFBE0': '\u06C5',
-   '\uFBE1': '\u06C5',
-   '\uFBE2': '\u06C9',
-   '\uFBE3': '\u06C9',
-   '\uFBE4': '\u06D0',
-   '\uFBE5': '\u06D0',
-   '\uFBE6': '\u06D0',
-   '\uFBE7': '\u06D0',
-   '\uFBE8': '\u0649',
-   '\uFBE9': '\u0649',
-   '\uFBEA': '\u0626\u0627',
-   '\uFBEB': '\u0626\u0627',
-   '\uFBEC': '\u0626\u06D5',
-   '\uFBED': '\u0626\u06D5',
-   '\uFBEE': '\u0626\u0648',
-   '\uFBEF': '\u0626\u0648',
-   '\uFBF0': '\u0626\u06C7',
-   '\uFBF1': '\u0626\u06C7',
-   '\uFBF2': '\u0626\u06C6',
-   '\uFBF3': '\u0626\u06C6',
-   '\uFBF4': '\u0626\u06C8',
-   '\uFBF5': '\u0626\u06C8',
-   '\uFBF6': '\u0626\u06D0',
-   '\uFBF7': '\u0626\u06D0',
-   '\uFBF8': '\u0626\u06D0',
-   '\uFBF9': '\u0626\u0649',
-   '\uFBFA': '\u0626\u0649',
-   '\uFBFB': '\u0626\u0649',
-   '\uFBFC': '\u06CC',
-   '\uFBFD': '\u06CC',
-   '\uFBFE': '\u06CC',
-   '\uFBFF': '\u06CC',
-   '\uFC00': '\u0626\u062C',
-   '\uFC01': '\u0626\u062D',
-   '\uFC02': '\u0626\u0645',
-   '\uFC03': '\u0626\u0649',
-   '\uFC04': '\u0626\u064A',
-   '\uFC05': '\u0628\u062C',
-   '\uFC06': '\u0628\u062D',
-   '\uFC07': '\u0628\u062E',
-   '\uFC08': '\u0628\u0645',
-   '\uFC09': '\u0628\u0649',
-   '\uFC0A': '\u0628\u064A',
-   '\uFC0B': '\u062A\u062C',
-   '\uFC0C': '\u062A\u062D',
-   '\uFC0D': '\u062A\u062E',
-   '\uFC0E': '\u062A\u0645',
-   '\uFC0F': '\u062A\u0649',
-   '\uFC10': '\u062A\u064A',
-   '\uFC11': '\u062B\u062C',
-   '\uFC12': '\u062B\u0645',
-   '\uFC13': '\u062B\u0649',
-   '\uFC14': '\u062B\u064A',
-   '\uFC15': '\u062C\u062D',
-   '\uFC16': '\u062C\u0645',
-   '\uFC17': '\u062D\u062C',
-   '\uFC18': '\u062D\u0645',
-   '\uFC19': '\u062E\u062C',
-   '\uFC1A': '\u062E\u062D',
-   '\uFC1B': '\u062E\u0645',
-   '\uFC1C': '\u0633\u062C',
-   '\uFC1D': '\u0633\u062D',
-   '\uFC1E': '\u0633\u062E',
-   '\uFC1F': '\u0633\u0645',
-   '\uFC20': '\u0635\u062D',
-   '\uFC21': '\u0635\u0645',
-   '\uFC22': '\u0636\u062C',
-   '\uFC23': '\u0636\u062D',
-   '\uFC24': '\u0636\u062E',
-   '\uFC25': '\u0636\u0645',
-   '\uFC26': '\u0637\u062D',
-   '\uFC27': '\u0637\u0645',
-   '\uFC28': '\u0638\u0645',
-   '\uFC29': '\u0639\u062C',
-   '\uFC2A': '\u0639\u0645',
-   '\uFC2B': '\u063A\u062C',
-   '\uFC2C': '\u063A\u0645',
-   '\uFC2D': '\u0641\u062C',
-   '\uFC2E': '\u0641\u062D',
-   '\uFC2F': '\u0641\u062E',
-   '\uFC30': '\u0641\u0645',
-   '\uFC31': '\u0641\u0649',
-   '\uFC32': '\u0641\u064A',
-   '\uFC33': '\u0642\u062D',
-   '\uFC34': '\u0642\u0645',
-   '\uFC35': '\u0642\u0649',
-   '\uFC36': '\u0642\u064A',
-   '\uFC37': '\u0643\u0627',
-   '\uFC38': '\u0643\u062C',
-   '\uFC39': '\u0643\u062D',
-   '\uFC3A': '\u0643\u062E',
-   '\uFC3B': '\u0643\u0644',
-   '\uFC3C': '\u0643\u0645',
-   '\uFC3D': '\u0643\u0649',
-   '\uFC3E': '\u0643\u064A',
-   '\uFC3F': '\u0644\u062C',
-   '\uFC40': '\u0644\u062D',
-   '\uFC41': '\u0644\u062E',
-   '\uFC42': '\u0644\u0645',
-   '\uFC43': '\u0644\u0649',
-   '\uFC44': '\u0644\u064A',
-   '\uFC45': '\u0645\u062C',
-   '\uFC46': '\u0645\u062D',
-   '\uFC47': '\u0645\u062E',
-   '\uFC48': '\u0645\u0645',
-   '\uFC49': '\u0645\u0649',
-   '\uFC4A': '\u0645\u064A',
-   '\uFC4B': '\u0646\u062C',
-   '\uFC4C': '\u0646\u062D',
-   '\uFC4D': '\u0646\u062E',
-   '\uFC4E': '\u0646\u0645',
-   '\uFC4F': '\u0646\u0649',
-   '\uFC50': '\u0646\u064A',
-   '\uFC51': '\u0647\u062C',
-   '\uFC52': '\u0647\u0645',
-   '\uFC53': '\u0647\u0649',
-   '\uFC54': '\u0647\u064A',
-   '\uFC55': '\u064A\u062C',
-   '\uFC56': '\u064A\u062D',
-   '\uFC57': '\u064A\u062E',
-   '\uFC58': '\u064A\u0645',
-   '\uFC59': '\u064A\u0649',
-   '\uFC5A': '\u064A\u064A',
-   '\uFC5B': '\u0630\u0670',
-   '\uFC5C': '\u0631\u0670',
-   '\uFC5D': '\u0649\u0670',
-   '\uFC5E': '\u0020\u064C\u0651',
-   '\uFC5F': '\u0020\u064D\u0651',
-   '\uFC60': '\u0020\u064E\u0651',
-   '\uFC61': '\u0020\u064F\u0651',
-   '\uFC62': '\u0020\u0650\u0651',
-   '\uFC63': '\u0020\u0651\u0670',
-   '\uFC64': '\u0626\u0631',
-   '\uFC65': '\u0626\u0632',
-   '\uFC66': '\u0626\u0645',
-   '\uFC67': '\u0626\u0646',
-   '\uFC68': '\u0626\u0649',
-   '\uFC69': '\u0626\u064A',
-   '\uFC6A': '\u0628\u0631',
-   '\uFC6B': '\u0628\u0632',
-   '\uFC6C': '\u0628\u0645',
-   '\uFC6D': '\u0628\u0646',
-   '\uFC6E': '\u0628\u0649',
-   '\uFC6F': '\u0628\u064A',
-   '\uFC70': '\u062A\u0631',
-   '\uFC71': '\u062A\u0632',
-   '\uFC72': '\u062A\u0645',
-   '\uFC73': '\u062A\u0646',
-   '\uFC74': '\u062A\u0649',
-   '\uFC75': '\u062A\u064A',
-   '\uFC76': '\u062B\u0631',
-   '\uFC77': '\u062B\u0632',
-   '\uFC78': '\u062B\u0645',
-   '\uFC79': '\u062B\u0646',
-   '\uFC7A': '\u062B\u0649',
-   '\uFC7B': '\u062B\u064A',
-   '\uFC7C': '\u0641\u0649',
-   '\uFC7D': '\u0641\u064A',
-   '\uFC7E': '\u0642\u0649',
-   '\uFC7F': '\u0642\u064A',
-   '\uFC80': '\u0643\u0627',
-   '\uFC81': '\u0643\u0644',
-   '\uFC82': '\u0643\u0645',
-   '\uFC83': '\u0643\u0649',
-   '\uFC84': '\u0643\u064A',
-   '\uFC85': '\u0644\u0645',
-   '\uFC86': '\u0644\u0649',
-   '\uFC87': '\u0644\u064A',
-   '\uFC88': '\u0645\u0627',
-   '\uFC89': '\u0645\u0645',
-   '\uFC8A': '\u0646\u0631',
-   '\uFC8B': '\u0646\u0632',
-   '\uFC8C': '\u0646\u0645',
-   '\uFC8D': '\u0646\u0646',
-   '\uFC8E': '\u0646\u0649',
-   '\uFC8F': '\u0646\u064A',
-   '\uFC90': '\u0649\u0670',
-   '\uFC91': '\u064A\u0631',
-   '\uFC92': '\u064A\u0632',
-   '\uFC93': '\u064A\u0645',
-   '\uFC94': '\u064A\u0646',
-   '\uFC95': '\u064A\u0649',
-   '\uFC96': '\u064A\u064A',
-   '\uFC97': '\u0626\u062C',
-   '\uFC98': '\u0626\u062D',
-   '\uFC99': '\u0626\u062E',
-   '\uFC9A': '\u0626\u0645',
-   '\uFC9B': '\u0626\u0647',
-   '\uFC9C': '\u0628\u062C',
-   '\uFC9D': '\u0628\u062D',
-   '\uFC9E': '\u0628\u062E',
-   '\uFC9F': '\u0628\u0645',
-   '\uFCA0': '\u0628\u0647',
-   '\uFCA1': '\u062A\u062C',
-   '\uFCA2': '\u062A\u062D',
-   '\uFCA3': '\u062A\u062E',
-   '\uFCA4': '\u062A\u0645',
-   '\uFCA5': '\u062A\u0647',
-   '\uFCA6': '\u062B\u0645',
-   '\uFCA7': '\u062C\u062D',
-   '\uFCA8': '\u062C\u0645',
-   '\uFCA9': '\u062D\u062C',
-   '\uFCAA': '\u062D\u0645',
-   '\uFCAB': '\u062E\u062C',
-   '\uFCAC': '\u062E\u0645',
-   '\uFCAD': '\u0633\u062C',
-   '\uFCAE': '\u0633\u062D',
-   '\uFCAF': '\u0633\u062E',
-   '\uFCB0': '\u0633\u0645',
-   '\uFCB1': '\u0635\u062D',
-   '\uFCB2': '\u0635\u062E',
-   '\uFCB3': '\u0635\u0645',
-   '\uFCB4': '\u0636\u062C',
-   '\uFCB5': '\u0636\u062D',
-   '\uFCB6': '\u0636\u062E',
-   '\uFCB7': '\u0636\u0645',
-   '\uFCB8': '\u0637\u062D',
-   '\uFCB9': '\u0638\u0645',
-   '\uFCBA': '\u0639\u062C',
-   '\uFCBB': '\u0639\u0645',
-   '\uFCBC': '\u063A\u062C',
-   '\uFCBD': '\u063A\u0645',
-   '\uFCBE': '\u0641\u062C',
-   '\uFCBF': '\u0641\u062D',
-   '\uFCC0': '\u0641\u062E',
-   '\uFCC1': '\u0641\u0645',
-   '\uFCC2': '\u0642\u062D',
-   '\uFCC3': '\u0642\u0645',
-   '\uFCC4': '\u0643\u062C',
-   '\uFCC5': '\u0643\u062D',
-   '\uFCC6': '\u0643\u062E',
-   '\uFCC7': '\u0643\u0644',
-   '\uFCC8': '\u0643\u0645',
-   '\uFCC9': '\u0644\u062C',
-   '\uFCCA': '\u0644\u062D',
-   '\uFCCB': '\u0644\u062E',
-   '\uFCCC': '\u0644\u0645',
-   '\uFCCD': '\u0644\u0647',
-   '\uFCCE': '\u0645\u062C',
-   '\uFCCF': '\u0645\u062D',
-   '\uFCD0': '\u0645\u062E',
-   '\uFCD1': '\u0645\u0645',
-   '\uFCD2': '\u0646\u062C',
-   '\uFCD3': '\u0646\u062D',
-   '\uFCD4': '\u0646\u062E',
-   '\uFCD5': '\u0646\u0645',
-   '\uFCD6': '\u0646\u0647',
-   '\uFCD7': '\u0647\u062C',
-   '\uFCD8': '\u0647\u0645',
-   '\uFCD9': '\u0647\u0670',
-   '\uFCDA': '\u064A\u062C',
-   '\uFCDB': '\u064A\u062D',
-   '\uFCDC': '\u064A\u062E',
-   '\uFCDD': '\u064A\u0645',
-   '\uFCDE': '\u064A\u0647',
-   '\uFCDF': '\u0626\u0645',
-   '\uFCE0': '\u0626\u0647',
-   '\uFCE1': '\u0628\u0645',
-   '\uFCE2': '\u0628\u0647',
-   '\uFCE3': '\u062A\u0645',
-   '\uFCE4': '\u062A\u0647',
-   '\uFCE5': '\u062B\u0645',
-   '\uFCE6': '\u062B\u0647',
-   '\uFCE7': '\u0633\u0645',
-   '\uFCE8': '\u0633\u0647',
-   '\uFCE9': '\u0634\u0645',
-   '\uFCEA': '\u0634\u0647',
-   '\uFCEB': '\u0643\u0644',
-   '\uFCEC': '\u0643\u0645',
-   '\uFCED': '\u0644\u0645',
-   '\uFCEE': '\u0646\u0645',
-   '\uFCEF': '\u0646\u0647',
-   '\uFCF0': '\u064A\u0645',
-   '\uFCF1': '\u064A\u0647',
-   '\uFCF2': '\u0640\u064E\u0651',
-   '\uFCF3': '\u0640\u064F\u0651',
-   '\uFCF4': '\u0640\u0650\u0651',
-   '\uFCF5': '\u0637\u0649',
-   '\uFCF6': '\u0637\u064A',
-   '\uFCF7': '\u0639\u0649',
-   '\uFCF8': '\u0639\u064A',
-   '\uFCF9': '\u063A\u0649',
-   '\uFCFA': '\u063A\u064A',
-   '\uFCFB': '\u0633\u0649',
-   '\uFCFC': '\u0633\u064A',
-   '\uFCFD': '\u0634\u0649',
-   '\uFCFE': '\u0634\u064A',
-   '\uFCFF': '\u062D\u0649',
-   '\uFD00': '\u062D\u064A',
-   '\uFD01': '\u062C\u0649',
-   '\uFD02': '\u062C\u064A',
-   '\uFD03': '\u062E\u0649',
-   '\uFD04': '\u062E\u064A',
-   '\uFD05': '\u0635\u0649',
-   '\uFD06': '\u0635\u064A',
-   '\uFD07': '\u0636\u0649',
-   '\uFD08': '\u0636\u064A',
-   '\uFD09': '\u0634\u062C',
-   '\uFD0A': '\u0634\u062D',
-   '\uFD0B': '\u0634\u062E',
-   '\uFD0C': '\u0634\u0645',
-   '\uFD0D': '\u0634\u0631',
-   '\uFD0E': '\u0633\u0631',
-   '\uFD0F': '\u0635\u0631',
-   '\uFD10': '\u0636\u0631',
-   '\uFD11': '\u0637\u0649',
-   '\uFD12': '\u0637\u064A',
-   '\uFD13': '\u0639\u0649',
-   '\uFD14': '\u0639\u064A',
-   '\uFD15': '\u063A\u0649',
-   '\uFD16': '\u063A\u064A',
-   '\uFD17': '\u0633\u0649',
-   '\uFD18': '\u0633\u064A',
-   '\uFD19': '\u0634\u0649',
-   '\uFD1A': '\u0634\u064A',
-   '\uFD1B': '\u062D\u0649',
-   '\uFD1C': '\u062D\u064A',
-   '\uFD1D': '\u062C\u0649',
-   '\uFD1E': '\u062C\u064A',
-   '\uFD1F': '\u062E\u0649',
-   '\uFD20': '\u062E\u064A',
-   '\uFD21': '\u0635\u0649',
-   '\uFD22': '\u0635\u064A',
-   '\uFD23': '\u0636\u0649',
-   '\uFD24': '\u0636\u064A',
-   '\uFD25': '\u0634\u062C',
-   '\uFD26': '\u0634\u062D',
-   '\uFD27': '\u0634\u062E',
-   '\uFD28': '\u0634\u0645',
-   '\uFD29': '\u0634\u0631',
-   '\uFD2A': '\u0633\u0631',
-   '\uFD2B': '\u0635\u0631',
-   '\uFD2C': '\u0636\u0631',
-   '\uFD2D': '\u0634\u062C',
-   '\uFD2E': '\u0634\u062D',
-   '\uFD2F': '\u0634\u062E',
-   '\uFD30': '\u0634\u0645',
-   '\uFD31': '\u0633\u0647',
-   '\uFD32': '\u0634\u0647',
-   '\uFD33': '\u0637\u0645',
-   '\uFD34': '\u0633\u062C',
-   '\uFD35': '\u0633\u062D',
-   '\uFD36': '\u0633\u062E',
-   '\uFD37': '\u0634\u062C',
-   '\uFD38': '\u0634\u062D',
-   '\uFD39': '\u0634\u062E',
-   '\uFD3A': '\u0637\u0645',
-   '\uFD3B': '\u0638\u0645',
-   '\uFD3C': '\u0627\u064B',
-   '\uFD3D': '\u0627\u064B',
-   '\uFD50': '\u062A\u062C\u0645',
-   '\uFD51': '\u062A\u062D\u062C',
-   '\uFD52': '\u062A\u062D\u062C',
-   '\uFD53': '\u062A\u062D\u0645',
-   '\uFD54': '\u062A\u062E\u0645',
-   '\uFD55': '\u062A\u0645\u062C',
-   '\uFD56': '\u062A\u0645\u062D',
-   '\uFD57': '\u062A\u0645\u062E',
-   '\uFD58': '\u062C\u0645\u062D',
-   '\uFD59': '\u062C\u0645\u062D',
-   '\uFD5A': '\u062D\u0645\u064A',
-   '\uFD5B': '\u062D\u0645\u0649',
-   '\uFD5C': '\u0633\u062D\u062C',
-   '\uFD5D': '\u0633\u062C\u062D',
-   '\uFD5E': '\u0633\u062C\u0649',
-   '\uFD5F': '\u0633\u0645\u062D',
-   '\uFD60': '\u0633\u0645\u062D',
-   '\uFD61': '\u0633\u0645\u062C',
-   '\uFD62': '\u0633\u0645\u0645',
-   '\uFD63': '\u0633\u0645\u0645',
-   '\uFD64': '\u0635\u062D\u062D',
-   '\uFD65': '\u0635\u062D\u062D',
-   '\uFD66': '\u0635\u0645\u0645',
-   '\uFD67': '\u0634\u062D\u0645',
-   '\uFD68': '\u0634\u062D\u0645',
-   '\uFD69': '\u0634\u062C\u064A',
-   '\uFD6A': '\u0634\u0645\u062E',
-   '\uFD6B': '\u0634\u0645\u062E',
-   '\uFD6C': '\u0634\u0645\u0645',
-   '\uFD6D': '\u0634\u0645\u0645',
-   '\uFD6E': '\u0636\u062D\u0649',
-   '\uFD6F': '\u0636\u062E\u0645',
-   '\uFD70': '\u0636\u062E\u0645',
-   '\uFD71': '\u0637\u0645\u062D',
-   '\uFD72': '\u0637\u0645\u062D',
-   '\uFD73': '\u0637\u0645\u0645',
-   '\uFD74': '\u0637\u0645\u064A',
-   '\uFD75': '\u0639\u062C\u0645',
-   '\uFD76': '\u0639\u0645\u0645',
-   '\uFD77': '\u0639\u0645\u0645',
-   '\uFD78': '\u0639\u0645\u0649',
-   '\uFD79': '\u063A\u0645\u0645',
-   '\uFD7A': '\u063A\u0645\u064A',
-   '\uFD7B': '\u063A\u0645\u0649',
-   '\uFD7C': '\u0641\u062E\u0645',
-   '\uFD7D': '\u0641\u062E\u0645',
-   '\uFD7E': '\u0642\u0645\u062D',
-   '\uFD7F': '\u0642\u0645\u0645',
-   '\uFD80': '\u0644\u062D\u0645',
-   '\uFD81': '\u0644\u062D\u064A',
-   '\uFD82': '\u0644\u062D\u0649',
-   '\uFD83': '\u0644\u062C\u062C',
-   '\uFD84': '\u0644\u062C\u062C',
-   '\uFD85': '\u0644\u062E\u0645',
-   '\uFD86': '\u0644\u062E\u0645',
-   '\uFD87': '\u0644\u0645\u062D',
-   '\uFD88': '\u0644\u0645\u062D',
-   '\uFD89': '\u0645\u062D\u062C',
-   '\uFD8A': '\u0645\u062D\u0645',
-   '\uFD8B': '\u0645\u062D\u064A',
-   '\uFD8C': '\u0645\u062C\u062D',
-   '\uFD8D': '\u0645\u062C\u0645',
-   '\uFD8E': '\u0645\u062E\u062C',
-   '\uFD8F': '\u0645\u062E\u0645',
-   '\uFD92': '\u0645\u062C\u062E',
-   '\uFD93': '\u0647\u0645\u062C',
-   '\uFD94': '\u0647\u0645\u0645',
-   '\uFD95': '\u0646\u062D\u0645',
-   '\uFD96': '\u0646\u062D\u0649',
-   '\uFD97': '\u0646\u062C\u0645',
-   '\uFD98': '\u0646\u062C\u0645',
-   '\uFD99': '\u0646\u062C\u0649',
-   '\uFD9A': '\u0646\u0645\u064A',
-   '\uFD9B': '\u0646\u0645\u0649',
-   '\uFD9C': '\u064A\u0645\u0645',
-   '\uFD9D': '\u064A\u0645\u0645',
-   '\uFD9E': '\u0628\u062E\u064A',
-   '\uFD9F': '\u062A\u062C\u064A',
-   '\uFDA0': '\u062A\u062C\u0649',
-   '\uFDA1': '\u062A\u062E\u064A',
-   '\uFDA2': '\u062A\u062E\u0649',
-   '\uFDA3': '\u062A\u0645\u064A',
-   '\uFDA4': '\u062A\u0645\u0649',
-   '\uFDA5': '\u062C\u0645\u064A',
-   '\uFDA6': '\u062C\u062D\u0649',
-   '\uFDA7': '\u062C\u0645\u0649',
-   '\uFDA8': '\u0633\u062E\u0649',
-   '\uFDA9': '\u0635\u062D\u064A',
-   '\uFDAA': '\u0634\u062D\u064A',
-   '\uFDAB': '\u0636\u062D\u064A',
-   '\uFDAC': '\u0644\u062C\u064A',
-   '\uFDAD': '\u0644\u0645\u064A',
-   '\uFDAE': '\u064A\u062D\u064A',
-   '\uFDAF': '\u064A\u062C\u064A',
-   '\uFDB0': '\u064A\u0645\u064A',
-   '\uFDB1': '\u0645\u0645\u064A',
-   '\uFDB2': '\u0642\u0645\u064A',
-   '\uFDB3': '\u0646\u062D\u064A',
-   '\uFDB4': '\u0642\u0645\u062D',
-   '\uFDB5': '\u0644\u062D\u0645',
-   '\uFDB6': '\u0639\u0645\u064A',
-   '\uFDB7': '\u0643\u0645\u064A',
-   '\uFDB8': '\u0646\u062C\u062D',
-   '\uFDB9': '\u0645\u062E\u064A',
-   '\uFDBA': '\u0644\u062C\u0645',
-   '\uFDBB': '\u0643\u0645\u0645',
-   '\uFDBC': '\u0644\u062C\u0645',
-   '\uFDBD': '\u0646\u062C\u062D',
-   '\uFDBE': '\u062C\u062D\u064A',
-   '\uFDBF': '\u062D\u062C\u064A',
-   '\uFDC0': '\u0645\u062C\u064A',
-   '\uFDC1': '\u0641\u0645\u064A',
-   '\uFDC2': '\u0628\u062D\u064A',
-   '\uFDC3': '\u0643\u0645\u0645',
-   '\uFDC4': '\u0639\u062C\u0645',
-   '\uFDC5': '\u0635\u0645\u0645',
-   '\uFDC6': '\u0633\u062E\u064A',
-   '\uFDC7': '\u0646\u062C\u064A',
-   '\uFE49': '\u203E',
-   '\uFE4A': '\u203E',
-   '\uFE4B': '\u203E',
-   '\uFE4C': '\u203E',
-   '\uFE4D': '\u005F',
-   '\uFE4E': '\u005F',
-   '\uFE4F': '\u005F',
-   '\uFE80': '\u0621',
-   '\uFE81': '\u0622',
-   '\uFE82': '\u0622',
-   '\uFE83': '\u0623',
-   '\uFE84': '\u0623',
-   '\uFE85': '\u0624',
-   '\uFE86': '\u0624',
-   '\uFE87': '\u0625',
-   '\uFE88': '\u0625',
-   '\uFE89': '\u0626',
-   '\uFE8A': '\u0626',
-   '\uFE8B': '\u0626',
-   '\uFE8C': '\u0626',
-   '\uFE8D': '\u0627',
-   '\uFE8E': '\u0627',
-   '\uFE8F': '\u0628',
-   '\uFE90': '\u0628',
-   '\uFE91': '\u0628',
-   '\uFE92': '\u0628',
-   '\uFE93': '\u0629',
-   '\uFE94': '\u0629',
-   '\uFE95': '\u062A',
-   '\uFE96': '\u062A',
-   '\uFE97': '\u062A',
-   '\uFE98': '\u062A',
-   '\uFE99': '\u062B',
-   '\uFE9A': '\u062B',
-   '\uFE9B': '\u062B',
-   '\uFE9C': '\u062B',
-   '\uFE9D': '\u062C',
-   '\uFE9E': '\u062C',
-   '\uFE9F': '\u062C',
-   '\uFEA0': '\u062C',
-   '\uFEA1': '\u062D',
-   '\uFEA2': '\u062D',
-   '\uFEA3': '\u062D',
-   '\uFEA4': '\u062D',
-   '\uFEA5': '\u062E',
-   '\uFEA6': '\u062E',
-   '\uFEA7': '\u062E',
-   '\uFEA8': '\u062E',
-   '\uFEA9': '\u062F',
-   '\uFEAA': '\u062F',
-   '\uFEAB': '\u0630',
-   '\uFEAC': '\u0630',
-   '\uFEAD': '\u0631',
-   '\uFEAE': '\u0631',
-   '\uFEAF': '\u0632',
-   '\uFEB0': '\u0632',
-   '\uFEB1': '\u0633',
-   '\uFEB2': '\u0633',
-   '\uFEB3': '\u0633',
-   '\uFEB4': '\u0633',
-   '\uFEB5': '\u0634',
-   '\uFEB6': '\u0634',
-   '\uFEB7': '\u0634',
-   '\uFEB8': '\u0634',
-   '\uFEB9': '\u0635',
-   '\uFEBA': '\u0635',
-   '\uFEBB': '\u0635',
-   '\uFEBC': '\u0635',
-   '\uFEBD': '\u0636',
-   '\uFEBE': '\u0636',
-   '\uFEBF': '\u0636',
-   '\uFEC0': '\u0636',
-   '\uFEC1': '\u0637',
-   '\uFEC2': '\u0637',
-   '\uFEC3': '\u0637',
-   '\uFEC4': '\u0637',
-   '\uFEC5': '\u0638',
-   '\uFEC6': '\u0638',
-   '\uFEC7': '\u0638',
-   '\uFEC8': '\u0638',
-   '\uFEC9': '\u0639',
-   '\uFECA': '\u0639',
-   '\uFECB': '\u0639',
-   '\uFECC': '\u0639',
-   '\uFECD': '\u063A',
-   '\uFECE': '\u063A',
-   '\uFECF': '\u063A',
-   '\uFED0': '\u063A',
-   '\uFED1': '\u0641',
-   '\uFED2': '\u0641',
-   '\uFED3': '\u0641',
-   '\uFED4': '\u0641',
-   '\uFED5': '\u0642',
-   '\uFED6': '\u0642',
-   '\uFED7': '\u0642',
-   '\uFED8': '\u0642',
-   '\uFED9': '\u0643',
-   '\uFEDA': '\u0643',
-   '\uFEDB': '\u0643',
-   '\uFEDC': '\u0643',
-   '\uFEDD': '\u0644',
-   '\uFEDE': '\u0644',
-   '\uFEDF': '\u0644',
-   '\uFEE0': '\u0644',
-   '\uFEE1': '\u0645',
-   '\uFEE2': '\u0645',
-   '\uFEE3': '\u0645',
-   '\uFEE4': '\u0645',
-   '\uFEE5': '\u0646',
-   '\uFEE6': '\u0646',
-   '\uFEE7': '\u0646',
-   '\uFEE8': '\u0646',
-   '\uFEE9': '\u0647',
-   '\uFEEA': '\u0647',
-   '\uFEEB': '\u0647',
-   '\uFEEC': '\u0647',
-   '\uFEED': '\u0648',
-   '\uFEEE': '\u0648',
-   '\uFEEF': '\u0649',
-   '\uFEF0': '\u0649',
-   '\uFEF1': '\u064A',
-   '\uFEF2': '\u064A',
-   '\uFEF3': '\u064A',
-   '\uFEF4': '\u064A',
-   '\uFEF5': '\u0644\u0622',
-   '\uFEF6': '\u0644\u0622',
-   '\uFEF7': '\u0644\u0623',
-   '\uFEF8': '\u0644\u0623',
-   '\uFEF9': '\u0644\u0625',
-   '\uFEFA': '\u0644\u0625',
-   '\uFEFB': '\u0644\u0627',
-   '\uFEFC': '\u0644\u0627'
- };
- 
- function reverseIfRtl(chars) {
-   var charsLength = chars.length;
-   //reverse an arabic ligature
-   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;
- }
- 
- function adjustWidths(properties) {
-   if (properties.fontMatrix[0] === FONT_IDENTITY_MATRIX[0]) {
-     return;
-   }
-   // adjusting width to fontMatrix scale
-   var scale = 0.001 / properties.fontMatrix[0];
-   var glyphsWidths = properties.widths;
-   for (var glyph in glyphsWidths) {
-     glyphsWidths[glyph] *= scale;
-   }
-   properties.defaultWidth *= scale;
- }
- 
- /**
-  * '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).
-  *
-  * For example to read a Type1 font and to attach it to the document:
-  *   var type1Font = new Font("MyFontName", binaryFile, propertiesObject);
-  *   type1Font.bind();
-  */
- var Font = (function FontClosure() {
-   function Font(name, file, properties) {
-     if (arguments.length === 1) {
-       // importing translated data
-       var data = arguments[0];
-       for (var i in data) {
-         this[i] = data[i];
-       }
-       return;
-     }
- 
-     this.name = name;
-     this.loadedName = properties.loadedName;
-     this.coded = properties.coded;
-     this.loadCharProcs = properties.coded;
-     this.sizes = [];
- 
-     var names = name.split('+');
-     names = names.length > 1 ? names[1] : names[0];
-     names = names.split(/[-,_]/g)[0];
-     this.isSerifFont = !!(properties.flags & FontFlags.Serif);
-     this.isSymbolicFont = !!(properties.flags & FontFlags.Symbolic);
-     this.isMonospace = !!(properties.flags & FontFlags.FixedPitch);
- 
-     var type = properties.type;
-     this.type = type;
- 
-     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.fontMatrix = properties.fontMatrix;
-     if (properties.type == 'Type3') {
-       this.encoding = properties.baseEncoding;
-       return;
-     }
- 
-     // Trying to fix encoding using glyph CIDSystemInfo.
-     this.loadCidToUnicode(properties);
-     this.cidEncoding = properties.cidEncoding;
-     this.vertical = properties.vertical;
-     if (this.vertical) {
-       this.vmetrics = properties.vmetrics;
-       this.defaultVMetrics = properties.defaultVMetrics;
-     }
- 
-     if (properties.toUnicode && properties.toUnicode.length > 0)
-       this.toUnicode = properties.toUnicode;
-     else
-       this.rebuildToUnicode(properties);
- 
-     this.toFontChar = this.buildToFontChar(this.toUnicode);
- 
-     if (!file) {
-       // The file data is not specified. Trying to fix the font name
-       // to be used with the canvas.font.
-       var fontName = name.replace(/[,_]/g, '-');
-       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);
- 
-       // 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.encoding = properties.baseEncoding;
-       this.noUnicodeAdaptation = true;
-       this.loadedName = fontName.split('-')[0];
-       this.loading = false;
-       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')
-       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') {
-       type = 'OpenType';
-     }
- 
-     var data;
-     switch (type) {
-       case 'Type1':
-       case 'CIDFontType0':
-         this.mimetype = 'font/opentype';
- 
-         var cff = (subtype == 'Type1C' || subtype == 'CIDFontType0C') ?
-           new CFFFont(file, properties) : new Type1Font(name, file, properties);
- 
-         adjustWidths(properties);
- 
-         // Wrap the CFF data inside an OTF font file
-         data = this.convert(name, cff, properties);
-         break;
- 
-       case 'TrueType':
-       case 'CIDFontType2':
-         this.mimetype = 'font/opentype';
- 
-         // Repair the TrueType file. It is can be damaged in the point of
-         // view of the sanitizer
-         data = this.checkAndRepair(name, file, properties);
-         if (!data) {
-           // TrueType data is not found, e.g. when the font is an OpenType font
-           warn('Font is not a TrueType font');
-         }
-         break;
- 
-       default:
-         warn('Font ' + type + ' is not supported');
-         break;
-     }
- 
-     this.data = data;
- 
-     // Transfer some properties again that could change during font conversion
-     this.fontMatrix = properties.fontMatrix;
-     this.widths = properties.widths;
-     this.defaultWidth = properties.defaultWidth;
-     this.encoding = properties.baseEncoding;
-     this.seacMap = properties.seacMap;
- 
-     this.loading = true;
-   }
- 
-   var numFonts = 0;
-   function getUniqueName() {
-     return 'pdfFont' + numFonts++;
-   }
- 
-   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 string16(value) {
-     return String.fromCharCode((value >> 8) & 0xff) +
-            String.fromCharCode(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);
-   }
- 
-   function string32(value) {
-     return String.fromCharCode((value >> 24) & 0xff) +
-            String.fromCharCode((value >> 16) & 0xff) +
-            String.fromCharCode((value >> 8) & 0xff) +
-            String.fromCharCode(value & 0xff);
-   }
- 
-   function createOpenTypeHeader(sfnt, file, numTables) {
-     // Windows hates the Mac TrueType sfnt version number
-     if (sfnt == 'true')
-       sfnt = string32(0x00010000);
- 
-     // sfnt version (4 bytes)
-     var header = sfnt;
- 
-     // numTables (2 bytes)
-     header += string16(numTables);
- 
-     // 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;
-   }
- 
-   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) {
-     // 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 });
-     codes.sort(function fontGetRangesSort(a, b) {
-       return a.unicode - b.unicode;
-     });
- 
-     // Split the sorted codes into ranges.
-     var ranges = [];
-     for (var n = 0; n < length; ) {
-       var start = codes[n].unicode;
-       var codeIndices = [codes[n].code];
-       ++n;
-       var end = start;
-       while (n < length && end + 1 == codes[n].unicode) {
-         codeIndices.push(codes[n].code);
-         ++end;
-         ++n;
-         if (end === 0x10000) { break; }
-       }
-       ranges.push([start, end, codeIndices]);
-     }
- 
-     return ranges;
-   }
- 
-   function createCmapTable(glyphs, deltas) {
-     var ranges = getRanges(glyphs);
- 
-     var numTables = ranges[ranges.length - 1][1] > 0xFFFF ? 2 : 1;
-     var cmap = '\x00\x00' + // version
-                string16(numTables) +  // numTables
-                '\x00\x03' + // platformID
-                '\x00\x01' + // encodingID
-                string32(4 + numTables * 8); // start of the table record
- 
-     for (var i = ranges.length - 1; i >= 0; --i) {
-       if (ranges[i][0] <= 0xFFFF) { break; }
-     }
-     var bmpLength = i + 1;
- 
-     if (ranges[i][1] === 0xFFFF) { ranges[i][1] = 0xFFFE; }
-     var segCount = bmpLength + 1;
-     var segCount2 = segCount * 2;
-     var searchRange = getMaxPower2(segCount) * 2;
-     var searchEntry = Math.log(segCount) / Math.log(2);
-     var rangeShift = 2 * segCount - searchRange;
- 
-     // Fill up the 4 parallel arrays describing the segments.
-     var startCount = '';
-     var endCount = '';
-     var idDeltas = '';
-     var idRangeOffsets = '';
-     var glyphsIds = '';
-     var bias = 0;
- 
-     if (deltas) {
-       for (var i = 0, ii = bmpLength; i < ii; i++) {
-         var range = ranges[i];
-         var start = range[0];
-         var end = range[1];
-         var offset = (segCount - i) * 2 + bias * 2;
-         bias += (end - start + 1);
- 
-         startCount += string16(start);
-         endCount += string16(end);
-         idDeltas += string16(0);
-         idRangeOffsets += string16(offset);
- 
-         var codes = range[2];
-         for (var j = 0, jj = codes.length; j < jj; ++j)
-           glyphsIds += string16(deltas[codes[j]]);
-       }
-     } else {
-       for (var i = 0, ii = bmpLength; i < ii; i++) {
-         var range = ranges[i];
-         var start = range[0];
-         var end = range[1];
-         var startCode = range[2][0];
- 
-         startCount += string16(start);
-         endCount += string16(end);
-         idDeltas += string16((startCode - start + 1) & 0xFFFF);
-         idRangeOffsets += string16(0);
-       }
-     }
- 
-     endCount += '\xFF\xFF';
-     startCount += '\xFF\xFF';
-     idDeltas += '\x00\x01';
-     idRangeOffsets += '\x00\x00';
- 
-     var format314 = '\x00\x00' + // language
-                     string16(segCount2) +
-                     string16(searchRange) +
-                     string16(searchEntry) +
-                     string16(rangeShift) +
-                     endCount + '\x00\x00' + startCount +
-                     idDeltas + idRangeOffsets + glyphsIds;
- 
-     var format31012 = '';
-     var header31012 = '';
-     if (numTables > 1) {
-       cmap += '\x00\x03' + // platformID
-               '\x00\x0A' + // encodingID
-               string32(4 + numTables * 8 +
-                        4 + format314.length); // start of the table record
-       format31012 = '';
-       if (deltas) {
-         for (var i = 0, ii = ranges.length; i < ii; i++) {
-           var range = ranges[i];
-           var start = range[0];
-           var codes = range[2];
-           var code = deltas[codes[0]];
-           for (var j = 1, jj = codes.length; j < jj; ++j) {
-             if (deltas[codes[j]] !== deltas[codes[j - 1]] + 1) {
-               var end = range[0] + j - 1;
-               format31012 += string32(start) + // startCharCode
-                              string32(end) + // endCharCode
-                              string32(code); // startGlyphID
-               start = end + 1;
-               code = deltas[codes[j]];
-             }
-           }
-           format31012 += string32(start) + // startCharCode
-                          string32(range[1]) + // endCharCode
-                          string32(code); // startGlyphID
-         }
-       } else {
-         for (var i = 0, ii = ranges.length; i < ii; i++) {
-           var range = ranges[i];
-           var start = range[0];
-           var codes = range[2];
-           var code = codes[0];
-           for (var j = 1, jj = codes.length; j < jj; ++j) {
-             if (codes[j] !== codes[j - 1] + 1) {
-               var end = range[0] + j - 1;
-               format31012 += string32(start) + // startCharCode
-                              string32(end) + // endCharCode
-                              string32(code); // startGlyphID
-               start = end + 1;
-               code = codes[j];
-             }
-           }
-           format31012 += string32(start) + // startCharCode
-                          string32(range[1]) + // endCharCode
-                          string32(code); // startGlyphID
-         }
-       }
-       header31012 = '\x00\x0C' + // format
-                     '\x00\x00' + // reserved
-                     string32(format31012.length + 16) + // length
-                     '\x00\x00\x00\x00' + // language
-                     string32(format31012.length / 12); // nGroups
-     }
- 
-     return stringToArray(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));
-     // 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));
-     if (version < 4 && (selection & 0x0300)) {
-       return false;
-     }
-     var firstChar = int16(stream.getBytes(2));
-     var lastChar = int16(stream.getBytes(2));
-     if (firstChar > lastChar) {
-       return false;
-     }
-     stream.getBytes(6); // skipping sTypoAscender/Descender/LineGap
-     var usWinAscent = int16(stream.getBytes(2));
-     if (usWinAscent === 0) { // makes font unreadable by windows
-       return false;
-     }
- 
-     // OS/2 appears to be valid, resetting some fields
-     os2.data[8] = os2.data[9] = 0; // IE rejects fonts if fsType != 0
-     return true;
-   }
- 
-   function createOS2Table(properties, charstrings, override) {
-     override = override || {
-       unitsPerEm: 0,
-       yMax: 0,
-       yMin: 0,
-       ascent: 0,
-       descent: 0
-     };
- 
-     var ulUnicodeRange1 = 0;
-     var ulUnicodeRange2 = 0;
-     var ulUnicodeRange3 = 0;
-     var ulUnicodeRange4 = 0;
- 
-     var firstCharIndex = null;
-     var lastCharIndex = 0;
- 
-     if (charstrings) {
-       for (var i = 0; i < charstrings.length; ++i) {
-         var code = charstrings[i].unicode;
-         if (firstCharIndex > code || !firstCharIndex)
-           firstCharIndex = code;
-         if (lastCharIndex < code)
-           lastCharIndex = code;
- 
-         var position = getUnicodeRangeFor(code);
-         if (position < 32) {
-           ulUnicodeRange1 |= 1 << position;
-         } else if (position < 64) {
-           ulUnicodeRange2 |= 1 << position - 32;
-         } else if (position < 96) {
-           ulUnicodeRange3 |= 1 << position - 64;
-         } else if (position < 123) {
-           ulUnicodeRange4 |= 1 << position - 96;
-         } else {
-           error('Unicode ranges Bits > 123 are reserved for internal usage');
-         }
-       }
-     } else {
-       // TODO
-       firstCharIndex = 0;
-       lastCharIndex = 255;
-     }
- 
-     var bbox = properties.bbox || [0, 0, 0, 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 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
-     }
-     var winAscent = override.yMax || typoAscent;
-     var winDescent = -override.yMin || -typoDescent;
- 
-     return '\x00\x03' + // version
-            '\x02\x24' + // xAvgCharWidth
-            '\x01\xF4' + // usWeightClass
-            '\x00\x05' + // usWidthClass
-            '\x00\x00' + // fstype (0 to let the font loads via font-face on IE)
-            '\x02\x8A' + // ySubscriptXSize
-            '\x02\xBB' + // ySubscriptYSize
-            '\x00\x00' + // ySubscriptXOffset
-            '\x00\x8C' + // ySubscriptYOffset
-            '\x02\x8A' + // ySuperScriptXSize
-            '\x02\xBB' + // ySuperScriptYSize
-            '\x00\x00' + // ySuperScriptXOffset
-            '\x01\xDF' + // ySuperScriptYOffset
-            '\x00\x31' + // yStrikeOutSize
-            '\x01\x02' + // yStrikeOutPosition
-            '\x00\x00' + // sFamilyClass
-            '\x00\x00\x06' +
-            String.fromCharCode(properties.fixedPitch ? 0x09 : 0x00) +
-            '\x00\x00\x00\x00\x00\x00' + // Panose
-            string32(ulUnicodeRange1) + // ulUnicodeRange1 (Bits 0-31)
-            string32(ulUnicodeRange2) + // ulUnicodeRange2 (Bits 32-63)
-            string32(ulUnicodeRange3) + // ulUnicodeRange3 (Bits 64-95)
-            string32(ulUnicodeRange4) + // ulUnicodeRange4 (Bits 96-127)
-            '\x2A\x32\x31\x2A' + // achVendID
-            string16(properties.italicAngle ? 1 : 0) + // fsSelection
-            string16(firstCharIndex ||
-                     properties.firstChar) + // usFirstCharIndex
-            string16(lastCharIndex || properties.lastChar) +  // usLastCharIndex
-            string16(typoAscent) + // sTypoAscender
-            string16(typoDescent) + // sTypoDescender
-            '\x00\x64' + // sTypoLineGap (7%-10% of the unitsPerEM value)
-            string16(winAscent) + // usWinAscent
-            string16(winDescent) + // usWinDescent
-            '\x00\x00\x00\x00' + // ulCodePageRange1 (Bits 0-31)
-            '\x00\x00\x00\x00' + // ulCodePageRange2 (Bits 32-63)
-            string16(properties.xHeight) + // sxHeight
-            string16(properties.capHeight) + // sCapHeight
-            string16(0) + // usDefaultChar
-            string16(firstCharIndex || properties.firstChar) + // usBreakChar
-            '\x00\x03';  // usMaxContext
-   }
- 
-   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
-   }
- 
-   function createNameTable(name, proto) {
-     if (!proto) {
-       proto = [[], []]; // no strings and unicode strings
-     }
- 
-     var strings = [
-       proto[0][0] || 'Original licence',  // 0.Copyright
-       proto[0][1] || name,                // 1.Font family
-       proto[0][2] || 'Unknown',           // 2.Font subfamily (font weight)
-       proto[0][3] || 'uniqueID',          // 3.Unique ID
-       proto[0][4] || name,                // 4.Full font name
-       proto[0][5] || 'Version 0.11',      // 5.Version
-       proto[0][6] || '',                  // 6.Postscript name
-       proto[0][7] || 'Unknown',           // 7.Trademark
-       proto[0][8] || 'Unknown',           // 8.Manufacturer
-       proto[0][9] || 'Unknown'            // 9.Designer
-     ];
- 
-     // 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 strUnicode = '';
-       for (var j = 0, jj = str.length; j < jj; j++)
-         strUnicode += string16(str.charCodeAt(j));
-       stringsUnicode.push(strUnicode);
-     }
- 
-     var names = [strings, stringsUnicode];
-     var platforms = ['\x00\x01', '\x00\x03'];
-     var encodings = ['\x00\x00', '\x00\x01'];
-     var languages = ['\x00\x00', '\x04\x09'];
- 
-     var namesRecordCount = strings.length * platforms.length;
-     var nameTable =
-       '\x00\x00' +                           // format
-       string16(namesRecordCount) +           // Number of names Record
-       string16(namesRecordCount * 12 + 6);   // Storage
- 
-     // Build the name records field
-     var strOffset = 0;
-     for (var 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];
-         var nameRecord =
-           platforms[i] + // platform ID
-           encodings[i] + // encoding ID
-           languages[i] + // language ID
-           string16(j) + // name ID
-           string16(str.length) +
-           string16(strOffset);
-         nameTable += nameRecord;
-         strOffset += str.length;
-       }
-     }
- 
-     nameTable += strings.join('') + stringsUnicode.join('');
-     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];
-         }
++      for (i = c, j = r; i < j; i++, j--) {
++        t = stack[i]; stack[i] = stack[j]; stack[j] = t;
 +      }
 +    }
-     return unicode;
++  };
++  return PostScriptStack;
++})();
++var PostScriptEvaluator = (function PostScriptEvaluatorClosure() {
++  function PostScriptEvaluator(operators) {
++    this.operators = operators;
 +  }
- 
- 
-   Font.prototype = {
-     name: null,
-     font: null,
-     mimetype: null,
-     encoding: null,
- 
-     exportData: function Font_exportData() {
-       var data = {};
-       for (var i in this) {
-         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 checksum = int32(file.getBytes(4));
-         var offset = int32(file.getBytes(4));
-         var length = int32(file.getBytes(4));
- 
-         // Read the table associated data
-         var previousPosition = file.pos;
-         file.pos = file.start ? file.start : 0;
-         file.skip(offset);
-         var data = file.getBytes(length);
-         file.pos = previousPosition;
- 
-         if (tag == 'head') {
-           // clearing checksum adjustment
-           data[8] = data[9] = data[10] = data[11] = 0;
-           data[17] |= 0x20; //Set font optimized for cleartype flag
-         }
- 
-         return {
-           tag: tag,
-           checksum: checksum,
-           length: length,
-           offset: offset,
-           data: data
-         };
-       }
- 
-       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))
-         };
-       }
- 
-       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.hasEncoding)
-           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) {
-         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 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.
-         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 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) {
-             useTable = true;
-             canBreak = true;
-             foundPreferredTable = true;
-           } else if (hasEncoding && platformId === 3 && encodingId === 1) {
-             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
-             };
-           }
-           if (canBreak) {
-             break;
-           }
-         }
- 
-         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;
-         }
- 
-         font.pos = start + potentialTable.offset;
-         var format = int16(font.getBytes(2));
-         var length = int16(font.getBytes(2));
-         var language = int16(font.getBytes(2));
- 
-         var hasShortCmap = false;
-         var mappings = [];
- 
-         // TODO(mack): refactor this cmap subtable reading logic out
-         if (format === 0) {
-           for (var j = 0; j < 256; j++) {
-             var index = font.getByte();
-             if (!index) {
-               continue;
-             }
-             mappings.push({
-               charcode: j,
-               glyphId: index
-             });
-           }
-           hasShortCmap = true;
-         } else if (format === 4) {
-           // re-creating the table in format 4 since the encoding
-           // might be changed
-           var segCount = (int16(font.getBytes(2)) >> 1);
-           font.getBytes(6); // skipping range fields
-           var segIndex, segments = [];
-           for (segIndex = 0; segIndex < segCount; segIndex++) {
-             segments.push({ end: int16(font.getBytes(2)) });
-           }
-           font.getBytes(2);
-           for (segIndex = 0; segIndex < segCount; segIndex++) {
-             segments[segIndex].start = int16(font.getBytes(2));
-           }
- 
-           for (segIndex = 0; segIndex < segCount; segIndex++) {
-             segments[segIndex].delta = int16(font.getBytes(2));
-           }
- 
-           var offsetsCount = 0;
-           for (segIndex = 0; segIndex < segCount; segIndex++) {
-             var segment = segments[segIndex];
-             var rangeOffset = int16(font.getBytes(2));
-             if (!rangeOffset) {
-               segment.offsetIndex = -1;
-               continue;
-             }
- 
-             var offsetIndex = (rangeOffset >> 1) - (segCount - segIndex);
-             segment.offsetIndex = offsetIndex;
-             offsetsCount = Math.max(offsetsCount, offsetIndex +
-               segment.end - segment.start + 1);
-           }
- 
-           var offsets = [];
-           for (var j = 0; j < offsetsCount; j++) {
-             offsets.push(int16(font.getBytes(2)));
-           }
- 
-           for (segIndex = 0; segIndex < segCount; segIndex++) {
-             var segment = segments[segIndex];
-             var start = segment.start, end = segment.end;
-             var delta = segment.delta, offsetIndex = segment.offsetIndex;
- 
-             for (var j = start; j <= end; j++) {
-               if (j == 0xFFFF) {
-                 continue;
-               }
- 
-               var glyphId = offsetIndex < 0 ? j :
-                 offsets[offsetIndex + j - start];
-               glyphId = (glyphId + delta) & 0xFFFF;
-               if (glyphId === 0) {
-                 continue;
-               }
-               mappings.push({
-                 charcode: j,
-                 glyphId: glyphId
-               });
-             }
-           }
-         } 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 glyphs = [];
-           var ids = [];
-           for (var j = 0; j < entryCount; j++) {
-             var glyphId = int16(font.getBytes(2));
-             var charcode = firstCode + j;
- 
-             mappings.push({
-               charcode: charcode,
-               glyphId: glyphId
-             });
-           }
-         } else {
-           error('cmap table has unsupported format: ' + format);
-         }
- 
-         return {
-           platformId: potentialTable.platformId,
-           encodingId: potentialTable.encodingId,
-           isSymbolicFont: potentialTable.isSymbolicFont,
-           mappings: mappings,
-           hasShortCmap: hasShortCmap
-         };
-       }
- 
-       function sanitizeMetrics(font, header, metrics, numGlyphs) {
-         if (!header) {
-           if (metrics) {
-             metrics.data = null;
-           }
-           return;
-         }
- 
-         font.pos = (font.start ? font.start : 0) + header.offset;
-         font.pos += header.length - 2;
-         var numOfMetrics = int16(font.getBytes(2));
- 
-         if (numOfMetrics > numGlyphs) {
-           info('The numOfMetrics (' + numOfMetrics + ') should not be ' +
-                'greater than the numGlyphs (' + numGlyphs + ')');
-           // Reduce numOfMetrics if it is greater than numGlyphs
-           numOfMetrics = numGlyphs;
-           header.data[34] = (numOfMetrics & 0xff00) >> 8;
-           header.data[35] = numOfMetrics & 0x00ff;
-         }
- 
-         var numOfSidebearings = numGlyphs - numOfMetrics;
-         var numMissing = numOfSidebearings -
-           ((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);
-         }
-       }
- 
-       function sanitizeGlyph(source, sourceStart, sourceEnd, dest, destStart) {
-         if (sourceEnd - sourceStart <= 12) {
-           // glyph with data less than 12 is invalid one
-           return 0;
-         }
-         var glyf = source.subarray(sourceStart, sourceEnd);
-         var contoursCount = (glyf[0] << 8) | glyf[1];
-         if (contoursCount & 0x8000) {
-           // complex glyph, writing as is
-           dest.set(glyf, destStart);
-           return glyf.length;
-         }
- 
-         var j = 10, flagsCount = 0;
-         for (var i = 0; i < contoursCount; i++) {
-           var endPoint = (glyf[j] << 8) | glyf[j + 1];
-           flagsCount = endPoint + 1;
-           j += 2;
-         }
-         // skipping instructions
-         var instructionsLength = (glyf[j] << 8) | glyf[j + 1];
-         j += 2 + instructionsLength;
-         // validating flags
-         var coordinatesLength = 0;
-         for (var i = 0; i < flagsCount; i++) {
-           var flag = glyf[j++];
-           if (flag & 0xC0) {
-             // reserved flags must be zero, rejecting
-             return 0;
-           }
-           var xyLength = ((flag & 2) ? 1 : (flag & 16) ? 0 : 2) +
-                          ((flag & 4) ? 1 : (flag & 32) ? 0 : 2);
-           coordinatesLength += xyLength;
-           if (flag & 8) {
-             var repeat = glyf[j++];
-             i += repeat;
-             coordinatesLength += repeat * xyLength;
-           }
-         }
-         var glyphDataLength = j + coordinatesLength;
-         if (glyphDataLength > glyf.length) {
-           // not enough data for coordinates
-           return 0;
-         }
-         if (glyf.length - glyphDataLength > 3) {
-           // truncating and aligning to 4 bytes the long glyph data
-           glyphDataLength = (glyphDataLength + 3) & ~3;
-           dest.set(glyf.subarray(0, glyphDataLength), destStart);
-           return glyphDataLength;
-         }
-         // glyph data is fine
-         dest.set(glyf, destStart);
-         return glyf.length;
-       }
- 
-       function sanitizeHead(head, numGlyphs, locaLength) {
-         var data = head.data;
- 
-         // Validate version:
-         // Should always be 0x00010000
-         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;
-           data[1] = 1;
-           data[2] = 0;
-           data[3] = 0;
-         }
- 
-         var indexToLocFormat = int16([data[50], data[51]]);
-         if (indexToLocFormat < 0 || indexToLocFormat > 1) {
-           info('Attempting to fix invalid indexToLocFormat in head table: ' +
-                indexToLocFormat);
- 
-           // The value of indexToLocFormat should be 0 if the loca table
-           // consists of short offsets, and should be 1 if the loca table
-           // consists of long offsets.
-           //
-           // The number of entries in the loca table should be numGlyphs + 1.
-           //
-           // Using this information, we can work backwards to deduce if the
-           // size of each offset in the loca table, and thus figure out the
-           // appropriate value for indexToLocFormat.
- 
-           var numGlyphsPlusOne = numGlyphs + 1;
-           if (locaLength === numGlyphsPlusOne << 1) {
-             // 0x0000 indicates the loca table consists of short offsets
-             data[50] = 0;
-             data[51] = 0;
-           } else if (locaLength === numGlyphsPlusOne << 2) {
-             // 0x0001 indicates the loca table consists of long offsets
-             data[50] = 0;
-             data[51] = 1;
-           } else {
-             warn('Could not fix indexToLocFormat: ' + indexToLocFormat);
-           }
-         }
-       }
- 
-       function sanitizeGlyphLocations(loca, glyf, numGlyphs,
-                                       isGlyphLocationsLong) {
-         var itemSize, itemDecode, itemEncode;
-         if (isGlyphLocationsLong) {
-           itemSize = 4;
-           itemDecode = function fontItemDecodeLong(data, offset) {
-             return (data[offset] << 24) | (data[offset + 1] << 16) |
-                    (data[offset + 2] << 8) | data[offset + 3];
-           };
-           itemEncode = function fontItemEncodeLong(data, offset, value) {
-             data[offset] = (value >>> 24) & 0xFF;
-             data[offset + 1] = (value >> 16) & 0xFF;
-             data[offset + 2] = (value >> 8) & 0xFF;
-             data[offset + 3] = value & 0xFF;
-           };
-         } else {
-           itemSize = 2;
-           itemDecode = function fontItemDecode(data, offset) {
-             return (data[offset] << 9) | (data[offset + 1] << 1);
-           };
-           itemEncode = function fontItemEncode(data, offset, value) {
-             data[offset] = (value >> 9) & 0xFF;
-             data[offset + 1] = (value >> 1) & 0xFF;
-           };
-         }
-         var locaData = loca.data;
-         // removing the invalid glyphs
-         var oldGlyfData = glyf.data;
-         var oldGlyfDataLength = oldGlyfData.length;
-         var newGlyfData = new Uint8Array(oldGlyfDataLength);
-         var startOffset = itemDecode(locaData, 0);
-         var writeOffset = 0;
-         itemEncode(locaData, 0, writeOffset);
-         for (var i = 0, j = itemSize; i < numGlyphs; i++, j += itemSize) {
-           var endOffset = itemDecode(locaData, j);
-           if (endOffset > oldGlyfDataLength) {
-             // glyph end offset points outside glyf data, rejecting the glyph
-             itemEncode(locaData, j, writeOffset);
-             startOffset = endOffset;
-             continue;
-           }
- 
-           var newLength = sanitizeGlyph(oldGlyfData, startOffset, endOffset,
-                                         newGlyfData, writeOffset);
-           writeOffset += newLength;
-           itemEncode(locaData, j, writeOffset);
-           startOffset = endOffset;
-         }
- 
-         if (writeOffset === 0) {
-           // glyf table cannot be empty -- redoing the glyf and loca tables
-           // 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)
-             itemEncode(locaData, j, simpleGlyph.length);
-           glyf.data = simpleGlyph;
-           return;
-         }
- 
-         glyf.data = newGlyfData.subarray(0, writeOffset);
-       }
- 
-       function findEmptyGlyphs(locaTable, isGlyphLocationsLong, emptyGlyphIds) {
-         var itemSize, itemDecode;
-         if (isGlyphLocationsLong) {
-           itemSize = 4;
-           itemDecode = function fontItemDecodeLong(data, offset) {
-             return (data[offset] << 24) | (data[offset + 1] << 16) |
-                    (data[offset + 2] << 8) | data[offset + 3];
-           };
-         } else {
-           itemSize = 2;
-           itemDecode = function fontItemDecode(data, offset) {
-             return (data[offset] << 9) | (data[offset + 1] << 1);
-           };
-         }
-         var data = locaTable.data, length = data.length;
-         var lastOffset = itemDecode(data, 0);
-         for (var i = itemSize, j = 0; i < length; i += itemSize, j++) {
-           var offset = itemDecode(data, i);
-           if (offset == lastOffset)
-             emptyGlyphIds[j] = true;
-           lastOffset = offset;
-         }
-       }
- 
-       function readPostScriptTable(post, properties, maxpNumGlyphs) {
-         var start = (font.start ? font.start : 0) + post.offset;
-         font.pos = start;
- 
-         var length = post.length, end = start + length;
-         var version = int32(font.getBytes(4));
-         // skip rest to the tables
-         font.getBytes(28);
- 
-         var glyphNames;
-         var valid = true;
-         switch (version) {
-           case 0x00010000:
-             glyphNames = MacStandardGlyphOrdering;
-             break;
-           case 0x00020000:
-             var numGlyphs = int16(font.getBytes(2));
-             if (numGlyphs != maxpNumGlyphs) {
-               valid = false;
-               break;
-             }
-             var glyphNameIndexes = [];
-             for (var i = 0; i < numGlyphs; ++i) {
-               var index = int16(font.getBytes(2));
-               if (index >= 32768) {
-                 valid = false;
-                 break;
-               }
-               glyphNameIndexes.push(index);
-             }
-             if (!valid) {
-               break;
-             }
-             var customNames = [];
-             while (font.pos < end) {
-               var stringLength = font.getByte();
-               var string = '';
-               for (var i = 0; i < stringLength; ++i)
-                 string += font.getChar();
-               customNames.push(string);
-             }
-             glyphNames = [];
-             for (var i = 0; i < numGlyphs; ++i) {
-               var j = glyphNameIndexes[i];
-               if (j < 258) {
-                 glyphNames.push(MacStandardGlyphOrdering[j]);
-                 continue;
-               }
-               glyphNames.push(customNames[j - 258]);
-             }
-             break;
-           case 0x00030000:
-             break;
-           default:
-             warn('Unknown/unsupported post table version ' + version);
-             valid = false;
-             break;
-         }
-         properties.glyphNames = glyphNames;
-         return valid;
-       }
- 
-       function readNameTable(nameTable) {
-         var start = (font.start ? font.start : 0) + nameTable.offset;
-         font.pos = start;
- 
-         var names = [[], []];
-         var length = nameTable.length, end = start + length;
-         var format = int16(font.getBytes(2));
-         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 records = [];
-         var NAME_RECORD_LENGTH = 12;
-         for (var 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))
-           };
-           // 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)) {
-             records.push(r);
-           }
-         }
-         for (var i = 0, ii = records.length; i < ii; i++) {
-           var record = records[i];
-           var pos = start + stringsStart + record.offset;
-           if (pos + record.length > end) {
-             continue; // outside of name table, ignoring
-           }
-           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)));
-             }
-             names[1][nameIndex] = str;
-           } else {
-             names[0][nameIndex] = bytesToString(font.getBytes(record.length));
-           }
-         }
-         return names;
-       }
- 
-       var TTOpsStackDeltas = [
-         0, 0, 0, 0, 0, 0, 0, 0, -2, -2, -2, -2, 0, 0, -2, -5,
-         -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, -1, 0, -1, -1, -1, -1,
-         1, -1, -999, 0, 1, 0, 0, -2, 0, -1, -2, -1, -999, -999, -1, -1,
-         0, 0, -999, -999, -1, -1, -1, -1, -2, -999, -2, -2, -2, 0, -2, -2,
-         0, 0, -2, 0, -2, 0, 0, 0, -2, -1, -1, 1, 1, 0, 0, -1,
-         -1, -1, -1, -1, -1, -1, 0, 0, -1, 0, -1, -1, 0, -999, -1, -1,
-         -1, -1, -1, -1, 0, 0, 0, 0, -1, -1, 0, 0, 0, 0, 0, 0,
-         -2, -999, -999, -999, -999, -999, -1, -1, -2, -2, 0, 0, 0, 0, -1, -1,
-         -999, -2, -2, 0, 0, -1, -2, -2, 0, -999, 0, 0, 0, -1, -2];
-         // 0xC0-DF == -1 and 0xE0-FF == -2
- 
-       function sanitizeTTProgram(table, ttContext) {
-         var data = table.data;
-         var i = 0, n, lastEndf = 0, lastDeff = 0;
-         var stack = [];
-         var tooComplexToFollowFunctions =
-           ttContext.tooComplexToFollowFunctions;
-         for (var ii = data.length; i < ii;) {
-           var op = data[i++];
-           // The TrueType instruction set docs can be found at
-           // https://developer.apple.com/fonts/TTRefMan/RM05/Chap5.html
-           if (op === 0x40) { // NPUSHB - pushes n bytes
-             n = data[i++];
-             for (var j = 0; j < n; j++) {
-               stack.push(data[i++]);
-             }
-           } else if (op === 0x41) { // NPUSHW - pushes n words
-             n = data[i++];
-             for (var j = 0; j < n; j++) {
-               var b = data[i++];
-               stack.push((b << 8) | data[i++]);
-             }
-           } else if ((op & 0xF8) === 0xB0) { // PUSHB - pushes bytes
-             n = op - 0xB0 + 1;
-             for (var j = 0; j < n; j++) {
-               stack.push(data[i++]);
-             }
-           } else if ((op & 0xF8) === 0xB8) { // PUSHW - pushes words
-             n = op - 0xB8 + 1;
-             for (var j = 0; j < n; j++) {
-               var b = data[i++];
-               stack.push((b << 8) | data[i++]);
-             }
-           } else if (op === 0x2B && !tooComplexToFollowFunctions) { // CALL
-             // collecting inforamtion about which functions are used
-             var funcId = stack[stack.length - 1];
-             ttContext.functionsUsed[funcId] = true;
-             if (i >= 2 && data[i - 2] === 0x2B) {
-               // all data in stack, calls are performed in sequence
-               tooComplexToFollowFunctions = true;
-             }
-           } else if (op === 0x2C && !tooComplexToFollowFunctions) { // FDEF
-             // collecting inforamtion about which functions are defined
-             lastDeff = i;
-             var funcId = stack[stack.length - 1];
-             ttContext.functionsDefined[funcId] = true;
-             if (i >= 2 && data[i - 2] === 0x2D) {
-               // all function ids in stack, FDEF/ENDF perfomed in sequence
-               tooComplexToFollowFunctions = true;
-             }
-           } else if (op === 0x2D) { // ENDF - end of function
-             lastEndf = i;
-           } else if (op === 0x89) { // IDEF - instruction definition
-             // recording it as a function to track ENDF
-             lastDeff = i;
-           }
-           // Adjusting stack not extactly, but just enough to get function id
-           var stackDelta = op <= 0x8E ? TTOpsStackDeltas[op] :
-             op >= 0xC0 && op <= 0xDF ? -1 : op >= 0xE0 ? -2 : 0;
-           while (stackDelta < 0 && stack.length > 0) {
-             stack.pop();
-             stackDelta++;
-           }
-           while (stackDelta > 0) {
-             stack.push(NaN); // pushing any number into stack
-             stackDelta--;
-           }
-         }
-         ttContext.tooComplexToFollowFunctions = tooComplexToFollowFunctions;
-         var content = [data];
-         if (i > data.length) {
-           content.push(new Uint8Array(i - data.length));
-         }
-         if (lastDeff > lastEndf) {
-           // new function definition started, but not finished
-           // complete function by [CLEAR, ENDF]
-           content.push(new Uint8Array([0x22, 0x2D]));
-         }
-         if (ttContext.defineMissingFunctions && !tooComplexToFollowFunctions) {
-           for (var j = 0, jj = ttContext.functionsUsed.length; j < jj; j++) {
-             if (!ttContext.functionsUsed[j] || ttContext.functionsDefined[j]) {
-               continue;
-             }
-             // function is used, but not defined
-             // creating empty one [PUSHB, function-id, FDEF, ENDF]
-             content.push(new Uint8Array([0xB0, j, 0x2C, 0x2D]));
-           }
-         }
-         if (content.length > 1) {
-           // concatenating the content items
-           var newLength = 0;
-           for (var 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++) {
-             result.set(content[j], pos);
-             pos += content[j].length;
-           }
-           table.data = result;
-           table.length = newLength;
-         }
-       }
- 
-       function sanitizeTTPrograms(fpgm, prep) {
-         var ttContext = {
-           functionsDefined: [],
-           functionsUsed: [],
-           tooComplexToFollowFunctions: false
-         };
-         if (prep) {
-           // collecting prep functions info first
-           sanitizeTTProgram(prep, ttContext);
-         }
-         if (fpgm) {
-           ttContext.defineMissingFunctions = true;
-           sanitizeTTProgram(fpgm, ttContext);
-         }
-       }
- 
-       // Check that required tables are present
-       var requiredTables = ['OS/2', 'cmap', 'head', 'hhea',
-                              'hmtx', 'maxp', 'name', 'post'];
- 
-       var header = readOpenTypeHeader(font);
-       var numTables = header.numTables;
- 
-       var cmap, post, maxp, hhea, hmtx, head, os2;
-       var glyf, fpgm, loca, prep, cvt;
-       var tables = [];
-       for (var i = 0; i < numTables; i++) {
-         var table = readTableEntry(font);
-         var index = requiredTables.indexOf(table.tag);
-         if (index != -1) {
-           if (table.tag == 'cmap')
-             cmap = table;
-           else if (table.tag == 'post')
-             post = table;
-           else if (table.tag == 'maxp')
-             maxp = table;
-           else if (table.tag == 'hhea')
-             hhea = table;
-           else if (table.tag == 'hmtx')
-             hmtx = table;
-           else if (table.tag == 'head')
-             head = table;
-           else if (table.tag == 'OS/2')
-             os2 = table;
- 
-           requiredTables.splice(index, 1);
-         } else {
-           if (table.tag == 'loca')
-             loca = table;
-           else if (table.tag == 'glyf')
-             glyf = table;
-           else if (table.tag == 'fpgm')
-             fpgm = table;
-           else if (table.tag == 'prep')
-             prep = table;
-           else if (table.tag == 'cvt ')
-             cvt = table;
-           else if (table.tag == 'CFF ')
-             return null; // XXX: OpenType font is found, stopping
-           else // skipping table if it's not a required or optional table
-             continue;
-         }
-         tables.push(table);
-       }
- 
-       var numTables = tables.length + requiredTables.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
-       font.pos = (font.start || 0) + maxp.offset;
-       var version = int16(font.getBytes(4));
-       var numGlyphs = int16(font.getBytes(2));
- 
-       sanitizeMetrics(font, hhea, hmtx, numGlyphs);
- 
-       sanitizeTTPrograms(fpgm, prep);
- 
-       if (head) {
-         sanitizeHead(head, numGlyphs, loca.length);
-       }
- 
-       var isGlyphLocationsLong = int16([head.data[50], head.data[51]]);
-       if (head && loca && glyf) {
-         sanitizeGlyphLocations(loca, glyf, numGlyphs, isGlyphLocationsLong);
-       }
- 
-       var emptyGlyphIds = [];
-       if (glyf)
-         findEmptyGlyphs(loca, isGlyphLocationsLong, emptyGlyphIds);
- 
-       // Sanitizer reduces the glyph advanceWidth to the maxAdvanceWidth
-       // Sometimes it's 0. That needs to be fixed
-       if (hhea.data[10] === 0 && hhea.data[11] === 0) {
-         hhea.data[10] = 0xFF;
-         hhea.data[11] = 0xFF;
-       }
- 
-       // The 'post' table has glyphs names.
-       if (post) {
-         var valid = readPostScriptTable(post, properties, numGlyphs);
-         if (!valid) {
-           tables.splice(tables.indexOf(post), 1);
-           post = null;
-         }
-       }
- 
-       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 (!cmap) {
-           cmap = {
-             tag: 'cmap',
-             data: null
-           };
-           tables.push(cmap);
-         }
- 
-         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;
-           }
-           // 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++;
-           }
-         }
- 
-         glyphs = [];
-         ids = [];
- 
-         var usedUnicodes = [];
-         var unassignedUnicodeItems = [];
-         var toFontChar = this.cidToFontChar || this.toFontChar;
-         for (var i = 1; i < numGlyphs; i++) {
-           var cid = gidToCidMap[i] || 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] || 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);
-           }
-         }
-       } 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(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 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);
- 
-           if (!unicode) {
-             // TODO(mack): gotta check if skipping mappings where we cannot find
-             // a unicode is the correct behaviour
-             continue;
-           }
-           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;
-           }
++  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;
 +        }
- 
-         // 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)) {
-               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];
-             }
- 
-             // Finally, any undefined entries in the table shall be filled
-             // using StandardEncoding
-             if (!glyphName) {
-               glyphName = Encodings.StandardEncoding[charcode];
++        switch (operator) {
++          // non standard ps operators
++          case 'jz': // jump if false
++            b = stack.pop();
++            a = stack.pop();
++            if (!a) {
++              counter = b;
 +            }
- 
-             // 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;
-           }
-         }
-         this.toFontChar = toFontChar = newToFontChar;
- 
-         createGlyphNameMap(glyphs, ids, properties);
-         this.glyphNameMap = properties.glyphNameMap;
-       }
- 
-       if (glyphs.length === 0) {
-         // defines at least one glyph
-         glyphs.push({ unicode: 0xF000, code: 0xF000, glyph: '.notdef' });
-         ids.push(0);
-       }
- 
-       // Converting glyphs and ids into font's cmap table
-       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;
- 
-       if (os2 && !validateOS2Table(os2)) {
-         tables.splice(tables.indexOf(os2), 1);
-         os2 = null;
-       }
- 
-       if (!os2) {
-         // extract some more font properties from the OpenType head and
-         // hhea tables; yMin and descent value are always negative
-         var override = {
-           unitsPerEm: int16([head.data[18], head.data[19]]),
-           yMax: int16([head.data[42], head.data[43]]),
-           yMin: int16([head.data[38], head.data[39]]) - 0x10000,
-           ascent: int16([hhea.data[4], hhea.data[5]]),
-           descent: int16([hhea.data[6], hhea.data[7]]) - 0x10000
-         };
- 
-         tables.push({
-           tag: 'OS/2',
-           data: stringToArray(createOS2Table(properties, glyphs, override))
-         });
-       }
- 
-       // Rewrite the 'post' table if needed
-       if (!post) {
-         tables.push({
-           tag: 'post',
-           data: stringToArray(createPostTable(properties))
-         });
-       }
- 
-       // Re-creating 'name' table
-       if (requiredTables.indexOf('name') != -1) {
-         tables.push({
-           tag: 'name',
-           data: stringToArray(createNameTable(this.name))
-         });
-       } else {
-         // ... using existing 'name' table as prototype
-         for (var i = 0, ii = tables.length; i < ii; i++) {
-           var table = tables[i];
-           if (table.tag === 'name') {
-             var namePrototype = readNameTable(table);
-             table.data = stringToArray(createNameTable(name, namePrototype));
 +            break;
-           }
-         }
-       }
- 
-       // Tables needs to be written by ascendant alphabetic order
-       tables.sort(function tables_sort(a, b) {
-         return (a.tag > b.tag) - (a.tag < b.tag);
-       });
- 
-       // rewrite the tables but tweak offsets
-       for (var i = 0, ii = tables.length; i < ii; i++) {
-         var table = tables[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);
-       }
- 
-       // Add the table datas
-       for (var i = 0, ii = tables.length; i < ii; i++) {
-         var table = tables[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);
-     },
- 
-     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;
-         }
-         return true;
-       }
- 
-       // 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;
-       }
-       this.glyphNameMap = glyphNameMap;
- 
-       var seacs = font.seacs;
-       if (SEAC_ANALYSIS_ENABLED && seacs) {
-         var seacMap = [];
-         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 baseGlyphName = Encodings.StandardEncoding[seac[2]];
-           var baseUnicode = glyphNameMap[baseGlyphName];
-           var accentGlyphName = Encodings.StandardEncoding[seac[3]];
-           var accentUnicode = glyphNameMap[accentGlyphName];
-           if (!baseUnicode || !accentUnicode) {
-             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
-           };
-         }
-         properties.seacMap = seacMap;
-       }
- 
-       if (!properties.hasEncoding && (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,
- 
-         // OS/2 and Windows Specific metrics
-         'OS/2': stringToArray(createOS2Table(properties, charstrings)),
- 
-         // 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() {
-           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;
-             hmtx += string16(width) + string16(0);
-           }
-           return stringToArray(hmtx);
-         })(),
- 
-         // Maximum profile
-         'maxp': (function fontFieldsMaxp() {
-           return stringToArray(
-               '\x00\x00\x50\x00' + // Version number
-              string16(charstrings.length + 1)); // Num of glyphs
-         })(),
- 
-         // Naming tables
-         'name': stringToArray(createNameTable(fontName)),
- 
-         // PostScript informations
-         'post': stringToArray(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);
-     },
- 
-     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')
-           result[i] = fontCharCode;
-       }
-       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 ? i : toUnicode[i];
-         }
-       } 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] = 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) {
-           TODO('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];
-       }
++          case 'j': // jump
++            a = stack.pop();
++            counter = a;
++            break;
 +
-       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;
++          // 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);
 +            }
-           }
-           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;
-               }
-               cid++;
-               k++;
++            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);
 +            }
-           } else
-             cid += unicode.s;
-         } else if (unicode) {
-           cidToUnicodeMap[cid] = unicode;
-           if (!unicodeToCIDMap[unicode] || overwrite) {
-             unicodeToCIDMap[unicode] = cid;
-           }
-           cid++;
-         } else
-           cid++;
-       }
- 
-       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 = [];
-       }
-     },
- 
-     bindDOM: function Font_bindDOM() {
-       if (!this.data)
-         return null;
- 
-       var data = bytesToString(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 + '}';
- 
-       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);
-       }
- 
-       var styleSheet = styleElement.sheet;
-       styleSheet.insertRule(rule, styleSheet.cssRules.length);
- 
-       if (PDFJS.pdfBug && 'FontInspector' in globalScope &&
-           globalScope['FontInspector'].enabled)
-         globalScope['FontInspector'].fontAdded(this, url);
- 
-       return rule;
-     },
- 
-     get spaceWidth() {
-       if ('_shadowWidth' in this) {
-         return this._shadowWidth;
-       }
- 
-       // trying to estimate space character width
-       var possibleSpaceReplacements = ['space', 'minus', 'one', 'i'];
-       var width;
-       for (var i = 0, ii = possibleSpaceReplacements.length; i < ii; i++) {
-         var glyphName = possibleSpaceReplacements[i];
-         // if possible, getting width by glyph name
-         if (glyphName in this.widths) {
-           width = this.widths[glyphName];
-           break;
-         }
-         var glyphUnicode = GlyphsUnicode[glyphName];
-         // finding the charcode via unicodeToCID map
-         var charcode = 0;
-         if (this.composite)
-           charcode = this.unicodeToCID[glyphUnicode];
-         // ... via toUnicode map
-         if (!charcode && 'toUnicode' in this)
-           charcode = this.toUnicode.indexOf(glyphUnicode);
-         // setting it to unicode if negative or undefined
-         if (charcode <= 0)
-           charcode = glyphUnicode;
-         // trying to get width via charcode
-         width = this.widths[charcode];
-         if (width)
-           break; // the non-zero width found
-       }
-       width = width || this.defaultWidth;
-       // Do not shadow the property here. See discussion:
-       // https://github.com/mozilla/pdf.js/pull/2127#discussion_r1662280
-       this._shadowWidth = width;
-       return width;
-     },
- 
-     charToGlyph: function Font_charToGlyph(charcode) {
-       var fontCharCode, width, operatorList, disabled;
- 
-       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;
++          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;
-           }
-           fontCharCode = this.toFontChar[charcode] || charcode;
-           break;
-         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);
++          case 'lt':
++            b = stack.pop();
++            a = stack.pop();
++            stack.push(a < b);
 +            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;
++          case 'mod':
++            b = stack.pop();
++            a = stack.pop();
++            stack.push(a % b);
 +            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;
++          case 'mul':
++            b = stack.pop();
++            a = stack.pop();
++            stack.push(a * b);
 +            break;
-           }
-           if (!this.hasEncoding || this.isSymbolicFont) {
-             fontCharCode = this.useToFontChar ? this.toFontChar[charcode] :
-               charcode;
++          case 'ne':
++            b = stack.pop();
++            a = stack.pop();
++            stack.push(a != b);
 +            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 unicodeChars = !('toUnicode' in this) ? charcode :
-         this.toUnicode[charcode] || charcode;
-       if (typeof unicodeChars === 'number') {
-         unicodeChars = String.fromCharCode(unicodeChars);
-       }
- 
-       width = isNum(width) ? width : this.defaultWidth;
-       disabled = this.unicodeIsEnabled ?
-         !this.unicodeIsEnabled[fontCharCode] : false;
- 
-       var accent = null;
-       if (this.seacMap && this.seacMap[fontCharCode]) {
-         var seac = this.seacMap[fontCharCode];
-         fontCharCode = seac.baseUnicode;
-         accent = {
-           fontChar: String.fromCharCode(seac.accentUnicode),
-           offset: seac.accentOffset
-         };
-       }
- 
-       return {
-         fontChar: String.fromCharCode(fontCharCode),
-         unicode: unicodeChars,
-         accent: accent,
-         width: width,
-         vmetric: vmetric,
-         disabled: disabled,
-         operatorList: operatorList
-       };
-     },
- 
-     charsToGlyphs: function Font_charsToGlyphs(chars) {
-       var charsCache = this.charsCache;
-       var glyphs;
- 
-       // if we translated this string before, just grab it from the cache
-       if (charsCache) {
-         glyphs = charsCache[chars];
-         if (glyphs)
-           return glyphs;
-       }
- 
-       // lazily create the translation cache
-       if (!charsCache)
-         charsCache = this.charsCache = Object.create(null);
- 
-       glyphs = [];
-       var charsCacheKey = chars;
- 
-       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.wideChars) {
-         // composite fonts have multi-byte strings convert the string from
-         // single-byte to multi-byte
-         // XXX assuming CIDFonts are two-byte - later need to extract the
-         // correct byte encoding according to the PDF spec
-         var length = chars.length - 1; // looping over two bytes at a time so
-                                        // loop should never end on the last byte
-         for (var i = 0; i < length; i++) {
-           var charcode = int16([chars.charCodeAt(i++), chars.charCodeAt(i)]);
-           var glyph = this.charToGlyph(charcode);
-           glyphs.push(glyph);
-           // placing null after each word break charcode (ASCII SPACE)
-           if (charcode == 0x20)
-             glyphs.push(null);
-         }
-       }
-       else {
-         for (var i = 0, ii = chars.length; i < ii; ++i) {
-           var charcode = chars.charCodeAt(i);
-           var glyph = this.charToGlyph(charcode);
-           glyphs.push(glyph);
-           if (charcode == 0x20)
-             glyphs.push(null);
-         }
-       }
- 
-       // Enter the translated string into the cache
-       return (charsCache[charsCacheKey] = glyphs);
-     }
-   };
- 
-   return Font;
- })();
- 
- var ErrorFont = (function ErrorFontClosure() {
-   function ErrorFont(error) {
-     this.error = error;
-   }
- 
-   ErrorFont.prototype = {
-     charsToGlyphs: function ErrorFont_charsToGlyphs() {
-       return [];
-     },
-     exportData: function ErrorFont_exportData() {
-       return {error: this.error};
-     }
-   };
- 
-   return ErrorFont;
- })();
- 
- /*
-  * CharStrings are encoded following the the CharString Encoding sequence
-  * describe in Chapter 6 of the "Adobe Type1 Font Format" specification.
-  * The value in a byte indicates a command, a number, or subsequent bytes
-  * that are to be interpreted in a special way.
-  *
-  * CharString Number Encoding:
-  *  A CharString byte containing the values from 32 through 255 inclusive
-  *  indicate an integer. These values are decoded in four ranges.
-  *
-  * 1. A CharString byte containing a value, v, between 32 and 246 inclusive,
-  * indicate the integer v - 139. Thus, the integer values from -107 through
-  * 107 inclusive may be encoded in single byte.
-  *
-  * 2. A CharString byte containing a value, v, between 247 and 250 inclusive,
-  * indicates an integer involving the next byte, w, according to the formula:
-  * [(v - 247) x 256] + w + 108
-  *
-  * 3. A CharString byte containing a value, v, between 251 and 254 inclusive,
-  * indicates an integer involving the next byte, w, according to the formula:
-  * -[(v - 251) * 256] - w - 108
-  *
-  * 4. A CharString containing the value 255 indicates that the next 4 bytes
-  * are a two complement signed integer. The first of these bytes contains the
-  * highest order bits, the second byte contains the next higher order bits
-  * and the fourth byte contain the lowest order bits.
-  *
-  *
-  * CharString Command Encoding:
-  *  CharStrings commands are encoded in 1 or 2 bytes.
-  *
-  *  Single byte commands are encoded in 1 byte that contains a value between
-  *  0 and 31 inclusive.
-  *  If a command byte contains the value 12, then the value in the next byte
-  *  indicates a command. This "escape" mechanism allows many extra commands
-  * to be encoded and this encoding technique helps to minimize the length of
-  * the charStrings.
-  */
- var Type1CharString = (function Type1CharStringClosure() {
-   var COMMAND_MAP = {
-     'hstem': [1],
-     'vstem': [3],
-     'vmoveto': [4],
-     'rlineto': [5],
-     'hlineto': [6],
-     'vlineto': [7],
-     'rrcurveto': [8],
-     'callsubr': [10],
-     'flex': [12, 35],
-     'drop' : [12, 18],
-     'endchar': [14],
-     'rmoveto': [21],
-     'hmoveto': [22],
-     'vhcurveto': [30],
-     'hvcurveto': [31]
-   };
- 
-   function Type1CharString() {
-     this.width = 0;
-     this.lsb = 0;
-     this.flexing = false;
-     this.output = [];
-     this.stack = [];
-   }
- 
-   Type1CharString.prototype = {
-     convert: function Type1CharString_convert(encoded, subrs) {
-       var count = encoded.length;
-       var error = false;
-       for (var i = 0; i < count; i++) {
-         var value = encoded[i];
-         if (value < 32) {
-           if (value === 12) {
-             value = (value << 8) + encoded[++i];
-           }
-           switch (value) {
-             case 1: // hstem
-               if (!HINTING_ENABLED) {
-                 this.stack = [];
-                 break;
-               }
-               error = this.executeCommand(2, COMMAND_MAP.hstem);
-               break;
-             case 3: // vstem
-               if (!HINTING_ENABLED) {
-                 this.stack = [];
-                 break;
-               }
-               error = this.executeCommand(2, COMMAND_MAP.vstem);
-               break;
-             case 4: // vmoveto
-               if (this.flexing) {
-                 if (this.stack.length < 1) {
-                   error = true;
-                   break;
-                 }
-                 // Add the dx for flex and but also swap the values so they are
-                 // the right order.
-                 var dy = this.stack.pop();
-                 this.stack.push(0, dy);
-                 break;
-               }
-               error = this.executeCommand(1, COMMAND_MAP.vmoveto);
-               break;
-             case 5: // rlineto
-               error = this.executeCommand(2, COMMAND_MAP.rlineto);
-               break;
-             case 6: // hlineto
-               error = this.executeCommand(1, COMMAND_MAP.hlineto);
-               break;
-             case 7: // vlineto
-               error = this.executeCommand(1, COMMAND_MAP.vlineto);
-               break;
-             case 8: // rrcurveto
-               error = this.executeCommand(6, COMMAND_MAP.rrcurveto);
-               break;
-             case 9: // closepath
-               // closepath is a Type1 command that does not take argument and is
-               // useless in Type2 and it can simply be ignored.
-               this.stack = [];
-               break;
-             case 10: // callsubr
-               if (this.stack.length < 1) {
-                 error = true;
-                 break;
-               }
-               var subrNumber = this.stack.pop();
-               error = this.convert(subrs[subrNumber], subrs);
-               break;
-             case 11: // return
-               return error;
-             case 13: // hsbw
-               if (this.stack.length < 2) {
-                 error = true;
-                 break;
-               }
-               // 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();
-               this.lsb = sbx;
-               this.width = wx;
-               this.stack.push(sbx);
-               error = this.executeCommand(1, COMMAND_MAP.hmoveto);
-               break;
-             case 14: // endchar
-               this.output.push(COMMAND_MAP.endchar[0]);
-               break;
-             case 21: // rmoveto
-               if (this.flexing) {
-                 break;
-               }
-               error = this.executeCommand(2, COMMAND_MAP.rmoveto);
-               break;
-             case 22: // hmoveto
-               if (this.flexing) {
-                 // Add the dy for flex.
-                 this.stack.push(0);
-                 break;
-               }
-               error = this.executeCommand(1, COMMAND_MAP.hmoveto);
-               break;
-             case 30: // vhcurveto
-               error = this.executeCommand(4, COMMAND_MAP.vhcurveto);
-               break;
-             case 31: // hvcurveto
-               error = this.executeCommand(4, COMMAND_MAP.hvcurveto);
-               break;
-             case (12 << 8) + 0: // dotsection
-               // dotsection is a Type1 command to specify some hinting feature
-               // for dots that do not take a parameter and it can safely be
-               // ignored for Type2.
-               this.stack = [];
-               break;
-             case (12 << 8) + 1: // vstem3
-               if (!HINTING_ENABLED) {
-                 this.stack = [];
-                 break;
-               }
-               // [vh]stem3 are Type1 only and Type2 supports [vh]stem with
-               // multiple parameters, so instead of returning [vh]stem3 take a
-               // shortcut and return [vhstem] instead.
-               error = this.executeCommand(2, COMMAND_MAP.vstem);
-               break;
-             case (12 << 8) + 2: // hstem3
-               if (!HINTING_ENABLED) {
-                  this.stack = [];
-                 break;
-               }
-               // See vstem3.
-               error = this.executeCommand(2, COMMAND_MAP.hstem);
-               break;
-             case (12 << 8) + 6: // seac
-               // seac is like type 2's special endchar but it doesn't use the
-               // first argument asb, so remove it.
-               if (SEAC_ANALYSIS_ENABLED) {
-                 this.seac = this.stack.splice(-4, 4);
-                 error = this.executeCommand(0, COMMAND_MAP.endchar);
-               } else {
-                 error = this.executeCommand(4, COMMAND_MAP.endchar);
-               }
-               break;
-             case (12 << 8) + 7: // sbw
-               if (this.stack.length < 4) {
-                 error = true;
-                 break;
-               }
-               // To convert to type2 we have to move the width value to the
-               // first part of the charstring and then use rmoveto with
-               // (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();
-               var sby = this.stack.pop();
-               var sbx = this.stack.pop();
-               this.lsb = sbx;
-               this.width = wx;
-               this.stack.push(sbx, sby);
-               error = this.executeCommand(2, COMMAND_MAP.rmoveto);
-               break;
-             case (12 << 8) + 12: // div
-               if (this.stack.length < 2) {
-                 error = true;
-                 break;
-               }
-               var num2 = this.stack.pop();
-               var num1 = this.stack.pop();
-               this.stack.push(num1 / num2);
-               break;
-             case (12 << 8) + 16: // callothersubr
-               if (this.stack.length < 2) {
-                 error = true;
-                 break;
-               }
-               var subrNumber = this.stack.pop();
-               var numArgs = this.stack.pop();
-               if (subrNumber === 0 && numArgs === 3) {
-                 var flexArgs = this.stack.splice(this.stack.length - 17, 17);
-                 this.stack.push(
-                   flexArgs[2] + flexArgs[0], // bcp1x + rpx
-                   flexArgs[3] + flexArgs[1], // bcp1y + rpy
-                   flexArgs[4], // bcp2x
-                   flexArgs[5], // bcp2y
-                   flexArgs[6], // p2x
-                   flexArgs[7], // p2y
-                   flexArgs[8], // bcp3x
-                   flexArgs[9], // bcp3y
-                   flexArgs[10], // bcp4x
-                   flexArgs[11], // bcp4y
-                   flexArgs[12], // p3x
-                   flexArgs[13], // p3y
-                   flexArgs[14] // flexDepth
-                   // 15 = finalx unused by flex
-                   // 16 = finaly unused by flex
-                 );
-                 error = this.executeCommand(13, COMMAND_MAP.flex, true);
-                 this.flexing = false;
-                 this.stack.push(flexArgs[15], flexArgs[16]);
-               } else if (subrNumber === 1 && numArgs === 0) {
-                 this.flexing = true;
-               }
-               break;
-             case (12 << 8) + 17: // pop
-               // Ignore this since it is only used with othersubr.
-               break;
-             case (12 << 8) + 33: // setcurrentpoint
-               // Ignore for now.
-               this.stack = [];
-               break;
-             default:
-               warn('Unknown type 1 charstring command of "' + value + '"');
-               break;
-           }
-           if (error) {
++          case 'neg':
++            a = stack.pop();
++            stack.push(-b);
 +            break;
-           }
-           continue;
-         } else if (value <= 246) {
-           value = value - 139;
-         } else if (value <= 250) {
-           value = ((value - 247) * 256) + encoded[++i] + 108;
-         } else if (value <= 254) {
-           value = -((value - 251) * 256) - encoded[++i] - 108;
-         } else {
-           value = (encoded[++i] & 0xff) << 24 | (encoded[++i] & 0xff) << 16 |
-                   (encoded[++i] & 0xff) << 8 | (encoded[++i] & 0xff) << 0;
-         }
-         this.stack.push(value);
-       }
-       return error;
-     },
- 
-     executeCommand: function(howManyArgs, command, keepStack) {
-       var stackLength = this.stack.length;
-       if (howManyArgs > stackLength) {
-         return true;
-       }
-       var start = stackLength - howManyArgs;
-       for (var i = start; i < stackLength; i++) {
-         var value = this.stack[i];
-         if (value === (value | 0)) { // int
-           this.output.push(28, (value >> 8) & 0xff, value & 0xff);
-         } else { // fixed point
-           value = (65536 * value) | 0;
-           this.output.push(255,
-                            (value >> 24) & 0xFF,
-                            (value >> 16) & 0xFF,
-                            (value >> 8) & 0xFF,
-                            value & 0xFF);
-         }
-       }
-       this.output.push.apply(this.output, command);
-       if (keepStack) {
-         this.stack.splice(start, howManyArgs);
-       } else {
-         this.stack = [];
-       }
-       return false;
-     }
-   };
- 
-   return Type1CharString;
- })();
- 
- /*
-  * Type1Parser encapsulate the needed code for parsing a Type1 font
-  * program. Some of its logic depends on the Type2 charstrings
-  * structure.
-  */
- var Type1Parser = function type1Parser() {
-   /*
-    * Decrypt a Sequence of Ciphertext Bytes to Produce the Original Sequence
-    * of Plaintext Bytes. The function took a key as a parameter which can be
-    * for decrypting the eexec block of for decoding charStrings.
-    */
-   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 = [];
- 
-     var value = '';
-     var count = stream.length;
-     for (var i = 0; i < count; i++) {
-       value = stream[i];
-       decryptedString[i] = value ^ (r >> 8);
-       r = ((value + r) * c1 + c2) & ((1 << 16) - 1);
-     }
-     return decryptedString.slice(discardNumber);
-   }
- 
-   /*
-    * Returns an object containing a Subrs array and a CharStrings
-    * array extracted from and eexec encrypted block of data
-    */
-   function readNumberArray(str, index) {
-     var start = index;
-     while (str[index++] != '[')
-       start++;
-     start++;
- 
-     var count = 0;
-     while (str[index++] != ']')
-       count++;
- 
-     str = str.substr(start, count);
- 
-     str = str.trim();
-     // Remove adjacent spaces
-     str = str.replace(/\s+/g, ' ');
- 
-     var array = str.split(' ');
-     for (var i = 0, ii = array.length; i < ii; i++)
-       array[i] = parseFloat(array[i] || 0);
-     return array;
-   }
- 
-   function readNumber(str, index) {
-     while (str[index] == ' ')
-       index++;
- 
-     var start = index;
- 
-     var count = 0;
-     while (str[index++] != ' ')
-       count++;
- 
-     return parseFloat(str.substr(start, count) || 0);
-   }
- 
-   function readBoolean(str, index) {
-     while (str[index] == ' ')
-       index++;
- 
-     var start = index;
- 
-     var count = 0;
-     var length = str.length;
-     while (index < length && str[index++] != ' ') {
-       count++;
-     }
- 
-     // Use 1 and 0 since that's what type2 charstrings use.
-     return str.substr(start, count) === 'true' ? 1 : 0;
-   }
- 
- 
-   function isSeparator(c) {
-     return c == ' ' || c == '\n' || c == '\x0d';
-   }
- 
-   this.extractFontProgram = function Type1Parser_extractFontProgram(stream) {
-     var eexec = decrypt(stream, EEXEC_ENCRYPT_KEY, 4);
-     var eexecStr = '';
-     for (var i = 0, ii = eexec.length; i < ii; i++)
-       eexecStr += String.fromCharCode(eexec[i]);
- 
-     var glyphsSection = false, subrsSection = false;
-     var subrs = [], charstrings = [];
-     var program = {
-       subrs: [],
-       charstrings: [],
-       properties: {
-         'privateData': {
-           'lenIV': 4
-         }
-       }
-     };
- 
-     var glyph = '';
-     var token = '';
-     var length = 0;
- 
-     var c = '';
-     var count = eexecStr.length;
-     for (var i = 0; i < count; i++) {
-       var getToken = function getToken() {
-         while (i < count && isSeparator(eexecStr[i]))
-           ++i;
- 
-         var token = '';
-         while (i < count && !isSeparator(eexecStr[i]))
-           token += eexecStr[i++];
- 
-         return token;
-       };
-       var c = eexecStr[i];
- 
-       if ((glyphsSection || subrsSection) &&
-           (token == 'RD' || token == '-|')) {
-         i++;
-         var data = eexec.slice(i, i + length);
-         var lenIV = program.properties.privateData['lenIV'];
-         var encoded = decrypt(data, CHAR_STRS_ENCRYPT_KEY, lenIV);
- 
-         if (glyphsSection) {
-           charstrings.push({
-             glyph: glyph,
-             encoded: encoded
-           });
-         } else {
-           subrs.push(encoded);
-         }
-         i += length;
-         token = '';
-       } else if (isSeparator(c)) {
-         // Use '| 0' to prevent setting a double into length such as the double
-         // does not flow into the loop variable.
-         length = parseInt(token, 10) | 0;
-         token = '';
-       } else {
-         token += c;
-         if (!glyphsSection) {
-           switch (token) {
-             case '/CharString':
-               glyphsSection = true;
-               break;
-             case '/Subrs':
-               ++i;
-               var num = parseInt(getToken(), 10);
-               getToken(); // read in 'array'
-               for (var j = 0; j < num; ++j) {
-                 var t = getToken(); // read in 'dup'
-                 if (t == 'ND' || t == '|-' || t == 'noaccess')
-                   break;
-                 var index = parseInt(getToken(), 10);
-                 if (index > j)
-                   j = index;
-                 var length = parseInt(getToken(), 10);
-                 getToken(); // read in 'RD'
-                 var data = eexec.slice(i + 1, i + 1 + length);
-                 var lenIV = program.properties.privateData['lenIV'];
-                 var encoded = decrypt(data, CHAR_STRS_ENCRYPT_KEY, lenIV);
-                 i = i + 1 + length;
-                 t = getToken(); // read in 'NP'
-                 if (t == 'noaccess')
-                   getToken(); // read in 'put'
-                 subrs[index] = encoded;
-               }
-               break;
-             case '/BlueValues':
-             case '/OtherBlues':
-             case '/FamilyBlues':
-             case '/FamilyOtherBlues':
-               var blueArray = readNumberArray(eexecStr, i + 1);
-               // *Blue* values may contain invalid data: disables reading of
-               // those values when hinting is disabled.
-               if (blueArray.length > 0 && (blueArray.length % 2) === 0 &&
-                   HINTING_ENABLED) {
-                 program.properties.privateData[token.substring(1)] = blueArray;
-               }
-               break;
-             case '/StemSnapH':
-             case '/StemSnapV':
-               program.properties.privateData[token.substring(1)] =
-                 readNumberArray(eexecStr, i + 1);
-               break;
-             case '/StdHW':
-             case '/StdVW':
-               program.properties.privateData[token.substring(1)] =
-                 readNumberArray(eexecStr, i + 1)[0];
-               break;
-             case '/BlueShift':
-             case '/lenIV':
-             case '/BlueFuzz':
-             case '/BlueScale':
-             case '/LanguageGroup':
-             case '/ExpansionFactor':
-               program.properties.privateData[token.substring(1)] =
-                 readNumber(eexecStr, i + 1);
-               break;
-             case '/ForceBold':
-               program.properties.privateData[token.substring(1)] =
-                 readBoolean(eexecStr, i + 1);
-               break;
-           }
-         } else if (c == '/') {
-           token = glyph = '';
-           while ((c = eexecStr[++i]) != ' ')
-             glyph += c;
-         }
-       }
-     }
- 
-     for (var i = 0; i < charstrings.length; i++) {
-       var glyph = charstrings[i].glyph;
-       var encoded = charstrings[i].encoded;
-       var charString = new Type1CharString();
-       var error = charString.convert(encoded, subrs);
-       var output = charString.output;
-       if (error) {
-         // It seems when FreeType encounters an error while evaluating a glyph
-         // that it completely ignores the glyph so we'll mimic that behaviour
-         // here and put an endchar to make the validator happy.
-         output = [14];
-       }
-       program.charstrings.push({
-         glyph: glyph,
-         data: output,
-         seac: charString.seac,
-         lsb: charString.lsb,
-         width: charString.width
-       });
-     }
- 
-     return program;
-   };
- 
-   this.extractFontHeader = function Type1Parser_extractFontHeader(stream,
-                                                                   properties) {
-     var headerString = '';
-     for (var i = 0, ii = stream.length; i < ii; i++)
-       headerString += String.fromCharCode(stream[i]);
- 
-     var token = '';
-     var count = headerString.length;
-     for (var i = 0; i < count; i++) {
-       var getToken = function getToken() {
-         var character = headerString[i];
-         while (i < count && (isSeparator(character) || character == '/'))
-           character = headerString[++i];
- 
-         var token = '';
-         while (i < count && !(isSeparator(character) || character == '/')) {
-           token += character;
-           character = headerString[++i];
-         }
- 
-         return token;
-       };
- 
-       var c = headerString[i];
-       if (isSeparator(c)) {
-         switch (token) {
-           case '/FontMatrix':
-             var matrix = readNumberArray(headerString, i + 1);
-             properties.fontMatrix = matrix;
++          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 '/Encoding':
-             var encodingArg = getToken();
-             var encoding;
-             if (!/^\d+$/.test(encodingArg)) {
-               // encoding name is specified
-               encoding = Encodings[encodingArg];
++          case 'xor':
++            b = stack.pop();
++            a = stack.pop();
++            if (isBool(a) && isBool(b)) {
++              stack.push(a != b);
 +            } else {
-               encoding = [];
-               var size = parseInt(encodingArg, 10);
-               getToken(); // read in 'array'
- 
-               for (var j = 0; j < size; j++) {
-                 var token = getToken();
-                 if (token == 'dup') {
-                   var index = parseInt(getToken(), 10);
-                   var glyph = getToken();
-                   encoding[index] = glyph;
-                   getToken(); // read the in 'put'
-                 }
-               }
-             }
-             if (!properties.hasEncoding && encoding) {
-               properties.baseEncoding = encoding;
-               break;
++              stack.push(a ^ b);
 +            }
 +            break;
++          default:
++            error('Unknown operator ' + operator);
++            break;
 +        }
-         token = '';
-       } else {
-         token += c;
 +      }
++      return stack.stack;
 +    }
 +  };
- };
- 
- /**
-  * The CFF class takes a Type1 file and wrap it into a
-  * 'Compact Font Format' which itself embed Type2 charstrings.
-  */
- var CFFStandardStrings = [
-   '.notdef', 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent',
-   'ampersand', 'quoteright', 'parenleft', 'parenright', 'asterisk', 'plus',
-   'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 'two', 'three', 'four',
-   'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon', 'less',
-   'equal', 'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
-   'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
-   'X', 'Y', 'Z', 'bracketleft', 'backslash', 'bracketright', 'asciicircum',
-   'underscore', 'quoteleft', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
-   'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y',
-   'z', 'braceleft', 'bar', 'braceright', 'asciitilde', 'exclamdown', 'cent',
-   'sterling', 'fraction', 'yen', 'florin', 'section', 'currency',
-   'quotesingle', 'quotedblleft', 'guillemotleft', 'guilsinglleft',
-   'guilsinglright', 'fi', 'fl', 'endash', 'dagger', 'daggerdbl',
-   'periodcentered', 'paragraph', 'bullet', 'quotesinglbase', 'quotedblbase',
-   'quotedblright', 'guillemotright', 'ellipsis', 'perthousand', 'questiondown',
-   'grave', 'acute', 'circumflex', 'tilde', 'macron', 'breve', 'dotaccent',
-   'dieresis', 'ring', 'cedilla', 'hungarumlaut', 'ogonek', 'caron', 'emdash',
-   'AE', 'ordfeminine', 'Lslash', 'Oslash', 'OE', 'ordmasculine', 'ae',
-   'dotlessi', 'lslash', 'oslash', 'oe', 'germandbls', 'onesuperior',
-   'logicalnot', 'mu', 'trademark', 'Eth', 'onehalf', 'plusminus', 'Thorn',
-   'onequarter', 'divide', 'brokenbar', 'degree', 'thorn', 'threequarters',
-   'twosuperior', 'registered', 'minus', 'eth', 'multiply', 'threesuperior',
-   'copyright', 'Aacute', 'Acircumflex', 'Adieresis', 'Agrave', 'Aring',
-   'Atilde', 'Ccedilla', 'Eacute', 'Ecircumflex', 'Edieresis', 'Egrave',
-   'Iacute', 'Icircumflex', 'Idieresis', 'Igrave', 'Ntilde', 'Oacute',
-   'Ocircumflex', 'Odieresis', 'Ograve', 'Otilde', 'Scaron', 'Uacute',
-   'Ucircumflex', 'Udieresis', 'Ugrave', 'Yacute', 'Ydieresis', 'Zcaron',
-   'aacute', 'acircumflex', 'adieresis', 'agrave', 'aring', 'atilde',
-   'ccedilla', 'eacute', 'ecircumflex', 'edieresis', 'egrave', 'iacute',
-   'icircumflex', 'idieresis', 'igrave', 'ntilde', 'oacute', 'ocircumflex',
-   'odieresis', 'ograve', 'otilde', 'scaron', 'uacute', 'ucircumflex',
-   'udieresis', 'ugrave', 'yacute', 'ydieresis', 'zcaron', 'exclamsmall',
-   'Hungarumlautsmall', 'dollaroldstyle', 'dollarsuperior', 'ampersandsmall',
-   'Acutesmall', 'parenleftsuperior', 'parenrightsuperior', '266 ff',
-   'onedotenleader', 'zerooldstyle', 'oneoldstyle', 'twooldstyle',
-   'threeoldstyle', 'fouroldstyle', 'fiveoldstyle', 'sixoldstyle',
-   'sevenoldstyle', 'eightoldstyle', 'nineoldstyle', 'commasuperior',
-   'threequartersemdash', 'periodsuperior', 'questionsmall', 'asuperior',
-   'bsuperior', 'centsuperior', 'dsuperior', 'esuperior', 'isuperior',
-   'lsuperior', 'msuperior', 'nsuperior', 'osuperior', 'rsuperior', 'ssuperior',
-   'tsuperior', 'ff', 'ffi', 'ffl', 'parenleftinferior', 'parenrightinferior',
-   'Circumflexsmall', 'hyphensuperior', 'Gravesmall', 'Asmall', 'Bsmall',
-   'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall', 'Hsmall', 'Ismall',
-   'Jsmall', 'Ksmall', 'Lsmall', 'Msmall', 'Nsmall', 'Osmall', 'Psmall',
-   'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall', 'Vsmall', 'Wsmall',
-   'Xsmall', 'Ysmall', 'Zsmall', 'colonmonetary', 'onefitted', 'rupiah',
-   'Tildesmall', 'exclamdownsmall', 'centoldstyle', 'Lslashsmall',
-   'Scaronsmall', 'Zcaronsmall', 'Dieresissmall', 'Brevesmall', 'Caronsmall',
-   'Dotaccentsmall', 'Macronsmall', 'figuredash', 'hypheninferior',
-   'Ogoneksmall', 'Ringsmall', 'Cedillasmall', 'questiondownsmall', 'oneeighth',
-   'threeeighths', 'fiveeighths', 'seveneighths', 'onethird', 'twothirds',
-   'zerosuperior', 'foursuperior', 'fivesuperior', 'sixsuperior',
-   'sevensuperior', 'eightsuperior', 'ninesuperior', 'zeroinferior',
-   'oneinferior', 'twoinferior', 'threeinferior', 'fourinferior',
-   'fiveinferior', 'sixinferior', 'seveninferior', 'eightinferior',
-   'nineinferior', 'centinferior', 'dollarinferior', 'periodinferior',
-   'commainferior', 'Agravesmall', 'Aacutesmall', 'Acircumflexsmall',
-   'Atildesmall', 'Adieresissmall', 'Aringsmall', 'AEsmall', 'Ccedillasmall',
-   'Egravesmall', 'Eacutesmall', 'Ecircumflexsmall', 'Edieresissmall',
-   'Igravesmall', 'Iacutesmall', 'Icircumflexsmall', 'Idieresissmall',
-   'Ethsmall', 'Ntildesmall', 'Ogravesmall', 'Oacutesmall', 'Ocircumflexsmall',
-   'Otildesmall', 'Odieresissmall', 'OEsmall', 'Oslashsmall', 'Ugravesmall',
-   'Uacutesmall', 'Ucircumflexsmall', 'Udieresissmall', 'Yacutesmall',
-   'Thornsmall', 'Ydieresissmall', '001.000', '001.001', '001.002', '001.003',
-   'Black', 'Bold', 'Book', 'Light', 'Medium', 'Regular', 'Roman', 'Semibold'
- ];
- 
- var type1Parser = new Type1Parser();
- 
- // Type1Font is also a CIDFontType0.
- var Type1Font = function Type1Font(name, file, properties) {
-   // Get the data block containing glyphs and subrs informations
-   var headerBlock = file.getBytes(properties.length1);
-   type1Parser.extractFontHeader(headerBlock, properties);
++  return PostScriptEvaluator;
++})();
 +
-   // Decrypt the data blocks and retrieve it's content
-   var eexecBlock = file.getBytes(properties.length2);
-   var data = type1Parser.extractFontProgram(eexecBlock);
-   for (var info in data.properties)
-     properties[info] = data.properties[info];
 +
-   var charstrings = this.getOrderedCharStrings(data.charstrings, properties);
-   var type2Charstrings = this.getType2Charstrings(charstrings);
-   var subrs = this.getType2Subrs(data.subrs);
++var HIGHLIGHT_OFFSET = 4; // px
++var SUPPORTED_TYPES = ['Link', 'Text', 'Widget'];
 +
-   this.charstrings = charstrings;
-   this.data = this.wrap(name, type2Charstrings, this.charstrings,
-                         subrs, properties);
-   this.seacs = this.getSeacs(data.charstrings);
- };
++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];
 +
- 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++;
-       }
-       usedUnicodes[unicode] = true;
-       charstrings.push({
-         glyph: glyphName,
-         unicode: unicode,
-         gid: i,
-         charstring: item.data,
-         width: item.width,
-         lsb: item.lsb
-       });
++    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]];
 +    }
 +
-     charstrings.sort(function charstrings_sort(a, b) {
-       return a.unicode - b.unicode;
-     });
-     return charstrings;
-   },
++    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
++    ];
++  }
 +
-   getSeacs: function Type1Font_getSeacs(charstrings) {
-     var i, ii;
-     var seacMap = [];
-     for (i = 0, ii = charstrings.length; i < ii; i++) {
-       var charstring = charstrings[i];
-       if (charstring.seac) {
-         seacMap[i] = charstring.seac;
-       }
++  function getDefaultAppearance(dict) {
++    var appearanceState = dict.get('AP');
++    if (!isDict(appearanceState)) {
++      return;
 +    }
-     return seacMap;
-   },
 +
-   getType2Charstrings: function Type1Font_getType2Charstrings(
-                                   type1Charstrings) {
-     var type2Charstrings = [];
-     for (var i = 0, ii = type1Charstrings.length; i < ii; i++) {
-       type2Charstrings.push(type1Charstrings[i].charstring);
++    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 type2Charstrings;
-   },
++    return appearance;
++  }
 +
-   getType2Subrs: function Type1Font_getType2Subrs(type1Subrs) {
-     var bias = 0;
-     var count = type1Subrs.length;
-     if (count < 1133)
-       bias = 107;
-     else if (count < 33769)
-       bias = 1131;
-     else
-       bias = 32768;
- 
-     // Add a bunch of empty subrs to deal with the Type2 bias
-     var type2Subrs = [];
-     for (var i = 0; i < bias; i++)
-       type2Subrs.push([0x0B]);
- 
-     for (var i = 0; i < count; i++) {
-       type2Subrs.push(type1Subrs[i]);
++  function Annotation(params) {
++    if (params.data) {
++      this.data = params.data;
++      return;
 +    }
 +
-     return type2Subrs;
-   },
++    var dict = params.dict;
++    var data = this.data = {};
 +
-   wrap: function Type1Font_wrap(name, glyphs, charstrings, subrs, properties) {
-     var cff = new CFF();
-     cff.header = new CFFHeader(1, 0, 4, 4);
- 
-     cff.names = [name];
- 
-     var topDict = new CFFTopDict();
-     // CFF strings IDs 0...390 are predefined names, so refering
-     // to entries in our own String INDEX starts at SID 391.
-     topDict.setByName('version', 391);
-     topDict.setByName('Notice', 392);
-     topDict.setByName('FullName', 393);
-     topDict.setByName('FamilyName', 394);
-     topDict.setByName('Weight', 395);
-     topDict.setByName('Encoding', null); // placeholder
-     topDict.setByName('FontMatrix', properties.fontMatrix);
-     topDict.setByName('FontBBox', properties.bbox);
-     topDict.setByName('charset', null); // placeholder
-     topDict.setByName('CharStrings', null); // placeholder
-     topDict.setByName('Private', null); // placeholder
-     cff.topDict = topDict;
- 
-     var strings = new CFFStrings();
-     strings.add('Version 0.11'); // Version
-     strings.add('See original notice'); // Notice
-     strings.add(name); // FullName
-     strings.add(name); // FamilyName
-     strings.add('Medium'); // Weight
-     cff.strings = strings;
- 
-     cff.globalSubrIndex = new CFFIndex();
- 
-     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)
-         index = 0;
- 
-       charsetArray.push((index >> 8) & 0xff, index & 0xff);
-     }
-     cff.charset = new CFFCharset(false, 0, [], charsetArray);
++    data.subtype = dict.get('Subtype').name;
++    var rect = dict.get('Rect');
++    data.rect = Util.normalizeRect(rect);
++    data.annotationFlags = dict.get('F');
 +
-     var charStringsIndex = new CFFIndex();
-     charStringsIndex.add([0x8B, 0x0E]); // .notdef
-     for (var i = 0; i < count; i++) {
-       charStringsIndex.add(glyphs[i]);
-     }
-     cff.charStrings = charStringsIndex;
- 
-     var privateDict = new CFFPrivateDict();
-     privateDict.setByName('Subrs', null); // placeholder
-     var fields = [
-       'BlueValues',
-       'OtherBlues',
-       'FamilyBlues',
-       'FamilyOtherBlues',
-       'StemSnapH',
-       'StemSnapV',
-       'BlueShift',
-       'BlueFuzz',
-       'BlueScale',
-       'LanguageGroup',
-       'ExpansionFactor',
-       'ForceBold',
-       'StdHW',
-       'StdVW'
-     ];
-     for (var i = 0, ii = fields.length; i < ii; i++) {
-       var field = fields[i];
-       if (!properties.privateData.hasOwnProperty(field))
-         continue;
-       privateDict.setByName(field, properties.privateData[field]);
++    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];
 +    }
-     cff.topDict.privateDict = privateDict;
 +
-     var subrIndex = new CFFIndex();
-     for (var i = 0, ii = subrs.length; i < ii; i++) {
-       subrIndex.add(subrs[i]);
++    // 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 && isArray(dashArray)) {
++        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++) {
++            if (!(+dashArray[i] >= 0)) {
++              isInvalid = true;
++              break;
++            } else if (dashArray[i] > 0) {
++              numPositive++;
++            }
++          }
++          if (isInvalid || numPositive === 0) {
++            data.borderWidth = 0;
++          }
++        }
++      }
 +    }
-     privateDict.subrsIndex = subrIndex;
 +
-     var compiler = new CFFCompiler(cff);
-     return compiler.compile();
++    this.appearance = getDefaultAppearance(dict);
++    data.hasAppearance = !!this.appearance;
 +  }
- };
 +
- var CFFFont = (function CFFFontClosure() {
-   function CFFFont(file, properties) {
-     this.properties = properties;
- 
-     var parser = new CFFParser(file, properties);
-     var cff = parser.parse();
-     var compiler = new CFFCompiler(cff);
-     this.readExtra(cff);
-     try {
-       this.data = compiler.compile();
-     } catch (e) {
-       warn('Failed to compile font ' + properties.loadedName);
-       // There may have just been an issue with the compiler, set the data
-       // anyway and hope the font loaded.
-       this.data = file;
-     }
-   }
++  Annotation.prototype = {
 +
-   CFFFont.prototype = {
-     readExtra: function CFFFont_readExtra(cff) {
-       // charstrings contains info about glyphs (one element per glyph
-       // containing mappings for {unicode, width})
-       var charset = cff.charset.charset;
-       var encoding = cff.encoding ? cff.encoding.encoding : null;
-       var charstrings = this.getCharStrings(charset, encoding);
- 
-       // 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 = cff.seacs;
++    getData: function Annotation_getData() {
++      return this.data;
 +    },
-     getCharStrings: function CFFFont_getCharStrings(charsets, encoding) {
-       var charstrings = [];
-       var unicodeUsed = [];
-       var unassignedUnicodeItems = [];
-       var inverseEncoding = [];
-       // CID fonts don't have an encoding.
-       if (encoding !== null)
-         for (var charcode in encoding)
-           inverseEncoding[encoding[charcode]] = charcode | 0;
-       else
-         inverseEncoding = charsets;
-       var i = charsets[0] == '.notdef' ? 1 : 0;
-       for (var ii = charsets.length; i < ii; i++) {
-         var glyph = charsets[i];
- 
-         var code = inverseEncoding[i];
-         if (!code || isSpecialUnicode(code)) {
-           unassignedUnicodeItems.push(i);
-           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) {
-         var i = unassignedUnicodeItems[j];
-         // giving unicode value anyway
-         while (nextUnusedUnicode in unicodeUsed)
-           nextUnusedUnicode++;
-         var unicode = nextUnusedUnicode++;
-         charstrings.push({
-           unicode: unicode,
-           code: inverseEncoding[i] || 0,
-           gid: i,
-           glyph: charsets[i]
-         });
-       }
++    hasHtml: function Annotation_hasHtml() {
++      return false;
++    },
 +
-       // sort the array by the unicode value (again)
-       charstrings.sort(function getCharStringsSort(a, b) {
-         return a.unicode - b.unicode;
-       });
-       return charstrings;
-     }
-   };
++    getHtmlElement: function Annotation_getHtmlElement(commonObjs) {
++      throw new NotImplementedException(
++        'getHtmlElement() should be implemented in subclass');
++    },
 +
-   return CFFFont;
- })();
++    // TODO(mack): Remove this, it's not really that helpful.
++    getEmptyContainer: function Annotation_getEmptyContainer(tagName, rect,
++                                                             borderWidth) {
++      assert(!isWorker,
++        'getEmptyContainer() should be called from main thread');
 +
- var CFFParser = (function CFFParserClosure() {
-   var CharstringValidationData = [
-     null,
-     { id: 'hstem', min: 2, resetStack: true, stem: true },
-     null,
-     { id: 'vstem', min: 2, resetStack: true, stem: true },
-     { id: 'vmoveto', min: 1, resetStack: true },
-     { id: 'rlineto', min: 2, resetStack: true },
-     { id: 'hlineto', min: 1, resetStack: true },
-     { id: 'vlineto', min: 1, resetStack: true },
-     { id: 'rrcurveto', min: 6, resetStack: true },
-     null,
-     { id: 'callsubr', min: 1, undefStack: true },
-     { id: 'return', min: 0, undefStack: true },
-     null, // 12
-     null,
-     null, // endchar
-     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: 'rcurveline', min: 8, resetStack: true },
-     { id: 'rlinecurve', min: 8, resetStack: true },
-     { id: 'vvcurveto', min: 4, resetStack: true },
-     { id: 'hhcurveto', min: 4, resetStack: true },
-     null, // shortint
-     { id: 'callgsubr', min: 1, undefStack: true },
-     { id: 'vhcurveto', min: 4, resetStack: true },
-     { id: 'hvcurveto', min: 4, resetStack: true }
-   ];
-   var CharstringValidationData12 = [
-     null,
-     null,
-     null,
-     { id: 'and', min: 2, stackDelta: -1 },
-     { id: 'or', min: 2, stackDelta: -1 },
-     { id: 'not', min: 1, stackDelta: 0 },
-     null,
-     null,
-     null,
-     { id: 'abs', min: 1, stackDelta: 0 },
-     { id: 'add', min: 2, stackDelta: -1,
-       stackFn: function stack_div(stack, index) {
-         stack[index - 2] = stack[index - 2] + stack[index - 1];
-       }
-     },
-     { id: 'sub', min: 2, stackDelta: -1,
-       stackFn: function stack_div(stack, index) {
-         stack[index - 2] = stack[index - 2] - stack[index - 1];
-       }
-     },
-     { id: 'div', min: 2, stackDelta: -1,
-       stackFn: function stack_div(stack, index) {
-         stack[index - 2] = stack[index - 2] / stack[index - 1];
-       }
++      var bWidth = borderWidth || 0;
++
++      rect = rect || this.data.rect;
++      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;
 +    },
-     null,
-     { id: 'neg', min: 1, stackDelta: 0,
-       stackFn: function stack_div(stack, index) {
-         stack[index - 1] = -stack[index - 1];
++
++    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
 +      }
 +    },
-     { id: 'eq', min: 2, stackDelta: -1 },
-     null,
-     null,
-     { id: 'drop', min: 1, stackDelta: -1 },
-     null,
-     { id: 'put', min: 2, stackDelta: -2 },
-     { id: 'get', min: 1, stackDelta: 0 },
-     { id: 'ifelse', min: 4, stackDelta: -3 },
-     { id: 'random', min: 0, stackDelta: 1 },
-     { id: 'mul', min: 2, stackDelta: -1,
-       stackFn: function stack_div(stack, index) {
-         stack[index - 2] = stack[index - 2] * stack[index - 1];
-       }
++
++    isViewable: function Annotation_isViewable() {
++      var data = this.data;
++      return !!(!this.isInvisible() &&
++                data &&
++                (!data.annotationFlags ||
++                 !(data.annotationFlags & 0x22)) &&  // Hidden or NoView
++                data.rect);                          // rectangle is nessessary
 +    },
-     null,
-     { id: 'sqrt', min: 1, stackDelta: 0 },
-     { id: 'dup', min: 1, stackDelta: 1 },
-     { id: 'exch', min: 2, stackDelta: 0 },
-     { id: 'index', min: 2, stackDelta: 0 },
-     { id: 'roll', min: 3, stackDelta: -2 },
-     null,
-     null,
-     null,
-     { id: 'hflex', min: 7, resetStack: true },
-     { id: 'flex', min: 13, resetStack: true },
-     { id: 'hflex1', min: 9, resetStack: true },
-     { id: 'flex1', min: 11, resetStack: true }
-   ];
- 
-   function CFFParser(file, properties) {
-     this.bytes = file.getBytes();
-     this.properties = properties;
-   }
-   CFFParser.prototype = {
-     parse: function CFFParser_parse() {
-       var properties = this.properties;
-       var cff = new CFF();
-       this.cff = cff;
- 
-       // The first five sections must be in order, all the others are reached
-       // via offsets contained in one of the below.
-       var header = this.parseHeader();
-       var nameIndex = this.parseIndex(header.endPos);
-       var topDictIndex = this.parseIndex(nameIndex.endPos);
-       var stringIndex = this.parseIndex(topDictIndex.endPos);
-       var globalSubrIndex = this.parseIndex(stringIndex.endPos);
- 
-       var topDictParsed = this.parseDict(topDictIndex.obj.get(0));
-       var topDict = this.createDict(CFFTopDict, topDictParsed, cff.strings);
- 
-       cff.header = header.obj;
-       cff.names = this.parseNameIndex(nameIndex.obj);
-       cff.strings = this.parseStringIndex(stringIndex.obj);
-       cff.topDict = topDict;
-       cff.globalSubrIndex = globalSubrIndex.obj;
- 
-       this.parsePrivateDict(cff.topDict);
- 
-       cff.isCIDFont = topDict.hasName('ROS');
- 
-       var charStringOffset = topDict.getByName('CharStrings');
-       var charStringsAndSeacs = this.parseCharStrings(charStringOffset);
-       cff.charStrings = charStringsAndSeacs.charStrings;
-       cff.seacs = charStringsAndSeacs.seacs;
- 
-       var fontMatrix = topDict.getByName('FontMatrix');
-       if (fontMatrix) {
-         properties.fontMatrix = fontMatrix;
-       }
 +
-       var fontBBox = topDict.getByName('FontBBox');
-       if (fontBBox) {
-         // adjusting ascent/descent
-         properties.ascent = fontBBox[3];
-         properties.descent = fontBBox[1];
-         properties.ascentScaled = true;
-       }
++    isPrintable: function Annotation_isPrintable() {
++      var data = this.data;
++      return !!(!this.isInvisible() &&
++                data &&
++                data.annotationFlags &&              // Default: not printable
++                data.annotationFlags & 0x4 &&        // Print
++                data.rect);                          // rectangle is nessessary
++    },
 +
-       var charset, encoding;
-       if (cff.isCIDFont) {
-         var fdArrayIndex = this.parseIndex(topDict.getByName('FDArray')).obj;
-         for (var i = 0, ii = fdArrayIndex.count; i < ii; ++i) {
-           var dictRaw = fdArrayIndex.get(i);
-           var fontDict = this.createDict(CFFTopDict, this.parseDict(dictRaw),
-                                          cff.strings);
-           this.parsePrivateDict(fontDict);
-           cff.fdArray.push(fontDict);
++    loadResources: function(keys) {
++      var promise = new LegacyPromise();
++      this.appearance.dict.getAsync('Resources').then(function(resources) {
++        if (!resources) {
++          promise.resolve();
++          return;
 +        }
-         // cid fonts don't have an encoding
-         encoding = null;
-         charset = this.parseCharsets(topDict.getByName('charset'),
-                                      cff.charStrings.count, cff.strings, true);
-         cff.fdSelect = this.parseFDSelect(topDict.getByName('FDSelect'),
-                                              cff.charStrings.count);
-       } else {
-         charset = this.parseCharsets(topDict.getByName('charset'),
-                                      cff.charStrings.count, cff.strings, false);
-         encoding = this.parseEncoding(topDict.getByName('Encoding'),
-                                       properties,
-                                       cff.strings, charset.charset);
-       }
-       cff.charset = charset;
-       cff.encoding = encoding;
++        var objectLoader = new ObjectLoader(resources.map,
++                                            keys,
++                                            resources.xref);
++        objectLoader.load().then(function() {
++          promise.resolve(resources);
++        });
++      }.bind(this));
 +
-       return cff;
++      return promise;
 +    },
-     parseHeader: function CFFParser_parseHeader() {
-       var bytes = this.bytes;
-       var offset = 0;
 +
-       while (bytes[offset] != 1)
-         ++offset;
++    getOperatorList: function Annotation_getOperatorList(evaluator) {
 +
-       if (offset !== 0) {
-         info('cff data is shifted');
-         bytes = bytes.subarray(offset);
-         this.bytes = bytes;
-       }
-       var major = bytes[0];
-       var minor = bytes[1];
-       var hdrSize = bytes[2];
-       var offSize = bytes[3];
-       var header = new CFFHeader(major, minor, hdrSize, offSize);
-       return {obj: header, endPos: hdrSize};
-     },
-     parseDict: function CFFParser_parseDict(dict) {
-       var pos = 0;
- 
-       function parseOperand() {
-         var value = dict[pos++];
-         if (value === 30) {
-           return parseFloatOperand(pos);
-         } else if (value === 28) {
-           value = dict[pos++];
-           value = ((value << 24) | (dict[pos++] << 16)) >> 16;
-           return value;
-         } else if (value === 29) {
-           value = dict[pos++];
-           value = (value << 8) | dict[pos++];
-           value = (value << 8) | dict[pos++];
-           value = (value << 8) | dict[pos++];
-           return value;
-         } else if (value >= 32 && value <= 246) {
-           return value - 139;
-         } else if (value >= 247 && value <= 250) {
-           return ((value - 247) * 256) + dict[pos++] + 108;
-         } else if (value >= 251 && value <= 254) {
-           return -((value - 251) * 256) - dict[pos++] - 108;
-         } else {
-           error('255 is not a valid DICT command');
-         }
-         return -1;
++      var promise = new LegacyPromise();
++
++      if (!this.appearance) {
++        promise.resolve(new OperatorList());
++        return promise;
 +      }
 +
-       function parseFloatOperand() {
-         var str = '';
-         var eof = 15;
-         var lookup = ['0', '1', '2', '3', '4', '5', '6', '7', '8',
-             '9', '.', 'E', 'E-', null, '-'];
-         var length = dict.length;
-         while (pos < length) {
-           var b = dict[pos++];
-           var b1 = b >> 4;
-           var b2 = b & 15;
- 
-           if (b1 == eof)
-             break;
-           str += lookup[b1];
++      var data = this.data;
 +
-           if (b2 == eof)
-             break;
-           str += lookup[b2];
-         }
-         return parseFloat(str);
-       }
++      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 operands = [];
-       var entries = [];
- 
-       var pos = 0;
-       var end = dict.length;
-       while (pos < end) {
-         var b = dict[pos];
-         if (b <= 21) {
-           if (b === 12)
-             b = (b << 8) | dict[++pos];
-           entries.push([b, operands]);
-           operands = [];
-           ++pos;
-         } else {
-           operands.push(parseOperand());
-         }
-       }
-       return entries;
-     },
-     parseIndex: function CFFParser_parseIndex(pos) {
-       var cffIndex = new CFFIndex();
-       var bytes = this.bytes;
-       var count = (bytes[pos++] << 8) | bytes[pos++];
-       var offsets = [];
-       var start = pos;
-       var end = pos;
- 
-       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) {
-           var offset = 0;
-           for (var j = 0; j < offsetSize; ++j) {
-             offset <<= 8;
-             offset += bytes[pos++];
-           }
-           offsets.push(startPos + offset);
-         }
-         end = offsets[count];
-       }
-       for (var i = 0, ii = offsets.length - 1; i < ii; ++i) {
-         var offsetStart = offsets[i];
-         var offsetEnd = offsets[i + 1];
-         cffIndex.add(bytes.subarray(offsetStart, offsetEnd));
-       }
-       return {obj: cffIndex, endPos: end};
-     },
-     parseNameIndex: function CFFParser_parseNameIndex(index) {
-       var names = [];
-       for (var i = 0, ii = index.count; i < ii; ++i) {
-         var name = index.get(i);
-         // OTS doesn't allow names to be over 127 characters.
-         var length = Math.min(name.length, 127);
-         var data = [];
-         // OTS also only permits certain characters in the name.
-         for (var j = 0; j < length; ++j) {
-           var c = name[j];
-           if (j === 0 && c === 0) {
-             data[j] = c;
-             continue;
-           }
-           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 /* % */) {
-             data[j] = 95;
-             continue;
-           }
-           data[j] = c;
-         }
-         names.push(String.fromCharCode.apply(null, data));
-       }
-       return names;
-     },
-     parseStringIndex: function CFFParser_parseStringIndex(index) {
-       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));
-       }
-       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];
-         var value = pair[1];
-         cffDict.setByKey(key, value);
-       }
-       return cffDict;
-     },
-     parseCharStrings: function CFFParser_parseCharStrings(charStringOffset) {
-       var charStrings = this.parseIndex(charStringOffset).obj;
-       var seacs = [];
-       var count = charStrings.count;
-       for (var i = 0; i < count; i++) {
-         var charstring = charStrings.get(i);
- 
-         var stackSize = 0;
-         var stack = [];
-         var undefStack = true;
-         var hints = 0;
-         var valid = true;
-         var data = charstring;
-         var length = data.length;
-         for (var j = 0; j < length;) {
-           var value = data[j++];
-           var validationCommand = null;
-           if (value == 12) {
-             var q = data[j++];
-             if (q === 0) {
-               // The CFF specification state that the 'dotsection' command
-               // (12, 0) is deprecated and treated as a no-op, but all Type2
-               // charstrings processors should support them. Unfortunately
-               // the font sanitizer don't. As a workaround the sequence (12, 0)
-               // is replaced by a useless (0, hmoveto).
-               data[j - 2] = 139;
-               data[j - 1] = 22;
-               stackSize = 0;
-             } else {
-               validationCommand = CharstringValidationData12[q];
-             }
-           } else if (value === 28) { // number (16 bit)
-             stack[stackSize] = ((data[j] << 24) | (data[j + 1] << 16)) >> 16;
-             j += 2;
-             stackSize++;
-           } else if (value == 14) {
-             if (stackSize >= 4) {
-               stackSize -= 4;
-               if (SEAC_ANALYSIS_ENABLED) {
-                 seacs[i] = stack.slice(stackSize, stackSize + 4);
-                 valid = false;
-               }
-             }
-           } 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;
-             j++;
-             stackSize++;
-           } else if (value == 255) {  // number (32 bit)
-             stack[stackSize] = ((data[j] << 24) | (data[j + 1] << 16) |
-               (data[j + 2] << 8) | data[j + 3]) / 65536;
-             j += 4;
-             stackSize++;
-           } else if (value == 19 || value == 20) {
-             hints += stackSize >> 1;
-             j += (hints + 7) >> 3; // skipping right amount of hints flag data
-             stackSize = 0;
-           } else {
-             validationCommand = CharstringValidationData[value];
-           }
-           if (validationCommand) {
-             if (validationCommand.stem) {
-               hints += stackSize >> 1;
-             }
-             if ('min' in validationCommand) {
-               if (!undefStack && stackSize < validationCommand.min) {
-                 warn('Not enough parameters for ' + validationCommand.id +
-                      '; actual: ' + stackSize +
-                      ', expected: ' + validationCommand.min);
-                 valid = false;
-                 break;
-               }
-             }
-             if ('stackDelta' in validationCommand) {
-               if ('stackFn' in validationCommand) {
-                 validationCommand.stackFn(stack, stackSize);
-               }
-               stackSize += validationCommand.stackDelta;
-             } else if (validationCommand.resetStack) {
-               stackSize = 0;
-               undefStack = false;
-             } else if (validationCommand.undefStack) {
-               stackSize = 0;
-               undefStack = true;
-             }
-           }
-         }
-         if (!valid) {
-           // resetting invalid charstring to single 'endchar'
-           charStrings.set(i, new Uint8Array([14]));
-         }
-       }
-       return { charStrings: charStrings, seacs: seacs };
-     },
-     emptyPrivateDictionary:
-       function CFFParser_emptyPrivateDictionary(parentDict) {
-       var privateDict = this.createDict(CFFPrivateDict, [],
-                                         parentDict.strings);
-       parentDict.setByKey(18, [0, 0]);
-       parentDict.privateDict = privateDict;
-     },
-     parsePrivateDict: function CFFParser_parsePrivateDict(parentDict) {
-       // no private dict, do nothing
-       if (!parentDict.hasName('Private')) {
-         this.emptyPrivateDictionary(parentDict);
-         return;
-       }
-       var privateOffset = parentDict.getByName('Private');
-       // make sure the params are formatted correctly
-       if (!isArray(privateOffset) || privateOffset.length !== 2) {
-         parentDict.removeByName('Private');
-         return;
-       }
-       var size = privateOffset[0];
-       var offset = privateOffset[1];
-       // remove empty dicts or ones that refer to invalid location
-       if (size === 0 || offset >= this.bytes.length) {
-         this.emptyPrivateDictionary(parentDict);
-         return;
-       }
++      var border = data.border;
 +
-       var privateDictEnd = offset + size;
-       var dictData = this.bytes.subarray(offset, privateDictEnd);
-       var dict = this.parseDict(dictData);
-       var privateDict = this.createDict(CFFPrivateDict, dict,
-                                         parentDict.strings);
-       parentDict.privateDict = privateDict;
++      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);
 +
-       // Parse the Subrs index also since it's relative to the private dict.
-       if (!privateDict.getByName('Subrs'))
-         return;
-       var subrsOffset = privateDict.getByName('Subrs');
-       var relativeOffset = offset + subrsOffset;
-       // Validate the offset.
-       if (subrsOffset === 0 || relativeOffset >= this.bytes.length) {
-         this.emptyPrivateDictionary(parentDict);
++        this.appearance.reset();
++      }.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;
 +      }
-       var subrsIndex = this.parseIndex(relativeOffset);
-       privateDict.subrsIndex = subrsIndex.obj;
-     },
-     parseCharsets: function CFFParser_parseCharsets(pos, length, strings, cid) {
-       if (pos === 0) {
-         return new CFFCharset(true, CFFCharsetPredefinedTypes.ISO_ADOBE,
-                               ISOAdobeCharset);
-       } else if (pos == 1) {
-         return new CFFCharset(true, CFFCharsetPredefinedTypes.EXPERT,
-                               ExpertCharset);
-       } else if (pos == 2) {
-         return new CFFCharset(true, CFFCharsetPredefinedTypes.EXPERT_SUBSET,
-                               ExpertSubsetCharset);
++
++      if (fieldType === 'Tx') {
++        return TextWidgetAnnotation;
++      } else {
++        return WidgetAnnotation;
 +      }
++    } else {
++      return Annotation;
++    }
++  };
 +
-       var bytes = this.bytes;
-       var start = pos;
-       var format = bytes[pos++];
-       var charset = ['.notdef'];
++  // 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 });
++    }
++  };
 +
-       // subtract 1 for the .notdef glyph
-       length -= 1;
++  Annotation.fromRef = function Annotation_fromRef(xref, ref) {
 +
-       switch (format) {
-         case 0:
-           for (var i = 0; i < length; i++) {
-             var 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++)
-               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++)
-               charset.push(cid ? id++ : strings.get(id++));
-           }
-           break;
-         default:
-           error('Unknown charset format');
-       }
-       // Raw won't be needed if we actually compile the charset.
-       var end = pos;
-       var raw = bytes.subarray(start, end);
++    var dict = xref.fetchIfRef(ref);
++    if (!isDict(dict)) {
++      return;
++    }
 +
-       return new CFFCharset(false, format, charset, raw);
-     },
-     parseEncoding: function CFFParser_parseEncoding(pos,
-                                                     properties,
-                                                     strings,
-                                                     charset) {
-       var encoding = {};
-       var bytes = this.bytes;
-       var predefined = false;
-       var hasSupplement = false;
-       var format;
-       var raw = null;
- 
-       function readSupplement() {
-         var supplementsCount = bytes[pos++];
-         for (var i = 0; i < supplementsCount; i++) {
-           var code = bytes[pos++];
-           var sid = (bytes[pos++] << 8) + (bytes[pos++] & 0xff);
-           encoding[code] = properties.differences.indexOf(strings.get(sid));
-         }
-       }
++    var subtype = dict.get('Subtype');
++    subtype = isName(subtype) ? subtype.name : '';
++    if (!subtype) {
++      return;
++    }
 +
-       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++) {
-           var index = baseEncoding.indexOf(charset[i]);
-           if (index != -1) {
-             encoding[index] = i;
-           }
-         }
-       } else {
-         var dataStart = pos;
-         var format = bytes[pos++];
-         switch (format & 0x7f) {
-           case 0:
-             var glyphsCount = bytes[pos++];
-             for (var i = 1; i <= glyphsCount; i++)
-               encoding[bytes[pos++]] = i;
-             break;
++    var fieldType = Util.getInheritableProperty(dict, 'FT');
++    fieldType = isName(fieldType) ? fieldType.name : '';
 +
-           case 1:
-             var rangesCount = bytes[pos++];
-             var gid = 1;
-             for (var i = 0; i < rangesCount; i++) {
-               var start = bytes[pos++];
-               var left = bytes[pos++];
-               for (var j = start; j <= start + left; j++)
-                 encoding[j] = gid++;
-             }
-             break;
++    var Constructor = Annotation.getConstructor(subtype, fieldType);
++    if (!Constructor) {
++      return;
++    }
 +
-           default:
-             error('Unknow encoding format: ' + format + ' in CFF');
-             break;
-         }
-         var dataEnd = pos;
-         if (format & 0x80) {
-           // The font sanitizer does not support CFF encoding with a
-           // supplement, since the encoding is not really used to map
-           // between gid to glyph, let's overwrite what is declared in
-           // the top dictionary to let the sanitizer think the font use
-           // StandardEncoding, that's a lie but that's ok.
-           bytes[dataStart] &= 0x7f;
-           readSupplement();
-           hasSupplement = true;
-         }
-         raw = bytes.subarray(dataStart, dataEnd);
-       }
-       format = format & 0x7f;
-       return new CFFEncoding(predefined, format, encoding, raw);
-     },
-     parseFDSelect: function CFFParser_parseFDSelect(pos, length) {
-       var start = pos;
-       var bytes = this.bytes;
-       var format = bytes[pos++];
-       var fdSelect = [];
-       switch (format) {
-         case 0:
-           for (var 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) {
-             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)
-               fdSelect.push(fdIndex);
-           }
-           // Advance past the sentinel(next).
-           pos += 2;
-           break;
-         default:
-           error('Unknown fdselect format ' + format);
-           break;
-       }
-       var end = pos;
-       return new CFFFDSelect(fdSelect, bytes.subarray(start, end));
++    var params = {
++      dict: dict,
++      ref: ref,
++    };
++
++    var annotation = new Constructor(params);
++
++    if (annotation.isViewable() || annotation.isPrintable()) {
++      return annotation;
++    } else {
++      warn('unimplemented annotation type: ' + subtype);
 +    }
 +  };
-   return CFFParser;
- })();
 +
- // Compact Font Format
- var CFF = (function CFFClosure() {
-   function CFF() {
-     this.header = null;
-     this.names = [];
-     this.topDict = null;
-     this.strings = new CFFStrings();
-     this.globalSubrIndex = null;
- 
-     // The following could really be per font, but since we only have one font
-     // store them here.
-     this.encoding = null;
-     this.charset = null;
-     this.charStrings = null;
-     this.fdArray = [];
-     this.fdSelect = null;
- 
-     this.isCIDFont = false;
-   }
-   return CFF;
- })();
++  Annotation.appendToOperatorList = function Annotation_appendToOperatorList(
++      annotations, opList, pdfManager, partialEvaluator, intent) {
 +
- var CFFHeader = (function CFFHeaderClosure() {
-   function CFFHeader(major, minor, hdrSize, offSize) {
-     this.major = major;
-     this.minor = minor;
-     this.hdrSize = hdrSize;
-     this.offSize = offSize;
-   }
-   return CFFHeader;
- })();
++    function reject(e) {
++      annotationsReadyPromise.reject(e);
++    }
 +
- var CFFStrings = (function CFFStringsClosure() {
-   function CFFStrings() {
-     this.strings = [];
-   }
-   CFFStrings.prototype = {
-     get: function CFFStrings_get(index) {
-       if (index >= 0 && index <= 390)
-         return CFFStandardStrings[index];
-       if (index - 391 <= this.strings.length)
-         return this.strings[index - 391];
-       return CFFStandardStrings[0];
-     },
-     add: function CFFStrings_add(value) {
-       this.strings.push(value);
-     },
-     get count() {
-       return this.strings.length;
++    var annotationsReadyPromise = new LegacyPromise();
++
++    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, []);
++      annotationsReadyPromise.resolve();
++    }, reject);
++
++    return annotationsReadyPromise;
 +  };
-   return CFFStrings;
++
++  return Annotation;
 +})();
++PDFJS.Annotation = Annotation;
 +
- var CFFIndex = (function CFFIndexClosure() {
-   function CFFIndex() {
-     this.objects = [];
-     this.length = 0;
-   }
-   CFFIndex.prototype = {
-     add: function CFFIndex_add(data) {
-       this.length += data.length;
-       this.objects.push(data);
-     },
-     set: function CFFIndex_set(index, data) {
-       this.length += data.length - this.objects[index].length;
-       this.objects[index] = data;
-     },
-     get: function CFFIndex_get(index) {
-       return this.objects[index];
-     },
-     get count() {
-       return this.objects.length;
++
++var WidgetAnnotation = (function WidgetAnnotationClosure() {
++
++  function WidgetAnnotation(params) {
++    Annotation.call(this, params);
++
++    if (params.data) {
++      return;
 +    }
-   };
-   return CFFIndex;
- })();
 +
- var CFFDict = (function CFFDictClosure() {
-   function CFFDict(tables, strings) {
-     this.keyToNameMap = tables.keyToNameMap;
-     this.nameToKeyMap = tables.nameToKeyMap;
-     this.defaults = tables.defaults;
-     this.types = tables.types;
-     this.opcodes = tables.opcodes;
-     this.order = tables.order;
-     this.strings = strings;
-     this.values = {};
++    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('.');
 +  }
-   CFFDict.prototype = {
-     // value should always be an array
-     setByKey: function CFFDict_setByKey(key, value) {
-       if (!(key in this.keyToNameMap))
++
++  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;
-       // ignore empty values
-       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')
-         value = value[0];
-       this.values[key] = value;
-       return true;
-     },
-     setByName: function CFFDict_setByName(name, value) {
-       if (!(name in this.nameToKeyMap)) {
-         error('Invalid dictionary name "' + name + '"');
 +      }
-       this.values[this.nameToKeyMap[name]] = value;
-     },
-     hasName: function CFFDict_hasName(name) {
-       return this.nameToKeyMap[name] in this.values;
-     },
-     getByName: function CFFDict_getByName(name) {
-       if (!(name in this.nameToKeyMap))
-         error('Invalid dictionary name "' + name + '"');
-       var key = this.nameToKeyMap[name];
-       if (!(key in this.values))
-         return this.defaults[key];
-       return this.values[key];
-     },
-     removeByName: function CFFDict_removeByName(name) {
-       delete this.values[this.nameToKeyMap[name]];
-     }
-   };
-   CFFDict.createTables = function CFFDict_createTables(layout) {
-     var tables = {
-       keyToNameMap: {},
-       nameToKeyMap: {},
-       defaults: {},
-       types: {},
-       opcodes: {},
-       order: []
-     };
-     for (var i = 0, ii = layout.length; i < ii; ++i) {
-       var entry = layout[i];
-       var key = isArray(entry[0]) ? (entry[0][0] << 8) + entry[0][1] : entry[0];
-       tables.keyToNameMap[key] = entry[1];
-       tables.nameToKeyMap[entry[1]] = key;
-       tables.types[key] = entry[2];
-       tables.defaults[key] = entry[3];
-       tables.opcodes[key] = isArray(entry[0]) ? entry[0] : [entry[0]];
-       tables.order.push(key);
-     }
-     return tables;
-   };
-   return CFFDict;
- })();
 +
- var CFFTopDict = (function CFFTopDictClosure() {
-   var layout = [
-     [[12, 30], 'ROS', ['sid', 'sid', 'num'], null],
-     [[12, 20], 'SyntheticBase', 'num', null],
-     [0, 'version', 'sid', null],
-     [1, 'Notice', 'sid', null],
-     [[12, 0], 'Copyright', 'sid', null],
-     [2, 'FullName', 'sid', null],
-     [3, 'FamilyName', 'sid', null],
-     [4, 'Weight', 'sid', null],
-     [[12, 1], 'isFixedPitch', 'num', 0],
-     [[12, 2], 'ItalicAngle', 'num', 0],
-     [[12, 3], 'UnderlinePosition', 'num', -100],
-     [[12, 4], 'UnderlineThickness', 'num', 50],
-     [[12, 5], 'PaintType', 'num', 0],
-     [[12, 6], 'CharstringType', 'num', 2],
-     [[12, 7], 'FontMatrix', ['num', 'num', 'num', 'num', 'num', 'num'],
-                             [0.001, 0, 0, 0.001, 0, 0]],
-     [13, 'UniqueID', 'num', null],
-     [5, 'FontBBox', ['num', 'num', 'num', 'num'], [0, 0, 0, 0]],
-     [[12, 8], 'StrokeWidth', 'num', 0],
-     [14, 'XUID', 'array', null],
-     [15, 'charset', 'offset', 0],
-     [16, 'Encoding', 'offset', 0],
-     [17, 'CharStrings', 'offset', 0],
-     [18, 'Private', ['offset', 'offset'], null],
-     [[12, 21], 'PostScript', 'sid', null],
-     [[12, 22], 'BaseFontName', 'sid', null],
-     [[12, 23], 'BaseFontBlend', 'delta', null],
-     [[12, 31], 'CIDFontVersion', 'num', 0],
-     [[12, 32], 'CIDFontRevision', 'num', 0],
-     [[12, 33], 'CIDFontType', 'num', 0],
-     [[12, 34], 'CIDCount', 'num', 8720],
-     [[12, 35], 'UIDBase', 'num', null],
-     // XXX: CID Fonts on DirectWrite 6.1 only seem to work if FDSelect comes
-     // before FDArray.
-     [[12, 37], 'FDSelect', 'offset', null],
-     [[12, 36], 'FDArray', 'offset', null],
-     [[12, 38], 'FontName', 'sid', null]
-   ];
-   var tables = null;
-   function CFFTopDict(strings) {
-     if (tables === null)
-       tables = CFFDict.createTables(layout);
-     CFFDict.call(this, tables, strings);
-     this.privateDict = null;
-   }
-   CFFTopDict.prototype = Object.create(CFFDict.prototype);
-   return CFFTopDict;
++      return parent.isViewable.call(this);
++    }
++  });
++
++  return WidgetAnnotation;
 +})();
 +
- var CFFPrivateDict = (function CFFPrivateDictClosure() {
-   var layout = [
-     [6, 'BlueValues', 'delta', null],
-     [7, 'OtherBlues', 'delta', null],
-     [8, 'FamilyBlues', 'delta', null],
-     [9, 'FamilyOtherBlues', 'delta', null],
-     [[12, 9], 'BlueScale', 'num', 0.039625],
-     [[12, 10], 'BlueShift', 'num', 7],
-     [[12, 11], 'BlueFuzz', 'num', 1],
-     [10, 'StdHW', 'num', null],
-     [11, 'StdVW', 'num', null],
-     [[12, 12], 'StemSnapH', 'delta', null],
-     [[12, 13], 'StemSnapV', 'delta', null],
-     [[12, 14], 'ForceBold', 'num', 0],
-     [[12, 17], 'LanguageGroup', 'num', 0],
-     [[12, 18], 'ExpansionFactor', 'num', 0.06],
-     [[12, 19], 'initialRandomSeed', 'num', 0],
-     [20, 'defaultWidthX', 'num', 0],
-     [21, 'nominalWidthX', 'num', 0],
-     [19, 'Subrs', 'offset', null]
-   ];
-   var tables = null;
-   function CFFPrivateDict(strings) {
-     if (tables === null)
-       tables = CFFDict.createTables(layout);
-     CFFDict.call(this, tables, strings);
-     this.subrsIndex = null;
-   }
-   CFFPrivateDict.prototype = Object.create(CFFDict.prototype);
-   return CFFPrivateDict;
- })();
++var TextWidgetAnnotation = (function TextWidgetAnnotationClosure() {
++  function TextWidgetAnnotation(params) {
++    WidgetAnnotation.call(this, params);
 +
- var CFFCharsetPredefinedTypes = {
-   ISO_ADOBE: 0,
-   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;
-     this.format = format;
-     this.charset = charset;
-     this.raw = raw;
-   }
-   return CFFCharset;
- })();
++    if (params.data) {
++      return;
++    }
 +
- 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;
-     this.format = format;
-     this.encoding = encoding;
-     this.raw = raw;
++    this.data.textAlignment = Util.getInheritableProperty(params.dict, 'Q');
 +  }
-   return CFFEncoding;
- })();
 +
- var CFFFDSelect = (function CFFFDSelectClosure() {
-   function CFFFDSelect(fdSelect, raw) {
-     this.fdSelect = fdSelect;
-     this.raw = raw;
-   }
-   return CFFFDSelect;
- })();
++  // TODO(mack): This dupes some of the logic in CanvasGraphics.setFont()
++  function setTextStyles(element, item, fontObj) {
 +
- // Helper class to keep track of where an offset is within the data and helps
- // filling in that offset once it's known.
- var CFFOffsetTracker = (function CFFOffsetTrackerClosure() {
-   function CFFOffsetTracker() {
-     this.offsets = {};
-   }
-   CFFOffsetTracker.prototype = {
-     isTracking: function CFFOffsetTracker_isTracking(key) {
-       return key in this.offsets;
-     },
-     track: function CFFOffsetTracker_track(key, location) {
-       if (key in this.offsets)
-         error('Already tracking location of ' + key);
-       this.offsets[key] = location;
-     },
-     offset: function CFFOffsetTracker_offset(value) {
-       for (var key in this.offsets) {
-         this.offsets[key] += value;
-       }
-     },
-     setEntryLocation: function CFFOffsetTracker_setEntryLocation(key,
-                                                                  values,
-                                                                  output) {
-       if (!(key in this.offsets))
-         error('Not tracking location of ' + key);
-       var data = output.data;
-       var dataOffset = this.offsets[key];
-       var size = 5;
-       for (var i = 0, ii = values.length; i < ii; ++i) {
-         var offset0 = i * size + dataOffset;
-         var offset1 = offset0 + 1;
-         var offset2 = offset0 + 2;
-         var offset3 = offset0 + 3;
-         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)
-           error('writing to an offset that is not empty');
-         var value = values[i];
-         data[offset0] = 0x1d;
-         data[offset1] = (value >> 24) & 0xFF;
-         data[offset2] = (value >> 16) & 0xFF;
-         data[offset3] = (value >> 8) & 0xFF;
-         data[offset4] = value & 0xFF;
-       }
++    var style = element.style;
++    style.fontSize = item.fontSize + 'px';
++    style.direction = item.fontDirection < 0 ? 'rtl': 'ltr';
++
++    if (!fontObj) {
++      return;
 +    }
-   };
-   return CFFOffsetTracker;
- })();
 +
- // 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);
++    style.fontWeight = fontObj.black ?
++                            (fontObj.bold ? 'bolder' : 'bold') :
++                            (fontObj.bold ? 'bold' : 'normal');
++    style.fontStyle = fontObj.italic ? 'italic' : 'normal';
 +
-     return array;
++    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;
 +  }
-   function CFFCompiler(cff) {
-     this.cff = cff;
-   }
-   CFFCompiler.prototype = {
-     compile: function CFFCompiler_compile() {
-       var cff = this.cff;
-       var output = {
-         data: [],
-         length: 0,
-         add: function CFFCompiler_add(data) {
-           this.data = this.data.concat(data);
-           this.length = this.data.length;
-         }
-       };
 +
-       // Compile the five entries that must be in order.
-       var header = this.compileHeader(cff.header);
-       output.add(header);
 +
-       var nameIndex = this.compileNameIndex(cff.names);
-       output.add(nameIndex);
++  var parent = WidgetAnnotation.prototype;
++  Util.inherit(TextWidgetAnnotation, WidgetAnnotation, {
++    hasHtml: function TextWidgetAnnotation_hasHtml() {
++      return !this.data.hasAppearance && !!this.data.fieldValue;
++    },
 +
-       var compiled = this.compileTopDicts([cff.topDict],
-                                           output.length,
-                                           cff.isCIDFont);
-       output.add(compiled.output);
-       var topDictTracker = compiled.trackers[0];
++    getHtmlElement: function TextWidgetAnnotation_getHtmlElement(commonObjs) {
++      assert(!isWorker, 'getHtmlElement() shall be called from main thread');
 +
-       var stringIndex = this.compileStringIndex(cff.strings.strings);
-       output.add(stringIndex);
++      var item = this.data;
 +
-       var globalSubrIndex = this.compileIndex(cff.globalSubrIndex);
-       output.add(globalSubrIndex);
++      var element = this.getEmptyContainer('div');
++      element.style.display = 'table';
 +
-       // Now start on the other entries that have no specfic order.
-       if (cff.encoding && cff.topDict.hasName('Encoding')) {
-         if (cff.encoding.predefined) {
-           topDictTracker.setEntryLocation('Encoding', [cff.encoding.format],
-                                           output);
-         } else {
-           var encoding = this.compileEncoding(cff.encoding);
-           topDictTracker.setEntryLocation('Encoding', [output.length], output);
-           output.add(encoding);
-         }
-       }
++      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';
 +
-       if (cff.charset && cff.topDict.hasName('charset')) {
-         if (cff.charset.predefined) {
-           topDictTracker.setEntryLocation('charset', [cff.charset.format],
-                                           output);
-         } else {
-           var charset = this.compileCharset(cff.charset);
-           topDictTracker.setEntryLocation('charset', [output.length], output);
-           output.add(charset);
-         }
-       }
++      var fontObj = item.fontRefName ?
++                    commonObjs.getData(item.fontRefName) : null;
++      var cssRules = setTextStyles(content, item, fontObj);
 +
-       var charStrings = this.compileCharStrings(cff.charStrings);
-       topDictTracker.setEntryLocation('CharStrings', [output.length], output);
-       output.add(charStrings);
- 
-       if (cff.isCIDFont) {
-         // For some reason FDSelect must be in front of FDArray on windows. OSX
-         // and linux don't seem to care.
-         topDictTracker.setEntryLocation('FDSelect', [output.length], output);
-         var fdSelect = this.compileFDSelect(cff.fdSelect.raw);
-         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);
-         topDictTracker.setEntryLocation('FDArray', [output.length], output);
-         output.add(compiled.output);
-         var fontDictTrackers = compiled.trackers;
- 
-         this.compilePrivateDicts(cff.fdArray, fontDictTrackers, output);
++      element.appendChild(content);
++
++      return element;
++    },
++
++    getOperatorList: function TextWidgetAnnotation_getOperatorList(evaluator) {
++      if (this.appearance) {
++        return Annotation.prototype.getOperatorList.call(this, evaluator);
 +      }
 +
-       this.compilePrivateDicts([cff.topDict], [topDictTracker], output);
++      var promise = new LegacyPromise();
++      var opList = new OperatorList();
++      var data = this.data;
 +
-       // If the font data ends with INDEX whose object data is zero-length,
-       // the sanitizer will bail out. Add a dummy byte to avoid that.
-       output.add([0]);
++      // Even if there is an appearance stream, ignore it. This is the
++      // behaviour used by Adobe Reader.
 +
-       return output.data;
-     },
-     encodeNumber: function CFFCompiler_encodeNumber(value) {
-       if (parseFloat(value) == parseInt(value, 10) && !isNaN(value)) // isInt
-         return this.encodeInteger(value);
-       else
-         return this.encodeFloat(value);
-     },
-     encodeFloat: function CFFCompiler_encodeFloat(num) {
-       var value = num.toString();
-       var nibbles = '';
-       for (var i = 0, ii = value.length; i < ii; ++i) {
-         var a = value[i];
-         if (a === 'e') {
-           nibbles += value[++i] === '-' ? 'c' : 'b';
-         } else if (a === '.') {
-           nibbles += 'a';
-         } else if (a === '-') {
-           nibbles += 'e';
-         } else {
-           nibbles += a;
-         }
++      var defaultAppearance = data.defaultAppearance;
++      if (!defaultAppearance) {
++        promise.resolve(opList);
++        return promise;
 +      }
-       nibbles += (nibbles.length & 1) ? 'f' : 'ff';
-       var out = [30];
-       for (var i = 0, ii = nibbles.length; i < ii; i += 2) {
-         out.push(parseInt(nibbles.substr(i, 2), 16));
++
++      // 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];
++        }
 +      }
-       return out;
++      promise.resolve(opList);
++      return promise;
++    }
++  });
++
++  return TextWidgetAnnotation;
++})();
++
++var InteractiveAnnotation = (function InteractiveAnnotationClosure() {
++  function InteractiveAnnotation(params) {
++    Annotation.call(this, params);
++  }
++
++  Util.inherit(InteractiveAnnotation, Annotation, {
++    hasHtml: function InteractiveAnnotation_hasHtml() {
++      return true;
 +    },
-     encodeInteger: function CFFCompiler_encodeInteger(value) {
-       var code;
-       if (value >= -107 && value <= 107) {
-         code = [value + 139];
-       } else if (value >= 108 && value <= 1131) {
-         value = [value - 108];
-         code = [(value >> 8) + 247, value & 0xFF];
-       } else if (value >= -1131 && value <= -108) {
-         value = -value - 108;
-         code = [(value >> 8) + 251, value & 0xFF];
-       } else if (value >= -32768 && value <= 32767) {
-         code = [0x1c, (value >> 8) & 0xFF, value & 0xFF];
-       } else {
-         code = [0x1d,
-                 (value >> 24) & 0xFF,
-                 (value >> 16) & 0xFF,
-                 (value >> 8) & 0xFF,
-                  value & 0xFF];
++
++    highlight: function InteractiveAnnotation_highlight() {
++      if (this.highlightElement &&
++         this.highlightElement.hasAttribute('hidden')) {
++        this.highlightElement.removeAttribute('hidden');
 +      }
-       return code;
-     },
-     compileHeader: function CFFCompiler_compileHeader(header) {
-       return [
-         header.major,
-         header.minor,
-         header.hdrSize,
-         header.offSize
-       ];
 +    },
-     compileNameIndex: function CFFCompiler_compileNameIndex(names) {
-       var nameIndex = new CFFIndex();
-       for (var i = 0, ii = names.length; i < ii; ++i)
-         nameIndex.add(stringToArray(names[i]));
-       return this.compileIndex(nameIndex);
-     },
-     compileTopDicts: function CFFCompiler_compileTopDicts(dicts,
-                                                           length,
-                                                           removeCidKeys) {
-       var fontDictTrackers = [];
-       var fdArrayIndex = new CFFIndex();
-       for (var i = 0, ii = dicts.length; i < ii; ++i) {
-         var fontDict = dicts[i];
-         if (removeCidKeys) {
-           fontDict.removeByName('CIDFontVersion');
-           fontDict.removeByName('CIDFontRevision');
-           fontDict.removeByName('CIDFontType');
-           fontDict.removeByName('CIDCount');
-           fontDict.removeByName('UIDBase');
-         }
-         var fontDictTracker = new CFFOffsetTracker();
-         var fontDictData = this.compileDict(fontDict, fontDictTracker);
-         fontDictTrackers.push(fontDictTracker);
-         fdArrayIndex.add(fontDictData);
-         fontDictTracker.offset(length);
++
++    unhighlight: function InteractiveAnnotation_unhighlight() {
++      if (this.highlightElement &&
++         !this.highlightElement.hasAttribute('hidden')) {
++        this.highlightElement.setAttribute('hidden', true);
 +      }
-       fdArrayIndex = this.compileIndex(fdArrayIndex, fontDictTrackers);
-       return {
-         trackers: fontDictTrackers,
-         output: fdArrayIndex
-       };
 +    },
-     compilePrivateDicts: function CFFCompiler_compilePrivateDicts(dicts,
-                                                                   trackers,
-                                                                   output) {
-       for (var i = 0, ii = dicts.length; i < ii; ++i) {
-         var fontDict = dicts[i];
-         assert(fontDict.privateDict && fontDict.hasName('Private'),
-                'There must be an private dictionary.');
-         var privateDict = fontDict.privateDict;
-         var privateDictTracker = new CFFOffsetTracker();
-         var privateDictData = this.compileDict(privateDict, privateDictTracker);
- 
-         var outputLength = output.length;
-         privateDictTracker.offset(outputLength);
-         if (!privateDictData.length) {
-           // The private dictionary was empty, set the output length to zero to
-           // ensure the offset length isn't out of bounds in the eyes of the
-           // sanitizer.
-           outputLength = 0;
-         }
 +
-         trackers[i].setEntryLocation('Private',
-                                      [privateDictData.length, outputLength],
-                                      output);
-         output.add(privateDictData);
++    initContainer: function InteractiveAnnotation_initContainer() {
 +
-         if (privateDict.subrsIndex && privateDict.hasName('Subrs')) {
-           var subrs = this.compileIndex(privateDict.subrsIndex);
-           privateDictTracker.setEntryLocation('Subrs', [privateDictData.length],
-                                               output);
-           output.add(subrs);
-         }
-       }
-     },
-     compileDict: function CFFCompiler_compileDict(dict, offsetTracker) {
-       var out = [];
-       // The dictionary keys must be in a certain order.
-       var order = dict.order;
-       for (var i = 0; i < order.length; ++i) {
-         var key = order[i];
-         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];
++      var item = this.data;
++      var rect = item.rect;
 +
-         // Remove any empty dict values.
-         if (values.length === 0)
-           continue;
++      var container = this.getEmptyContainer('section', rect, item.borderWidth);
++      container.style.backgroundColor = item.color;
 +
-         for (var j = 0, jj = types.length; j < jj; ++j) {
-           var type = types[j];
-           var value = values[j];
-           switch (type) {
-             case 'num':
-             case 'sid':
-               out = out.concat(this.encodeNumber(value));
-               break;
-             case 'offset':
-               // For offsets we just insert a 32bit integer so we don't have to
-               // deal with figuring out the length of the offset when it gets
-               // replaced later on by the compiler.
-               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))
-                 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)
-                 out = out.concat(this.encodeNumber(values[k]));
-               break;
-             default:
-               error('Unknown data type of ' + type);
-               break;
-           }
-         }
-         out = out.concat(dict.opcodes[key]);
++      var color = item.color;
++      var rgb = [];
++      for (var i = 0; i < 3; ++i) {
++        rgb[i] = Math.round(color[i] * 255);
 +      }
-       return out;
-     },
-     compileStringIndex: function CFFCompiler_compileStringIndex(strings) {
-       var stringIndex = new CFFIndex();
-       for (var i = 0, ii = strings.length; i < ii; ++i)
-         stringIndex.add(stringToArray(strings[i]));
-       return this.compileIndex(stringIndex);
-     },
-     compileGlobalSubrIndex: function CFFCompiler_compileGlobalSubrIndex() {
-       var globalSubrIndex = this.cff.globalSubrIndex;
-       this.out.writeByteArray(this.compileIndex(globalSubrIndex));
-     },
-     compileCharStrings: function CFFCompiler_compileCharStrings(charStrings) {
-       return this.compileIndex(charStrings);
-     },
-     compileCharset: function CFFCompiler_compileCharset(charset) {
-       return this.compileTypedArray(charset.raw);
-     },
-     compileEncoding: function CFFCompiler_compileEncoding(encoding) {
-       return this.compileTypedArray(encoding.raw);
-     },
-     compileFDSelect: function CFFCompiler_compileFDSelect(fdSelect) {
-       return this.compileTypedArray(fdSelect);
-     },
-     compileTypedArray: function CFFCompiler_compileTypedArray(data) {
-       var out = [];
-       for (var i = 0, ii = data.length; i < ii; ++i)
-         out[i] = data[i];
-       return out;
-     },
-     compileIndex: function CFFCompiler_compileIndex(index, trackers) {
-       trackers = trackers || [];
-       var objects = index.objects;
-       // First 2 bytes contains the number of objects contained into this index
-       var count = objects.length;
- 
-       // 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)
-         return [0, 0, 0];
- 
-       var data = [(count >> 8) & 0xFF, count & 0xff];
- 
-       var lastOffset = 1;
-       for (var i = 0; i < count; ++i)
-         lastOffset += objects[i].length;
- 
-       var offsetSize;
-       if (lastOffset < 0x100)
-         offsetSize = 1;
-       else if (lastOffset < 0x10000)
-         offsetSize = 2;
-       else if (lastOffset < 0x1000000)
-         offsetSize = 3;
-       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++) {
-         if (offsetSize === 1) {
-           data.push(relativeOffset & 0xFF);
-         } else if (offsetSize === 2) {
-           data.push((relativeOffset >> 8) & 0xFF,
-                      relativeOffset & 0xFF);
-         } else if (offsetSize === 3) {
-           data.push((relativeOffset >> 16) & 0xFF,
-                     (relativeOffset >> 8) & 0xFF,
-                      relativeOffset & 0xFF);
-         } else {
-           data.push((relativeOffset >>> 24) & 0xFF,
-                     (relativeOffset >> 16) & 0xFF,
-                     (relativeOffset >> 8) & 0xFF,
-                      relativeOffset & 0xFF);
-         }
++      item.colorCssRgb = Util.makeCssRgb(rgb);
 +
-         if (objects[i])
-           relativeOffset += objects[i].length;
-       }
-       var offset = data.length;
++      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);
 +
-       for (var i = 0; i < count; i++) {
-         // Notify the tracker where the object will be offset in the data.
-         if (trackers[i])
-           trackers[i].offset(data.length);
-         for (var j = 0, jj = objects[i].length; j < jj; j++)
-           data.push(objects[i][j]);
-       }
-       return data;
-     }
-   };
-   return CFFCompiler;
- })();
++      this.highlightElement = highlight;
++      container.appendChild(this.highlightElement);
 +
- // Workaround for seac on Windows.
- (function checkSeacSupport() {
-   if (/Windows/.test(navigator.userAgent)) {
-     SEAC_ANALYSIS_ENABLED = true;
-   }
- })();
++      return container;
++    }
++  });
 +
- // Workaround for Private Use Area characters in Chrome on Windows
- // http://code.google.com/p/chromium/issues/detail?id=122465
- // https://github.com/mozilla/pdf.js/issues/1689
- (function checkChromeWindows() {
-   if (/Windows.*Chrome/.test(navigator.userAgent)) {
-     SYMBOLIC_FONT_GLYPH_OFFSET = 0xF100;
-   }
++  return InteractiveAnnotation;
 +})();
 +
++var TextAnnotation = (function TextAnnotationClosure() {
++  function TextAnnotation(params) {
++    InteractiveAnnotation.call(this, params);
 +
- var GlyphsUnicode = {
-   A: 0x0041,
-   AE: 0x00C6,
-   AEacute: 0x01FC,
-   AEmacron: 0x01E2,
-   AEsmall: 0xF7E6,
-   Aacute: 0x00C1,
-   Aacutesmall: 0xF7E1,
-   Abreve: 0x0102,
-   Abreveacute: 0x1EAE,
-   Abrevecyrillic: 0x04D0,
-   Abrevedotbelow: 0x1EB6,
-   Abrevegrave: 0x1EB0,
-   Abrevehookabove: 0x1EB2,
-   Abrevetilde: 0x1EB4,
-   Acaron: 0x01CD,
-   Acircle: 0x24B6,
-   Acircumflex: 0x00C2,
-   Acircumflexacute: 0x1EA4,
-   Acircumflexdotbelow: 0x1EAC,
-   Acircumflexgrave: 0x1EA6,
-   Acircumflexhookabove: 0x1EA8,
-   Acircumflexsmall: 0xF7E2,
-   Acircumflextilde: 0x1EAA,
-   Acute: 0xF6C9,
-   Acutesmall: 0xF7B4,
-   Acyrillic: 0x0410,
-   Adblgrave: 0x0200,
-   Adieresis: 0x00C4,
-   Adieresiscyrillic: 0x04D2,
-   Adieresismacron: 0x01DE,
-   Adieresissmall: 0xF7E4,
-   Adotbelow: 0x1EA0,
-   Adotmacron: 0x01E0,
-   Agrave: 0x00C0,
-   Agravesmall: 0xF7E0,
-   Ahookabove: 0x1EA2,
-   Aiecyrillic: 0x04D4,
-   Ainvertedbreve: 0x0202,
-   Alpha: 0x0391,
-   Alphatonos: 0x0386,
-   Amacron: 0x0100,
-   Amonospace: 0xFF21,
-   Aogonek: 0x0104,
-   Aring: 0x00C5,
-   Aringacute: 0x01FA,
-   Aringbelow: 0x1E00,
-   Aringsmall: 0xF7E5,
-   Asmall: 0xF761,
-   Atilde: 0x00C3,
-   Atildesmall: 0xF7E3,
-   Aybarmenian: 0x0531,
-   B: 0x0042,
-   Bcircle: 0x24B7,
-   Bdotaccent: 0x1E02,
-   Bdotbelow: 0x1E04,
-   Becyrillic: 0x0411,
-   Benarmenian: 0x0532,
-   Beta: 0x0392,
-   Bhook: 0x0181,
-   Blinebelow: 0x1E06,
-   Bmonospace: 0xFF22,
-   Brevesmall: 0xF6F4,
-   Bsmall: 0xF762,
-   Btopbar: 0x0182,
-   C: 0x0043,
-   Caarmenian: 0x053E,
-   Cacute: 0x0106,
-   Caron: 0xF6CA,
-   Caronsmall: 0xF6F5,
-   Ccaron: 0x010C,
-   Ccedilla: 0x00C7,
-   Ccedillaacute: 0x1E08,
-   Ccedillasmall: 0xF7E7,
-   Ccircle: 0x24B8,
-   Ccircumflex: 0x0108,
-   Cdot: 0x010A,
-   Cdotaccent: 0x010A,
-   Cedillasmall: 0xF7B8,
-   Chaarmenian: 0x0549,
-   Cheabkhasiancyrillic: 0x04BC,
-   Checyrillic: 0x0427,
-   Chedescenderabkhasiancyrillic: 0x04BE,
-   Chedescendercyrillic: 0x04B6,
-   Chedieresiscyrillic: 0x04F4,
-   Cheharmenian: 0x0543,
-   Chekhakassiancyrillic: 0x04CB,
-   Cheverticalstrokecyrillic: 0x04B8,
-   Chi: 0x03A7,
-   Chook: 0x0187,
-   Circumflexsmall: 0xF6F6,
-   Cmonospace: 0xFF23,
-   Coarmenian: 0x0551,
-   Csmall: 0xF763,
-   D: 0x0044,
-   DZ: 0x01F1,
-   DZcaron: 0x01C4,
-   Daarmenian: 0x0534,
-   Dafrican: 0x0189,
-   Dcaron: 0x010E,
-   Dcedilla: 0x1E10,
-   Dcircle: 0x24B9,
-   Dcircumflexbelow: 0x1E12,
-   Dcroat: 0x0110,
-   Ddotaccent: 0x1E0A,
-   Ddotbelow: 0x1E0C,
-   Decyrillic: 0x0414,
-   Deicoptic: 0x03EE,
-   Delta: 0x2206,
-   Deltagreek: 0x0394,
-   Dhook: 0x018A,
-   Dieresis: 0xF6CB,
-   DieresisAcute: 0xF6CC,
-   DieresisGrave: 0xF6CD,
-   Dieresissmall: 0xF7A8,
-   Digammagreek: 0x03DC,
-   Djecyrillic: 0x0402,
-   Dlinebelow: 0x1E0E,
-   Dmonospace: 0xFF24,
-   Dotaccentsmall: 0xF6F7,
-   Dslash: 0x0110,
-   Dsmall: 0xF764,
-   Dtopbar: 0x018B,
-   Dz: 0x01F2,
-   Dzcaron: 0x01C5,
-   Dzeabkhasiancyrillic: 0x04E0,
-   Dzecyrillic: 0x0405,
-   Dzhecyrillic: 0x040F,
-   E: 0x0045,
-   Eacute: 0x00C9,
-   Eacutesmall: 0xF7E9,
-   Ebreve: 0x0114,
-   Ecaron: 0x011A,
-   Ecedillabreve: 0x1E1C,
-   Echarmenian: 0x0535,
-   Ecircle: 0x24BA,
-   Ecircumflex: 0x00CA,
-   Ecircumflexacute: 0x1EBE,
-   Ecircumflexbelow: 0x1E18,
-   Ecircumflexdotbelow: 0x1EC6,
-   Ecircumflexgrave: 0x1EC0,
-   Ecircumflexhookabove: 0x1EC2,
-   Ecircumflexsmall: 0xF7EA,
-   Ecircumflextilde: 0x1EC4,
-   Ecyrillic: 0x0404,
-   Edblgrave: 0x0204,
-   Edieresis: 0x00CB,
-   Edieresissmall: 0xF7EB,
-   Edot: 0x0116,
-   Edotaccent: 0x0116,
-   Edotbelow: 0x1EB8,
-   Efcyrillic: 0x0424,
-   Egrave: 0x00C8,
-   Egravesmall: 0xF7E8,
-   Eharmenian: 0x0537,
-   Ehookabove: 0x1EBA,
-   Eightroman: 0x2167,
-   Einvertedbreve: 0x0206,
-   Eiotifiedcyrillic: 0x0464,
-   Elcyrillic: 0x041B,
-   Elevenroman: 0x216A,
-   Emacron: 0x0112,
-   Emacronacute: 0x1E16,
-   Emacrongrave: 0x1E14,
-   Emcyrillic: 0x041C,
-   Emonospace: 0xFF25,
-   Encyrillic: 0x041D,
-   Endescendercyrillic: 0x04A2,
-   Eng: 0x014A,
-   Enghecyrillic: 0x04A4,
-   Enhookcyrillic: 0x04C7,
-   Eogonek: 0x0118,
-   Eopen: 0x0190,
-   Epsilon: 0x0395,
-   Epsilontonos: 0x0388,
-   Ercyrillic: 0x0420,
-   Ereversed: 0x018E,
-   Ereversedcyrillic: 0x042D,
-   Escyrillic: 0x0421,
-   Esdescendercyrillic: 0x04AA,
-   Esh: 0x01A9,
-   Esmall: 0xF765,
-   Eta: 0x0397,
-   Etarmenian: 0x0538,
-   Etatonos: 0x0389,
-   Eth: 0x00D0,
-   Ethsmall: 0xF7F0,
-   Etilde: 0x1EBC,
-   Etildebelow: 0x1E1A,
-   Euro: 0x20AC,
-   Ezh: 0x01B7,
-   Ezhcaron: 0x01EE,
-   Ezhreversed: 0x01B8,
-   F: 0x0046,
-   Fcircle: 0x24BB,
-   Fdotaccent: 0x1E1E,
-   Feharmenian: 0x0556,
-   Feicoptic: 0x03E4,
-   Fhook: 0x0191,
-   Fitacyrillic: 0x0472,
-   Fiveroman: 0x2164,
-   Fmonospace: 0xFF26,
-   Fourroman: 0x2163,
-   Fsmall: 0xF766,
-   G: 0x0047,
-   GBsquare: 0x3387,
-   Gacute: 0x01F4,
-   Gamma: 0x0393,
-   Gammaafrican: 0x0194,
-   Gangiacoptic: 0x03EA,
-   Gbreve: 0x011E,
-   Gcaron: 0x01E6,
-   Gcedilla: 0x0122,
-   Gcircle: 0x24BC,
-   Gcircumflex: 0x011C,
-   Gcommaaccent: 0x0122,
-   Gdot: 0x0120,
-   Gdotaccent: 0x0120,
-   Gecyrillic: 0x0413,
-   Ghadarmenian: 0x0542,
-   Ghemiddlehookcyrillic: 0x0494,
-   Ghestrokecyrillic: 0x0492,
-   Gheupturncyrillic: 0x0490,
-   Ghook: 0x0193,
-   Gimarmenian: 0x0533,
-   Gjecyrillic: 0x0403,
-   Gmacron: 0x1E20,
-   Gmonospace: 0xFF27,
-   Grave: 0xF6CE,
-   Gravesmall: 0xF760,
-   Gsmall: 0xF767,
-   Gsmallhook: 0x029B,
-   Gstroke: 0x01E4,
-   H: 0x0048,
-   H18533: 0x25CF,
-   H18543: 0x25AA,
-   H18551: 0x25AB,
-   H22073: 0x25A1,
-   HPsquare: 0x33CB,
-   Haabkhasiancyrillic: 0x04A8,
-   Hadescendercyrillic: 0x04B2,
-   Hardsigncyrillic: 0x042A,
-   Hbar: 0x0126,
-   Hbrevebelow: 0x1E2A,
-   Hcedilla: 0x1E28,
-   Hcircle: 0x24BD,
-   Hcircumflex: 0x0124,
-   Hdieresis: 0x1E26,
-   Hdotaccent: 0x1E22,
-   Hdotbelow: 0x1E24,
-   Hmonospace: 0xFF28,
-   Hoarmenian: 0x0540,
-   Horicoptic: 0x03E8,
-   Hsmall: 0xF768,
-   Hungarumlaut: 0xF6CF,
-   Hungarumlautsmall: 0xF6F8,
-   Hzsquare: 0x3390,
-   I: 0x0049,
-   IAcyrillic: 0x042F,
-   IJ: 0x0132,
-   IUcyrillic: 0x042E,
-   Iacute: 0x00CD,
-   Iacutesmall: 0xF7ED,
-   Ibreve: 0x012C,
-   Icaron: 0x01CF,
-   Icircle: 0x24BE,
-   Icircumflex: 0x00CE,
-   Icircumflexsmall: 0xF7EE,
-   Icyrillic: 0x0406,
-   Idblgrave: 0x0208,
-   Idieresis: 0x00CF,
-   Idieresisacute: 0x1E2E,
-   Idieresiscyrillic: 0x04E4,
-   Idieresissmall: 0xF7EF,
-   Idot: 0x0130,
-   Idotaccent: 0x0130,
-   Idotbelow: 0x1ECA,
-   Iebrevecyrillic: 0x04D6,
-   Iecyrillic: 0x0415,
-   Ifraktur: 0x2111,
-   Igrave: 0x00CC,
-   Igravesmall: 0xF7EC,
-   Ihookabove: 0x1EC8,
-   Iicyrillic: 0x0418,
-   Iinvertedbreve: 0x020A,
-   Iishortcyrillic: 0x0419,
-   Imacron: 0x012A,
-   Imacroncyrillic: 0x04E2,
-   Imonospace: 0xFF29,
-   Iniarmenian: 0x053B,
-   Iocyrillic: 0x0401,
-   Iogonek: 0x012E,
-   Iota: 0x0399,
-   Iotaafrican: 0x0196,
-   Iotadieresis: 0x03AA,
-   Iotatonos: 0x038A,
-   Ismall: 0xF769,
-   Istroke: 0x0197,
-   Itilde: 0x0128,
-   Itildebelow: 0x1E2C,
-   Izhitsacyrillic: 0x0474,
-   Izhitsadblgravecyrillic: 0x0476,
-   J: 0x004A,
-   Jaarmenian: 0x0541,
-   Jcircle: 0x24BF,
-   Jcircumflex: 0x0134,
-   Jecyrillic: 0x0408,
-   Jheharmenian: 0x054B,
-   Jmonospace: 0xFF2A,
-   Jsmall: 0xF76A,
-   K: 0x004B,
-   KBsquare: 0x3385,
-   KKsquare: 0x33CD,
-   Kabashkircyrillic: 0x04A0,
-   Kacute: 0x1E30,
-   Kacyrillic: 0x041A,
-   Kadescendercyrillic: 0x049A,
-   Kahookcyrillic: 0x04C3,
-   Kappa: 0x039A,
-   Kastrokecyrillic: 0x049E,
-   Kaverticalstrokecyrillic: 0x049C,
-   Kcaron: 0x01E8,
-   Kcedilla: 0x0136,
-   Kcircle: 0x24C0,
-   Kcommaaccent: 0x0136,
-   Kdotbelow: 0x1E32,
-   Keharmenian: 0x0554,
-   Kenarmenian: 0x053F,
-   Khacyrillic: 0x0425,
-   Kheicoptic: 0x03E6,
-   Khook: 0x0198,
-   Kjecyrillic: 0x040C,
-   Klinebelow: 0x1E34,
-   Kmonospace: 0xFF2B,
-   Koppacyrillic: 0x0480,
-   Koppagreek: 0x03DE,
-   Ksicyrillic: 0x046E,
-   Ksmall: 0xF76B,
-   L: 0x004C,
-   LJ: 0x01C7,
-   LL: 0xF6BF,
-   Lacute: 0x0139,
-   Lambda: 0x039B,
-   Lcaron: 0x013D,
-   Lcedilla: 0x013B,
-   Lcircle: 0x24C1,
-   Lcircumflexbelow: 0x1E3C,
-   Lcommaaccent: 0x013B,
-   Ldot: 0x013F,
-   Ldotaccent: 0x013F,
-   Ldotbelow: 0x1E36,
-   Ldotbelowmacron: 0x1E38,
-   Liwnarmenian: 0x053C,
-   Lj: 0x01C8,
-   Ljecyrillic: 0x0409,
-   Llinebelow: 0x1E3A,
-   Lmonospace: 0xFF2C,
-   Lslash: 0x0141,
-   Lslashsmall: 0xF6F9,
-   Lsmall: 0xF76C,
-   M: 0x004D,
-   MBsquare: 0x3386,
-   Macron: 0xF6D0,
-   Macronsmall: 0xF7AF,
-   Macute: 0x1E3E,
-   Mcircle: 0x24C2,
-   Mdotaccent: 0x1E40,
-   Mdotbelow: 0x1E42,
-   Menarmenian: 0x0544,
-   Mmonospace: 0xFF2D,
-   Msmall: 0xF76D,
-   Mturned: 0x019C,
-   Mu: 0x039C,
-   N: 0x004E,
-   NJ: 0x01CA,
-   Nacute: 0x0143,
-   Ncaron: 0x0147,
-   Ncedilla: 0x0145,
-   Ncircle: 0x24C3,
-   Ncircumflexbelow: 0x1E4A,
-   Ncommaaccent: 0x0145,
-   Ndotaccent: 0x1E44,
-   Ndotbelow: 0x1E46,
-   Nhookleft: 0x019D,
-   Nineroman: 0x2168,
-   Nj: 0x01CB,
-   Njecyrillic: 0x040A,
-   Nlinebelow: 0x1E48,
-   Nmonospace: 0xFF2E,
-   Nowarmenian: 0x0546,
-   Nsmall: 0xF76E,
-   Ntilde: 0x00D1,
-   Ntildesmall: 0xF7F1,
-   Nu: 0x039D,
-   O: 0x004F,
-   OE: 0x0152,
-   OEsmall: 0xF6FA,
-   Oacute: 0x00D3,
-   Oacutesmall: 0xF7F3,
-   Obarredcyrillic: 0x04E8,
-   Obarreddieresiscyrillic: 0x04EA,
-   Obreve: 0x014E,
-   Ocaron: 0x01D1,
-   Ocenteredtilde: 0x019F,
-   Ocircle: 0x24C4,
-   Ocircumflex: 0x00D4,
-   Ocircumflexacute: 0x1ED0,
-   Ocircumflexdotbelow: 0x1ED8,
-   Ocircumflexgrave: 0x1ED2,
-   Ocircumflexhookabove: 0x1ED4,
-   Ocircumflexsmall: 0xF7F4,
-   Ocircumflextilde: 0x1ED6,
-   Ocyrillic: 0x041E,
-   Odblacute: 0x0150,
-   Odblgrave: 0x020C,
-   Odieresis: 0x00D6,
-   Odieresiscyrillic: 0x04E6,
-   Odieresissmall: 0xF7F6,
-   Odotbelow: 0x1ECC,
-   Ogoneksmall: 0xF6FB,
-   Ograve: 0x00D2,
-   Ogravesmall: 0xF7F2,
-   Oharmenian: 0x0555,
-   Ohm: 0x2126,
-   Ohookabove: 0x1ECE,
-   Ohorn: 0x01A0,
-   Ohornacute: 0x1EDA,
-   Ohorndotbelow: 0x1EE2,
-   Ohorngrave: 0x1EDC,
-   Ohornhookabove: 0x1EDE,
-   Ohorntilde: 0x1EE0,
-   Ohungarumlaut: 0x0150,
-   Oi: 0x01A2,
-   Oinvertedbreve: 0x020E,
-   Omacron: 0x014C,
-   Omacronacute: 0x1E52,
-   Omacrongrave: 0x1E50,
-   Omega: 0x2126,
-   Omegacyrillic: 0x0460,
-   Omegagreek: 0x03A9,
-   Omegaroundcyrillic: 0x047A,
-   Omegatitlocyrillic: 0x047C,
-   Omegatonos: 0x038F,
-   Omicron: 0x039F,
-   Omicrontonos: 0x038C,
-   Omonospace: 0xFF2F,
-   Oneroman: 0x2160,
-   Oogonek: 0x01EA,
-   Oogonekmacron: 0x01EC,
-   Oopen: 0x0186,
-   Oslash: 0x00D8,
-   Oslashacute: 0x01FE,
-   Oslashsmall: 0xF7F8,
-   Osmall: 0xF76F,
-   Ostrokeacute: 0x01FE,
-   Otcyrillic: 0x047E,
-   Otilde: 0x00D5,
-   Otildeacute: 0x1E4C,
-   Otildedieresis: 0x1E4E,
-   Otildesmall: 0xF7F5,
-   P: 0x0050,
-   Pacute: 0x1E54,
-   Pcircle: 0x24C5,
-   Pdotaccent: 0x1E56,
-   Pecyrillic: 0x041F,
-   Peharmenian: 0x054A,
-   Pemiddlehookcyrillic: 0x04A6,
-   Phi: 0x03A6,
-   Phook: 0x01A4,
-   Pi: 0x03A0,
-   Piwrarmenian: 0x0553,
-   Pmonospace: 0xFF30,
-   Psi: 0x03A8,
-   Psicyrillic: 0x0470,
-   Psmall: 0xF770,
-   Q: 0x0051,
-   Qcircle: 0x24C6,
-   Qmonospace: 0xFF31,
-   Qsmall: 0xF771,
-   R: 0x0052,
-   Raarmenian: 0x054C,
-   Racute: 0x0154,
-   Rcaron: 0x0158,
-   Rcedilla: 0x0156,
-   Rcircle: 0x24C7,
-   Rcommaaccent: 0x0156,
-   Rdblgrave: 0x0210,
-   Rdotaccent: 0x1E58,
-   Rdotbelow: 0x1E5A,
-   Rdotbelowmacron: 0x1E5C,
-   Reharmenian: 0x0550,
-   Rfraktur: 0x211C,
-   Rho: 0x03A1,
-   Ringsmall: 0xF6FC,
-   Rinvertedbreve: 0x0212,
-   Rlinebelow: 0x1E5E,
-   Rmonospace: 0xFF32,
-   Rsmall: 0xF772,
-   Rsmallinverted: 0x0281,
-   Rsmallinvertedsuperior: 0x02B6,
-   S: 0x0053,
-   SF010000: 0x250C,
-   SF020000: 0x2514,
-   SF030000: 0x2510,
-   SF040000: 0x2518,
-   SF050000: 0x253C,
-   SF060000: 0x252C,
-   SF070000: 0x2534,
-   SF080000: 0x251C,
-   SF090000: 0x2524,
-   SF100000: 0x2500,
-   SF110000: 0x2502,
-   SF190000: 0x2561,
-   SF200000: 0x2562,
-   SF210000: 0x2556,
-   SF220000: 0x2555,
-   SF230000: 0x2563,
-   SF240000: 0x2551,
-   SF250000: 0x2557,
-   SF260000: 0x255D,
-   SF270000: 0x255C,
-   SF280000: 0x255B,
-   SF360000: 0x255E,
-   SF370000: 0x255F,
-   SF380000: 0x255A,
-   SF390000: 0x2554,
-   SF400000: 0x2569,
-   SF410000: 0x2566,
-   SF420000: 0x2560,
-   SF430000: 0x2550,
-   SF440000: 0x256C,
-   SF450000: 0x2567,
-   SF460000: 0x2568,
-   SF470000: 0x2564,
-   SF480000: 0x2565,
-   SF490000: 0x2559,
-   SF500000: 0x2558,
-   SF510000: 0x2552,
-   SF520000: 0x2553,
-   SF530000: 0x256B,
-   SF540000: 0x256A,
-   Sacute: 0x015A,
-   Sacutedotaccent: 0x1E64,
-   Sampigreek: 0x03E0,
-   Scaron: 0x0160,
-   Scarondotaccent: 0x1E66,
-   Scaronsmall: 0xF6FD,
-   Scedilla: 0x015E,
-   Schwa: 0x018F,
-   Schwacyrillic: 0x04D8,
-   Schwadieresiscyrillic: 0x04DA,
-   Scircle: 0x24C8,
-   Scircumflex: 0x015C,
-   Scommaaccent: 0x0218,
-   Sdotaccent: 0x1E60,
-   Sdotbelow: 0x1E62,
-   Sdotbelowdotaccent: 0x1E68,
-   Seharmenian: 0x054D,
-   Sevenroman: 0x2166,
-   Shaarmenian: 0x0547,
-   Shacyrillic: 0x0428,
-   Shchacyrillic: 0x0429,
-   Sheicoptic: 0x03E2,
-   Shhacyrillic: 0x04BA,
-   Shimacoptic: 0x03EC,
-   Sigma: 0x03A3,
-   Sixroman: 0x2165,
-   Smonospace: 0xFF33,
-   Softsigncyrillic: 0x042C,
-   Ssmall: 0xF773,
-   Stigmagreek: 0x03DA,
-   T: 0x0054,
-   Tau: 0x03A4,
-   Tbar: 0x0166,
-   Tcaron: 0x0164,
-   Tcedilla: 0x0162,
-   Tcircle: 0x24C9,
-   Tcircumflexbelow: 0x1E70,
-   Tcommaaccent: 0x0162,
-   Tdotaccent: 0x1E6A,
-   Tdotbelow: 0x1E6C,
-   Tecyrillic: 0x0422,
-   Tedescendercyrillic: 0x04AC,
-   Tenroman: 0x2169,
-   Tetsecyrillic: 0x04B4,
-   Theta: 0x0398,
-   Thook: 0x01AC,
-   Thorn: 0x00DE,
-   Thornsmall: 0xF7FE,
-   Threeroman: 0x2162,
-   Tildesmall: 0xF6FE,
-   Tiwnarmenian: 0x054F,
-   Tlinebelow: 0x1E6E,
-   Tmonospace: 0xFF34,
-   Toarmenian: 0x0539,
-   Tonefive: 0x01BC,
-   Tonesix: 0x0184,
-   Tonetwo: 0x01A7,
-   Tretroflexhook: 0x01AE,
-   Tsecyrillic: 0x0426,
-   Tshecyrillic: 0x040B,
-   Tsmall: 0xF774,
-   Twelveroman: 0x216B,
-   Tworoman: 0x2161,
-   U: 0x0055,
-   Uacute: 0x00DA,
-   Uacutesmall: 0xF7FA,
-   Ubreve: 0x016C,
-   Ucaron: 0x01D3,
-   Ucircle: 0x24CA,
-   Ucircumflex: 0x00DB,
-   Ucircumflexbelow: 0x1E76,
-   Ucircumflexsmall: 0xF7FB,
-   Ucyrillic: 0x0423,
-   Udblacute: 0x0170,
-   Udblgrave: 0x0214,
-   Udieresis: 0x00DC,
-   Udieresisacute: 0x01D7,
-   Udieresisbelow: 0x1E72,
-   Udieresiscaron: 0x01D9,
-   Udieresiscyrillic: 0x04F0,
-   Udieresisgrave: 0x01DB,
-   Udieresismacron: 0x01D5,
-   Udieresissmall: 0xF7FC,
-   Udotbelow: 0x1EE4,
-   Ugrave: 0x00D9,
-   Ugravesmall: 0xF7F9,
-   Uhookabove: 0x1EE6,
-   Uhorn: 0x01AF,
-   Uhornacute: 0x1EE8,
-   Uhorndotbelow: 0x1EF0,
-   Uhorngrave: 0x1EEA,
-   Uhornhookabove: 0x1EEC,
-   Uhorntilde: 0x1EEE,
-   Uhungarumlaut: 0x0170,
-   Uhungarumlautcyrillic: 0x04F2,
-   Uinvertedbreve: 0x0216,
-   Ukcyrillic: 0x0478,
-   Umacron: 0x016A,
-   Umacroncyrillic: 0x04EE,
-   Umacrondieresis: 0x1E7A,
-   Umonospace: 0xFF35,
-   Uogonek: 0x0172,
-   Upsilon: 0x03A5,
-   Upsilon1: 0x03D2,
-   Upsilonacutehooksymbolgreek: 0x03D3,
-   Upsilonafrican: 0x01B1,
-   Upsilondieresis: 0x03AB,
-   Upsilondieresishooksymbolgreek: 0x03D4,
-   Upsilonhooksymbol: 0x03D2,
-   Upsilontonos: 0x038E,
-   Uring: 0x016E,
-   Ushortcyrillic: 0x040E,
-   Usmall: 0xF775,
-   Ustraightcyrillic: 0x04AE,
-   Ustraightstrokecyrillic: 0x04B0,
-   Utilde: 0x0168,
-   Utildeacute: 0x1E78,
-   Utildebelow: 0x1E74,
-   V: 0x0056,
-   Vcircle: 0x24CB,
-   Vdotbelow: 0x1E7E,
-   Vecyrillic: 0x0412,
-   Vewarmenian: 0x054E,
-   Vhook: 0x01B2,
-   Vmonospace: 0xFF36,
-   Voarmenian: 0x0548,
-   Vsmall: 0xF776,
-   Vtilde: 0x1E7C,
-   W: 0x0057,
-   Wacute: 0x1E82,
-   Wcircle: 0x24CC,
-   Wcircumflex: 0x0174,
-   Wdieresis: 0x1E84,
-   Wdotaccent: 0x1E86,
-   Wdotbelow: 0x1E88,
-   Wgrave: 0x1E80,
-   Wmonospace: 0xFF37,
-   Wsmall: 0xF777,
-   X: 0x0058,
-   Xcircle: 0x24CD,
-   Xdieresis: 0x1E8C,
-   Xdotaccent: 0x1E8A,
-   Xeharmenian: 0x053D,
-   Xi: 0x039E,
-   Xmonospace: 0xFF38,
-   Xsmall: 0xF778,
-   Y: 0x0059,
-   Yacute: 0x00DD,
-   Yacutesmall: 0xF7FD,
-   Yatcyrillic: 0x0462,
-   Ycircle: 0x24CE,
-   Ycircumflex: 0x0176,
-   Ydieresis: 0x0178,
-   Ydieresissmall: 0xF7FF,
-   Ydotaccent: 0x1E8E,
-   Ydotbelow: 0x1EF4,
-   Yericyrillic: 0x042B,
-   Yerudieresiscyrillic: 0x04F8,
-   Ygrave: 0x1EF2,
-   Yhook: 0x01B3,
-   Yhookabove: 0x1EF6,
-   Yiarmenian: 0x0545,
-   Yicyrillic: 0x0407,
-   Yiwnarmenian: 0x0552,
-   Ymonospace: 0xFF39,
-   Ysmall: 0xF779,
-   Ytilde: 0x1EF8,
-   Yusbigcyrillic: 0x046A,
-   Yusbigiotifiedcyrillic: 0x046C,
-   Yuslittlecyrillic: 0x0466,
-   Yuslittleiotifiedcyrillic: 0x0468,
-   Z: 0x005A,
-   Zaarmenian: 0x0536,
-   Zacute: 0x0179,
-   Zcaron: 0x017D,
-   Zcaronsmall: 0xF6FF,
-   Zcircle: 0x24CF,
-   Zcircumflex: 0x1E90,
-   Zdot: 0x017B,
-   Zdotaccent: 0x017B,
-   Zdotbelow: 0x1E92,
-   Zecyrillic: 0x0417,
-   Zedescendercyrillic: 0x0498,
-   Zedieresiscyrillic: 0x04DE,
-   Zeta: 0x0396,
-   Zhearmenian: 0x053A,
-   Zhebrevecyrillic: 0x04C1,
-   Zhecyrillic: 0x0416,
-   Zhedescendercyrillic: 0x0496,
-   Zhedieresiscyrillic: 0x04DC,
-   Zlinebelow: 0x1E94,
-   Zmonospace: 0xFF3A,
-   Zsmall: 0xF77A,
-   Zstroke: 0x01B5,
-   a: 0x0061,
-   aabengali: 0x0986,
-   aacute: 0x00E1,
-   aadeva: 0x0906,
-   aagujarati: 0x0A86,
-   aagurmukhi: 0x0A06,
-   aamatragurmukhi: 0x0A3E,
-   aarusquare: 0x3303,
-   aavowelsignbengali: 0x09BE,
-   aavowelsigndeva: 0x093E,
-   aavowelsigngujarati: 0x0ABE,
-   abbreviationmarkarmenian: 0x055F,
-   abbreviationsigndeva: 0x0970,
-   abengali: 0x0985,
-   abopomofo: 0x311A,
-   abreve: 0x0103,
-   abreveacute: 0x1EAF,
-   abrevecyrillic: 0x04D1,
-   abrevedotbelow: 0x1EB7,
-   abrevegrave: 0x1EB1,
-   abrevehookabove: 0x1EB3,
-   abrevetilde: 0x1EB5,
-   acaron: 0x01CE,
-   acircle: 0x24D0,
-   acircumflex: 0x00E2,
-   acircumflexacute: 0x1EA5,
-   acircumflexdotbelow: 0x1EAD,
-   acircumflexgrave: 0x1EA7,
-   acircumflexhookabove: 0x1EA9,
-   acircumflextilde: 0x1EAB,
-   acute: 0x00B4,
-   acutebelowcmb: 0x0317,
-   acutecmb: 0x0301,
-   acutecomb: 0x0301,
-   acutedeva: 0x0954,
-   acutelowmod: 0x02CF,
-   acutetonecmb: 0x0341,
-   acyrillic: 0x0430,
-   adblgrave: 0x0201,
-   addakgurmukhi: 0x0A71,
-   adeva: 0x0905,
-   adieresis: 0x00E4,
-   adieresiscyrillic: 0x04D3,
-   adieresismacron: 0x01DF,
-   adotbelow: 0x1EA1,
-   adotmacron: 0x01E1,
-   ae: 0x00E6,
-   aeacute: 0x01FD,
-   aekorean: 0x3150,
-   aemacron: 0x01E3,
-   afii00208: 0x2015,
-   afii08941: 0x20A4,
-   afii10017: 0x0410,
-   afii10018: 0x0411,
-   afii10019: 0x0412,
-   afii10020: 0x0413,
-   afii10021: 0x0414,
-   afii10022: 0x0415,
-   afii10023: 0x0401,
-   afii10024: 0x0416,
-   afii10025: 0x0417,
-   afii10026: 0x0418,
-   afii10027: 0x0419,
-   afii10028: 0x041A,
-   afii10029: 0x041B,
-   afii10030: 0x041C,
-   afii10031: 0x041D,
-   afii10032: 0x041E,
-   afii10033: 0x041F,
-   afii10034: 0x0420,
-   afii10035: 0x0421,
-   afii10036: 0x0422,
-   afii10037: 0x0423,
-   afii10038: 0x0424,
-   afii10039: 0x0425,
-   afii10040: 0x0426,
-   afii10041: 0x0427,
-   afii10042: 0x0428,
-   afii10043: 0x0429,
-   afii10044: 0x042A,
-   afii10045: 0x042B,
-   afii10046: 0x042C,
-   afii10047: 0x042D,
-   afii10048: 0x042E,
-   afii10049: 0x042F,
-   afii10050: 0x0490,
-   afii10051: 0x0402,
-   afii10052: 0x0403,
-   afii10053: 0x0404,
-   afii10054: 0x0405,
-   afii10055: 0x0406,
-   afii10056: 0x0407,
-   afii10057: 0x0408,
-   afii10058: 0x0409,
-   afii10059: 0x040A,
-   afii10060: 0x040B,
-   afii10061: 0x040C,
-   afii10062: 0x040E,
-   afii10063: 0xF6C4,
-   afii10064: 0xF6C5,
-   afii10065: 0x0430,
-   afii10066: 0x0431,
-   afii10067: 0x0432,
-   afii10068: 0x0433,
-   afii10069: 0x0434,
-   afii10070: 0x0435,
-   afii10071: 0x0451,
-   afii10072: 0x0436,
-   afii10073: 0x0437,
-   afii10074: 0x0438,
-   afii10075: 0x0439,
-   afii10076: 0x043A,
-   afii10077: 0x043B,
-   afii10078: 0x043C,
-   afii10079: 0x043D,
-   afii10080: 0x043E,
-   afii10081: 0x043F,
-   afii10082: 0x0440,
-   afii10083: 0x0441,
-   afii10084: 0x0442,
-   afii10085: 0x0443,
-   afii10086: 0x0444,
-   afii10087: 0x0445,
-   afii10088: 0x0446,
-   afii10089: 0x0447,
-   afii10090: 0x0448,
-   afii10091: 0x0449,
-   afii10092: 0x044A,
-   afii10093: 0x044B,
-   afii10094: 0x044C,
-   afii10095: 0x044D,
-   afii10096: 0x044E,
-   afii10097: 0x044F,
-   afii10098: 0x0491,
-   afii10099: 0x0452,
-   afii10100: 0x0453,
-   afii10101: 0x0454,
-   afii10102: 0x0455,
-   afii10103: 0x0456,
-   afii10104: 0x0457,
-   afii10105: 0x0458,
-   afii10106: 0x0459,
-   afii10107: 0x045A,
-   afii10108: 0x045B,
-   afii10109: 0x045C,
-   afii10110: 0x045E,
-   afii10145: 0x040F,
-   afii10146: 0x0462,
-   afii10147: 0x0472,
-   afii10148: 0x0474,
-   afii10192: 0xF6C6,
-   afii10193: 0x045F,
-   afii10194: 0x0463,
-   afii10195: 0x0473,
-   afii10196: 0x0475,
-   afii10831: 0xF6C7,
-   afii10832: 0xF6C8,
-   afii10846: 0x04D9,
-   afii299: 0x200E,
-   afii300: 0x200F,
-   afii301: 0x200D,
-   afii57381: 0x066A,
-   afii57388: 0x060C,
-   afii57392: 0x0660,
-   afii57393: 0x0661,
-   afii57394: 0x0662,
-   afii57395: 0x0663,
-   afii57396: 0x0664,
-   afii57397: 0x0665,
-   afii57398: 0x0666,
-   afii57399: 0x0667,
-   afii57400: 0x0668,
-   afii57401: 0x0669,
-   afii57403: 0x061B,
-   afii57407: 0x061F,
-   afii57409: 0x0621,
-   afii57410: 0x0622,
-   afii57411: 0x0623,
-   afii57412: 0x0624,
-   afii57413: 0x0625,
-   afii57414: 0x0626,
-   afii57415: 0x0627,
-   afii57416: 0x0628,
-   afii57417: 0x0629,
-   afii57418: 0x062A,
-   afii57419: 0x062B,
-   afii57420: 0x062C,
-   afii57421: 0x062D,
-   afii57422: 0x062E,
-   afii57423: 0x062F,
-   afii57424: 0x0630,
-   afii57425: 0x0631,
-   afii57426: 0x0632,
-   afii57427: 0x0633,
-   afii57428: 0x0634,
-   afii57429: 0x0635,
-   afii57430: 0x0636,
-   afii57431: 0x0637,
-   afii57432: 0x0638,
-   afii57433: 0x0639,
-   afii57434: 0x063A,
-   afii57440: 0x0640,
-   afii57441: 0x0641,
-   afii57442: 0x0642,
-   afii57443: 0x0643,
-   afii57444: 0x0644,
-   afii57445: 0x0645,
-   afii57446: 0x0646,
-   afii57448: 0x0648,
-   afii57449: 0x0649,
-   afii57450: 0x064A,
-   afii57451: 0x064B,
-   afii57452: 0x064C,
-   afii57453: 0x064D,
-   afii57454: 0x064E,
-   afii57455: 0x064F,
-   afii57456: 0x0650,
-   afii57457: 0x0651,
-   afii57458: 0x0652,
-   afii57470: 0x0647,
-   afii57505: 0x06A4,
-   afii57506: 0x067E,
-   afii57507: 0x0686,
-   afii57508: 0x0698,
-   afii57509: 0x06AF,
-   afii57511: 0x0679,
-   afii57512: 0x0688,
-   afii57513: 0x0691,
-   afii57514: 0x06BA,
-   afii57519: 0x06D2,
-   afii57534: 0x06D5,
-   afii57636: 0x20AA,
-   afii57645: 0x05BE,
-   afii57658: 0x05C3,
-   afii57664: 0x05D0,
-   afii57665: 0x05D1,
-   afii57666: 0x05D2,
-   afii57667: 0x05D3,
-   afii57668: 0x05D4,
-   afii57669: 0x05D5,
-   afii57670: 0x05D6,
-   afii57671: 0x05D7,
-   afii57672: 0x05D8,
-   afii57673: 0x05D9,
-   afii57674: 0x05DA,
-   afii57675: 0x05DB,
-   afii57676: 0x05DC,
-   afii57677: 0x05DD,
-   afii57678: 0x05DE,
-   afii57679: 0x05DF,
-   afii57680: 0x05E0,
-   afii57681: 0x05E1,
-   afii57682: 0x05E2,
-   afii57683: 0x05E3,
-   afii57684: 0x05E4,
-   afii57685: 0x05E5,
-   afii57686: 0x05E6,
-   afii57687: 0x05E7,
-   afii57688: 0x05E8,
-   afii57689: 0x05E9,
-   afii57690: 0x05EA,
-   afii57694: 0xFB2A,
-   afii57695: 0xFB2B,
-   afii57700: 0xFB4B,
-   afii57705: 0xFB1F,
-   afii57716: 0x05F0,
-   afii57717: 0x05F1,
-   afii57718: 0x05F2,
-   afii57723: 0xFB35,
-   afii57793: 0x05B4,
-   afii57794: 0x05B5,
-   afii57795: 0x05B6,
-   afii57796: 0x05BB,
-   afii57797: 0x05B8,
-   afii57798: 0x05B7,
-   afii57799: 0x05B0,
-   afii57800: 0x05B2,
-   afii57801: 0x05B1,
-   afii57802: 0x05B3,
-   afii57803: 0x05C2,
-   afii57804: 0x05C1,
-   afii57806: 0x05B9,
-   afii57807: 0x05BC,
-   afii57839: 0x05BD,
-   afii57841: 0x05BF,
-   afii57842: 0x05C0,
-   afii57929: 0x02BC,
-   afii61248: 0x2105,
-   afii61289: 0x2113,
-   afii61352: 0x2116,
-   afii61573: 0x202C,
-   afii61574: 0x202D,
-   afii61575: 0x202E,
-   afii61664: 0x200C,
-   afii63167: 0x066D,
-   afii64937: 0x02BD,
-   agrave: 0x00E0,
-   agujarati: 0x0A85,
-   agurmukhi: 0x0A05,
-   ahiragana: 0x3042,
-   ahookabove: 0x1EA3,
-   aibengali: 0x0990,
-   aibopomofo: 0x311E,
-   aideva: 0x0910,
-   aiecyrillic: 0x04D5,
-   aigujarati: 0x0A90,
-   aigurmukhi: 0x0A10,
-   aimatragurmukhi: 0x0A48,
-   ainarabic: 0x0639,
-   ainfinalarabic: 0xFECA,
-   aininitialarabic: 0xFECB,
-   ainmedialarabic: 0xFECC,
-   ainvertedbreve: 0x0203,
-   aivowelsignbengali: 0x09C8,
-   aivowelsigndeva: 0x0948,
-   aivowelsigngujarati: 0x0AC8,
-   akatakana: 0x30A2,
-   akatakanahalfwidth: 0xFF71,
-   akorean: 0x314F,
-   alef: 0x05D0,
-   alefarabic: 0x0627,
-   alefdageshhebrew: 0xFB30,
-   aleffinalarabic: 0xFE8E,
-   alefhamzaabovearabic: 0x0623,
-   alefhamzaabovefinalarabic: 0xFE84,
-   alefhamzabelowarabic: 0x0625,
-   alefhamzabelowfinalarabic: 0xFE88,
-   alefhebrew: 0x05D0,
-   aleflamedhebrew: 0xFB4F,
-   alefmaddaabovearabic: 0x0622,
-   alefmaddaabovefinalarabic: 0xFE82,
-   alefmaksuraarabic: 0x0649,
-   alefmaksurafinalarabic: 0xFEF0,
-   alefmaksurainitialarabic: 0xFEF3,
-   alefmaksuramedialarabic: 0xFEF4,
-   alefpatahhebrew: 0xFB2E,
-   alefqamatshebrew: 0xFB2F,
-   aleph: 0x2135,
-   allequal: 0x224C,
-   alpha: 0x03B1,
-   alphatonos: 0x03AC,
-   amacron: 0x0101,
-   amonospace: 0xFF41,
-   ampersand: 0x0026,
-   ampersandmonospace: 0xFF06,
-   ampersandsmall: 0xF726,
-   amsquare: 0x33C2,
-   anbopomofo: 0x3122,
-   angbopomofo: 0x3124,
-   angbracketleft: 0x3008, // This glyph is missing from Adobe's original list.
-   angbracketright: 0x3009, // This glyph is missing from Adobe's original list.
-   angkhankhuthai: 0x0E5A,
-   angle: 0x2220,
-   anglebracketleft: 0x3008,
-   anglebracketleftvertical: 0xFE3F,
-   anglebracketright: 0x3009,
-   anglebracketrightvertical: 0xFE40,
-   angleleft: 0x2329,
-   angleright: 0x232A,
-   angstrom: 0x212B,
-   anoteleia: 0x0387,
-   anudattadeva: 0x0952,
-   anusvarabengali: 0x0982,
-   anusvaradeva: 0x0902,
-   anusvaragujarati: 0x0A82,
-   aogonek: 0x0105,
-   apaatosquare: 0x3300,
-   aparen: 0x249C,
-   apostrophearmenian: 0x055A,
-   apostrophemod: 0x02BC,
-   apple: 0xF8FF,
-   approaches: 0x2250,
-   approxequal: 0x2248,
-   approxequalorimage: 0x2252,
-   approximatelyequal: 0x2245,
-   araeaekorean: 0x318E,
-   araeakorean: 0x318D,
-   arc: 0x2312,
-   arighthalfring: 0x1E9A,
-   aring: 0x00E5,
-   aringacute: 0x01FB,
-   aringbelow: 0x1E01,
-   arrowboth: 0x2194,
-   arrowdashdown: 0x21E3,
-   arrowdashleft: 0x21E0,
-   arrowdashright: 0x21E2,
-   arrowdashup: 0x21E1,
-   arrowdblboth: 0x21D4,
-   arrowdbldown: 0x21D3,
-   arrowdblleft: 0x21D0,
-   arrowdblright: 0x21D2,
-   arrowdblup: 0x21D1,
-   arrowdown: 0x2193,
-   arrowdownleft: 0x2199,
-   arrowdownright: 0x2198,
-   arrowdownwhite: 0x21E9,
-   arrowheaddownmod: 0x02C5,
-   arrowheadleftmod: 0x02C2,
-   arrowheadrightmod: 0x02C3,
-   arrowheadupmod: 0x02C4,
-   arrowhorizex: 0xF8E7,
-   arrowleft: 0x2190,
-   arrowleftdbl: 0x21D0,
-   arrowleftdblstroke: 0x21CD,
-   arrowleftoverright: 0x21C6,
-   arrowleftwhite: 0x21E6,
-   arrowright: 0x2192,
-   arrowrightdblstroke: 0x21CF,
-   arrowrightheavy: 0x279E,
-   arrowrightoverleft: 0x21C4,
-   arrowrightwhite: 0x21E8,
-   arrowtableft: 0x21E4,
-   arrowtabright: 0x21E5,
-   arrowup: 0x2191,
-   arrowupdn: 0x2195,
-   arrowupdnbse: 0x21A8,
-   arrowupdownbase: 0x21A8,
-   arrowupleft: 0x2196,
-   arrowupleftofdown: 0x21C5,
-   arrowupright: 0x2197,
-   arrowupwhite: 0x21E7,
-   arrowvertex: 0xF8E6,
-   asciicircum: 0x005E,
-   asciicircummonospace: 0xFF3E,
-   asciitilde: 0x007E,
-   asciitildemonospace: 0xFF5E,
-   ascript: 0x0251,
-   ascriptturned: 0x0252,
-   asmallhiragana: 0x3041,
-   asmallkatakana: 0x30A1,
-   asmallkatakanahalfwidth: 0xFF67,
-   asterisk: 0x002A,
-   asteriskaltonearabic: 0x066D,
-   asteriskarabic: 0x066D,
-   asteriskmath: 0x2217,
-   asteriskmonospace: 0xFF0A,
-   asterisksmall: 0xFE61,
-   asterism: 0x2042,
-   asuperior: 0xF6E9,
-   asymptoticallyequal: 0x2243,
-   at: 0x0040,
-   atilde: 0x00E3,
-   atmonospace: 0xFF20,
-   atsmall: 0xFE6B,
-   aturned: 0x0250,
-   aubengali: 0x0994,
-   aubopomofo: 0x3120,
-   audeva: 0x0914,
-   augujarati: 0x0A94,
-   augurmukhi: 0x0A14,
-   aulengthmarkbengali: 0x09D7,
-   aumatragurmukhi: 0x0A4C,
-   auvowelsignbengali: 0x09CC,
-   auvowelsigndeva: 0x094C,
-   auvowelsigngujarati: 0x0ACC,
-   avagrahadeva: 0x093D,
-   aybarmenian: 0x0561,
-   ayin: 0x05E2,
-   ayinaltonehebrew: 0xFB20,
-   ayinhebrew: 0x05E2,
-   b: 0x0062,
-   babengali: 0x09AC,
-   backslash: 0x005C,
-   backslashmonospace: 0xFF3C,
-   badeva: 0x092C,
-   bagujarati: 0x0AAC,
-   bagurmukhi: 0x0A2C,
-   bahiragana: 0x3070,
-   bahtthai: 0x0E3F,
-   bakatakana: 0x30D0,
-   bar: 0x007C,
-   barmonospace: 0xFF5C,
-   bbopomofo: 0x3105,
-   bcircle: 0x24D1,
-   bdotaccent: 0x1E03,
-   bdotbelow: 0x1E05,
-   beamedsixteenthnotes: 0x266C,
-   because: 0x2235,
-   becyrillic: 0x0431,
-   beharabic: 0x0628,
-   behfinalarabic: 0xFE90,
-   behinitialarabic: 0xFE91,
-   behiragana: 0x3079,
-   behmedialarabic: 0xFE92,
-   behmeeminitialarabic: 0xFC9F,
-   behmeemisolatedarabic: 0xFC08,
-   behnoonfinalarabic: 0xFC6D,
-   bekatakana: 0x30D9,
-   benarmenian: 0x0562,
-   bet: 0x05D1,
-   beta: 0x03B2,
-   betasymbolgreek: 0x03D0,
-   betdagesh: 0xFB31,
-   betdageshhebrew: 0xFB31,
-   bethebrew: 0x05D1,
-   betrafehebrew: 0xFB4C,
-   bhabengali: 0x09AD,
-   bhadeva: 0x092D,
-   bhagujarati: 0x0AAD,
-   bhagurmukhi: 0x0A2D,
-   bhook: 0x0253,
-   bihiragana: 0x3073,
-   bikatakana: 0x30D3,
-   bilabialclick: 0x0298,
-   bindigurmukhi: 0x0A02,
-   birusquare: 0x3331,
-   blackcircle: 0x25CF,
-   blackdiamond: 0x25C6,
-   blackdownpointingtriangle: 0x25BC,
-   blackleftpointingpointer: 0x25C4,
-   blackleftpointingtriangle: 0x25C0,
-   blacklenticularbracketleft: 0x3010,
-   blacklenticularbracketleftvertical: 0xFE3B,
-   blacklenticularbracketright: 0x3011,
-   blacklenticularbracketrightvertical: 0xFE3C,
-   blacklowerlefttriangle: 0x25E3,
-   blacklowerrighttriangle: 0x25E2,
-   blackrectangle: 0x25AC,
-   blackrightpointingpointer: 0x25BA,
-   blackrightpointingtriangle: 0x25B6,
-   blacksmallsquare: 0x25AA,
-   blacksmilingface: 0x263B,
-   blacksquare: 0x25A0,
-   blackstar: 0x2605,
-   blackupperlefttriangle: 0x25E4,
-   blackupperrighttriangle: 0x25E5,
-   blackuppointingsmalltriangle: 0x25B4,
-   blackuppointingtriangle: 0x25B2,
-   blank: 0x2423,
-   blinebelow: 0x1E07,
-   block: 0x2588,
-   bmonospace: 0xFF42,
-   bobaimaithai: 0x0E1A,
-   bohiragana: 0x307C,
-   bokatakana: 0x30DC,
-   bparen: 0x249D,
-   bqsquare: 0x33C3,
-   braceex: 0xF8F4,
-   braceleft: 0x007B,
-   braceleftbt: 0xF8F3,
-   braceleftmid: 0xF8F2,
-   braceleftmonospace: 0xFF5B,
-   braceleftsmall: 0xFE5B,
-   bracelefttp: 0xF8F1,
-   braceleftvertical: 0xFE37,
-   braceright: 0x007D,
-   bracerightbt: 0xF8FE,
-   bracerightmid: 0xF8FD,
-   bracerightmonospace: 0xFF5D,
-   bracerightsmall: 0xFE5C,
-   bracerighttp: 0xF8FC,
-   bracerightvertical: 0xFE38,
-   bracketleft: 0x005B,
-   bracketleftbt: 0xF8F0,
-   bracketleftex: 0xF8EF,
-   bracketleftmonospace: 0xFF3B,
-   bracketlefttp: 0xF8EE,
-   bracketright: 0x005D,
-   bracketrightbt: 0xF8FB,
-   bracketrightex: 0xF8FA,
-   bracketrightmonospace: 0xFF3D,
-   bracketrighttp: 0xF8F9,
-   breve: 0x02D8,
-   brevebelowcmb: 0x032E,
-   brevecmb: 0x0306,
-   breveinvertedbelowcmb: 0x032F,
-   breveinvertedcmb: 0x0311,
-   breveinverteddoublecmb: 0x0361,
-   bridgebelowcmb: 0x032A,
-   bridgeinvertedbelowcmb: 0x033A,
-   brokenbar: 0x00A6,
-   bstroke: 0x0180,
-   bsuperior: 0xF6EA,
-   btopbar: 0x0183,
-   buhiragana: 0x3076,
-   bukatakana: 0x30D6,
-   bullet: 0x2022,
-   bulletinverse: 0x25D8,
-   bulletoperator: 0x2219,
-   bullseye: 0x25CE,
-   c: 0x0063,
-   caarmenian: 0x056E,
-   cabengali: 0x099A,
-   cacute: 0x0107,
-   cadeva: 0x091A,
-   cagujarati: 0x0A9A,
-   cagurmukhi: 0x0A1A,
-   calsquare: 0x3388,
-   candrabindubengali: 0x0981,
-   candrabinducmb: 0x0310,
-   candrabindudeva: 0x0901,
-   candrabindugujarati: 0x0A81,
-   capslock: 0x21EA,
-   careof: 0x2105,
-   caron: 0x02C7,
-   caronbelowcmb: 0x032C,
-   caroncmb: 0x030C,
-   carriagereturn: 0x21B5,
-   cbopomofo: 0x3118,
-   ccaron: 0x010D,
-   ccedilla: 0x00E7,
-   ccedillaacute: 0x1E09,
-   ccircle: 0x24D2,
-   ccircumflex: 0x0109,
-   ccurl: 0x0255,
-   cdot: 0x010B,
-   cdotaccent: 0x010B,
-   cdsquare: 0x33C5,
-   cedilla: 0x00B8,
-   cedillacmb: 0x0327,
-   cent: 0x00A2,
-   centigrade: 0x2103,
-   centinferior: 0xF6DF,
-   centmonospace: 0xFFE0,
-   centoldstyle: 0xF7A2,
-   centsuperior: 0xF6E0,
-   chaarmenian: 0x0579,
-   chabengali: 0x099B,
-   chadeva: 0x091B,
-   chagujarati: 0x0A9B,
-   chagurmukhi: 0x0A1B,
-   chbopomofo: 0x3114,
-   cheabkhasiancyrillic: 0x04BD,
-   checkmark: 0x2713,
-   checyrillic: 0x0447,
-   chedescenderabkhasiancyrillic: 0x04BF,
-   chedescendercyrillic: 0x04B7,
-   chedieresiscyrillic: 0x04F5,
-   cheharmenian: 0x0573,
-   chekhakassiancyrillic: 0x04CC,
-   cheverticalstrokecyrillic: 0x04B9,
-   chi: 0x03C7,
-   chieuchacirclekorean: 0x3277,
-   chieuchaparenkorean: 0x3217,
-   chieuchcirclekorean: 0x3269,
-   chieuchkorean: 0x314A,
-   chieuchparenkorean: 0x3209,
-   chochangthai: 0x0E0A,
-   chochanthai: 0x0E08,
-   chochingthai: 0x0E09,
-   chochoethai: 0x0E0C,
-   chook: 0x0188,
-   cieucacirclekorean: 0x3276,
-   cieucaparenkorean: 0x3216,
-   cieuccirclekorean: 0x3268,
-   cieuckorean: 0x3148,
-   cieucparenkorean: 0x3208,
-   cieucuparenkorean: 0x321C,
-   circle: 0x25CB,
-   circlecopyrt: 0x00A9, // This glyph is missing from Adobe's original list.
-   circlemultiply: 0x2297,
-   circleot: 0x2299,
-   circleplus: 0x2295,
-   circlepostalmark: 0x3036,
-   circlewithlefthalfblack: 0x25D0,
-   circlewithrighthalfblack: 0x25D1,
-   circumflex: 0x02C6,
-   circumflexbelowcmb: 0x032D,
-   circumflexcmb: 0x0302,
-   clear: 0x2327,
-   clickalveolar: 0x01C2,
-   clickdental: 0x01C0,
-   clicklateral: 0x01C1,
-   clickretroflex: 0x01C3,
-   club: 0x2663,
-   clubsuitblack: 0x2663,
-   clubsuitwhite: 0x2667,
-   cmcubedsquare: 0x33A4,
-   cmonospace: 0xFF43,
-   cmsquaredsquare: 0x33A0,
-   coarmenian: 0x0581,
-   colon: 0x003A,
-   colonmonetary: 0x20A1,
-   colonmonospace: 0xFF1A,
-   colonsign: 0x20A1,
-   colonsmall: 0xFE55,
-   colontriangularhalfmod: 0x02D1,
-   colontriangularmod: 0x02D0,
-   comma: 0x002C,
-   commaabovecmb: 0x0313,
-   commaaboverightcmb: 0x0315,
-   commaaccent: 0xF6C3,
-   commaarabic: 0x060C,
-   commaarmenian: 0x055D,
-   commainferior: 0xF6E1,
-   commamonospace: 0xFF0C,
-   commareversedabovecmb: 0x0314,
-   commareversedmod: 0x02BD,
-   commasmall: 0xFE50,
-   commasuperior: 0xF6E2,
-   commaturnedabovecmb: 0x0312,
-   commaturnedmod: 0x02BB,
-   compass: 0x263C,
-   congruent: 0x2245,
-   contourintegral: 0x222E,
-   control: 0x2303,
-   controlACK: 0x0006,
-   controlBEL: 0x0007,
-   controlBS: 0x0008,
-   controlCAN: 0x0018,
-   controlCR: 0x000D,
-   controlDC1: 0x0011,
-   controlDC2: 0x0012,
-   controlDC3: 0x0013,
-   controlDC4: 0x0014,
-   controlDEL: 0x007F,
-   controlDLE: 0x0010,
-   controlEM: 0x0019,
-   controlENQ: 0x0005,
-   controlEOT: 0x0004,
-   controlESC: 0x001B,
-   controlETB: 0x0017,
-   controlETX: 0x0003,
-   controlFF: 0x000C,
-   controlFS: 0x001C,
-   controlGS: 0x001D,
-   controlHT: 0x0009,
-   controlLF: 0x000A,
-   controlNAK: 0x0015,
-   controlRS: 0x001E,
-   controlSI: 0x000F,
-   controlSO: 0x000E,
-   controlSOT: 0x0002,
-   controlSTX: 0x0001,
-   controlSUB: 0x001A,
-   controlSYN: 0x0016,
-   controlUS: 0x001F,
-   controlVT: 0x000B,
-   copyright: 0x00A9,
-   copyrightsans: 0xF8E9,
-   copyrightserif: 0xF6D9,
-   cornerbracketleft: 0x300C,
-   cornerbracketlefthalfwidth: 0xFF62,
-   cornerbracketleftvertical: 0xFE41,
-   cornerbracketright: 0x300D,
-   cornerbracketrighthalfwidth: 0xFF63,
-   cornerbracketrightvertical: 0xFE42,
-   corporationsquare: 0x337F,
-   cosquare: 0x33C7,
-   coverkgsquare: 0x33C6,
-   cparen: 0x249E,
-   cruzeiro: 0x20A2,
-   cstretched: 0x0297,
-   curlyand: 0x22CF,
-   curlyor: 0x22CE,
-   currency: 0x00A4,
-   cyrBreve: 0xF6D1,
-   cyrFlex: 0xF6D2,
-   cyrbreve: 0xF6D4,
-   cyrflex: 0xF6D5,
-   d: 0x0064,
-   daarmenian: 0x0564,
-   dabengali: 0x09A6,
-   dadarabic: 0x0636,
-   dadeva: 0x0926,
-   dadfinalarabic: 0xFEBE,
-   dadinitialarabic: 0xFEBF,
-   dadmedialarabic: 0xFEC0,
-   dagesh: 0x05BC,
-   dageshhebrew: 0x05BC,
-   dagger: 0x2020,
-   daggerdbl: 0x2021,
-   dagujarati: 0x0AA6,
-   dagurmukhi: 0x0A26,
-   dahiragana: 0x3060,
-   dakatakana: 0x30C0,
-   dalarabic: 0x062F,
-   dalet: 0x05D3,
-   daletdagesh: 0xFB33,
-   daletdageshhebrew: 0xFB33,
-   dalethebrew: 0x05D3,
-   dalfinalarabic: 0xFEAA,
-   dammaarabic: 0x064F,
-   dammalowarabic: 0x064F,
-   dammatanaltonearabic: 0x064C,
-   dammatanarabic: 0x064C,
-   danda: 0x0964,
-   dargahebrew: 0x05A7,
-   dargalefthebrew: 0x05A7,
-   dasiapneumatacyrilliccmb: 0x0485,
-   dblGrave: 0xF6D3,
-   dblanglebracketleft: 0x300A,
-   dblanglebracketleftvertical: 0xFE3D,
-   dblanglebracketright: 0x300B,
-   dblanglebracketrightvertical: 0xFE3E,
-   dblarchinvertedbelowcmb: 0x032B,
-   dblarrowleft: 0x21D4,
-   dblarrowright: 0x21D2,
-   dbldanda: 0x0965,
-   dblgrave: 0xF6D6,
-   dblgravecmb: 0x030F,
-   dblintegral: 0x222C,
-   dbllowline: 0x2017,
-   dbllowlinecmb: 0x0333,
-   dbloverlinecmb: 0x033F,
-   dblprimemod: 0x02BA,
-   dblverticalbar: 0x2016,
-   dblverticallineabovecmb: 0x030E,
-   dbopomofo: 0x3109,
-   dbsquare: 0x33C8,
-   dcaron: 0x010F,
-   dcedilla: 0x1E11,
-   dcircle: 0x24D3,
-   dcircumflexbelow: 0x1E13,
-   dcroat: 0x0111,
-   ddabengali: 0x09A1,
-   ddadeva: 0x0921,
-   ddagujarati: 0x0AA1,
-   ddagurmukhi: 0x0A21,
-   ddalarabic: 0x0688,
-   ddalfinalarabic: 0xFB89,
-   dddhadeva: 0x095C,
-   ddhabengali: 0x09A2,
-   ddhadeva: 0x0922,
-   ddhagujarati: 0x0AA2,
-   ddhagurmukhi: 0x0A22,
-   ddotaccent: 0x1E0B,
-   ddotbelow: 0x1E0D,
-   decimalseparatorarabic: 0x066B,
-   decimalseparatorpersian: 0x066B,
-   decyrillic: 0x0434,
-   degree: 0x00B0,
-   dehihebrew: 0x05AD,
-   dehiragana: 0x3067,
-   deicoptic: 0x03EF,
-   dekatakana: 0x30C7,
-   deleteleft: 0x232B,
-   deleteright: 0x2326,
-   delta: 0x03B4,
-   deltaturned: 0x018D,
-   denominatorminusonenumeratorbengali: 0x09F8,
-   dezh: 0x02A4,
-   dhabengali: 0x09A7,
-   dhadeva: 0x0927,
-   dhagujarati: 0x0AA7,
-   dhagurmukhi: 0x0A27,
-   dhook: 0x0257,
-   dialytikatonos: 0x0385,
-   dialytikatonoscmb: 0x0344,
-   diamond: 0x2666,
-   diamondsuitwhite: 0x2662,
-   dieresis: 0x00A8,
-   dieresisacute: 0xF6D7,
-   dieresisbelowcmb: 0x0324,
-   dieresiscmb: 0x0308,
-   dieresisgrave: 0xF6D8,
-   dieresistonos: 0x0385,
-   dihiragana: 0x3062,
-   dikatakana: 0x30C2,
-   dittomark: 0x3003,
-   divide: 0x00F7,
-   divides: 0x2223,
-   divisionslash: 0x2215,
-   djecyrillic: 0x0452,
-   dkshade: 0x2593,
-   dlinebelow: 0x1E0F,
-   dlsquare: 0x3397,
-   dmacron: 0x0111,
-   dmonospace: 0xFF44,
-   dnblock: 0x2584,
-   dochadathai: 0x0E0E,
-   dodekthai: 0x0E14,
-   dohiragana: 0x3069,
-   dokatakana: 0x30C9,
-   dollar: 0x0024,
-   dollarinferior: 0xF6E3,
-   dollarmonospace: 0xFF04,
-   dollaroldstyle: 0xF724,
-   dollarsmall: 0xFE69,
-   dollarsuperior: 0xF6E4,
-   dong: 0x20AB,
-   dorusquare: 0x3326,
-   dotaccent: 0x02D9,
-   dotaccentcmb: 0x0307,
-   dotbelowcmb: 0x0323,
-   dotbelowcomb: 0x0323,
-   dotkatakana: 0x30FB,
-   dotlessi: 0x0131,
-   dotlessj: 0xF6BE,
-   dotlessjstrokehook: 0x0284,
-   dotmath: 0x22C5,
-   dottedcircle: 0x25CC,
-   doubleyodpatah: 0xFB1F,
-   doubleyodpatahhebrew: 0xFB1F,
-   downtackbelowcmb: 0x031E,
-   downtackmod: 0x02D5,
-   dparen: 0x249F,
-   dsuperior: 0xF6EB,
-   dtail: 0x0256,
-   dtopbar: 0x018C,
-   duhiragana: 0x3065,
-   dukatakana: 0x30C5,
-   dz: 0x01F3,
-   dzaltone: 0x02A3,
-   dzcaron: 0x01C6,
-   dzcurl: 0x02A5,
-   dzeabkhasiancyrillic: 0x04E1,
-   dzecyrillic: 0x0455,
-   dzhecyrillic: 0x045F,
-   e: 0x0065,
-   eacute: 0x00E9,
-   earth: 0x2641,
-   ebengali: 0x098F,
-   ebopomofo: 0x311C,
-   ebreve: 0x0115,
-   ecandradeva: 0x090D,
-   ecandragujarati: 0x0A8D,
-   ecandravowelsigndeva: 0x0945,
-   ecandravowelsigngujarati: 0x0AC5,
-   ecaron: 0x011B,
-   ecedillabreve: 0x1E1D,
-   echarmenian: 0x0565,
-   echyiwnarmenian: 0x0587,
-   ecircle: 0x24D4,
-   ecircumflex: 0x00EA,
-   ecircumflexacute: 0x1EBF,
-   ecircumflexbelow: 0x1E19,
-   ecircumflexdotbelow: 0x1EC7,
-   ecircumflexgrave: 0x1EC1,
-   ecircumflexhookabove: 0x1EC3,
-   ecircumflextilde: 0x1EC5,
-   ecyrillic: 0x0454,
-   edblgrave: 0x0205,
-   edeva: 0x090F,
-   edieresis: 0x00EB,
-   edot: 0x0117,
-   edotaccent: 0x0117,
-   edotbelow: 0x1EB9,
-   eegurmukhi: 0x0A0F,
-   eematragurmukhi: 0x0A47,
-   efcyrillic: 0x0444,
-   egrave: 0x00E8,
-   egujarati: 0x0A8F,
-   eharmenian: 0x0567,
-   ehbopomofo: 0x311D,
-   ehiragana: 0x3048,
-   ehookabove: 0x1EBB,
-   eibopomofo: 0x311F,
-   eight: 0x0038,
-   eightarabic: 0x0668,
-   eightbengali: 0x09EE,
-   eightcircle: 0x2467,
-   eightcircleinversesansserif: 0x2791,
-   eightdeva: 0x096E,
-   eighteencircle: 0x2471,
-   eighteenparen: 0x2485,
-   eighteenperiod: 0x2499,
-   eightgujarati: 0x0AEE,
-   eightgurmukhi: 0x0A6E,
-   eighthackarabic: 0x0668,
-   eighthangzhou: 0x3028,
-   eighthnotebeamed: 0x266B,
-   eightideographicparen: 0x3227,
-   eightinferior: 0x2088,
-   eightmonospace: 0xFF18,
-   eightoldstyle: 0xF738,
-   eightparen: 0x247B,
-   eightperiod: 0x248F,
-   eightpersian: 0x06F8,
-   eightroman: 0x2177,
-   eightsuperior: 0x2078,
-   eightthai: 0x0E58,
-   einvertedbreve: 0x0207,
-   eiotifiedcyrillic: 0x0465,
-   ekatakana: 0x30A8,
-   ekatakanahalfwidth: 0xFF74,
-   ekonkargurmukhi: 0x0A74,
-   ekorean: 0x3154,
-   elcyrillic: 0x043B,
-   element: 0x2208,
-   elevencircle: 0x246A,
-   elevenparen: 0x247E,
-   elevenperiod: 0x2492,
-   elevenroman: 0x217A,
-   ellipsis: 0x2026,
-   ellipsisvertical: 0x22EE,
-   emacron: 0x0113,
-   emacronacute: 0x1E17,
-   emacrongrave: 0x1E15,
-   emcyrillic: 0x043C,
-   emdash: 0x2014,
-   emdashvertical: 0xFE31,
-   emonospace: 0xFF45,
-   emphasismarkarmenian: 0x055B,
-   emptyset: 0x2205,
-   enbopomofo: 0x3123,
-   encyrillic: 0x043D,
-   endash: 0x2013,
-   endashvertical: 0xFE32,
-   endescendercyrillic: 0x04A3,
-   eng: 0x014B,
-   engbopomofo: 0x3125,
-   enghecyrillic: 0x04A5,
-   enhookcyrillic: 0x04C8,
-   enspace: 0x2002,
-   eogonek: 0x0119,
-   eokorean: 0x3153,
-   eopen: 0x025B,
-   eopenclosed: 0x029A,
-   eopenreversed: 0x025C,
-   eopenreversedclosed: 0x025E,
-   eopenreversedhook: 0x025D,
-   eparen: 0x24A0,
-   epsilon: 0x03B5,
-   epsilontonos: 0x03AD,
-   equal: 0x003D,
-   equalmonospace: 0xFF1D,
-   equalsmall: 0xFE66,
-   equalsuperior: 0x207C,
-   equivalence: 0x2261,
-   erbopomofo: 0x3126,
-   ercyrillic: 0x0440,
-   ereversed: 0x0258,
-   ereversedcyrillic: 0x044D,
-   escyrillic: 0x0441,
-   esdescendercyrillic: 0x04AB,
-   esh: 0x0283,
-   eshcurl: 0x0286,
-   eshortdeva: 0x090E,
-   eshortvowelsigndeva: 0x0946,
-   eshreversedloop: 0x01AA,
-   eshsquatreversed: 0x0285,
-   esmallhiragana: 0x3047,
-   esmallkatakana: 0x30A7,
-   esmallkatakanahalfwidth: 0xFF6A,
-   estimated: 0x212E,
-   esuperior: 0xF6EC,
-   eta: 0x03B7,
-   etarmenian: 0x0568,
-   etatonos: 0x03AE,
-   eth: 0x00F0,
-   etilde: 0x1EBD,
-   etildebelow: 0x1E1B,
-   etnahtafoukhhebrew: 0x0591,
-   etnahtafoukhlefthebrew: 0x0591,
-   etnahtahebrew: 0x0591,
-   etnahtalefthebrew: 0x0591,
-   eturned: 0x01DD,
-   eukorean: 0x3161,
-   euro: 0x20AC,
-   evowelsignbengali: 0x09C7,
-   evowelsigndeva: 0x0947,
-   evowelsigngujarati: 0x0AC7,
-   exclam: 0x0021,
-   exclamarmenian: 0x055C,
-   exclamdbl: 0x203C,
-   exclamdown: 0x00A1,
-   exclamdownsmall: 0xF7A1,
-   exclammonospace: 0xFF01,
-   exclamsmall: 0xF721,
-   existential: 0x2203,
-   ezh: 0x0292,
-   ezhcaron: 0x01EF,
-   ezhcurl: 0x0293,
-   ezhreversed: 0x01B9,
-   ezhtail: 0x01BA,
-   f: 0x0066,
-   fadeva: 0x095E,
-   fagurmukhi: 0x0A5E,
-   fahrenheit: 0x2109,
-   fathaarabic: 0x064E,
-   fathalowarabic: 0x064E,
-   fathatanarabic: 0x064B,
-   fbopomofo: 0x3108,
-   fcircle: 0x24D5,
-   fdotaccent: 0x1E1F,
-   feharabic: 0x0641,
-   feharmenian: 0x0586,
-   fehfinalarabic: 0xFED2,
-   fehinitialarabic: 0xFED3,
-   fehmedialarabic: 0xFED4,
-   feicoptic: 0x03E5,
-   female: 0x2640,
-   ff: 0xFB00,
-   ffi: 0xFB03,
-   ffl: 0xFB04,
-   fi: 0xFB01,
-   fifteencircle: 0x246E,
-   fifteenparen: 0x2482,
-   fifteenperiod: 0x2496,
-   figuredash: 0x2012,
-   filledbox: 0x25A0,
-   filledrect: 0x25AC,
-   finalkaf: 0x05DA,
-   finalkafdagesh: 0xFB3A,
-   finalkafdageshhebrew: 0xFB3A,
-   finalkafhebrew: 0x05DA,
-   finalmem: 0x05DD,
-   finalmemhebrew: 0x05DD,
-   finalnun: 0x05DF,
-   finalnunhebrew: 0x05DF,
-   finalpe: 0x05E3,
-   finalpehebrew: 0x05E3,
-   finaltsadi: 0x05E5,
-   finaltsadihebrew: 0x05E5,
-   firsttonechinese: 0x02C9,
-   fisheye: 0x25C9,
-   fitacyrillic: 0x0473,
-   five: 0x0035,
-   fivearabic: 0x0665,
-   fivebengali: 0x09EB,
-   fivecircle: 0x2464,
-   fivecircleinversesansserif: 0x278E,
-   fivedeva: 0x096B,
-   fiveeighths: 0x215D,
-   fivegujarati: 0x0AEB,
-   fivegurmukhi: 0x0A6B,
-   fivehackarabic: 0x0665,
-   fivehangzhou: 0x3025,
-   fiveideographicparen: 0x3224,
-   fiveinferior: 0x2085,
-   fivemonospace: 0xFF15,
-   fiveoldstyle: 0xF735,
-   fiveparen: 0x2478,
-   fiveperiod: 0x248C,
-   fivepersian: 0x06F5,
-   fiveroman: 0x2174,
-   fivesuperior: 0x2075,
-   fivethai: 0x0E55,
-   fl: 0xFB02,
-   florin: 0x0192,
-   fmonospace: 0xFF46,
-   fmsquare: 0x3399,
-   fofanthai: 0x0E1F,
-   fofathai: 0x0E1D,
-   fongmanthai: 0x0E4F,
-   forall: 0x2200,
-   four: 0x0034,
-   fourarabic: 0x0664,
-   fourbengali: 0x09EA,
-   fourcircle: 0x2463,
-   fourcircleinversesansserif: 0x278D,
-   fourdeva: 0x096A,
-   fourgujarati: 0x0AEA,
-   fourgurmukhi: 0x0A6A,
-   fourhackarabic: 0x0664,
-   fourhangzhou: 0x3024,
-   fourideographicparen: 0x3223,
-   fourinferior: 0x2084,
-   fourmonospace: 0xFF14,
-   fournumeratorbengali: 0x09F7,
-   fouroldstyle: 0xF734,
-   fourparen: 0x2477,
-   fourperiod: 0x248B,
-   fourpersian: 0x06F4,
-   fourroman: 0x2173,
-   foursuperior: 0x2074,
-   fourteencircle: 0x246D,
-   fourteenparen: 0x2481,
-   fourteenperiod: 0x2495,
-   fourthai: 0x0E54,
-   fourthtonechinese: 0x02CB,
-   fparen: 0x24A1,
-   fraction: 0x2044,
-   franc: 0x20A3,
-   g: 0x0067,
-   gabengali: 0x0997,
-   gacute: 0x01F5,
-   gadeva: 0x0917,
-   gafarabic: 0x06AF,
-   gaffinalarabic: 0xFB93,
-   gafinitialarabic: 0xFB94,
-   gafmedialarabic: 0xFB95,
-   gagujarati: 0x0A97,
-   gagurmukhi: 0x0A17,
-   gahiragana: 0x304C,
-   gakatakana: 0x30AC,
-   gamma: 0x03B3,
-   gammalatinsmall: 0x0263,
-   gammasuperior: 0x02E0,
-   gangiacoptic: 0x03EB,
-   gbopomofo: 0x310D,
-   gbreve: 0x011F,
-   gcaron: 0x01E7,
-   gcedilla: 0x0123,
-   gcircle: 0x24D6,
-   gcircumflex: 0x011D,
-   gcommaaccent: 0x0123,
-   gdot: 0x0121,
-   gdotaccent: 0x0121,
-   gecyrillic: 0x0433,
-   gehiragana: 0x3052,
-   gekatakana: 0x30B2,
-   geometricallyequal: 0x2251,
-   gereshaccenthebrew: 0x059C,
-   gereshhebrew: 0x05F3,
-   gereshmuqdamhebrew: 0x059D,
-   germandbls: 0x00DF,
-   gershayimaccenthebrew: 0x059E,
-   gershayimhebrew: 0x05F4,
-   getamark: 0x3013,
-   ghabengali: 0x0998,
-   ghadarmenian: 0x0572,
-   ghadeva: 0x0918,
-   ghagujarati: 0x0A98,
-   ghagurmukhi: 0x0A18,
-   ghainarabic: 0x063A,
-   ghainfinalarabic: 0xFECE,
-   ghaininitialarabic: 0xFECF,
-   ghainmedialarabic: 0xFED0,
-   ghemiddlehookcyrillic: 0x0495,
-   ghestrokecyrillic: 0x0493,
-   gheupturncyrillic: 0x0491,
-   ghhadeva: 0x095A,
-   ghhagurmukhi: 0x0A5A,
-   ghook: 0x0260,
-   ghzsquare: 0x3393,
-   gihiragana: 0x304E,
-   gikatakana: 0x30AE,
-   gimarmenian: 0x0563,
-   gimel: 0x05D2,
-   gimeldagesh: 0xFB32,
-   gimeldageshhebrew: 0xFB32,
-   gimelhebrew: 0x05D2,
-   gjecyrillic: 0x0453,
-   glottalinvertedstroke: 0x01BE,
-   glottalstop: 0x0294,
-   glottalstopinverted: 0x0296,
-   glottalstopmod: 0x02C0,
-   glottalstopreversed: 0x0295,
-   glottalstopreversedmod: 0x02C1,
-   glottalstopreversedsuperior: 0x02E4,
-   glottalstopstroke: 0x02A1,
-   glottalstopstrokereversed: 0x02A2,
-   gmacron: 0x1E21,
-   gmonospace: 0xFF47,
-   gohiragana: 0x3054,
-   gokatakana: 0x30B4,
-   gparen: 0x24A2,
-   gpasquare: 0x33AC,
-   gradient: 0x2207,
-   grave: 0x0060,
-   gravebelowcmb: 0x0316,
-   gravecmb: 0x0300,
-   gravecomb: 0x0300,
-   gravedeva: 0x0953,
-   gravelowmod: 0x02CE,
-   gravemonospace: 0xFF40,
-   gravetonecmb: 0x0340,
-   greater: 0x003E,
-   greaterequal: 0x2265,
-   greaterequalorless: 0x22DB,
-   greatermonospace: 0xFF1E,
-   greaterorequivalent: 0x2273,
-   greaterorless: 0x2277,
-   greateroverequal: 0x2267,
-   greatersmall: 0xFE65,
-   gscript: 0x0261,
-   gstroke: 0x01E5,
-   guhiragana: 0x3050,
-   guillemotleft: 0x00AB,
-   guillemotright: 0x00BB,
-   guilsinglleft: 0x2039,
-   guilsinglright: 0x203A,
-   gukatakana: 0x30B0,
-   guramusquare: 0x3318,
-   gysquare: 0x33C9,
-   h: 0x0068,
-   haabkhasiancyrillic: 0x04A9,
-   haaltonearabic: 0x06C1,
-   habengali: 0x09B9,
-   hadescendercyrillic: 0x04B3,
-   hadeva: 0x0939,
-   hagujarati: 0x0AB9,
-   hagurmukhi: 0x0A39,
-   haharabic: 0x062D,
-   hahfinalarabic: 0xFEA2,
-   hahinitialarabic: 0xFEA3,
-   hahiragana: 0x306F,
-   hahmedialarabic: 0xFEA4,
-   haitusquare: 0x332A,
-   hakatakana: 0x30CF,
-   hakatakanahalfwidth: 0xFF8A,
-   halantgurmukhi: 0x0A4D,
-   hamzaarabic: 0x0621,
-   hamzalowarabic: 0x0621,
-   hangulfiller: 0x3164,
-   hardsigncyrillic: 0x044A,
-   harpoonleftbarbup: 0x21BC,
-   harpoonrightbarbup: 0x21C0,
-   hasquare: 0x33CA,
-   hatafpatah: 0x05B2,
-   hatafpatah16: 0x05B2,
-   hatafpatah23: 0x05B2,
-   hatafpatah2f: 0x05B2,
-   hatafpatahhebrew: 0x05B2,
-   hatafpatahnarrowhebrew: 0x05B2,
-   hatafpatahquarterhebrew: 0x05B2,
-   hatafpatahwidehebrew: 0x05B2,
-   hatafqamats: 0x05B3,
-   hatafqamats1b: 0x05B3,
-   hatafqamats28: 0x05B3,
-   hatafqamats34: 0x05B3,
-   hatafqamatshebrew: 0x05B3,
-   hatafqamatsnarrowhebrew: 0x05B3,
-   hatafqamatsquarterhebrew: 0x05B3,
-   hatafqamatswidehebrew: 0x05B3,
-   hatafsegol: 0x05B1,
-   hatafsegol17: 0x05B1,
-   hatafsegol24: 0x05B1,
-   hatafsegol30: 0x05B1,
-   hatafsegolhebrew: 0x05B1,
-   hatafsegolnarrowhebrew: 0x05B1,
-   hatafsegolquarterhebrew: 0x05B1,
-   hatafsegolwidehebrew: 0x05B1,
-   hbar: 0x0127,
-   hbopomofo: 0x310F,
-   hbrevebelow: 0x1E2B,
-   hcedilla: 0x1E29,
-   hcircle: 0x24D7,
-   hcircumflex: 0x0125,
-   hdieresis: 0x1E27,
-   hdotaccent: 0x1E23,
-   hdotbelow: 0x1E25,
-   he: 0x05D4,
-   heart: 0x2665,
-   heartsuitblack: 0x2665,
-   heartsuitwhite: 0x2661,
-   hedagesh: 0xFB34,
-   hedageshhebrew: 0xFB34,
-   hehaltonearabic: 0x06C1,
-   heharabic: 0x0647,
-   hehebrew: 0x05D4,
-   hehfinalaltonearabic: 0xFBA7,
-   hehfinalalttwoarabic: 0xFEEA,
-   hehfinalarabic: 0xFEEA,
-   hehhamzaabovefinalarabic: 0xFBA5,
-   hehhamzaaboveisolatedarabic: 0xFBA4,
-   hehinitialaltonearabic: 0xFBA8,
-   hehinitialarabic: 0xFEEB,
-   hehiragana: 0x3078,
-   hehmedialaltonearabic: 0xFBA9,
-   hehmedialarabic: 0xFEEC,
-   heiseierasquare: 0x337B,
-   hekatakana: 0x30D8,
-   hekatakanahalfwidth: 0xFF8D,
-   hekutaarusquare: 0x3336,
-   henghook: 0x0267,
-   herutusquare: 0x3339,
-   het: 0x05D7,
-   hethebrew: 0x05D7,
-   hhook: 0x0266,
-   hhooksuperior: 0x02B1,
-   hieuhacirclekorean: 0x327B,
-   hieuhaparenkorean: 0x321B,
-   hieuhcirclekorean: 0x326D,
-   hieuhkorean: 0x314E,
-   hieuhparenkorean: 0x320D,
-   hihiragana: 0x3072,
-   hikatakana: 0x30D2,
-   hikatakanahalfwidth: 0xFF8B,
-   hiriq: 0x05B4,
-   hiriq14: 0x05B4,
-   hiriq21: 0x05B4,
-   hiriq2d: 0x05B4,
-   hiriqhebrew: 0x05B4,
-   hiriqnarrowhebrew: 0x05B4,
-   hiriqquarterhebrew: 0x05B4,
-   hiriqwidehebrew: 0x05B4,
-   hlinebelow: 0x1E96,
-   hmonospace: 0xFF48,
-   hoarmenian: 0x0570,
-   hohipthai: 0x0E2B,
-   hohiragana: 0x307B,
-   hokatakana: 0x30DB,
-   hokatakanahalfwidth: 0xFF8E,
-   holam: 0x05B9,
-   holam19: 0x05B9,
-   holam26: 0x05B9,
-   holam32: 0x05B9,
-   holamhebrew: 0x05B9,
-   holamnarrowhebrew: 0x05B9,
-   holamquarterhebrew: 0x05B9,
-   holamwidehebrew: 0x05B9,
-   honokhukthai: 0x0E2E,
-   hookabovecomb: 0x0309,
-   hookcmb: 0x0309,
-   hookpalatalizedbelowcmb: 0x0321,
-   hookretroflexbelowcmb: 0x0322,
-   hoonsquare: 0x3342,
-   horicoptic: 0x03E9,
-   horizontalbar: 0x2015,
-   horncmb: 0x031B,
-   hotsprings: 0x2668,
-   house: 0x2302,
-   hparen: 0x24A3,
-   hsuperior: 0x02B0,
-   hturned: 0x0265,
-   huhiragana: 0x3075,
-   huiitosquare: 0x3333,
-   hukatakana: 0x30D5,
-   hukatakanahalfwidth: 0xFF8C,
-   hungarumlaut: 0x02DD,
-   hungarumlautcmb: 0x030B,
-   hv: 0x0195,
-   hyphen: 0x002D,
-   hypheninferior: 0xF6E5,
-   hyphenmonospace: 0xFF0D,
-   hyphensmall: 0xFE63,
-   hyphensuperior: 0xF6E6,
-   hyphentwo: 0x2010,
-   i: 0x0069,
-   iacute: 0x00ED,
-   iacyrillic: 0x044F,
-   ibengali: 0x0987,
-   ibopomofo: 0x3127,
-   ibreve: 0x012D,
-   icaron: 0x01D0,
-   icircle: 0x24D8,
-   icircumflex: 0x00EE,
-   icyrillic: 0x0456,
-   idblgrave: 0x0209,
-   ideographearthcircle: 0x328F,
-   ideographfirecircle: 0x328B,
-   ideographicallianceparen: 0x323F,
-   ideographiccallparen: 0x323A,
-   ideographiccentrecircle: 0x32A5,
-   ideographicclose: 0x3006,
-   ideographiccomma: 0x3001,
-   ideographiccommaleft: 0xFF64,
-   ideographiccongratulationparen: 0x3237,
-   ideographiccorrectcircle: 0x32A3,
-   ideographicearthparen: 0x322F,
-   ideographicenterpriseparen: 0x323D,
-   ideographicexcellentcircle: 0x329D,
-   ideographicfestivalparen: 0x3240,
-   ideographicfinancialcircle: 0x3296,
-   ideographicfinancialparen: 0x3236,
-   ideographicfireparen: 0x322B,
-   ideographichaveparen: 0x3232,
-   ideographichighcircle: 0x32A4,
-   ideographiciterationmark: 0x3005,
-   ideographiclaborcircle: 0x3298,
-   ideographiclaborparen: 0x3238,
-   ideographicleftcircle: 0x32A7,
-   ideographiclowcircle: 0x32A6,
-   ideographicmedicinecircle: 0x32A9,
-   ideographicmetalparen: 0x322E,
-   ideographicmoonparen: 0x322A,
-   ideographicnameparen: 0x3234,
-   ideographicperiod: 0x3002,
-   ideographicprintcircle: 0x329E,
-   ideographicreachparen: 0x3243,
-   ideographicrepresentparen: 0x3239,
-   ideographicresourceparen: 0x323E,
-   ideographicrightcircle: 0x32A8,
-   ideographicsecretcircle: 0x3299,
-   ideographicselfparen: 0x3242,
-   ideographicsocietyparen: 0x3233,
-   ideographicspace: 0x3000,
-   ideographicspecialparen: 0x3235,
-   ideographicstockparen: 0x3231,
-   ideographicstudyparen: 0x323B,
-   ideographicsunparen: 0x3230,
-   ideographicsuperviseparen: 0x323C,
-   ideographicwaterparen: 0x322C,
-   ideographicwoodparen: 0x322D,
-   ideographiczero: 0x3007,
-   ideographmetalcircle: 0x328E,
-   ideographmooncircle: 0x328A,
-   ideographnamecircle: 0x3294,
-   ideographsuncircle: 0x3290,
-   ideographwatercircle: 0x328C,
-   ideographwoodcircle: 0x328D,
-   ideva: 0x0907,
-   idieresis: 0x00EF,
-   idieresisacute: 0x1E2F,
-   idieresiscyrillic: 0x04E5,
-   idotbelow: 0x1ECB,
-   iebrevecyrillic: 0x04D7,
-   iecyrillic: 0x0435,
-   ieungacirclekorean: 0x3275,
-   ieungaparenkorean: 0x3215,
-   ieungcirclekorean: 0x3267,
-   ieungkorean: 0x3147,
-   ieungparenkorean: 0x3207,
-   igrave: 0x00EC,
-   igujarati: 0x0A87,
-   igurmukhi: 0x0A07,
-   ihiragana: 0x3044,
-   ihookabove: 0x1EC9,
-   iibengali: 0x0988,
-   iicyrillic: 0x0438,
-   iideva: 0x0908,
-   iigujarati: 0x0A88,
-   iigurmukhi: 0x0A08,
-   iimatragurmukhi: 0x0A40,
-   iinvertedbreve: 0x020B,
-   iishortcyrillic: 0x0439,
-   iivowelsignbengali: 0x09C0,
-   iivowelsigndeva: 0x0940,
-   iivowelsigngujarati: 0x0AC0,
-   ij: 0x0133,
-   ikatakana: 0x30A4,
-   ikatakanahalfwidth: 0xFF72,
-   ikorean: 0x3163,
-   ilde: 0x02DC,
-   iluyhebrew: 0x05AC,
-   imacron: 0x012B,
-   imacroncyrillic: 0x04E3,
-   imageorapproximatelyequal: 0x2253,
-   imatragurmukhi: 0x0A3F,
-   imonospace: 0xFF49,
-   increment: 0x2206,
-   infinity: 0x221E,
-   iniarmenian: 0x056B,
-   integral: 0x222B,
-   integralbottom: 0x2321,
-   integralbt: 0x2321,
-   integralex: 0xF8F5,
-   integraltop: 0x2320,
-   integraltp: 0x2320,
-   intersection: 0x2229,
-   intisquare: 0x3305,
-   invbullet: 0x25D8,
-   invcircle: 0x25D9,
-   invsmileface: 0x263B,
-   iocyrillic: 0x0451,
-   iogonek: 0x012F,
-   iota: 0x03B9,
-   iotadieresis: 0x03CA,
-   iotadieresistonos: 0x0390,
-   iotalatin: 0x0269,
-   iotatonos: 0x03AF,
-   iparen: 0x24A4,
-   irigurmukhi: 0x0A72,
-   ismallhiragana: 0x3043,
-   ismallkatakana: 0x30A3,
-   ismallkatakanahalfwidth: 0xFF68,
-   issharbengali: 0x09FA,
-   istroke: 0x0268,
-   isuperior: 0xF6ED,
-   iterationhiragana: 0x309D,
-   iterationkatakana: 0x30FD,
-   itilde: 0x0129,
-   itildebelow: 0x1E2D,
-   iubopomofo: 0x3129,
-   iucyrillic: 0x044E,
-   ivowelsignbengali: 0x09BF,
-   ivowelsigndeva: 0x093F,
-   ivowelsigngujarati: 0x0ABF,
-   izhitsacyrillic: 0x0475,
-   izhitsadblgravecyrillic: 0x0477,
-   j: 0x006A,
-   jaarmenian: 0x0571,
-   jabengali: 0x099C,
-   jadeva: 0x091C,
-   jagujarati: 0x0A9C,
-   jagurmukhi: 0x0A1C,
-   jbopomofo: 0x3110,
-   jcaron: 0x01F0,
-   jcircle: 0x24D9,
-   jcircumflex: 0x0135,
-   jcrossedtail: 0x029D,
-   jdotlessstroke: 0x025F,
-   jecyrillic: 0x0458,
-   jeemarabic: 0x062C,
-   jeemfinalarabic: 0xFE9E,
-   jeeminitialarabic: 0xFE9F,
-   jeemmedialarabic: 0xFEA0,
-   jeharabic: 0x0698,
-   jehfinalarabic: 0xFB8B,
-   jhabengali: 0x099D,
-   jhadeva: 0x091D,
-   jhagujarati: 0x0A9D,
-   jhagurmukhi: 0x0A1D,
-   jheharmenian: 0x057B,
-   jis: 0x3004,
-   jmonospace: 0xFF4A,
-   jparen: 0x24A5,
-   jsuperior: 0x02B2,
-   k: 0x006B,
-   kabashkircyrillic: 0x04A1,
-   kabengali: 0x0995,
-   kacute: 0x1E31,
-   kacyrillic: 0x043A,
-   kadescendercyrillic: 0x049B,
-   kadeva: 0x0915,
-   kaf: 0x05DB,
-   kafarabic: 0x0643,
-   kafdagesh: 0xFB3B,
-   kafdageshhebrew: 0xFB3B,
-   kaffinalarabic: 0xFEDA,
-   kafhebrew: 0x05DB,
-   kafinitialarabic: 0xFEDB,
-   kafmedialarabic: 0xFEDC,
-   kafrafehebrew: 0xFB4D,
-   kagujarati: 0x0A95,
-   kagurmukhi: 0x0A15,
-   kahiragana: 0x304B,
-   kahookcyrillic: 0x04C4,
-   kakatakana: 0x30AB,
-   kakatakanahalfwidth: 0xFF76,
-   kappa: 0x03BA,
-   kappasymbolgreek: 0x03F0,
-   kapyeounmieumkorean: 0x3171,
-   kapyeounphieuphkorean: 0x3184,
-   kapyeounpieupkorean: 0x3178,
-   kapyeounssangpieupkorean: 0x3179,
-   karoriisquare: 0x330D,
-   kashidaautoarabic: 0x0640,
-   kashidaautonosidebearingarabic: 0x0640,
-   kasmallkatakana: 0x30F5,
-   kasquare: 0x3384,
-   kasraarabic: 0x0650,
-   kasratanarabic: 0x064D,
-   kastrokecyrillic: 0x049F,
-   katahiraprolongmarkhalfwidth: 0xFF70,
-   kaverticalstrokecyrillic: 0x049D,
-   kbopomofo: 0x310E,
-   kcalsquare: 0x3389,
-   kcaron: 0x01E9,
-   kcedilla: 0x0137,
-   kcircle: 0x24DA,
-   kcommaaccent: 0x0137,
-   kdotbelow: 0x1E33,
-   keharmenian: 0x0584,
-   kehiragana: 0x3051,
-   kekatakana: 0x30B1,
-   kekatakanahalfwidth: 0xFF79,
-   kenarmenian: 0x056F,
-   kesmallkatakana: 0x30F6,
-   kgreenlandic: 0x0138,
-   khabengali: 0x0996,
-   khacyrillic: 0x0445,
-   khadeva: 0x0916,
-   khagujarati: 0x0A96,
-   khagurmukhi: 0x0A16,
-   khaharabic: 0x062E,
-   khahfinalarabic: 0xFEA6,
-   khahinitialarabic: 0xFEA7,
-   khahmedialarabic: 0xFEA8,
-   kheicoptic: 0x03E7,
-   khhadeva: 0x0959,
-   khhagurmukhi: 0x0A59,
-   khieukhacirclekorean: 0x3278,
-   khieukhaparenkorean: 0x3218,
-   khieukhcirclekorean: 0x326A,
-   khieukhkorean: 0x314B,
-   khieukhparenkorean: 0x320A,
-   khokhaithai: 0x0E02,
-   khokhonthai: 0x0E05,
-   khokhuatthai: 0x0E03,
-   khokhwaithai: 0x0E04,
-   khomutthai: 0x0E5B,
-   khook: 0x0199,
-   khorakhangthai: 0x0E06,
-   khzsquare: 0x3391,
-   kihiragana: 0x304D,
-   kikatakana: 0x30AD,
-   kikatakanahalfwidth: 0xFF77,
-   kiroguramusquare: 0x3315,
-   kiromeetorusquare: 0x3316,
-   kirosquare: 0x3314,
-   kiyeokacirclekorean: 0x326E,
-   kiyeokaparenkorean: 0x320E,
-   kiyeokcirclekorean: 0x3260,
-   kiyeokkorean: 0x3131,
-   kiyeokparenkorean: 0x3200,
-   kiyeoksioskorean: 0x3133,
-   kjecyrillic: 0x045C,
-   klinebelow: 0x1E35,
-   klsquare: 0x3398,
-   kmcubedsquare: 0x33A6,
-   kmonospace: 0xFF4B,
-   kmsquaredsquare: 0x33A2,
-   kohiragana: 0x3053,
-   kohmsquare: 0x33C0,
-   kokaithai: 0x0E01,
-   kokatakana: 0x30B3,
-   kokatakanahalfwidth: 0xFF7A,
-   kooposquare: 0x331E,
-   koppacyrillic: 0x0481,
-   koreanstandardsymbol: 0x327F,
-   koroniscmb: 0x0343,
-   kparen: 0x24A6,
-   kpasquare: 0x33AA,
-   ksicyrillic: 0x046F,
-   ktsquare: 0x33CF,
-   kturned: 0x029E,
-   kuhiragana: 0x304F,
-   kukatakana: 0x30AF,
-   kukatakanahalfwidth: 0xFF78,
-   kvsquare: 0x33B8,
-   kwsquare: 0x33BE,
-   l: 0x006C,
-   labengali: 0x09B2,
-   lacute: 0x013A,
-   ladeva: 0x0932,
-   lagujarati: 0x0AB2,
-   lagurmukhi: 0x0A32,
-   lakkhangyaothai: 0x0E45,
-   lamaleffinalarabic: 0xFEFC,
-   lamalefhamzaabovefinalarabic: 0xFEF8,
-   lamalefhamzaaboveisolatedarabic: 0xFEF7,
-   lamalefhamzabelowfinalarabic: 0xFEFA,
-   lamalefhamzabelowisolatedarabic: 0xFEF9,
-   lamalefisolatedarabic: 0xFEFB,
-   lamalefmaddaabovefinalarabic: 0xFEF6,
-   lamalefmaddaaboveisolatedarabic: 0xFEF5,
-   lamarabic: 0x0644,
-   lambda: 0x03BB,
-   lambdastroke: 0x019B,
-   lamed: 0x05DC,
-   lameddagesh: 0xFB3C,
-   lameddageshhebrew: 0xFB3C,
-   lamedhebrew: 0x05DC,
-   lamfinalarabic: 0xFEDE,
-   lamhahinitialarabic: 0xFCCA,
-   laminitialarabic: 0xFEDF,
-   lamjeeminitialarabic: 0xFCC9,
-   lamkhahinitialarabic: 0xFCCB,
-   lamlamhehisolatedarabic: 0xFDF2,
-   lammedialarabic: 0xFEE0,
-   lammeemhahinitialarabic: 0xFD88,
-   lammeeminitialarabic: 0xFCCC,
-   largecircle: 0x25EF,
-   lbar: 0x019A,
-   lbelt: 0x026C,
-   lbopomofo: 0x310C,
-   lcaron: 0x013E,
-   lcedilla: 0x013C,
-   lcircle: 0x24DB,
-   lcircumflexbelow: 0x1E3D,
-   lcommaaccent: 0x013C,
-   ldot: 0x0140,
-   ldotaccent: 0x0140,
-   ldotbelow: 0x1E37,
-   ldotbelowmacron: 0x1E39,
-   leftangleabovecmb: 0x031A,
-   lefttackbelowcmb: 0x0318,
-   less: 0x003C,
-   lessequal: 0x2264,
-   lessequalorgreater: 0x22DA,
-   lessmonospace: 0xFF1C,
-   lessorequivalent: 0x2272,
-   lessorgreater: 0x2276,
-   lessoverequal: 0x2266,
-   lesssmall: 0xFE64,
-   lezh: 0x026E,
-   lfblock: 0x258C,
-   lhookretroflex: 0x026D,
-   lira: 0x20A4,
-   liwnarmenian: 0x056C,
-   lj: 0x01C9,
-   ljecyrillic: 0x0459,
-   ll: 0xF6C0,
-   lladeva: 0x0933,
-   llagujarati: 0x0AB3,
-   llinebelow: 0x1E3B,
-   llladeva: 0x0934,
-   llvocalicbengali: 0x09E1,
-   llvocalicdeva: 0x0961,
-   llvocalicvowelsignbengali: 0x09E3,
-   llvocalicvowelsigndeva: 0x0963,
-   lmiddletilde: 0x026B,
-   lmonospace: 0xFF4C,
-   lmsquare: 0x33D0,
-   lochulathai: 0x0E2C,
-   logicaland: 0x2227,
-   logicalnot: 0x00AC,
-   logicalnotreversed: 0x2310,
-   logicalor: 0x2228,
-   lolingthai: 0x0E25,
-   longs: 0x017F,
-   lowlinecenterline: 0xFE4E,
-   lowlinecmb: 0x0332,
-   lowlinedashed: 0xFE4D,
-   lozenge: 0x25CA,
-   lparen: 0x24A7,
-   lslash: 0x0142,
-   lsquare: 0x2113,
-   lsuperior: 0xF6EE,
-   ltshade: 0x2591,
-   luthai: 0x0E26,
-   lvocalicbengali: 0x098C,
-   lvocalicdeva: 0x090C,
-   lvocalicvowelsignbengali: 0x09E2,
-   lvocalicvowelsigndeva: 0x0962,
-   lxsquare: 0x33D3,
-   m: 0x006D,
-   mabengali: 0x09AE,
-   macron: 0x00AF,
-   macronbelowcmb: 0x0331,
-   macroncmb: 0x0304,
-   macronlowmod: 0x02CD,
-   macronmonospace: 0xFFE3,
-   macute: 0x1E3F,
-   madeva: 0x092E,
-   magujarati: 0x0AAE,
-   magurmukhi: 0x0A2E,
-   mahapakhhebrew: 0x05A4,
-   mahapakhlefthebrew: 0x05A4,
-   mahiragana: 0x307E,
-   maichattawalowleftthai: 0xF895,
-   maichattawalowrightthai: 0xF894,
-   maichattawathai: 0x0E4B,
-   maichattawaupperleftthai: 0xF893,
-   maieklowleftthai: 0xF88C,
-   maieklowrightthai: 0xF88B,
-   maiekthai: 0x0E48,
-   maiekupperleftthai: 0xF88A,
-   maihanakatleftthai: 0xF884,
-   maihanakatthai: 0x0E31,
-   maitaikhuleftthai: 0xF889,
-   maitaikhuthai: 0x0E47,
-   maitholowleftthai: 0xF88F,
-   maitholowrightthai: 0xF88E,
-   maithothai: 0x0E49,
-   maithoupperleftthai: 0xF88D,
-   maitrilowleftthai: 0xF892,
-   maitrilowrightthai: 0xF891,
-   maitrithai: 0x0E4A,
-   maitriupperleftthai: 0xF890,
-   maiyamokthai: 0x0E46,
-   makatakana: 0x30DE,
-   makatakanahalfwidth: 0xFF8F,
-   male: 0x2642,
-   mansyonsquare: 0x3347,
-   maqafhebrew: 0x05BE,
-   mars: 0x2642,
-   masoracirclehebrew: 0x05AF,
-   masquare: 0x3383,
-   mbopomofo: 0x3107,
-   mbsquare: 0x33D4,
-   mcircle: 0x24DC,
-   mcubedsquare: 0x33A5,
-   mdotaccent: 0x1E41,
-   mdotbelow: 0x1E43,
-   meemarabic: 0x0645,
-   meemfinalarabic: 0xFEE2,
-   meeminitialarabic: 0xFEE3,
-   meemmedialarabic: 0xFEE4,
-   meemmeeminitialarabic: 0xFCD1,
-   meemmeemisolatedarabic: 0xFC48,
-   meetorusquare: 0x334D,
-   mehiragana: 0x3081,
-   meizierasquare: 0x337E,
-   mekatakana: 0x30E1,
-   mekatakanahalfwidth: 0xFF92,
-   mem: 0x05DE,
-   memdagesh: 0xFB3E,
-   memdageshhebrew: 0xFB3E,
-   memhebrew: 0x05DE,
-   menarmenian: 0x0574,
-   merkhahebrew: 0x05A5,
-   merkhakefulahebrew: 0x05A6,
-   merkhakefulalefthebrew: 0x05A6,
-   merkhalefthebrew: 0x05A5,
-   mhook: 0x0271,
-   mhzsquare: 0x3392,
-   middledotkatakanahalfwidth: 0xFF65,
-   middot: 0x00B7,
-   mieumacirclekorean: 0x3272,
-   mieumaparenkorean: 0x3212,
-   mieumcirclekorean: 0x3264,
-   mieumkorean: 0x3141,
-   mieumpansioskorean: 0x3170,
-   mieumparenkorean: 0x3204,
-   mieumpieupkorean: 0x316E,
-   mieumsioskorean: 0x316F,
-   mihiragana: 0x307F,
-   mikatakana: 0x30DF,
-   mikatakanahalfwidth: 0xFF90,
-   minus: 0x2212,
-   minusbelowcmb: 0x0320,
-   minuscircle: 0x2296,
-   minusmod: 0x02D7,
-   minusplus: 0x2213,
-   minute: 0x2032,
-   miribaarusquare: 0x334A,
-   mirisquare: 0x3349,
-   mlonglegturned: 0x0270,
-   mlsquare: 0x3396,
-   mmcubedsquare: 0x33A3,
-   mmonospace: 0xFF4D,
-   mmsquaredsquare: 0x339F,
-   mohiragana: 0x3082,
-   mohmsquare: 0x33C1,
-   mokatakana: 0x30E2,
-   mokatakanahalfwidth: 0xFF93,
-   molsquare: 0x33D6,
-   momathai: 0x0E21,
-   moverssquare: 0x33A7,
-   moverssquaredsquare: 0x33A8,
-   mparen: 0x24A8,
-   mpasquare: 0x33AB,
-   mssquare: 0x33B3,
-   msuperior: 0xF6EF,
-   mturned: 0x026F,
-   mu: 0x00B5,
-   mu1: 0x00B5,
-   muasquare: 0x3382,
-   muchgreater: 0x226B,
-   muchless: 0x226A,
-   mufsquare: 0x338C,
-   mugreek: 0x03BC,
-   mugsquare: 0x338D,
-   muhiragana: 0x3080,
-   mukatakana: 0x30E0,
-   mukatakanahalfwidth: 0xFF91,
-   mulsquare: 0x3395,
-   multiply: 0x00D7,
-   mumsquare: 0x339B,
-   munahhebrew: 0x05A3,
-   munahlefthebrew: 0x05A3,
-   musicalnote: 0x266A,
-   musicalnotedbl: 0x266B,
-   musicflatsign: 0x266D,
-   musicsharpsign: 0x266F,
-   mussquare: 0x33B2,
-   muvsquare: 0x33B6,
-   muwsquare: 0x33BC,
-   mvmegasquare: 0x33B9,
-   mvsquare: 0x33B7,
-   mwmegasquare: 0x33BF,
-   mwsquare: 0x33BD,
-   n: 0x006E,
-   nabengali: 0x09A8,
-   nabla: 0x2207,
-   nacute: 0x0144,
-   nadeva: 0x0928,
-   nagujarati: 0x0AA8,
-   nagurmukhi: 0x0A28,
-   nahiragana: 0x306A,
-   nakatakana: 0x30CA,
-   nakatakanahalfwidth: 0xFF85,
-   napostrophe: 0x0149,
-   nasquare: 0x3381,
-   nbopomofo: 0x310B,
-   nbspace: 0x00A0,
-   ncaron: 0x0148,
-   ncedilla: 0x0146,
-   ncircle: 0x24DD,
-   ncircumflexbelow: 0x1E4B,
-   ncommaaccent: 0x0146,
-   ndotaccent: 0x1E45,
-   ndotbelow: 0x1E47,
-   nehiragana: 0x306D,
-   nekatakana: 0x30CD,
-   nekatakanahalfwidth: 0xFF88,
-   newsheqelsign: 0x20AA,
-   nfsquare: 0x338B,
-   ngabengali: 0x0999,
-   ngadeva: 0x0919,
-   ngagujarati: 0x0A99,
-   ngagurmukhi: 0x0A19,
-   ngonguthai: 0x0E07,
-   nhiragana: 0x3093,
-   nhookleft: 0x0272,
-   nhookretroflex: 0x0273,
-   nieunacirclekorean: 0x326F,
-   nieunaparenkorean: 0x320F,
-   nieuncieuckorean: 0x3135,
-   nieuncirclekorean: 0x3261,
-   nieunhieuhkorean: 0x3136,
-   nieunkorean: 0x3134,
-   nieunpansioskorean: 0x3168,
-   nieunparenkorean: 0x3201,
-   nieunsioskorean: 0x3167,
-   nieuntikeutkorean: 0x3166,
-   nihiragana: 0x306B,
-   nikatakana: 0x30CB,
-   nikatakanahalfwidth: 0xFF86,
-   nikhahitleftthai: 0xF899,
-   nikhahitthai: 0x0E4D,
-   nine: 0x0039,
-   ninearabic: 0x0669,
-   ninebengali: 0x09EF,
-   ninecircle: 0x2468,
-   ninecircleinversesansserif: 0x2792,
-   ninedeva: 0x096F,
-   ninegujarati: 0x0AEF,
-   ninegurmukhi: 0x0A6F,
-   ninehackarabic: 0x0669,
-   ninehangzhou: 0x3029,
-   nineideographicparen: 0x3228,
-   nineinferior: 0x2089,
-   ninemonospace: 0xFF19,
-   nineoldstyle: 0xF739,
-   nineparen: 0x247C,
-   nineperiod: 0x2490,
-   ninepersian: 0x06F9,
-   nineroman: 0x2178,
-   ninesuperior: 0x2079,
-   nineteencircle: 0x2472,
-   nineteenparen: 0x2486,
-   nineteenperiod: 0x249A,
-   ninethai: 0x0E59,
-   nj: 0x01CC,
-   njecyrillic: 0x045A,
-   nkatakana: 0x30F3,
-   nkatakanahalfwidth: 0xFF9D,
-   nlegrightlong: 0x019E,
-   nlinebelow: 0x1E49,
-   nmonospace: 0xFF4E,
-   nmsquare: 0x339A,
-   nnabengali: 0x09A3,
-   nnadeva: 0x0923,
-   nnagujarati: 0x0AA3,
-   nnagurmukhi: 0x0A23,
-   nnnadeva: 0x0929,
-   nohiragana: 0x306E,
-   nokatakana: 0x30CE,
-   nokatakanahalfwidth: 0xFF89,
-   nonbreakingspace: 0x00A0,
-   nonenthai: 0x0E13,
-   nonuthai: 0x0E19,
-   noonarabic: 0x0646,
-   noonfinalarabic: 0xFEE6,
-   noonghunnaarabic: 0x06BA,
-   noonghunnafinalarabic: 0xFB9F,
-   nooninitialarabic: 0xFEE7,
-   noonjeeminitialarabic: 0xFCD2,
-   noonjeemisolatedarabic: 0xFC4B,
-   noonmedialarabic: 0xFEE8,
-   noonmeeminitialarabic: 0xFCD5,
-   noonmeemisolatedarabic: 0xFC4E,
-   noonnoonfinalarabic: 0xFC8D,
-   notcontains: 0x220C,
-   notelement: 0x2209,
-   notelementof: 0x2209,
-   notequal: 0x2260,
-   notgreater: 0x226F,
-   notgreaternorequal: 0x2271,
-   notgreaternorless: 0x2279,
-   notidentical: 0x2262,
-   notless: 0x226E,
-   notlessnorequal: 0x2270,
-   notparallel: 0x2226,
-   notprecedes: 0x2280,
-   notsubset: 0x2284,
-   notsucceeds: 0x2281,
-   notsuperset: 0x2285,
-   nowarmenian: 0x0576,
-   nparen: 0x24A9,
-   nssquare: 0x33B1,
-   nsuperior: 0x207F,
-   ntilde: 0x00F1,
-   nu: 0x03BD,
-   nuhiragana: 0x306C,
-   nukatakana: 0x30CC,
-   nukatakanahalfwidth: 0xFF87,
-   nuktabengali: 0x09BC,
-   nuktadeva: 0x093C,
-   nuktagujarati: 0x0ABC,
-   nuktagurmukhi: 0x0A3C,
-   numbersign: 0x0023,
-   numbersignmonospace: 0xFF03,
-   numbersignsmall: 0xFE5F,
-   numeralsigngreek: 0x0374,
-   numeralsignlowergreek: 0x0375,
-   numero: 0x2116,
-   nun: 0x05E0,
-   nundagesh: 0xFB40,
-   nundageshhebrew: 0xFB40,
-   nunhebrew: 0x05E0,
-   nvsquare: 0x33B5,
-   nwsquare: 0x33BB,
-   nyabengali: 0x099E,
-   nyadeva: 0x091E,
-   nyagujarati: 0x0A9E,
-   nyagurmukhi: 0x0A1E,
-   o: 0x006F,
-   oacute: 0x00F3,
-   oangthai: 0x0E2D,
-   obarred: 0x0275,
-   obarredcyrillic: 0x04E9,
-   obarreddieresiscyrillic: 0x04EB,
-   obengali: 0x0993,
-   obopomofo: 0x311B,
-   obreve: 0x014F,
-   ocandradeva: 0x0911,
-   ocandragujarati: 0x0A91,
-   ocandravowelsigndeva: 0x0949,
-   ocandravowelsigngujarati: 0x0AC9,
-   ocaron: 0x01D2,
-   ocircle: 0x24DE,
-   ocircumflex: 0x00F4,
-   ocircumflexacute: 0x1ED1,
-   ocircumflexdotbelow: 0x1ED9,
-   ocircumflexgrave: 0x1ED3,
-   ocircumflexhookabove: 0x1ED5,
-   ocircumflextilde: 0x1ED7,
-   ocyrillic: 0x043E,
-   odblacute: 0x0151,
-   odblgrave: 0x020D,
-   odeva: 0x0913,
-   odieresis: 0x00F6,
-   odieresiscyrillic: 0x04E7,
-   odotbelow: 0x1ECD,
-   oe: 0x0153,
-   oekorean: 0x315A,
-   ogonek: 0x02DB,
-   ogonekcmb: 0x0328,
-   ograve: 0x00F2,
-   ogujarati: 0x0A93,
-   oharmenian: 0x0585,
-   ohiragana: 0x304A,
-   ohookabove: 0x1ECF,
-   ohorn: 0x01A1,
-   ohornacute: 0x1EDB,
-   ohorndotbelow: 0x1EE3,
-   ohorngrave: 0x1EDD,
-   ohornhookabove: 0x1EDF,
-   ohorntilde: 0x1EE1,
-   ohungarumlaut: 0x0151,
-   oi: 0x01A3,
-   oinvertedbreve: 0x020F,
-   okatakana: 0x30AA,
-   okatakanahalfwidth: 0xFF75,
-   okorean: 0x3157,
-   olehebrew: 0x05AB,
-   omacron: 0x014D,
-   omacronacute: 0x1E53,
-   omacrongrave: 0x1E51,
-   omdeva: 0x0950,
-   omega: 0x03C9,
-   omega1: 0x03D6,
-   omegacyrillic: 0x0461,
-   omegalatinclosed: 0x0277,
-   omegaroundcyrillic: 0x047B,
-   omegatitlocyrillic: 0x047D,
-   omegatonos: 0x03CE,
-   omgujarati: 0x0AD0,
-   omicron: 0x03BF,
-   omicrontonos: 0x03CC,
-   omonospace: 0xFF4F,
-   one: 0x0031,
-   onearabic: 0x0661,
-   onebengali: 0x09E7,
-   onecircle: 0x2460,
-   onecircleinversesansserif: 0x278A,
-   onedeva: 0x0967,
-   onedotenleader: 0x2024,
-   oneeighth: 0x215B,
-   onefitted: 0xF6DC,
-   onegujarati: 0x0AE7,
-   onegurmukhi: 0x0A67,
-   onehackarabic: 0x0661,
-   onehalf: 0x00BD,
-   onehangzhou: 0x3021,
-   oneideographicparen: 0x3220,
-   oneinferior: 0x2081,
-   onemonospace: 0xFF11,
-   onenumeratorbengali: 0x09F4,
-   oneoldstyle: 0xF731,
-   oneparen: 0x2474,
-   oneperiod: 0x2488,
-   onepersian: 0x06F1,
-   onequarter: 0x00BC,
-   oneroman: 0x2170,
-   onesuperior: 0x00B9,
-   onethai: 0x0E51,
-   onethird: 0x2153,
-   oogonek: 0x01EB,
-   oogonekmacron: 0x01ED,
-   oogurmukhi: 0x0A13,
-   oomatragurmukhi: 0x0A4B,
-   oopen: 0x0254,
-   oparen: 0x24AA,
-   openbullet: 0x25E6,
-   option: 0x2325,
-   ordfeminine: 0x00AA,
-   ordmasculine: 0x00BA,
-   orthogonal: 0x221F,
-   oshortdeva: 0x0912,
-   oshortvowelsigndeva: 0x094A,
-   oslash: 0x00F8,
-   oslashacute: 0x01FF,
-   osmallhiragana: 0x3049,
-   osmallkatakana: 0x30A9,
-   osmallkatakanahalfwidth: 0xFF6B,
-   ostrokeacute: 0x01FF,
-   osuperior: 0xF6F0,
-   otcyrillic: 0x047F,
-   otilde: 0x00F5,
-   otildeacute: 0x1E4D,
-   otildedieresis: 0x1E4F,
-   oubopomofo: 0x3121,
-   overline: 0x203E,
-   overlinecenterline: 0xFE4A,
-   overlinecmb: 0x0305,
-   overlinedashed: 0xFE49,
-   overlinedblwavy: 0xFE4C,
-   overlinewavy: 0xFE4B,
-   overscore: 0x00AF,
-   ovowelsignbengali: 0x09CB,
-   ovowelsigndeva: 0x094B,
-   ovowelsigngujarati: 0x0ACB,
-   p: 0x0070,
-   paampssquare: 0x3380,
-   paasentosquare: 0x332B,
-   pabengali: 0x09AA,
-   pacute: 0x1E55,
-   padeva: 0x092A,
-   pagedown: 0x21DF,
-   pageup: 0x21DE,
-   pagujarati: 0x0AAA,
-   pagurmukhi: 0x0A2A,
-   pahiragana: 0x3071,
-   paiyannoithai: 0x0E2F,
-   pakatakana: 0x30D1,
-   palatalizationcyrilliccmb: 0x0484,
-   palochkacyrillic: 0x04C0,
-   pansioskorean: 0x317F,
-   paragraph: 0x00B6,
-   parallel: 0x2225,
-   parenleft: 0x0028,
-   parenleftaltonearabic: 0xFD3E,
-   parenleftbt: 0xF8ED,
-   parenleftex: 0xF8EC,
-   parenleftinferior: 0x208D,
-   parenleftmonospace: 0xFF08,
-   parenleftsmall: 0xFE59,
-   parenleftsuperior: 0x207D,
-   parenlefttp: 0xF8EB,
-   parenleftvertical: 0xFE35,
-   parenright: 0x0029,
-   parenrightaltonearabic: 0xFD3F,
-   parenrightbt: 0xF8F8,
-   parenrightex: 0xF8F7,
-   parenrightinferior: 0x208E,
-   parenrightmonospace: 0xFF09,
-   parenrightsmall: 0xFE5A,
-   parenrightsuperior: 0x207E,
-   parenrighttp: 0xF8F6,
-   parenrightvertical: 0xFE36,
-   partialdiff: 0x2202,
-   paseqhebrew: 0x05C0,
-   pashtahebrew: 0x0599,
-   pasquare: 0x33A9,
-   patah: 0x05B7,
-   patah11: 0x05B7,
-   patah1d: 0x05B7,
-   patah2a: 0x05B7,
-   patahhebrew: 0x05B7,
-   patahnarrowhebrew: 0x05B7,
-   patahquarterhebrew: 0x05B7,
-   patahwidehebrew: 0x05B7,
-   pazerhebrew: 0x05A1,
-   pbopomofo: 0x3106,
-   pcircle: 0x24DF,
-   pdotaccent: 0x1E57,
-   pe: 0x05E4,
-   pecyrillic: 0x043F,
-   pedagesh: 0xFB44,
-   pedageshhebrew: 0xFB44,
-   peezisquare: 0x333B,
-   pefinaldageshhebrew: 0xFB43,
-   peharabic: 0x067E,
-   peharmenian: 0x057A,
-   pehebrew: 0x05E4,
-   pehfinalarabic: 0xFB57,
-   pehinitialarabic: 0xFB58,
-   pehiragana: 0x307A,
-   pehmedialarabic: 0xFB59,
-   pekatakana: 0x30DA,
-   pemiddlehookcyrillic: 0x04A7,
-   perafehebrew: 0xFB4E,
-   percent: 0x0025,
-   percentarabic: 0x066A,
-   percentmonospace: 0xFF05,
-   percentsmall: 0xFE6A,
-   period: 0x002E,
-   periodarmenian: 0x0589,
-   periodcentered: 0x00B7,
-   periodhalfwidth: 0xFF61,
-   periodinferior: 0xF6E7,
-   periodmonospace: 0xFF0E,
-   periodsmall: 0xFE52,
-   periodsuperior: 0xF6E8,
-   perispomenigreekcmb: 0x0342,
-   perpendicular: 0x22A5,
-   perthousand: 0x2030,
-   peseta: 0x20A7,
-   pfsquare: 0x338A,
-   phabengali: 0x09AB,
-   phadeva: 0x092B,
-   phagujarati: 0x0AAB,
-   phagurmukhi: 0x0A2B,
-   phi: 0x03C6,
-   phi1: 0x03D5,
-   phieuphacirclekorean: 0x327A,
-   phieuphaparenkorean: 0x321A,
-   phieuphcirclekorean: 0x326C,
-   phieuphkorean: 0x314D,
-   phieuphparenkorean: 0x320C,
-   philatin: 0x0278,
-   phinthuthai: 0x0E3A,
-   phisymbolgreek: 0x03D5,
-   phook: 0x01A5,
-   phophanthai: 0x0E1E,
-   phophungthai: 0x0E1C,
-   phosamphaothai: 0x0E20,
-   pi: 0x03C0,
-   pieupacirclekorean: 0x3273,
-   pieupaparenkorean: 0x3213,
-   pieupcieuckorean: 0x3176,
-   pieupcirclekorean: 0x3265,
-   pieupkiyeokkorean: 0x3172,
-   pieupkorean: 0x3142,
-   pieupparenkorean: 0x3205,
-   pieupsioskiyeokkorean: 0x3174,
-   pieupsioskorean: 0x3144,
-   pieupsiostikeutkorean: 0x3175,
-   pieupthieuthkorean: 0x3177,
-   pieuptikeutkorean: 0x3173,
-   pihiragana: 0x3074,
-   pikatakana: 0x30D4,
-   pisymbolgreek: 0x03D6,
-   piwrarmenian: 0x0583,
-   plus: 0x002B,
-   plusbelowcmb: 0x031F,
-   pluscircle: 0x2295,
-   plusminus: 0x00B1,
-   plusmod: 0x02D6,
-   plusmonospace: 0xFF0B,
-   plussmall: 0xFE62,
-   plussuperior: 0x207A,
-   pmonospace: 0xFF50,
-   pmsquare: 0x33D8,
-   pohiragana: 0x307D,
-   pointingindexdownwhite: 0x261F,
-   pointingindexleftwhite: 0x261C,
-   pointingindexrightwhite: 0x261E,
-   pointingindexupwhite: 0x261D,
-   pokatakana: 0x30DD,
-   poplathai: 0x0E1B,
-   postalmark: 0x3012,
-   postalmarkface: 0x3020,
-   pparen: 0x24AB,
-   precedes: 0x227A,
-   prescription: 0x211E,
-   primemod: 0x02B9,
-   primereversed: 0x2035,
-   product: 0x220F,
-   projective: 0x2305,
-   prolongedkana: 0x30FC,
-   propellor: 0x2318,
-   propersubset: 0x2282,
-   propersuperset: 0x2283,
-   proportion: 0x2237,
-   proportional: 0x221D,
-   psi: 0x03C8,
-   psicyrillic: 0x0471,
-   psilipneumatacyrilliccmb: 0x0486,
-   pssquare: 0x33B0,
-   puhiragana: 0x3077,
-   pukatakana: 0x30D7,
-   pvsquare: 0x33B4,
-   pwsquare: 0x33BA,
-   q: 0x0071,
-   qadeva: 0x0958,
-   qadmahebrew: 0x05A8,
-   qafarabic: 0x0642,
-   qaffinalarabic: 0xFED6,
-   qafinitialarabic: 0xFED7,
-   qafmedialarabic: 0xFED8,
-   qamats: 0x05B8,
-   qamats10: 0x05B8,
-   qamats1a: 0x05B8,
-   qamats1c: 0x05B8,
-   qamats27: 0x05B8,
-   qamats29: 0x05B8,
-   qamats33: 0x05B8,
-   qamatsde: 0x05B8,
-   qamatshebrew: 0x05B8,
-   qamatsnarrowhebrew: 0x05B8,
-   qamatsqatanhebrew: 0x05B8,
-   qamatsqatannarrowhebrew: 0x05B8,
-   qamatsqatanquarterhebrew: 0x05B8,
-   qamatsqatanwidehebrew: 0x05B8,
-   qamatsquarterhebrew: 0x05B8,
-   qamatswidehebrew: 0x05B8,
-   qarneyparahebrew: 0x059F,
-   qbopomofo: 0x3111,
-   qcircle: 0x24E0,
-   qhook: 0x02A0,
-   qmonospace: 0xFF51,
-   qof: 0x05E7,
-   qofdagesh: 0xFB47,
-   qofdageshhebrew: 0xFB47,
-   qofhebrew: 0x05E7,
-   qparen: 0x24AC,
-   quarternote: 0x2669,
-   qubuts: 0x05BB,
-   qubuts18: 0x05BB,
-   qubuts25: 0x05BB,
-   qubuts31: 0x05BB,
-   qubutshebrew: 0x05BB,
-   qubutsnarrowhebrew: 0x05BB,
-   qubutsquarterhebrew: 0x05BB,
-   qubutswidehebrew: 0x05BB,
-   question: 0x003F,
-   questionarabic: 0x061F,
-   questionarmenian: 0x055E,
-   questiondown: 0x00BF,
-   questiondownsmall: 0xF7BF,
-   questiongreek: 0x037E,
-   questionmonospace: 0xFF1F,
-   questionsmall: 0xF73F,
-   quotedbl: 0x0022,
-   quotedblbase: 0x201E,
-   quotedblleft: 0x201C,
-   quotedblmonospace: 0xFF02,
-   quotedblprime: 0x301E,
-   quotedblprimereversed: 0x301D,
-   quotedblright: 0x201D,
-   quoteleft: 0x2018,
-   quoteleftreversed: 0x201B,
-   quotereversed: 0x201B,
-   quoteright: 0x2019,
-   quoterightn: 0x0149,
-   quotesinglbase: 0x201A,
-   quotesingle: 0x0027,
-   quotesinglemonospace: 0xFF07,
-   r: 0x0072,
-   raarmenian: 0x057C,
-   rabengali: 0x09B0,
-   racute: 0x0155,
-   radeva: 0x0930,
-   radical: 0x221A,
-   radicalex: 0xF8E5,
-   radoverssquare: 0x33AE,
-   radoverssquaredsquare: 0x33AF,
-   radsquare: 0x33AD,
-   rafe: 0x05BF,
-   rafehebrew: 0x05BF,
-   ragujarati: 0x0AB0,
-   ragurmukhi: 0x0A30,
-   rahiragana: 0x3089,
-   rakatakana: 0x30E9,
-   rakatakanahalfwidth: 0xFF97,
-   ralowerdiagonalbengali: 0x09F1,
-   ramiddlediagonalbengali: 0x09F0,
-   ramshorn: 0x0264,
-   ratio: 0x2236,
-   rbopomofo: 0x3116,
-   rcaron: 0x0159,
-   rcedilla: 0x0157,
-   rcircle: 0x24E1,
-   rcommaaccent: 0x0157,
-   rdblgrave: 0x0211,
-   rdotaccent: 0x1E59,
-   rdotbelow: 0x1E5B,
-   rdotbelowmacron: 0x1E5D,
-   referencemark: 0x203B,
-   reflexsubset: 0x2286,
-   reflexsuperset: 0x2287,
-   registered: 0x00AE,
-   registersans: 0xF8E8,
-   registerserif: 0xF6DA,
-   reharabic: 0x0631,
-   reharmenian: 0x0580,
-   rehfinalarabic: 0xFEAE,
-   rehiragana: 0x308C,
-   rekatakana: 0x30EC,
-   rekatakanahalfwidth: 0xFF9A,
-   resh: 0x05E8,
-   reshdageshhebrew: 0xFB48,
-   reshhebrew: 0x05E8,
-   reversedtilde: 0x223D,
-   reviahebrew: 0x0597,
-   reviamugrashhebrew: 0x0597,
-   revlogicalnot: 0x2310,
-   rfishhook: 0x027E,
-   rfishhookreversed: 0x027F,
-   rhabengali: 0x09DD,
-   rhadeva: 0x095D,
-   rho: 0x03C1,
-   rhook: 0x027D,
-   rhookturned: 0x027B,
-   rhookturnedsuperior: 0x02B5,
-   rhosymbolgreek: 0x03F1,
-   rhotichookmod: 0x02DE,
-   rieulacirclekorean: 0x3271,
-   rieulaparenkorean: 0x3211,
-   rieulcirclekorean: 0x3263,
-   rieulhieuhkorean: 0x3140,
-   rieulkiyeokkorean: 0x313A,
-   rieulkiyeoksioskorean: 0x3169,
-   rieulkorean: 0x3139,
-   rieulmieumkorean: 0x313B,
-   rieulpansioskorean: 0x316C,
-   rieulparenkorean: 0x3203,
-   rieulphieuphkorean: 0x313F,
-   rieulpieupkorean: 0x313C,
-   rieulpieupsioskorean: 0x316B,
-   rieulsioskorean: 0x313D,
-   rieulthieuthkorean: 0x313E,
-   rieultikeutkorean: 0x316A,
-   rieulyeorinhieuhkorean: 0x316D,
-   rightangle: 0x221F,
-   righttackbelowcmb: 0x0319,
-   righttriangle: 0x22BF,
-   rihiragana: 0x308A,
-   rikatakana: 0x30EA,
-   rikatakanahalfwidth: 0xFF98,
-   ring: 0x02DA,
-   ringbelowcmb: 0x0325,
-   ringcmb: 0x030A,
-   ringhalfleft: 0x02BF,
-   ringhalfleftarmenian: 0x0559,
-   ringhalfleftbelowcmb: 0x031C,
-   ringhalfleftcentered: 0x02D3,
-   ringhalfright: 0x02BE,
-   ringhalfrightbelowcmb: 0x0339,
-   ringhalfrightcentered: 0x02D2,
-   rinvertedbreve: 0x0213,
-   rittorusquare: 0x3351,
-   rlinebelow: 0x1E5F,
-   rlongleg: 0x027C,
-   rlonglegturned: 0x027A,
-   rmonospace: 0xFF52,
-   rohiragana: 0x308D,
-   rokatakana: 0x30ED,
-   rokatakanahalfwidth: 0xFF9B,
-   roruathai: 0x0E23,
-   rparen: 0x24AD,
-   rrabengali: 0x09DC,
-   rradeva: 0x0931,
-   rragurmukhi: 0x0A5C,
-   rreharabic: 0x0691,
-   rrehfinalarabic: 0xFB8D,
-   rrvocalicbengali: 0x09E0,
-   rrvocalicdeva: 0x0960,
-   rrvocalicgujarati: 0x0AE0,
-   rrvocalicvowelsignbengali: 0x09C4,
-   rrvocalicvowelsigndeva: 0x0944,
-   rrvocalicvowelsigngujarati: 0x0AC4,
-   rsuperior: 0xF6F1,
-   rtblock: 0x2590,
-   rturned: 0x0279,
-   rturnedsuperior: 0x02B4,
-   ruhiragana: 0x308B,
-   rukatakana: 0x30EB,
-   rukatakanahalfwidth: 0xFF99,
-   rupeemarkbengali: 0x09F2,
-   rupeesignbengali: 0x09F3,
-   rupiah: 0xF6DD,
-   ruthai: 0x0E24,
-   rvocalicbengali: 0x098B,
-   rvocalicdeva: 0x090B,
-   rvocalicgujarati: 0x0A8B,
-   rvocalicvowelsignbengali: 0x09C3,
-   rvocalicvowelsigndeva: 0x0943,
-   rvocalicvowelsigngujarati: 0x0AC3,
-   s: 0x0073,
-   sabengali: 0x09B8,
-   sacute: 0x015B,
-   sacutedotaccent: 0x1E65,
-   sadarabic: 0x0635,
-   sadeva: 0x0938,
-   sadfinalarabic: 0xFEBA,
-   sadinitialarabic: 0xFEBB,
-   sadmedialarabic: 0xFEBC,
-   sagujarati: 0x0AB8,
-   sagurmukhi: 0x0A38,
-   sahiragana: 0x3055,
-   sakatakana: 0x30B5,
-   sakatakanahalfwidth: 0xFF7B,
-   sallallahoualayhewasallamarabic: 0xFDFA,
-   samekh: 0x05E1,
-   samekhdagesh: 0xFB41,
-   samekhdageshhebrew: 0xFB41,
-   samekhhebrew: 0x05E1,
-   saraaathai: 0x0E32,
-   saraaethai: 0x0E41,
-   saraaimaimalaithai: 0x0E44,
-   saraaimaimuanthai: 0x0E43,
-   saraamthai: 0x0E33,
-   saraathai: 0x0E30,
-   saraethai: 0x0E40,
-   saraiileftthai: 0xF886,
-   saraiithai: 0x0E35,
-   saraileftthai: 0xF885,
-   saraithai: 0x0E34,
-   saraothai: 0x0E42,
-   saraueeleftthai: 0xF888,
-   saraueethai: 0x0E37,
-   saraueleftthai: 0xF887,
-   sarauethai: 0x0E36,
-   sarauthai: 0x0E38,
-   sarauuthai: 0x0E39,
-   sbopomofo: 0x3119,
-   scaron: 0x0161,
-   scarondotaccent: 0x1E67,
-   scedilla: 0x015F,
-   schwa: 0x0259,
-   schwacyrillic: 0x04D9,
-   schwadieresiscyrillic: 0x04DB,
-   schwahook: 0x025A,
-   scircle: 0x24E2,
-   scircumflex: 0x015D,
-   scommaaccent: 0x0219,
-   sdotaccent: 0x1E61,
-   sdotbelow: 0x1E63,
-   sdotbelowdotaccent: 0x1E69,
-   seagullbelowcmb: 0x033C,
-   second: 0x2033,
-   secondtonechinese: 0x02CA,
-   section: 0x00A7,
-   seenarabic: 0x0633,
-   seenfinalarabic: 0xFEB2,
-   seeninitialarabic: 0xFEB3,
-   seenmedialarabic: 0xFEB4,
-   segol: 0x05B6,
-   segol13: 0x05B6,
-   segol1f: 0x05B6,
-   segol2c: 0x05B6,
-   segolhebrew: 0x05B6,
-   segolnarrowhebrew: 0x05B6,
-   segolquarterhebrew: 0x05B6,
-   segoltahebrew: 0x0592,
-   segolwidehebrew: 0x05B6,
-   seharmenian: 0x057D,
-   sehiragana: 0x305B,
-   sekatakana: 0x30BB,
-   sekatakanahalfwidth: 0xFF7E,
-   semicolon: 0x003B,
-   semicolonarabic: 0x061B,
-   semicolonmonospace: 0xFF1B,
-   semicolonsmall: 0xFE54,
-   semivoicedmarkkana: 0x309C,
-   semivoicedmarkkanahalfwidth: 0xFF9F,
-   sentisquare: 0x3322,
-   sentosquare: 0x3323,
-   seven: 0x0037,
-   sevenarabic: 0x0667,
-   sevenbengali: 0x09ED,
-   sevencircle: 0x2466,
-   sevencircleinversesansserif: 0x2790,
-   sevendeva: 0x096D,
-   seveneighths: 0x215E,
-   sevengujarati: 0x0AED,
-   sevengurmukhi: 0x0A6D,
-   sevenhackarabic: 0x0667,
-   sevenhangzhou: 0x3027,
-   sevenideographicparen: 0x3226,
-   seveninferior: 0x2087,
-   sevenmonospace: 0xFF17,
-   sevenoldstyle: 0xF737,
-   sevenparen: 0x247A,
-   sevenperiod: 0x248E,
-   sevenpersian: 0x06F7,
-   sevenroman: 0x2176,
-   sevensuperior: 0x2077,
-   seventeencircle: 0x2470,
-   seventeenparen: 0x2484,
-   seventeenperiod: 0x2498,
-   seventhai: 0x0E57,
-   sfthyphen: 0x00AD,
-   shaarmenian: 0x0577,
-   shabengali: 0x09B6,
-   shacyrillic: 0x0448,
-   shaddaarabic: 0x0651,
-   shaddadammaarabic: 0xFC61,
-   shaddadammatanarabic: 0xFC5E,
-   shaddafathaarabic: 0xFC60,
-   shaddakasraarabic: 0xFC62,
-   shaddakasratanarabic: 0xFC5F,
-   shade: 0x2592,
-   shadedark: 0x2593,
-   shadelight: 0x2591,
-   shademedium: 0x2592,
-   shadeva: 0x0936,
-   shagujarati: 0x0AB6,
-   shagurmukhi: 0x0A36,
-   shalshelethebrew: 0x0593,
-   shbopomofo: 0x3115,
-   shchacyrillic: 0x0449,
-   sheenarabic: 0x0634,
-   sheenfinalarabic: 0xFEB6,
-   sheeninitialarabic: 0xFEB7,
-   sheenmedialarabic: 0xFEB8,
-   sheicoptic: 0x03E3,
-   sheqel: 0x20AA,
-   sheqelhebrew: 0x20AA,
-   sheva: 0x05B0,
-   sheva115: 0x05B0,
-   sheva15: 0x05B0,
-   sheva22: 0x05B0,
-   sheva2e: 0x05B0,
-   shevahebrew: 0x05B0,
-   shevanarrowhebrew: 0x05B0,
-   shevaquarterhebrew: 0x05B0,
-   shevawidehebrew: 0x05B0,
-   shhacyrillic: 0x04BB,
-   shimacoptic: 0x03ED,
-   shin: 0x05E9,
-   shindagesh: 0xFB49,
-   shindageshhebrew: 0xFB49,
-   shindageshshindot: 0xFB2C,
-   shindageshshindothebrew: 0xFB2C,
-   shindageshsindot: 0xFB2D,
-   shindageshsindothebrew: 0xFB2D,
-   shindothebrew: 0x05C1,
-   shinhebrew: 0x05E9,
-   shinshindot: 0xFB2A,
-   shinshindothebrew: 0xFB2A,
-   shinsindot: 0xFB2B,
-   shinsindothebrew: 0xFB2B,
-   shook: 0x0282,
-   sigma: 0x03C3,
-   sigma1: 0x03C2,
-   sigmafinal: 0x03C2,
-   sigmalunatesymbolgreek: 0x03F2,
-   sihiragana: 0x3057,
-   sikatakana: 0x30B7,
-   sikatakanahalfwidth: 0xFF7C,
-   siluqhebrew: 0x05BD,
-   siluqlefthebrew: 0x05BD,
-   similar: 0x223C,
-   sindothebrew: 0x05C2,
-   siosacirclekorean: 0x3274,
-   siosaparenkorean: 0x3214,
-   sioscieuckorean: 0x317E,
-   sioscirclekorean: 0x3266,
-   sioskiyeokkorean: 0x317A,
-   sioskorean: 0x3145,
-   siosnieunkorean: 0x317B,
-   siosparenkorean: 0x3206,
-   siospieupkorean: 0x317D,
-   siostikeutkorean: 0x317C,
-   six: 0x0036,
-   sixarabic: 0x0666,
-   sixbengali: 0x09EC,
-   sixcircle: 0x2465,
-   sixcircleinversesansserif: 0x278F,
-   sixdeva: 0x096C,
-   sixgujarati: 0x0AEC,
-   sixgurmukhi: 0x0A6C,
-   sixhackarabic: 0x0666,
-   sixhangzhou: 0x3026,
-   sixideographicparen: 0x3225,
-   sixinferior: 0x2086,
-   sixmonospace: 0xFF16,
-   sixoldstyle: 0xF736,
-   sixparen: 0x2479,
-   sixperiod: 0x248D,
-   sixpersian: 0x06F6,
-   sixroman: 0x2175,
-   sixsuperior: 0x2076,
-   sixteencircle: 0x246F,
-   sixteencurrencydenominatorbengali: 0x09F9,
-   sixteenparen: 0x2483,
-   sixteenperiod: 0x2497,
-   sixthai: 0x0E56,
-   slash: 0x002F,
-   slashmonospace: 0xFF0F,
-   slong: 0x017F,
-   slongdotaccent: 0x1E9B,
-   smileface: 0x263A,
-   smonospace: 0xFF53,
-   sofpasuqhebrew: 0x05C3,
-   softhyphen: 0x00AD,
-   softsigncyrillic: 0x044C,
-   sohiragana: 0x305D,
-   sokatakana: 0x30BD,
-   sokatakanahalfwidth: 0xFF7F,
-   soliduslongoverlaycmb: 0x0338,
-   solidusshortoverlaycmb: 0x0337,
-   sorusithai: 0x0E29,
-   sosalathai: 0x0E28,
-   sosothai: 0x0E0B,
-   sosuathai: 0x0E2A,
-   space: 0x0020,
-   spacehackarabic: 0x0020,
-   spade: 0x2660,
-   spadesuitblack: 0x2660,
-   spadesuitwhite: 0x2664,
-   sparen: 0x24AE,
-   squarebelowcmb: 0x033B,
-   squarecc: 0x33C4,
-   squarecm: 0x339D,
-   squarediagonalcrosshatchfill: 0x25A9,
-   squarehorizontalfill: 0x25A4,
-   squarekg: 0x338F,
-   squarekm: 0x339E,
-   squarekmcapital: 0x33CE,
-   squareln: 0x33D1,
-   squarelog: 0x33D2,
-   squaremg: 0x338E,
-   squaremil: 0x33D5,
-   squaremm: 0x339C,
-   squaremsquared: 0x33A1,
-   squareorthogonalcrosshatchfill: 0x25A6,
-   squareupperlefttolowerrightfill: 0x25A7,
-   squareupperrighttolowerleftfill: 0x25A8,
-   squareverticalfill: 0x25A5,
-   squarewhitewithsmallblack: 0x25A3,
-   srsquare: 0x33DB,
-   ssabengali: 0x09B7,
-   ssadeva: 0x0937,
-   ssagujarati: 0x0AB7,
-   ssangcieuckorean: 0x3149,
-   ssanghieuhkorean: 0x3185,
-   ssangieungkorean: 0x3180,
-   ssangkiyeokkorean: 0x3132,
-   ssangnieunkorean: 0x3165,
-   ssangpieupkorean: 0x3143,
-   ssangsioskorean: 0x3146,
-   ssangtikeutkorean: 0x3138,
-   ssuperior: 0xF6F2,
-   sterling: 0x00A3,
-   sterlingmonospace: 0xFFE1,
-   strokelongoverlaycmb: 0x0336,
-   strokeshortoverlaycmb: 0x0335,
-   subset: 0x2282,
-   subsetnotequal: 0x228A,
-   subsetorequal: 0x2286,
-   succeeds: 0x227B,
-   suchthat: 0x220B,
-   suhiragana: 0x3059,
-   sukatakana: 0x30B9,
-   sukatakanahalfwidth: 0xFF7D,
-   sukunarabic: 0x0652,
-   summation: 0x2211,
-   sun: 0x263C,
-   superset: 0x2283,
-   supersetnotequal: 0x228B,
-   supersetorequal: 0x2287,
-   svsquare: 0x33DC,
-   syouwaerasquare: 0x337C,
-   t: 0x0074,
-   tabengali: 0x09A4,
-   tackdown: 0x22A4,
-   tackleft: 0x22A3,
-   tadeva: 0x0924,
-   tagujarati: 0x0AA4,
-   tagurmukhi: 0x0A24,
-   taharabic: 0x0637,
-   tahfinalarabic: 0xFEC2,
-   tahinitialarabic: 0xFEC3,
-   tahiragana: 0x305F,
-   tahmedialarabic: 0xFEC4,
-   taisyouerasquare: 0x337D,
-   takatakana: 0x30BF,
-   takatakanahalfwidth: 0xFF80,
-   tatweelarabic: 0x0640,
-   tau: 0x03C4,
-   tav: 0x05EA,
-   tavdages: 0xFB4A,
-   tavdagesh: 0xFB4A,
-   tavdageshhebrew: 0xFB4A,
-   tavhebrew: 0x05EA,
-   tbar: 0x0167,
-   tbopomofo: 0x310A,
-   tcaron: 0x0165,
-   tccurl: 0x02A8,
-   tcedilla: 0x0163,
-   tcheharabic: 0x0686,
-   tchehfinalarabic: 0xFB7B,
-   tchehinitialarabic: 0xFB7C,
-   tchehmedialarabic: 0xFB7D,
-   tcircle: 0x24E3,
-   tcircumflexbelow: 0x1E71,
-   tcommaaccent: 0x0163,
-   tdieresis: 0x1E97,
-   tdotaccent: 0x1E6B,
-   tdotbelow: 0x1E6D,
-   tecyrillic: 0x0442,
-   tedescendercyrillic: 0x04AD,
-   teharabic: 0x062A,
-   tehfinalarabic: 0xFE96,
-   tehhahinitialarabic: 0xFCA2,
-   tehhahisolatedarabic: 0xFC0C,
-   tehinitialarabic: 0xFE97,
-   tehiragana: 0x3066,
-   tehjeeminitialarabic: 0xFCA1,
-   tehjeemisolatedarabic: 0xFC0B,
-   tehmarbutaarabic: 0x0629,
-   tehmarbutafinalarabic: 0xFE94,
-   tehmedialarabic: 0xFE98,
-   tehmeeminitialarabic: 0xFCA4,
-   tehmeemisolatedarabic: 0xFC0E,
-   tehnoonfinalarabic: 0xFC73,
-   tekatakana: 0x30C6,
-   tekatakanahalfwidth: 0xFF83,
-   telephone: 0x2121,
-   telephoneblack: 0x260E,
-   telishagedolahebrew: 0x05A0,
-   telishaqetanahebrew: 0x05A9,
-   tencircle: 0x2469,
-   tenideographicparen: 0x3229,
-   tenparen: 0x247D,
-   tenperiod: 0x2491,
-   tenroman: 0x2179,
-   tesh: 0x02A7,
-   tet: 0x05D8,
-   tetdagesh: 0xFB38,
-   tetdageshhebrew: 0xFB38,
-   tethebrew: 0x05D8,
-   tetsecyrillic: 0x04B5,
-   tevirhebrew: 0x059B,
-   tevirlefthebrew: 0x059B,
-   thabengali: 0x09A5,
-   thadeva: 0x0925,
-   thagujarati: 0x0AA5,
-   thagurmukhi: 0x0A25,
-   thalarabic: 0x0630,
-   thalfinalarabic: 0xFEAC,
-   thanthakhatlowleftthai: 0xF898,
-   thanthakhatlowrightthai: 0xF897,
-   thanthakhatthai: 0x0E4C,
-   thanthakhatupperleftthai: 0xF896,
-   theharabic: 0x062B,
-   thehfinalarabic: 0xFE9A,
-   thehinitialarabic: 0xFE9B,
-   thehmedialarabic: 0xFE9C,
-   thereexists: 0x2203,
-   therefore: 0x2234,
-   theta: 0x03B8,
-   theta1: 0x03D1,
-   thetasymbolgreek: 0x03D1,
-   thieuthacirclekorean: 0x3279,
-   thieuthaparenkorean: 0x3219,
-   thieuthcirclekorean: 0x326B,
-   thieuthkorean: 0x314C,
-   thieuthparenkorean: 0x320B,
-   thirteencircle: 0x246C,
-   thirteenparen: 0x2480,
-   thirteenperiod: 0x2494,
-   thonangmonthothai: 0x0E11,
-   thook: 0x01AD,
-   thophuthaothai: 0x0E12,
-   thorn: 0x00FE,
-   thothahanthai: 0x0E17,
-   thothanthai: 0x0E10,
-   thothongthai: 0x0E18,
-   thothungthai: 0x0E16,
-   thousandcyrillic: 0x0482,
-   thousandsseparatorarabic: 0x066C,
-   thousandsseparatorpersian: 0x066C,
-   three: 0x0033,
-   threearabic: 0x0663,
-   threebengali: 0x09E9,
-   threecircle: 0x2462,
-   threecircleinversesansserif: 0x278C,
-   threedeva: 0x0969,
-   threeeighths: 0x215C,
-   threegujarati: 0x0AE9,
-   threegurmukhi: 0x0A69,
-   threehackarabic: 0x0663,
-   threehangzhou: 0x3023,
-   threeideographicparen: 0x3222,
-   threeinferior: 0x2083,
-   threemonospace: 0xFF13,
-   threenumeratorbengali: 0x09F6,
-   threeoldstyle: 0xF733,
-   threeparen: 0x2476,
-   threeperiod: 0x248A,
-   threepersian: 0x06F3,
-   threequarters: 0x00BE,
-   threequartersemdash: 0xF6DE,
-   threeroman: 0x2172,
-   threesuperior: 0x00B3,
-   threethai: 0x0E53,
-   thzsquare: 0x3394,
-   tihiragana: 0x3061,
-   tikatakana: 0x30C1,
-   tikatakanahalfwidth: 0xFF81,
-   tikeutacirclekorean: 0x3270,
-   tikeutaparenkorean: 0x3210,
-   tikeutcirclekorean: 0x3262,
-   tikeutkorean: 0x3137,
-   tikeutparenkorean: 0x3202,
-   tilde: 0x02DC,
-   tildebelowcmb: 0x0330,
-   tildecmb: 0x0303,
-   tildecomb: 0x0303,
-   tildedoublecmb: 0x0360,
-   tildeoperator: 0x223C,
-   tildeoverlaycmb: 0x0334,
-   tildeverticalcmb: 0x033E,
-   timescircle: 0x2297,
-   tipehahebrew: 0x0596,
-   tipehalefthebrew: 0x0596,
-   tippigurmukhi: 0x0A70,
-   titlocyrilliccmb: 0x0483,
-   tiwnarmenian: 0x057F,
-   tlinebelow: 0x1E6F,
-   tmonospace: 0xFF54,
-   toarmenian: 0x0569,
-   tohiragana: 0x3068,
-   tokatakana: 0x30C8,
-   tokatakanahalfwidth: 0xFF84,
-   tonebarextrahighmod: 0x02E5,
-   tonebarextralowmod: 0x02E9,
-   tonebarhighmod: 0x02E6,
-   tonebarlowmod: 0x02E8,
-   tonebarmidmod: 0x02E7,
-   tonefive: 0x01BD,
-   tonesix: 0x0185,
-   tonetwo: 0x01A8,
-   tonos: 0x0384,
-   tonsquare: 0x3327,
-   topatakthai: 0x0E0F,
-   tortoiseshellbracketleft: 0x3014,
-   tortoiseshellbracketleftsmall: 0xFE5D,
-   tortoiseshellbracketleftvertical: 0xFE39,
-   tortoiseshellbracketright: 0x3015,
-   tortoiseshellbracketrightsmall: 0xFE5E,
-   tortoiseshellbracketrightvertical: 0xFE3A,
-   totaothai: 0x0E15,
-   tpalatalhook: 0x01AB,
-   tparen: 0x24AF,
-   trademark: 0x2122,
-   trademarksans: 0xF8EA,
-   trademarkserif: 0xF6DB,
-   tretroflexhook: 0x0288,
-   triagdn: 0x25BC,
-   triaglf: 0x25C4,
-   triagrt: 0x25BA,
-   triagup: 0x25B2,
-   ts: 0x02A6,
-   tsadi: 0x05E6,
-   tsadidagesh: 0xFB46,
-   tsadidageshhebrew: 0xFB46,
-   tsadihebrew: 0x05E6,
-   tsecyrillic: 0x0446,
-   tsere: 0x05B5,
-   tsere12: 0x05B5,
-   tsere1e: 0x05B5,
-   tsere2b: 0x05B5,
-   tserehebrew: 0x05B5,
-   tserenarrowhebrew: 0x05B5,
-   tserequarterhebrew: 0x05B5,
-   tserewidehebrew: 0x05B5,
-   tshecyrillic: 0x045B,
-   tsuperior: 0xF6F3,
-   ttabengali: 0x099F,
-   ttadeva: 0x091F,
-   ttagujarati: 0x0A9F,
-   ttagurmukhi: 0x0A1F,
-   tteharabic: 0x0679,
-   ttehfinalarabic: 0xFB67,
-   ttehinitialarabic: 0xFB68,
-   ttehmedialarabic: 0xFB69,
-   tthabengali: 0x09A0,
-   tthadeva: 0x0920,
-   tthagujarati: 0x0AA0,
-   tthagurmukhi: 0x0A20,
-   tturned: 0x0287,
-   tuhiragana: 0x3064,
-   tukatakana: 0x30C4,
-   tukatakanahalfwidth: 0xFF82,
-   tusmallhiragana: 0x3063,
-   tusmallkatakana: 0x30C3,
-   tusmallkatakanahalfwidth: 0xFF6F,
-   twelvecircle: 0x246B,
-   twelveparen: 0x247F,
-   twelveperiod: 0x2493,
-   twelveroman: 0x217B,
-   twentycircle: 0x2473,
-   twentyhangzhou: 0x5344,
-   twentyparen: 0x2487,
-   twentyperiod: 0x249B,
-   two: 0x0032,
-   twoarabic: 0x0662,
-   twobengali: 0x09E8,
-   twocircle: 0x2461,
-   twocircleinversesansserif: 0x278B,
-   twodeva: 0x0968,
-   twodotenleader: 0x2025,
-   twodotleader: 0x2025,
-   twodotleadervertical: 0xFE30,
-   twogujarati: 0x0AE8,
-   twogurmukhi: 0x0A68,
-   twohackarabic: 0x0662,
-   twohangzhou: 0x3022,
-   twoideographicparen: 0x3221,
-   twoinferior: 0x2082,
-   twomonospace: 0xFF12,
-   twonumeratorbengali: 0x09F5,
-   twooldstyle: 0xF732,
-   twoparen: 0x2475,
-   twoperiod: 0x2489,
-   twopersian: 0x06F2,
-   tworoman: 0x2171,
-   twostroke: 0x01BB,
-   twosuperior: 0x00B2,
-   twothai: 0x0E52,
-   twothirds: 0x2154,
-   u: 0x0075,
-   uacute: 0x00FA,
-   ubar: 0x0289,
-   ubengali: 0x0989,
-   ubopomofo: 0x3128,
-   ubreve: 0x016D,
-   ucaron: 0x01D4,
-   ucircle: 0x24E4,
-   ucircumflex: 0x00FB,
-   ucircumflexbelow: 0x1E77,
-   ucyrillic: 0x0443,
-   udattadeva: 0x0951,
-   udblacute: 0x0171,
-   udblgrave: 0x0215,
-   udeva: 0x0909,
-   udieresis: 0x00FC,
-   udieresisacute: 0x01D8,
-   udieresisbelow: 0x1E73,
-   udieresiscaron: 0x01DA,
-   udieresiscyrillic: 0x04F1,
-   udieresisgrave: 0x01DC,
-   udieresismacron: 0x01D6,
-   udotbelow: 0x1EE5,
-   ugrave: 0x00F9,
-   ugujarati: 0x0A89,
-   ugurmukhi: 0x0A09,
-   uhiragana: 0x3046,
-   uhookabove: 0x1EE7,
-   uhorn: 0x01B0,
-   uhornacute: 0x1EE9,
-   uhorndotbelow: 0x1EF1,
-   uhorngrave: 0x1EEB,
-   uhornhookabove: 0x1EED,
-   uhorntilde: 0x1EEF,
-   uhungarumlaut: 0x0171,
-   uhungarumlautcyrillic: 0x04F3,
-   uinvertedbreve: 0x0217,
-   ukatakana: 0x30A6,
-   ukatakanahalfwidth: 0xFF73,
-   ukcyrillic: 0x0479,
-   ukorean: 0x315C,
-   umacron: 0x016B,
-   umacroncyrillic: 0x04EF,
-   umacrondieresis: 0x1E7B,
-   umatragurmukhi: 0x0A41,
-   umonospace: 0xFF55,
-   underscore: 0x005F,
-   underscoredbl: 0x2017,
-   underscoremonospace: 0xFF3F,
-   underscorevertical: 0xFE33,
-   underscorewavy: 0xFE4F,
-   union: 0x222A,
-   universal: 0x2200,
-   uogonek: 0x0173,
-   uparen: 0x24B0,
-   upblock: 0x2580,
-   upperdothebrew: 0x05C4,
-   upsilon: 0x03C5,
-   upsilondieresis: 0x03CB,
-   upsilondieresistonos: 0x03B0,
-   upsilonlatin: 0x028A,
-   upsilontonos: 0x03CD,
-   uptackbelowcmb: 0x031D,
-   uptackmod: 0x02D4,
-   uragurmukhi: 0x0A73,
-   uring: 0x016F,
-   ushortcyrillic: 0x045E,
-   usmallhiragana: 0x3045,
-   usmallkatakana: 0x30A5,
-   usmallkatakanahalfwidth: 0xFF69,
-   ustraightcyrillic: 0x04AF,
-   ustraightstrokecyrillic: 0x04B1,
-   utilde: 0x0169,
-   utildeacute: 0x1E79,
-   utildebelow: 0x1E75,
-   uubengali: 0x098A,
-   uudeva: 0x090A,
-   uugujarati: 0x0A8A,
-   uugurmukhi: 0x0A0A,
-   uumatragurmukhi: 0x0A42,
-   uuvowelsignbengali: 0x09C2,
-   uuvowelsigndeva: 0x0942,
-   uuvowelsigngujarati: 0x0AC2,
-   uvowelsignbengali: 0x09C1,
-   uvowelsigndeva: 0x0941,
-   uvowelsigngujarati: 0x0AC1,
-   v: 0x0076,
-   vadeva: 0x0935,
-   vagujarati: 0x0AB5,
-   vagurmukhi: 0x0A35,
-   vakatakana: 0x30F7,
-   vav: 0x05D5,
-   vavdagesh: 0xFB35,
-   vavdagesh65: 0xFB35,
-   vavdageshhebrew: 0xFB35,
-   vavhebrew: 0x05D5,
-   vavholam: 0xFB4B,
-   vavholamhebrew: 0xFB4B,
-   vavvavhebrew: 0x05F0,
-   vavyodhebrew: 0x05F1,
-   vcircle: 0x24E5,
-   vdotbelow: 0x1E7F,
-   vecyrillic: 0x0432,
-   veharabic: 0x06A4,
-   vehfinalarabic: 0xFB6B,
-   vehinitialarabic: 0xFB6C,
-   vehmedialarabic: 0xFB6D,
-   vekatakana: 0x30F9,
-   venus: 0x2640,
-   verticalbar: 0x007C,
-   verticallineabovecmb: 0x030D,
-   verticallinebelowcmb: 0x0329,
-   verticallinelowmod: 0x02CC,
-   verticallinemod: 0x02C8,
-   vewarmenian: 0x057E,
-   vhook: 0x028B,
-   vikatakana: 0x30F8,
-   viramabengali: 0x09CD,
-   viramadeva: 0x094D,
-   viramagujarati: 0x0ACD,
-   visargabengali: 0x0983,
-   visargadeva: 0x0903,
-   visargagujarati: 0x0A83,
-   vmonospace: 0xFF56,
-   voarmenian: 0x0578,
-   voicediterationhiragana: 0x309E,
-   voicediterationkatakana: 0x30FE,
-   voicedmarkkana: 0x309B,
-   voicedmarkkanahalfwidth: 0xFF9E,
-   vokatakana: 0x30FA,
-   vparen: 0x24B1,
-   vtilde: 0x1E7D,
-   vturned: 0x028C,
-   vuhiragana: 0x3094,
-   vukatakana: 0x30F4,
-   w: 0x0077,
-   wacute: 0x1E83,
-   waekorean: 0x3159,
-   wahiragana: 0x308F,
-   wakatakana: 0x30EF,
-   wakatakanahalfwidth: 0xFF9C,
-   wakorean: 0x3158,
-   wasmallhiragana: 0x308E,
-   wasmallkatakana: 0x30EE,
-   wattosquare: 0x3357,
-   wavedash: 0x301C,
-   wavyunderscorevertical: 0xFE34,
-   wawarabic: 0x0648,
-   wawfinalarabic: 0xFEEE,
-   wawhamzaabovearabic: 0x0624,
-   wawhamzaabovefinalarabic: 0xFE86,
-   wbsquare: 0x33DD,
-   wcircle: 0x24E6,
-   wcircumflex: 0x0175,
-   wdieresis: 0x1E85,
-   wdotaccent: 0x1E87,
-   wdotbelow: 0x1E89,
-   wehiragana: 0x3091,
-   weierstrass: 0x2118,
-   wekatakana: 0x30F1,
-   wekorean: 0x315E,
-   weokorean: 0x315D,
-   wgrave: 0x1E81,
-   whitebullet: 0x25E6,
-   whitecircle: 0x25CB,
-   whitecircleinverse: 0x25D9,
-   whitecornerbracketleft: 0x300E,
-   whitecornerbracketleftvertical: 0xFE43,
-   whitecornerbracketright: 0x300F,
-   whitecornerbracketrightvertical: 0xFE44,
-   whitediamond: 0x25C7,
-   whitediamondcontainingblacksmalldiamond: 0x25C8,
-   whitedownpointingsmalltriangle: 0x25BF,
-   whitedownpointingtriangle: 0x25BD,
-   whiteleftpointingsmalltriangle: 0x25C3,
-   whiteleftpointingtriangle: 0x25C1,
-   whitelenticularbracketleft: 0x3016,
-   whitelenticularbracketright: 0x3017,
-   whiterightpointingsmalltriangle: 0x25B9,
-   whiterightpointingtriangle: 0x25B7,
-   whitesmallsquare: 0x25AB,
-   whitesmilingface: 0x263A,
-   whitesquare: 0x25A1,
-   whitestar: 0x2606,
-   whitetelephone: 0x260F,
-   whitetortoiseshellbracketleft: 0x3018,
-   whitetortoiseshellbracketright: 0x3019,
-   whiteuppointingsmalltriangle: 0x25B5,
-   whiteuppointingtriangle: 0x25B3,
-   wihiragana: 0x3090,
-   wikatakana: 0x30F0,
-   wikorean: 0x315F,
-   wmonospace: 0xFF57,
-   wohiragana: 0x3092,
-   wokatakana: 0x30F2,
-   wokatakanahalfwidth: 0xFF66,
-   won: 0x20A9,
-   wonmonospace: 0xFFE6,
-   wowaenthai: 0x0E27,
-   wparen: 0x24B2,
-   wring: 0x1E98,
-   wsuperior: 0x02B7,
-   wturned: 0x028D,
-   wynn: 0x01BF,
-   x: 0x0078,
-   xabovecmb: 0x033D,
-   xbopomofo: 0x3112,
-   xcircle: 0x24E7,
-   xdieresis: 0x1E8D,
-   xdotaccent: 0x1E8B,
-   xeharmenian: 0x056D,
-   xi: 0x03BE,
-   xmonospace: 0xFF58,
-   xparen: 0x24B3,
-   xsuperior: 0x02E3,
-   y: 0x0079,
-   yaadosquare: 0x334E,
-   yabengali: 0x09AF,
-   yacute: 0x00FD,
-   yadeva: 0x092F,
-   yaekorean: 0x3152,
-   yagujarati: 0x0AAF,
-   yagurmukhi: 0x0A2F,
-   yahiragana: 0x3084,
-   yakatakana: 0x30E4,
-   yakatakanahalfwidth: 0xFF94,
-   yakorean: 0x3151,
-   yamakkanthai: 0x0E4E,
-   yasmallhiragana: 0x3083,
-   yasmallkatakana: 0x30E3,
-   yasmallkatakanahalfwidth: 0xFF6C,
-   yatcyrillic: 0x0463,
-   ycircle: 0x24E8,
-   ycircumflex: 0x0177,
-   ydieresis: 0x00FF,
-   ydotaccent: 0x1E8F,
-   ydotbelow: 0x1EF5,
-   yeharabic: 0x064A,
-   yehbarreearabic: 0x06D2,
-   yehbarreefinalarabic: 0xFBAF,
-   yehfinalarabic: 0xFEF2,
-   yehhamzaabovearabic: 0x0626,
-   yehhamzaabovefinalarabic: 0xFE8A,
-   yehhamzaaboveinitialarabic: 0xFE8B,
-   yehhamzaabovemedialarabic: 0xFE8C,
-   yehinitialarabic: 0xFEF3,
-   yehmedialarabic: 0xFEF4,
-   yehmeeminitialarabic: 0xFCDD,
-   yehmeemisolatedarabic: 0xFC58,
-   yehnoonfinalarabic: 0xFC94,
-   yehthreedotsbelowarabic: 0x06D1,
-   yekorean: 0x3156,
-   yen: 0x00A5,
-   yenmonospace: 0xFFE5,
-   yeokorean: 0x3155,
-   yeorinhieuhkorean: 0x3186,
-   yerahbenyomohebrew: 0x05AA,
-   yerahbenyomolefthebrew: 0x05AA,
-   yericyrillic: 0x044B,
-   yerudieresiscyrillic: 0x04F9,
-   yesieungkorean: 0x3181,
-   yesieungpansioskorean: 0x3183,
-   yesieungsioskorean: 0x3182,
-   yetivhebrew: 0x059A,
-   ygrave: 0x1EF3,
-   yhook: 0x01B4,
-   yhookabove: 0x1EF7,
-   yiarmenian: 0x0575,
-   yicyrillic: 0x0457,
-   yikorean: 0x3162,
-   yinyang: 0x262F,
-   yiwnarmenian: 0x0582,
-   ymonospace: 0xFF59,
-   yod: 0x05D9,
-   yoddagesh: 0xFB39,
-   yoddageshhebrew: 0xFB39,
-   yodhebrew: 0x05D9,
-   yodyodhebrew: 0x05F2,
-   yodyodpatahhebrew: 0xFB1F,
-   yohiragana: 0x3088,
-   yoikorean: 0x3189,
-   yokatakana: 0x30E8,
-   yokatakanahalfwidth: 0xFF96,
-   yokorean: 0x315B,
-   yosmallhiragana: 0x3087,
-   yosmallkatakana: 0x30E7,
-   yosmallkatakanahalfwidth: 0xFF6E,
-   yotgreek: 0x03F3,
-   yoyaekorean: 0x3188,
-   yoyakorean: 0x3187,
-   yoyakthai: 0x0E22,
-   yoyingthai: 0x0E0D,
-   yparen: 0x24B4,
-   ypogegrammeni: 0x037A,
-   ypogegrammenigreekcmb: 0x0345,
-   yr: 0x01A6,
-   yring: 0x1E99,
-   ysuperior: 0x02B8,
-   ytilde: 0x1EF9,
-   yturned: 0x028E,
-   yuhiragana: 0x3086,
-   yuikorean: 0x318C,
-   yukatakana: 0x30E6,
-   yukatakanahalfwidth: 0xFF95,
-   yukorean: 0x3160,
-   yusbigcyrillic: 0x046B,
-   yusbigiotifiedcyrillic: 0x046D,
-   yuslittlecyrillic: 0x0467,
-   yuslittleiotifiedcyrillic: 0x0469,
-   yusmallhiragana: 0x3085,
-   yusmallkatakana: 0x30E5,
-   yusmallkatakanahalfwidth: 0xFF6D,
-   yuyekorean: 0x318B,
-   yuyeokorean: 0x318A,
-   yyabengali: 0x09DF,
-   yyadeva: 0x095F,
-   z: 0x007A,
-   zaarmenian: 0x0566,
-   zacute: 0x017A,
-   zadeva: 0x095B,
-   zagurmukhi: 0x0A5B,
-   zaharabic: 0x0638,
-   zahfinalarabic: 0xFEC6,
-   zahinitialarabic: 0xFEC7,
-   zahiragana: 0x3056,
-   zahmedialarabic: 0xFEC8,
-   zainarabic: 0x0632,
-   zainfinalarabic: 0xFEB0,
-   zakatakana: 0x30B6,
-   zaqefgadolhebrew: 0x0595,
-   zaqefqatanhebrew: 0x0594,
-   zarqahebrew: 0x0598,
-   zayin: 0x05D6,
-   zayindagesh: 0xFB36,
-   zayindageshhebrew: 0xFB36,
-   zayinhebrew: 0x05D6,
-   zbopomofo: 0x3117,
-   zcaron: 0x017E,
-   zcircle: 0x24E9,
-   zcircumflex: 0x1E91,
-   zcurl: 0x0291,
-   zdot: 0x017C,
-   zdotaccent: 0x017C,
-   zdotbelow: 0x1E93,
-   zecyrillic: 0x0437,
-   zedescendercyrillic: 0x0499,
-   zedieresiscyrillic: 0x04DF,
-   zehiragana: 0x305C,
-   zekatakana: 0x30BC,
-   zero: 0x0030,
-   zeroarabic: 0x0660,
-   zerobengali: 0x09E6,
-   zerodeva: 0x0966,
-   zerogujarati: 0x0AE6,
-   zerogurmukhi: 0x0A66,
-   zerohackarabic: 0x0660,
-   zeroinferior: 0x2080,
-   zeromonospace: 0xFF10,
-   zerooldstyle: 0xF730,
-   zeropersian: 0x06F0,
-   zerosuperior: 0x2070,
-   zerothai: 0x0E50,
-   zerowidthjoiner: 0xFEFF,
-   zerowidthnonjoiner: 0x200C,
-   zerowidthspace: 0x200B,
-   zeta: 0x03B6,
-   zhbopomofo: 0x3113,
-   zhearmenian: 0x056A,
-   zhebrevecyrillic: 0x04C2,
-   zhecyrillic: 0x0436,
-   zhedescendercyrillic: 0x0497,
-   zhedieresiscyrillic: 0x04DD,
-   zihiragana: 0x3058,
-   zikatakana: 0x30B8,
-   zinorhebrew: 0x05AE,
-   zlinebelow: 0x1E95,
-   zmonospace: 0xFF5A,
-   zohiragana: 0x305E,
-   zokatakana: 0x30BE,
-   zparen: 0x24B5,
-   zretroflexhook: 0x0290,
-   zstroke: 0x01B6,
-   zuhiragana: 0x305A,
-   zukatakana: 0x30BA,
-   '.notdef': 0x0000
- };
++    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 || '');
 +
- 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) {
-     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 data = message.data;
-         var stream = new Stream(data, 0, data.length, image.dict);
-         promise.resolve(stream);
-       });
++    if (data.hasAppearance) {
++      data.name = 'NoIcon';
 +    } else {
-       promise.resolve(image);
++      data.name = dict.has('Name') ? dict.get('Name').name : 'Note';
 +    }
-   }
-   /**
-    * 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.
-    */
-   function decodeAndClamp(value, addend, coefficient, max) {
-     value = addend + value * coefficient;
-     // Clamp the value to the range
-     return value < 0 ? 0 : value > max ? max : value;
-   }
-   function PDFImage(xref, res, image, inline, smask, mask) {
-     this.image = image;
-     if (image.getParams) {
-       // JPX/JPEG2000 streams directly contain bits per component
-       // and color space mode information.
-       TODO('get params from actual stream');
-       // var bits = ...
-       // var colorspace = ...
++
++    if (dict.has('C')) {
++      data.hasBgColor = true;
 +    }
-     // TODO cache rendered images?
++  }
 +
-     var dict = image.dict;
-     this.width = dict.get('Width', 'W');
-     this.height = dict.get('Height', 'H');
++  var ANNOT_MIN_SIZE = 10;
 +
-     if (this.width < 1 || this.height < 1)
-       error('Invalid image width: ' + this.width + ' or height: ' +
-             this.height);
++  Util.inherit(TextAnnotation, InteractiveAnnotation, {
 +
-     this.interpolate = dict.get('Interpolate', 'I') || false;
-     this.imageMask = dict.get('ImageMask', 'IM') || false;
++    getHtmlElement: function TextAnnotation_getHtmlElement(commonObjs) {
++      assert(!isWorker, 'getHtmlElement() shall be called from main thread');
 +
-     var bitsPerComponent = image.bitsPerComponent;
-     if (!bitsPerComponent) {
-       bitsPerComponent = dict.get('BitsPerComponent', 'BPC');
-       if (!bitsPerComponent) {
-         if (this.imageMask)
-           bitsPerComponent = 1;
-         else
-           error('Bits per component missing in image: ' + this.imageMask);
-       }
-     }
-     this.bpc = bitsPerComponent;
++      var item = this.data;
++      var rect = item.rect;
 +
-     if (!this.imageMask) {
-       var colorSpace = dict.get('ColorSpace', 'CS');
-       if (!colorSpace) {
-         TODO('JPX images (which don"t require color spaces');
-         colorSpace = new Name('DeviceRGB');
++      // 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
 +      }
-       this.colorSpace = ColorSpace.parse(colorSpace, xref, res);
-       this.numComps = this.colorSpace.numComps;
-     }
 +
-     this.decode = dict.get('Decode', 'D');
-     this.needsDecode = false;
-     if (this.decode && this.colorSpace &&
-         !this.colorSpace.isDefaultDecode(this.decode)) {
-       this.needsDecode = true;
-       // Do some preprocessing to avoid more math.
-       var max = (1 << bitsPerComponent) - 1;
-       this.decodeCoefficients = [];
-       this.decodeAddends = [];
-       for (var i = 0, j = 0; i < this.decode.length; i += 2, ++j) {
-         var dmin = this.decode[i];
-         var dmax = this.decode[i + 1];
-         this.decodeCoefficients[j] = dmax - dmin;
-         this.decodeAddends[j] = max * dmin;
++      var container = this.initContainer();
++      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);
++      if (item.hasBgColor) {
++        var color = item.color;
++        var rgb = [];
++        for (var 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);
 +      }
-     }
 +
-     if (smask) {
-       this.smask = new PDFImage(xref, res, smask, false);
-     } else if (mask) {
-       if (isStream(mask)) {
-         this.mask = new PDFImage(xref, res, mask, false);
++      var title = document.createElement('h1');
++      var text = document.createElement('p');
++      title.textContent = item.title;
++
++      if (!item.content && !item.title) {
++        content.setAttribute('hidden', true);
 +      } else {
-         // Color key mask (just an array).
-         this.mask = mask;
++        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 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);
++          }
++        };
++
++        var self = this;
++        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;
 +    }
-   }
-   /**
-    * Handles processing of image data and calls the callback with an argument
-    * of a PDFImage when the image is ready to be used.
-    */
-   PDFImage.buildImage = function PDFImage_buildImage(callback, handler, xref,
-                                                      res, image, inline) {
-     var imageDataPromise = new Promise();
-     var smaskPromise = new Promise();
-     var maskPromise = new Promise();
-     // 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);
++  return TextAnnotation;
++})();
 +
-     var smask = image.dict.get('SMask');
-     var mask = image.dict.get('Mask');
++var LinkAnnotation = (function LinkAnnotationClosure() {
++  function LinkAnnotation(params) {
++    InteractiveAnnotation.call(this, params);
 +
-     if (smask) {
-       handleImageData(handler, xref, res, smask, smaskPromise);
-       maskPromise.resolve(null);
-     } else {
-       smaskPromise.resolve(null);
-       if (mask) {
-         if (isStream(mask)) {
-           handleImageData(handler, xref, res, mask, maskPromise);
-         } else if (isArray(mask)) {
-           maskPromise.resolve(mask);
-         } else {
-           warn('Unsupported mask format.');
-           maskPromise.resolve(null);
-         }
++    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 = 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 {
-         maskPromise.resolve(null);
++        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;
 +    }
-   };
++  }
 +
-   /**
-    * 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.
-    * @param {Number} components Number of color components, 1 or 3 is supported.
-    * @param {Number} w1 Original width.
-    * @param {Number} h1 Original height.
-    * @param {Number} w2 New width.
-    * @param {Number} h2 New height.
-    * @return {TypedArray} Resized image data.
-    */
-   PDFImage.resize = function PDFImage_resize(pixels, bpc, components,
-                                              w1, h1, w2, h2) {
-     var length = w2 * h2 * components;
-     var temp = 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];
-         }
-       }
++  // Lets URLs beginning with 'www.' default to using the 'http://' protocol.
++  function addDefaultProtocolToUrl(url) {
++    if (url && url.indexOf('www.') === 0) {
++      return ('http://' + url);
 +    }
-     return temp;
-   };
++    return url;
++  }
 +
-   PDFImage.prototype = {
-     get drawWidth() {
-       if (!this.smask)
-         return this.width;
-       return Math.max(this.width, this.smask.width);
-     },
-     get drawHeight() {
-       if (!this.smask)
-         return this.height;
-       return Math.max(this.height, this.smask.height);
++  Util.inherit(LinkAnnotation, InteractiveAnnotation, {
++    hasOperatorList: function LinkAnnotation_hasOperatorList() {
++      return false;
 +    },
-     getComponents: function PDFImage_getComponents(buffer) {
-       var bpc = this.bpc;
-       var needsDecode = this.needsDecode;
-       var decodeMap = this.decode;
- 
-       // This image doesn't require any extra work.
-       if (bpc == 8 && !needsDecode)
-         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 rowComps = width * numComps;
-       var decodeAddends, decodeCoefficients;
-       if (needsDecode) {
-         decodeAddends = this.decodeAddends;
-         decodeCoefficients = this.decodeCoefficients;
-       }
-       var max = (1 << bpc) - 1;
- 
-       if (bpc == 8) {
-         // Optimization for reading 8 bpc images that have a decode.
-         for (var i = 0, ii = length; i < ii; ++i) {
-           var compIndex = i % numComps;
-           var value = buffer[i];
-           value = decodeAndClamp(value, decodeAddends[compIndex],
-                           decodeCoefficients[compIndex], max);
-           output[i] = value;
-         }
-       } else if (bpc == 1) {
-         // Optimization for reading 1 bpc images.
-         var valueZero = 0, valueOne = 1;
-         if (decodeMap) {
-           valueZero = decodeMap[0] ? 1 : 0;
-           valueOne = decodeMap[1] ? 1 : 0;
-         }
-         var mask = 0;
-         var buf = 0;
++    getHtmlElement: function LinkAnnotation_getHtmlElement(commonObjs) {
 +
-         for (var i = 0, ii = length; i < ii; ++i) {
-           if (i % rowComps === 0) {
-             mask = 0;
-             buf = 0;
-           } else {
-             mask >>= 1;
-           }
++      var container = this.initContainer();
++      container.className = 'annotLink';
 +
-           if (mask <= 0) {
-             buf = buffer[bufferPos++];
-             mask = 128;
-           }
++      var item = this.data;
++      var rect = item.rect;
 +
-           output[i] = !(buf & mask) ? valueZero : valueOne;
-         }
-       } else {
-         // The general case that handles all other bpc values.
-         var bits = 0, buf = 0;
-         for (var i = 0, ii = length; i < ii; ++i) {
-           if (i % rowComps === 0) {
-             buf = 0;
-             bits = 0;
-           }
++      container.style.borderColor = item.colorCssRgb;
++      container.style.borderStyle = 'solid';
++
++      var link = document.createElement('a');
++      link.href = link.title = this.data.url || '';
++
++      container.appendChild(link);
++
++      return container;
++    }
++  });
++
++  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}
++ */
++PDFJS.maxImageSize = PDFJS.maxImageSize === undefined ? -1 : PDFJS.maxImageSize;
++
++/**
++ * 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}
++ */
++PDFJS.disableFontFace = PDFJS.disableFontFace === undefined ?
++                        false : PDFJS.disableFontFace;
++
++/**
++ * Path for image resources, mainly for annotation icons. Include trailing
++ * slash.
++ * @var {string}
++ */
++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}
++ */
++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}
++ */
++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}
++ */
++PDFJS.disableRange = PDFJS.disableRange === undefined ?
++                     false : PDFJS.disableRange;
++
++/**
++ * 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}
++ */
++PDFJS.disableAutoFetch = PDFJS.disableAutoFetch === undefined ?
++                         false : PDFJS.disableAutoFetch;
++
++/**
++ * Enables special hooks for debugging PDF.js.
++ * @var {boolean}
++ */
++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;
++
++/**
++ * Disables URL.createObjectURL usage.
++ * @var {boolean}
++ */
++PDFJS.disableCreateObjectURL = PDFJS.disableCreateObjectURL === undefined ?
++                               false : PDFJS.disableCreateObjectURL;
++
++/**
++ * Controls the logging level.
++ * The constants from PDFJS.VERBOSITY_LEVELS should be used:
++ * - errors
++ * - warnings [default]
++ * - infos
++ * @var {number}
++ */
++PDFJS.verbosity = PDFJS.verbosity === undefined ?
++                  PDFJS.VERBOSITY_LEVELS.warnings : PDFJS.verbosity;
++
++/**
++ * 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.
++ */
++
++/**
++ * This is the main entry point for loading a PDF and interacting with it.
++ * NOTE: If a URL is used to fetch the PDF data a standard XMLHttpRequest(XHR)
++ * 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|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
++ * to manually serve range requests for data in the PDF. See viewer.js for
++ * an example of pdfDataRangeTransport's interface.
++ *
++ * @param {function} passwordCallback is optional. It is used to request a
++ * password if wrong or no password was provided. The callback receives two
++ * parameters: function that needs to be called with new password and reason
++ * (see {PasswordResponses}).
++ *
++ * @return {Promise} A promise that is resolved with {@link PDFDocumentProxy}
++ *   object.
++ */
++PDFJS.getDocument = function getDocument(source,
++                                         pdfDataRangeTransport,
++                                         passwordCallback,
++                                         progressCallback) {
++  var workerInitializedPromise, workerReadyPromise, transport;
++
++  if (typeof source === 'string') {
++    source = { url: source };
++  } else if (isArrayBuffer(source)) {
++    source = { data: source };
++  } else if (typeof source !== 'object') {
++    error('Invalid parameter in getDocument, need either Uint8Array, ' +
++          'string or a parameter object');
++  }
++
++  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 = {};
++  for (var key in source) {
++    if (key === 'url' && typeof window !== 'undefined') {
++      params[key] = combineUrl(window.location.href, source[key]);
++      continue;
++    }
++    params[key] = source[key];
++  }
 +
-           while (bits < bpc) {
-             buf = (buf << 8) | buffer[bufferPos++];
-             bits += 8;
-           }
++  workerInitializedPromise = new PDFJS.LegacyPromise();
++  workerReadyPromise = new PDFJS.LegacyPromise();
++  transport = new WorkerTransport(workerInitializedPromise,
++      workerReadyPromise, pdfDataRangeTransport, progressCallback);
++  workerInitializedPromise.then(function transportInitialized() {
++    transport.passwordCallback = passwordCallback;
++    transport.fetchDocument(params);
++  });
++  return workerReadyPromise;
++};
 +
-           var remainingBits = bits - bpc;
-           var value = buf >> remainingBits;
-           if (needsDecode) {
-             var compIndex = i % numComps;
-             value = decodeAndClamp(value, decodeAddends[compIndex],
-                             decodeCoefficients[compIndex], max);
-           }
-           output[i] = value;
-           buf = buf & ((1 << remainingBits) - 1);
-           bits = remainingBits;
-         }
-       }
-       return output;
++/**
++ * 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 = /** @lends PDFDocumentProxy.prototype */ {
++    /**
++     * @return {number} Total number of pages the PDF contains.
++     */
++    get numPages() {
++      return this.pdfInfo.numPages;
 +    },
-     getOpacity: function PDFImage_getOpacity(width, height, image) {
-       var smask = this.smask;
-       var mask = this.mask;
-       var originalWidth = this.width;
-       var originalHeight = this.height;
-       var buf;
- 
-       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);
-       } else if (mask) {
-         if (mask instanceof PDFImage) {
-           var sw = mask.width;
-           var sh = mask.height;
-           buf = new Uint8Array(sw * sh);
-           mask.numComps = 1;
-           mask.fillGrayBuffer(buf);
- 
-           // Need to invert values in buffer
-           for (var i = 0, ii = sw * sh; i < ii; ++i)
-             buf[i] = 255 - buf[i];
- 
-           if (sw != width || sh != height)
-             buf = PDFImage.resize(buf, 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);
-           var numComps = this.numComps;
-           for (var i = 0, ii = width * height; i < ii; ++i) {
-             var opacity = 0;
-             var imageOffset = i * numComps;
-             for (var j = 0; j < numComps; ++j) {
-               var color = image[imageOffset + j];
-               var maskOffset = j * 2;
-               if (color < mask[maskOffset] || color > mask[maskOffset + 1]) {
-                 opacity = 255;
-                 break;
-               }
-             }
-             buf[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;
++    /**
++     * @return {string} A unique ID to identify a PDF. Not guaranteed to be
++     * unique.
++     */
++    get fingerprint() {
++      return this.pdfInfo.fingerprint;
 +    },
-     applyStencilMask: function PDFImage_applyStencilMask(buffer,
-                                                          inverseDecode) {
-       var width = this.width, height = this.height;
-       var bitStrideLength = (width + 7) >> 3;
-       var imgArray = this.getImageBytes(bitStrideLength * height);
-       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] = 0;
-           }
-           bufferPos += 4;
-           mask >>= 1;
-         }
-       }
++    /**
++     * @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(pageNumber) {
++      return this.transport.getPage(pageNumber);
 +    },
-     fillRgbaBuffer: function PDFImage_fillRgbaBuffer(buffer, width, height) {
-       var numComps = this.numComps;
-       var originalWidth = this.width;
-       var originalHeight = this.height;
-       var bpc = this.bpc;
- 
-       // rows start at byte boundary;
-       var rowBytes = (originalWidth * numComps * bpc + 7) >> 3;
-       var imgArray = this.getImageBytes(originalHeight * rowBytes);
- 
-       // imgArray can be incomplete (e.g. after CCITT fax encoding)
-       var actualHeight = 0 | (imgArray.length / rowBytes *
-                          height / originalHeight);
- 
-       var comps = this.colorSpace.createRgbBuffer(this.getComponents(imgArray),
-         0, originalWidth * originalHeight, bpc);
-       if (originalWidth != width || originalHeight != height)
-         comps = PDFImage.resize(comps, this.bpc, 3, originalWidth,
-                                 originalHeight, width, height);
-       var compsPos = 0;
-       var opacity = this.getOpacity(width, height, imgArray);
-       var opacityPos = 0;
-       var length = width * actualHeight * 4;
- 
-       for (var i = 0; i < length; i += 4) {
-         buffer[i] = comps[compsPos++];
-         buffer[i + 1] = comps[compsPos++];
-         buffer[i + 2] = comps[compsPos++];
-         buffer[i + 3] = opacity[opacityPos++];
-       }
++    /**
++     * @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.
++     */
++    getPageIndex: function PDFDocumentProxy_getPageIndex(ref) {
++      return this.transport.getPageIndex(ref);
 +    },
-     fillGrayBuffer: function PDFImage_fillGrayBuffer(buffer) {
-       var numComps = this.numComps;
-       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;
-       var rowBytes = (width * numComps * bpc + 7) >> 3;
-       var imgArray = this.getImageBytes(height * rowBytes);
- 
-       var comps = this.getComponents(imgArray);
-       var 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)
-         buffer[i] = (scale * comps[i]) | 0;
++    /**
++     * @return {Promise} A promise that is resolved with a lookup table for
++     * mapping named destinations to reference numbers.
++     */
++    getDestinations: function PDFDocumentProxy_getDestinations() {
++      return this.transport.getDestinations();
 +    },
-     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;
++    /**
++     * @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 {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:
++     * [
++     *  {
++     *   title: string,
++     *   bold: boolean,
++     *   italic: boolean,
++     *   color: rgb array,
++     *   dest: dest obj,
++     *   items: array of more items like this
++     *  },
++     *  ...
++     * ].
++     */
++    getOutline: function PDFDocumentProxy_getOutline() {
++      var promise = new PDFJS.LegacyPromise();
++      var outline = this.pdfInfo.outline;
++      promise.resolve(outline);
++      return promise;
++    },
++    /**
++     * @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;
++    },
++    /**
++     * @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 {Promise} A promise that is resolved when the document's data
++     * is loaded. It is resolved with an {Object} that contains the length
++     * property that indicates size of the PDF data in bytes.
++     */
++    getDownloadInfo: function PDFDocumentProxy_getDownloadInfo() {
++      return this.transport.downloadInfoPromise;
 +    },
-     getImageBytes: function PDFImage_getImageBytes(length) {
-       this.image.reset();
-       return this.image.getBytes(length);
++    /**
++     * 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();
 +    }
 +  };
-   return PDFImage;
++  return PDFDocumentProxy;
 +})();
 +
- function loadJpegStream(id, imageData, objs) {
-   var img = new Image();
-   img.onload = (function loadJpegStream_onloadClosure() {
-     objs.resolve(id, img);
-   });
-   img.src = 'data:image/jpeg;base64,' + window.btoa(imageData);
- }
- 
- 
- 
- // The Metrics object contains glyph widths (in glyph space units).
- // As per PDF spec, for most fonts (Type 3 being an exception) a glyph
- // space unit corresponds to 1/1000th of text space unit.
- var Metrics = {
-   'Courier': 600,
-   'Courier-Bold': 600,
-   'Courier-BoldOblique': 600,
-   'Courier-Oblique': 600,
-   'Helvetica' : {
-     'space': 278,
-     'exclam': 278,
-     'quotedbl': 355,
-     'numbersign': 556,
-     'dollar': 556,
-     'percent': 889,
-     'ampersand': 667,
-     'quoteright': 222,
-     'parenleft': 333,
-     'parenright': 333,
-     'asterisk': 389,
-     'plus': 584,
-     'comma': 278,
-     'hyphen': 333,
-     'period': 278,
-     'slash': 278,
-     'zero': 556,
-     'one': 556,
-     'two': 556,
-     'three': 556,
-     'four': 556,
-     'five': 556,
-     'six': 556,
-     'seven': 556,
-     'eight': 556,
-     'nine': 556,
-     'colon': 278,
-     'semicolon': 278,
-     'less': 584,
-     'equal': 584,
-     'greater': 584,
-     'question': 556,
-     'at': 1015,
-     'A': 667,
-     'B': 667,
-     'C': 722,
-     'D': 722,
-     'E': 667,
-     'F': 611,
-     'G': 778,
-     'H': 722,
-     'I': 278,
-     'J': 500,
-     'K': 667,
-     'L': 556,
-     'M': 833,
-     'N': 722,
-     'O': 778,
-     'P': 667,
-     'Q': 778,
-     'R': 722,
-     'S': 667,
-     'T': 611,
-     'U': 722,
-     'V': 667,
-     'W': 944,
-     'X': 667,
-     'Y': 667,
-     'Z': 611,
-     'bracketleft': 278,
-     'backslash': 278,
-     'bracketright': 278,
-     'asciicircum': 469,
-     'underscore': 556,
-     'quoteleft': 222,
-     'a': 556,
-     'b': 556,
-     'c': 500,
-     'd': 556,
-     'e': 556,
-     'f': 278,
-     'g': 556,
-     'h': 556,
-     'i': 222,
-     'j': 222,
-     'k': 500,
-     'l': 222,
-     'm': 833,
-     'n': 556,
-     'o': 556,
-     'p': 556,
-     'q': 556,
-     'r': 333,
-     's': 500,
-     't': 278,
-     'u': 556,
-     'v': 500,
-     'w': 722,
-     'x': 500,
-     'y': 500,
-     'z': 500,
-     'braceleft': 334,
-     'bar': 260,
-     'braceright': 334,
-     'asciitilde': 584,
-     'exclamdown': 333,
-     'cent': 556,
-     'sterling': 556,
-     'fraction': 167,
-     'yen': 556,
-     'florin': 556,
-     'section': 556,
-     'currency': 556,
-     'quotesingle': 191,
-     'quotedblleft': 333,
-     'guillemotleft': 556,
-     'guilsinglleft': 333,
-     'guilsinglright': 333,
-     'fi': 500,
-     'fl': 500,
-     'endash': 556,
-     'dagger': 556,
-     'daggerdbl': 556,
-     'periodcentered': 278,
-     'paragraph': 537,
-     'bullet': 350,
-     'quotesinglbase': 222,
-     'quotedblbase': 333,
-     'quotedblright': 333,
-     'guillemotright': 556,
-     'ellipsis': 1000,
-     'perthousand': 1000,
-     'questiondown': 611,
-     'grave': 333,
-     'acute': 333,
-     'circumflex': 333,
-     'tilde': 333,
-     'macron': 333,
-     'breve': 333,
-     'dotaccent': 333,
-     'dieresis': 333,
-     'ring': 333,
-     'cedilla': 333,
-     'hungarumlaut': 333,
-     'ogonek': 333,
-     'caron': 333,
-     'emdash': 1000,
-     'AE': 1000,
-     'ordfeminine': 370,
-     'Lslash': 556,
-     'Oslash': 778,
-     'OE': 1000,
-     'ordmasculine': 365,
-     'ae': 889,
-     'dotlessi': 278,
-     'lslash': 222,
-     'oslash': 611,
-     'oe': 944,
-     'germandbls': 611,
-     'Idieresis': 278,
-     'eacute': 556,
-     'abreve': 556,
-     'uhungarumlaut': 556,
-     'ecaron': 556,
-     'Ydieresis': 667,
-     'divide': 584,
-     'Yacute': 667,
-     'Acircumflex': 667,
-     'aacute': 556,
-     'Ucircumflex': 722,
-     'yacute': 500,
-     'scommaaccent': 500,
-     'ecircumflex': 556,
-     'Uring': 722,
-     'Udieresis': 722,
-     'aogonek': 556,
-     'Uacute': 722,
-     'uogonek': 556,
-     'Edieresis': 667,
-     'Dcroat': 722,
-     'commaaccent': 250,
-     'copyright': 737,
-     'Emacron': 667,
-     'ccaron': 500,
-     'aring': 556,
-     'Ncommaaccent': 722,
-     'lacute': 222,
-     'agrave': 556,
-     'Tcommaaccent': 611,
-     'Cacute': 722,
-     'atilde': 556,
-     'Edotaccent': 667,
-     'scaron': 500,
-     'scedilla': 500,
-     'iacute': 278,
-     'lozenge': 471,
-     'Rcaron': 722,
-     'Gcommaaccent': 778,
-     'ucircumflex': 556,
-     'acircumflex': 556,
-     'Amacron': 667,
-     'rcaron': 333,
-     'ccedilla': 500,
-     'Zdotaccent': 611,
-     'Thorn': 667,
-     'Omacron': 778,
-     'Racute': 722,
-     'Sacute': 667,
-     'dcaron': 643,
-     'Umacron': 722,
-     'uring': 556,
-     'threesuperior': 333,
-     'Ograve': 778,
-     'Agrave': 667,
-     'Abreve': 667,
-     'multiply': 584,
-     'uacute': 556,
-     'Tcaron': 611,
-     'partialdiff': 476,
-     'ydieresis': 500,
-     'Nacute': 722,
-     'icircumflex': 278,
-     'Ecircumflex': 667,
-     'adieresis': 556,
-     'edieresis': 556,
-     'cacute': 500,
-     'nacute': 556,
-     'umacron': 556,
-     'Ncaron': 722,
-     'Iacute': 278,
-     'plusminus': 584,
-     'brokenbar': 260,
-     'registered': 737,
-     'Gbreve': 778,
-     'Idotaccent': 278,
-     'summation': 600,
-     'Egrave': 667,
-     'racute': 333,
-     'omacron': 556,
-     'Zacute': 611,
-     'Zcaron': 611,
-     'greaterequal': 549,
-     'Eth': 722,
-     'Ccedilla': 722,
-     'lcommaaccent': 222,
-     'tcaron': 317,
-     'eogonek': 556,
-     'Uogonek': 722,
-     'Aacute': 667,
-     'Adieresis': 667,
-     'egrave': 556,
-     'zacute': 500,
-     'iogonek': 222,
-     'Oacute': 778,
-     'oacute': 556,
-     'amacron': 556,
-     'sacute': 500,
-     'idieresis': 278,
-     'Ocircumflex': 778,
-     'Ugrave': 722,
-     'Delta': 612,
-     'thorn': 556,
-     'twosuperior': 333,
-     'Odieresis': 778,
-     'mu': 556,
-     'igrave': 278,
-     'ohungarumlaut': 556,
-     'Eogonek': 667,
-     'dcroat': 556,
-     'threequarters': 834,
-     'Scedilla': 667,
-     'lcaron': 299,
-     'Kcommaaccent': 667,
-     'Lacute': 556,
-     'trademark': 1000,
-     'edotaccent': 556,
-     'Igrave': 278,
-     'Imacron': 278,
-     'Lcaron': 556,
-     'onehalf': 834,
-     'lessequal': 549,
-     'ocircumflex': 556,
-     'ntilde': 556,
-     'Uhungarumlaut': 722,
-     'Eacute': 667,
-     'emacron': 556,
-     'gbreve': 556,
-     'onequarter': 834,
-     'Scaron': 667,
-     'Scommaaccent': 667,
-     'Ohungarumlaut': 778,
-     'degree': 400,
-     'ograve': 556,
-     'Ccaron': 722,
-     'ugrave': 556,
-     'radical': 453,
-     'Dcaron': 722,
-     'rcommaaccent': 333,
-     'Ntilde': 722,
-     'otilde': 556,
-     'Rcommaaccent': 722,
-     'Lcommaaccent': 556,
-     'Atilde': 667,
-     'Aogonek': 667,
-     'Aring': 667,
-     'Otilde': 778,
-     'zdotaccent': 500,
-     'Ecaron': 667,
-     'Iogonek': 278,
-     'kcommaaccent': 500,
-     'minus': 584,
-     'Icircumflex': 278,
-     'ncaron': 556,
-     'tcommaaccent': 278,
-     'logicalnot': 584,
-     'odieresis': 556,
-     'udieresis': 556,
-     'notequal': 549,
-     'gcommaaccent': 556,
-     'eth': 556,
-     'zcaron': 500,
-     'ncommaaccent': 556,
-     'onesuperior': 333,
-     'imacron': 278,
-     'Euro': 556
-   },
-   'Helvetica-Bold': {
-     'space': 278,
-     'exclam': 333,
-     'quotedbl': 474,
-     'numbersign': 556,
-     'dollar': 556,
-     'percent': 889,
-     'ampersand': 722,
-     'quoteright': 278,
-     'parenleft': 333,
-     'parenright': 333,
-     'asterisk': 389,
-     'plus': 584,
-     'comma': 278,
-     'hyphen': 333,
-     'period': 278,
-     'slash': 278,
-     'zero': 556,
-     'one': 556,
-     'two': 556,
-     'three': 556,
-     'four': 556,
-     'five': 556,
-     'six': 556,
-     'seven': 556,
-     'eight': 556,
-     'nine': 556,
-     'colon': 333,
-     'semicolon': 333,
-     'less': 584,
-     'equal': 584,
-     'greater': 584,
-     'question': 611,
-     'at': 975,
-     'A': 722,
-     'B': 722,
-     'C': 722,
-     'D': 722,
-     'E': 667,
-     'F': 611,
-     'G': 778,
-     'H': 722,
-     'I': 278,
-     'J': 556,
-     'K': 722,
-     'L': 611,
-     'M': 833,
-     'N': 722,
-     'O': 778,
-     'P': 667,
-     'Q': 778,
-     'R': 722,
-     'S': 667,
-     'T': 611,
-     'U': 722,
-     'V': 667,
-     'W': 944,
-     'X': 667,
-     'Y': 667,
-     'Z': 611,
-     'bracketleft': 333,
-     'backslash': 278,
-     'bracketright': 333,
-     'asciicircum': 584,
-     'underscore': 556,
-     'quoteleft': 278,
-     'a': 556,
-     'b': 611,
-     'c': 556,
-     'd': 611,
-     'e': 556,
-     'f': 333,
-     'g': 611,
-     'h': 611,
-     'i': 278,
-     'j': 278,
-     'k': 556,
-     'l': 278,
-     'm': 889,
-     'n': 611,
-     'o': 611,
-     'p': 611,
-     'q': 611,
-     'r': 389,
-     's': 556,
-     't': 333,
-     'u': 611,
-     'v': 556,
-     'w': 778,
-     'x': 556,
-     'y': 556,
-     'z': 500,
-     'braceleft': 389,
-     'bar': 280,
-     'braceright': 389,
-     'asciitilde': 584,
-     'exclamdown': 333,
-     'cent': 556,
-     'sterling': 556,
-     'fraction': 167,
-     'yen': 556,
-     'florin': 556,
-     'section': 556,
-     'currency': 556,
-     'quotesingle': 238,
-     'quotedblleft': 500,
-     'guillemotleft': 556,
-     'guilsinglleft': 333,
-     'guilsinglright': 333,
-     'fi': 611,
-     'fl': 611,
-     'endash': 556,
-     'dagger': 556,
-     'daggerdbl': 556,
-     'periodcentered': 278,
-     'paragraph': 556,
-     'bullet': 350,
-     'quotesinglbase': 278,
-     'quotedblbase': 500,
-     'quotedblright': 500,
-     'guillemotright': 556,
-     'ellipsis': 1000,
-     'perthousand': 1000,
-     'questiondown': 611,
-     'grave': 333,
-     'acute': 333,
-     'circumflex': 333,
-     'tilde': 333,
-     'macron': 333,
-     'breve': 333,
-     'dotaccent': 333,
-     'dieresis': 333,
-     'ring': 333,
-     'cedilla': 333,
-     'hungarumlaut': 333,
-     'ogonek': 333,
-     'caron': 333,
-     'emdash': 1000,
-     'AE': 1000,
-     'ordfeminine': 370,
-     'Lslash': 611,
-     'Oslash': 778,
-     'OE': 1000,
-     'ordmasculine': 365,
-     'ae': 889,
-     'dotlessi': 278,
-     'lslash': 278,
-     'oslash': 611,
-     'oe': 944,
-     'germandbls': 611,
-     'Idieresis': 278,
-     'eacute': 556,
-     'abreve': 556,
-     'uhungarumlaut': 611,
-     'ecaron': 556,
-     'Ydieresis': 667,
-     'divide': 584,
-     'Yacute': 667,
-     'Acircumflex': 722,
-     'aacute': 556,
-     'Ucircumflex': 722,
-     'yacute': 556,
-     'scommaaccent': 556,
-     'ecircumflex': 556,
-     'Uring': 722,
-     'Udieresis': 722,
-     'aogonek': 556,
-     'Uacute': 722,
-     'uogonek': 611,
-     'Edieresis': 667,
-     'Dcroat': 722,
-     'commaaccent': 250,
-     'copyright': 737,
-     'Emacron': 667,
-     'ccaron': 556,
-     'aring': 556,
-     'Ncommaaccent': 722,
-     'lacute': 278,
-     'agrave': 556,
-     'Tcommaaccent': 611,
-     'Cacute': 722,
-     'atilde': 556,
-     'Edotaccent': 667,
-     'scaron': 556,
-     'scedilla': 556,
-     'iacute': 278,
-     'lozenge': 494,
-     'Rcaron': 722,
-     'Gcommaaccent': 778,
-     'ucircumflex': 611,
-     'acircumflex': 556,
-     'Amacron': 722,
-     'rcaron': 389,
-     'ccedilla': 556,
-     'Zdotaccent': 611,
-     'Thorn': 667,
-     'Omacron': 778,
-     'Racute': 722,
-     'Sacute': 667,
-     'dcaron': 743,
-     'Umacron': 722,
-     'uring': 611,
-     'threesuperior': 333,
-     'Ograve': 778,
-     'Agrave': 722,
-     'Abreve': 722,
-     'multiply': 584,
-     'uacute': 611,
-     'Tcaron': 611,
-     'partialdiff': 494,
-     'ydieresis': 556,
-     'Nacute': 722,
-     'icircumflex': 278,
-     'Ecircumflex': 667,
-     'adieresis': 556,
-     'edieresis': 556,
-     'cacute': 556,
-     'nacute': 611,
-     'umacron': 611,
-     'Ncaron': 722,
-     'Iacute': 278,
-     'plusminus': 584,
-     'brokenbar': 280,
-     'registered': 737,
-     'Gbreve': 778,
-     'Idotaccent': 278,
-     'summation': 600,
-     'Egrave': 667,
-     'racute': 389,
-     'omacron': 611,
-     'Zacute': 611,
-     'Zcaron': 611,
-     'greaterequal': 549,
-     'Eth': 722,
-     'Ccedilla': 722,
-     'lcommaaccent': 278,
-     'tcaron': 389,
-     'eogonek': 556,
-     'Uogonek': 722,
-     'Aacute': 722,
-     'Adieresis': 722,
-     'egrave': 556,
-     'zacute': 500,
-     'iogonek': 278,
-     'Oacute': 778,
-     'oacute': 611,
-     'amacron': 556,
-     'sacute': 556,
-     'idieresis': 278,
-     'Ocircumflex': 778,
-     'Ugrave': 722,
-     'Delta': 612,
-     'thorn': 611,
-     'twosuperior': 333,
-     'Odieresis': 778,
-     'mu': 611,
-     'igrave': 278,
-     'ohungarumlaut': 611,
-     'Eogonek': 667,
-     'dcroat': 611,
-     'threequarters': 834,
-     'Scedilla': 667,
-     'lcaron': 400,
-     'Kcommaaccent': 722,
-     'Lacute': 611,
-     'trademark': 1000,
-     'edotaccent': 556,
-     'Igrave': 278,
-     'Imacron': 278,
-     'Lcaron': 611,
-     'onehalf': 834,
-     'lessequal': 549,
-     'ocircumflex': 611,
-     'ntilde': 611,
-     'Uhungarumlaut': 722,
-     'Eacute': 667,
-     'emacron': 556,
-     'gbreve': 611,
-     'onequarter': 834,
-     'Scaron': 667,
-     'Scommaaccent': 667,
-     'Ohungarumlaut': 778,
-     'degree': 400,
-     'ograve': 611,
-     'Ccaron': 722,
-     'ugrave': 611,
-     'radical': 549,
-     'Dcaron': 722,
-     'rcommaaccent': 389,
-     'Ntilde': 722,
-     'otilde': 611,
-     'Rcommaaccent': 722,
-     'Lcommaaccent': 611,
-     'Atilde': 722,
-     'Aogonek': 722,
-     'Aring': 722,
-     'Otilde': 778,
-     'zdotaccent': 500,
-     'Ecaron': 667,
-     'Iogonek': 278,
-     'kcommaaccent': 556,
-     'minus': 584,
-     'Icircumflex': 278,
-     'ncaron': 611,
-     'tcommaaccent': 333,
-     'logicalnot': 584,
-     'odieresis': 611,
-     'udieresis': 611,
-     'notequal': 549,
-     'gcommaaccent': 611,
-     'eth': 611,
-     'zcaron': 500,
-     'ncommaaccent': 611,
-     'onesuperior': 333,
-     'imacron': 278,
-     'Euro': 556
-   },
-   'Helvetica-BoldOblique': {
-     'space': 278,
-     'exclam': 333,
-     'quotedbl': 474,
-     'numbersign': 556,
-     'dollar': 556,
-     'percent': 889,
-     'ampersand': 722,
-     'quoteright': 278,
-     'parenleft': 333,
-     'parenright': 333,
-     'asterisk': 389,
-     'plus': 584,
-     'comma': 278,
-     'hyphen': 333,
-     'period': 278,
-     'slash': 278,
-     'zero': 556,
-     'one': 556,
-     'two': 556,
-     'three': 556,
-     'four': 556,
-     'five': 556,
-     'six': 556,
-     'seven': 556,
-     'eight': 556,
-     'nine': 556,
-     'colon': 333,
-     'semicolon': 333,
-     'less': 584,
-     'equal': 584,
-     'greater': 584,
-     'question': 611,
-     'at': 975,
-     'A': 722,
-     'B': 722,
-     'C': 722,
-     'D': 722,
-     'E': 667,
-     'F': 611,
-     'G': 778,
-     'H': 722,
-     'I': 278,
-     'J': 556,
-     'K': 722,
-     'L': 611,
-     'M': 833,
-     'N': 722,
-     'O': 778,
-     'P': 667,
-     'Q': 778,
-     'R': 722,
-     'S': 667,
-     'T': 611,
-     'U': 722,
-     'V': 667,
-     'W': 944,
-     'X': 667,
-     'Y': 667,
-     'Z': 611,
-     'bracketleft': 333,
-     'backslash': 278,
-     'bracketright': 333,
-     'asciicircum': 584,
-     'underscore': 556,
-     'quoteleft': 278,
-     'a': 556,
-     'b': 611,
-     'c': 556,
-     'd': 611,
-     'e': 556,
-     'f': 333,
-     'g': 611,
-     'h': 611,
-     'i': 278,
-     'j': 278,
-     'k': 556,
-     'l': 278,
-     'm': 889,
-     'n': 611,
-     'o': 611,
-     'p': 611,
-     'q': 611,
-     'r': 389,
-     's': 556,
-     't': 333,
-     'u': 611,
-     'v': 556,
-     'w': 778,
-     'x': 556,
-     'y': 556,
-     'z': 500,
-     'braceleft': 389,
-     'bar': 280,
-     'braceright': 389,
-     'asciitilde': 584,
-     'exclamdown': 333,
-     'cent': 556,
-     'sterling': 556,
-     'fraction': 167,
-     'yen': 556,
-     'florin': 556,
-     'section': 556,
-     'currency': 556,
-     'quotesingle': 238,
-     'quotedblleft': 500,
-     'guillemotleft': 556,
-     'guilsinglleft': 333,
-     'guilsinglright': 333,
-     'fi': 611,
-     'fl': 611,
-     'endash': 556,
-     'dagger': 556,
-     'daggerdbl': 556,
-     'periodcentered': 278,
-     'paragraph': 556,
-     'bullet': 350,
-     'quotesinglbase': 278,
-     'quotedblbase': 500,
-     'quotedblright': 500,
-     'guillemotright': 556,
-     'ellipsis': 1000,
-     'perthousand': 1000,
-     'questiondown': 611,
-     'grave': 333,
-     'acute': 333,
-     'circumflex': 333,
-     'tilde': 333,
-     'macron': 333,
-     'breve': 333,
-     'dotaccent': 333,
-     'dieresis': 333,
-     'ring': 333,
-     'cedilla': 333,
-     'hungarumlaut': 333,
-     'ogonek': 333,
-     'caron': 333,
-     'emdash': 1000,
-     'AE': 1000,
-     'ordfeminine': 370,
-     'Lslash': 611,
-     'Oslash': 778,
-     'OE': 1000,
-     'ordmasculine': 365,
-     'ae': 889,
-     'dotlessi': 278,
-     'lslash': 278,
-     'oslash': 611,
-     'oe': 944,
-     'germandbls': 611,
-     'Idieresis': 278,
-     'eacute': 556,
-     'abreve': 556,
-     'uhungarumlaut': 611,
-     'ecaron': 556,
-     'Ydieresis': 667,
-     'divide': 584,
-     'Yacute': 667,
-     'Acircumflex': 722,
-     'aacute': 556,
-     'Ucircumflex': 722,
-     'yacute': 556,
-     'scommaaccent': 556,
-     'ecircumflex': 556,
-     'Uring': 722,
-     'Udieresis': 722,
-     'aogonek': 556,
-     'Uacute': 722,
-     'uogonek': 611,
-     'Edieresis': 667,
-     'Dcroat': 722,
-     'commaaccent': 250,
-     'copyright': 737,
-     'Emacron': 667,
-     'ccaron': 556,
-     'aring': 556,
-     'Ncommaaccent': 722,
-     'lacute': 278,
-     'agrave': 556,
-     'Tcommaaccent': 611,
-     'Cacute': 722,
-     'atilde': 556,
-     'Edotaccent': 667,
-     'scaron': 556,
-     'scedilla': 556,
-     'iacute': 278,
-     'lozenge': 494,
-     'Rcaron': 722,
-     'Gcommaaccent': 778,
-     'ucircumflex': 611,
-     'acircumflex': 556,
-     'Amacron': 722,
-     'rcaron': 389,
-     'ccedilla': 556,
-     'Zdotaccent': 611,
-     'Thorn': 667,
-     'Omacron': 778,
-     'Racute': 722,
-     'Sacute': 667,
-     'dcaron': 743,
-     'Umacron': 722,
-     'uring': 611,
-     'threesuperior': 333,
-     'Ograve': 778,
-     'Agrave': 722,
-     'Abreve': 722,
-     'multiply': 584,
-     'uacute': 611,
-     'Tcaron': 611,
-     'partialdiff': 494,
-     'ydieresis': 556,
-     'Nacute': 722,
-     'icircumflex': 278,
-     'Ecircumflex': 667,
-     'adieresis': 556,
-     'edieresis': 556,
-     'cacute': 556,
-     'nacute': 611,
-     'umacron': 611,
-     'Ncaron': 722,
-     'Iacute': 278,
-     'plusminus': 584,
-     'brokenbar': 280,
-     'registered': 737,
-     'Gbreve': 778,
-     'Idotaccent': 278,
-     'summation': 600,
-     'Egrave': 667,
-     'racute': 389,
-     'omacron': 611,
-     'Zacute': 611,
-     'Zcaron': 611,
-     'greaterequal': 549,
-     'Eth': 722,
-     'Ccedilla': 722,
-     'lcommaaccent': 278,
-     'tcaron': 389,
-     'eogonek': 556,
-     'Uogonek': 722,
-     'Aacute': 722,
-     'Adieresis': 722,
-     'egrave': 556,
-     'zacute': 500,
-     'iogonek': 278,
-     'Oacute': 778,
-     'oacute': 611,
-     'amacron': 556,
-     'sacute': 556,
-     'idieresis': 278,
-     'Ocircumflex': 778,
-     'Ugrave': 722,
-     'Delta': 612,
-     'thorn': 611,
-     'twosuperior': 333,
-     'Odieresis': 778,
-     'mu': 611,
-     'igrave': 278,
-     'ohungarumlaut': 611,
-     'Eogonek': 667,
-     'dcroat': 611,
-     'threequarters': 834,
-     'Scedilla': 667,
-     'lcaron': 400,
-     'Kcommaaccent': 722,
-     'Lacute': 611,
-     'trademark': 1000,
-     'edotaccent': 556,
-     'Igrave': 278,
-     'Imacron': 278,
-     'Lcaron': 611,
-     'onehalf': 834,
-     'lessequal': 549,
-     'ocircumflex': 611,
-     'ntilde': 611,
-     'Uhungarumlaut': 722,
-     'Eacute': 667,
-     'emacron': 556,
-     'gbreve': 611,
-     'onequarter': 834,
-     'Scaron': 667,
-     'Scommaaccent': 667,
-     'Ohungarumlaut': 778,
-     'degree': 400,
-     'ograve': 611,
-     'Ccaron': 722,
-     'ugrave': 611,
-     'radical': 549,
-     'Dcaron': 722,
-     'rcommaaccent': 389,
-     'Ntilde': 722,
-     'otilde': 611,
-     'Rcommaaccent': 722,
-     'Lcommaaccent': 611,
-     'Atilde': 722,
-     'Aogonek': 722,
-     'Aring': 722,
-     'Otilde': 778,
-     'zdotaccent': 500,
-     'Ecaron': 667,
-     'Iogonek': 278,
-     'kcommaaccent': 556,
-     'minus': 584,
-     'Icircumflex': 278,
-     'ncaron': 611,
-     'tcommaaccent': 333,
-     'logicalnot': 584,
-     'odieresis': 611,
-     'udieresis': 611,
-     'notequal': 549,
-     'gcommaaccent': 611,
-     'eth': 611,
-     'zcaron': 500,
-     'ncommaaccent': 611,
-     'onesuperior': 333,
-     'imacron': 278,
-     'Euro': 556
-   },
-   'Helvetica-Oblique' : {
-     'space': 278,
-     'exclam': 278,
-     'quotedbl': 355,
-     'numbersign': 556,
-     'dollar': 556,
-     'percent': 889,
-     'ampersand': 667,
-     'quoteright': 222,
-     'parenleft': 333,
-     'parenright': 333,
-     'asterisk': 389,
-     'plus': 584,
-     'comma': 278,
-     'hyphen': 333,
-     'period': 278,
-     'slash': 278,
-     'zero': 556,
-     'one': 556,
-     'two': 556,
-     'three': 556,
-     'four': 556,
-     'five': 556,
-     'six': 556,
-     'seven': 556,
-     'eight': 556,
-     'nine': 556,
-     'colon': 278,
-     'semicolon': 278,
-     'less': 584,
-     'equal': 584,
-     'greater': 584,
-     'question': 556,
-     'at': 1015,
-     'A': 667,
-     'B': 667,
-     'C': 722,
-     'D': 722,
-     'E': 667,
-     'F': 611,
-     'G': 778,
-     'H': 722,
-     'I': 278,
-     'J': 500,
-     'K': 667,
-     'L': 556,
-     'M': 833,
-     'N': 722,
-     'O': 778,
-     'P': 667,
-     'Q': 778,
-     'R': 722,
-     'S': 667,
-     'T': 611,
-     'U': 722,
-     'V': 667,
-     'W': 944,
-     'X': 667,
-     'Y': 667,
-     'Z': 611,
-     'bracketleft': 278,
-     'backslash': 278,
-     'bracketright': 278,
-     'asciicircum': 469,
-     'underscore': 556,
-     'quoteleft': 222,
-     'a': 556,
-     'b': 556,
-     'c': 500,
-     'd': 556,
-     'e': 556,
-     'f': 278,
-     'g': 556,
-     'h': 556,
-     'i': 222,
-     'j': 222,
-     'k': 500,
-     'l': 222,
-     'm': 833,
-     'n': 556,
-     'o': 556,
-     'p': 556,
-     'q': 556,
-     'r': 333,
-     's': 500,
-     't': 278,
-     'u': 556,
-     'v': 500,
-     'w': 722,
-     'x': 500,
-     'y': 500,
-     'z': 500,
-     'braceleft': 334,
-     'bar': 260,
-     'braceright': 334,
-     'asciitilde': 584,
-     'exclamdown': 333,
-     'cent': 556,
-     'sterling': 556,
-     'fraction': 167,
-     'yen': 556,
-     'florin': 556,
-     'section': 556,
-     'currency': 556,
-     'quotesingle': 191,
-     'quotedblleft': 333,
-     'guillemotleft': 556,
-     'guilsinglleft': 333,
-     'guilsinglright': 333,
-     'fi': 500,
-     'fl': 500,
-     'endash': 556,
-     'dagger': 556,
-     'daggerdbl': 556,
-     'periodcentered': 278,
-     'paragraph': 537,
-     'bullet': 350,
-     'quotesinglbase': 222,
-     'quotedblbase': 333,
-     'quotedblright': 333,
-     'guillemotright': 556,
-     'ellipsis': 1000,
-     'perthousand': 1000,
-     'questiondown': 611,
-     'grave': 333,
-     'acute': 333,
-     'circumflex': 333,
-     'tilde': 333,
-     'macron': 333,
-     'breve': 333,
-     'dotaccent': 333,
-     'dieresis': 333,
-     'ring': 333,
-     'cedilla': 333,
-     'hungarumlaut': 333,
-     'ogonek': 333,
-     'caron': 333,
-     'emdash': 1000,
-     'AE': 1000,
-     'ordfeminine': 370,
-     'Lslash': 556,
-     'Oslash': 778,
-     'OE': 1000,
-     'ordmasculine': 365,
-     'ae': 889,
-     'dotlessi': 278,
-     'lslash': 222,
-     'oslash': 611,
-     'oe': 944,
-     'germandbls': 611,
-     'Idieresis': 278,
-     'eacute': 556,
-     'abreve': 556,
-     'uhungarumlaut': 556,
-     'ecaron': 556,
-     'Ydieresis': 667,
-     'divide': 584,
-     'Yacute': 667,
-     'Acircumflex': 667,
-     'aacute': 556,
-     'Ucircumflex': 722,
-     'yacute': 500,
-     'scommaaccent': 500,
-     'ecircumflex': 556,
-     'Uring': 722,
-     'Udieresis': 722,
-     'aogonek': 556,
-     'Uacute': 722,
-     'uogonek': 556,
-     'Edieresis': 667,
-     'Dcroat': 722,
-     'commaaccent': 250,
-     'copyright': 737,
-     'Emacron': 667,
-     'ccaron': 500,
-     'aring': 556,
-     'Ncommaaccent': 722,
-     'lacute': 222,
-     'agrave': 556,
-     'Tcommaaccent': 611,
-     'Cacute': 722,
-     'atilde': 556,
-     'Edotaccent': 667,
-     'scaron': 500,
-     'scedilla': 500,
-     'iacute': 278,
-     'lozenge': 471,
-     'Rcaron': 722,
-     'Gcommaaccent': 778,
-     'ucircumflex': 556,
-     'acircumflex': 556,
-     'Amacron': 667,
-     'rcaron': 333,
-     'ccedilla': 500,
-     'Zdotaccent': 611,
-     'Thorn': 667,
-     'Omacron': 778,
-     'Racute': 722,
-     'Sacute': 667,
-     'dcaron': 643,
-     'Umacron': 722,
-     'uring': 556,
-     'threesuperior': 333,
-     'Ograve': 778,
-     'Agrave': 667,
-     'Abreve': 667,
-     'multiply': 584,
-     'uacute': 556,
-     'Tcaron': 611,
-     'partialdiff': 476,
-     'ydieresis': 500,
-     'Nacute': 722,
-     'icircumflex': 278,
-     'Ecircumflex': 667,
-     'adieresis': 556,
-     'edieresis': 556,
-     'cacute': 500,
-     'nacute': 556,
-     'umacron': 556,
-     'Ncaron': 722,
-     'Iacute': 278,
-     'plusminus': 584,
-     'brokenbar': 260,
-     'registered': 737,
-     'Gbreve': 778,
-     'Idotaccent': 278,
-     'summation': 600,
-     'Egrave': 667,
-     'racute': 333,
-     'omacron': 556,
-     'Zacute': 611,
-     'Zcaron': 611,
-     'greaterequal': 549,
-     'Eth': 722,
-     'Ccedilla': 722,
-     'lcommaaccent': 222,
-     'tcaron': 317,
-     'eogonek': 556,
-     'Uogonek': 722,
-     'Aacute': 667,
-     'Adieresis': 667,
-     'egrave': 556,
-     'zacute': 500,
-     'iogonek': 222,
-     'Oacute': 778,
-     'oacute': 556,
-     'amacron': 556,
-     'sacute': 500,
-     'idieresis': 278,
-     'Ocircumflex': 778,
-     'Ugrave': 722,
-     'Delta': 612,
-     'thorn': 556,
-     'twosuperior': 333,
-     'Odieresis': 778,
-     'mu': 556,
-     'igrave': 278,
-     'ohungarumlaut': 556,
-     'Eogonek': 667,
-     'dcroat': 556,
-     'threequarters': 834,
-     'Scedilla': 667,
-     'lcaron': 299,
-     'Kcommaaccent': 667,
-     'Lacute': 556,
-     'trademark': 1000,
-     'edotaccent': 556,
-     'Igrave': 278,
-     'Imacron': 278,
-     'Lcaron': 556,
-     'onehalf': 834,
-     'lessequal': 549,
-     'ocircumflex': 556,
-     'ntilde': 556,
-     'Uhungarumlaut': 722,
-     'Eacute': 667,
-     'emacron': 556,
-     'gbreve': 556,
-     'onequarter': 834,
-     'Scaron': 667,
-     'Scommaaccent': 667,
-     'Ohungarumlaut': 778,
-     'degree': 400,
-     'ograve': 556,
-     'Ccaron': 722,
-     'ugrave': 556,
-     'radical': 453,
-     'Dcaron': 722,
-     'rcommaaccent': 333,
-     'Ntilde': 722,
-     'otilde': 556,
-     'Rcommaaccent': 722,
-     'Lcommaaccent': 556,
-     'Atilde': 667,
-     'Aogonek': 667,
-     'Aring': 667,
-     'Otilde': 778,
-     'zdotaccent': 500,
-     'Ecaron': 667,
-     'Iogonek': 278,
-     'kcommaaccent': 500,
-     'minus': 584,
-     'Icircumflex': 278,
-     'ncaron': 556,
-     'tcommaaccent': 278,
-     'logicalnot': 584,
-     'odieresis': 556,
-     'udieresis': 556,
-     'notequal': 549,
-     'gcommaaccent': 556,
-     'eth': 556,
-     'zcaron': 500,
-     'ncommaaccent': 556,
-     'onesuperior': 333,
-     'imacron': 278,
-     'Euro': 556
-   },
-   'Symbol': {
-     'space': 250,
-     'exclam': 333,
-     'universal': 713,
-     'numbersign': 500,
-     'existential': 549,
-     'percent': 833,
-     'ampersand': 778,
-     'suchthat': 439,
-     'parenleft': 333,
-     'parenright': 333,
-     'asteriskmath': 500,
-     'plus': 549,
-     'comma': 250,
-     'minus': 549,
-     'period': 250,
-     'slash': 278,
-     'zero': 500,
-     'one': 500,
-     'two': 500,
-     'three': 500,
-     'four': 500,
-     'five': 500,
-     'six': 500,
-     'seven': 500,
-     'eight': 500,
-     'nine': 500,
-     'colon': 278,
-     'semicolon': 278,
-     'less': 549,
-     'equal': 549,
-     'greater': 549,
-     'question': 444,
-     'congruent': 549,
-     'Alpha': 722,
-     'Beta': 667,
-     'Chi': 722,
-     'Delta': 612,
-     'Epsilon': 611,
-     'Phi': 763,
-     'Gamma': 603,
-     'Eta': 722,
-     'Iota': 333,
-     'theta1': 631,
-     'Kappa': 722,
-     'Lambda': 686,
-     'Mu': 889,
-     'Nu': 722,
-     'Omicron': 722,
-     'Pi': 768,
-     'Theta': 741,
-     'Rho': 556,
-     'Sigma': 592,
-     'Tau': 611,
-     'Upsilon': 690,
-     'sigma1': 439,
-     'Omega': 768,
-     'Xi': 645,
-     'Psi': 795,
-     'Zeta': 611,
-     'bracketleft': 333,
-     'therefore': 863,
-     'bracketright': 333,
-     'perpendicular': 658,
-     'underscore': 500,
-     'radicalex': 500,
-     'alpha': 631,
-     'beta': 549,
-     'chi': 549,
-     'delta': 494,
-     'epsilon': 439,
-     'phi': 521,
-     'gamma': 411,
-     'eta': 603,
-     'iota': 329,
-     'phi1': 603,
-     'kappa': 549,
-     'lambda': 549,
-     'mu': 576,
-     'nu': 521,
-     'omicron': 549,
-     'pi': 549,
-     'theta': 521,
-     'rho': 549,
-     'sigma': 603,
-     'tau': 439,
-     'upsilon': 576,
-     'omega1': 713,
-     'omega': 686,
-     'xi': 493,
-     'psi': 686,
-     'zeta': 494,
-     'braceleft': 480,
-     'bar': 200,
-     'braceright': 480,
-     'similar': 549,
-     'Euro': 750,
-     'Upsilon1': 620,
-     'minute': 247,
-     'lessequal': 549,
-     'fraction': 167,
-     'infinity': 713,
-     'florin': 500,
-     'club': 753,
-     'diamond': 753,
-     'heart': 753,
-     'spade': 753,
-     'arrowboth': 1042,
-     'arrowleft': 987,
-     'arrowup': 603,
-     'arrowright': 987,
-     'arrowdown': 603,
-     'degree': 400,
-     'plusminus': 549,
-     'second': 411,
-     'greaterequal': 549,
-     'multiply': 549,
-     'proportional': 713,
-     'partialdiff': 494,
-     'bullet': 460,
-     'divide': 549,
-     'notequal': 549,
-     'equivalence': 549,
-     'approxequal': 549,
-     'ellipsis': 1000,
-     'arrowvertex': 603,
-     'arrowhorizex': 1000,
-     'carriagereturn': 658,
-     'aleph': 823,
-     'Ifraktur': 686,
-     'Rfraktur': 795,
-     'weierstrass': 987,
-     'circlemultiply': 768,
-     'circleplus': 768,
-     'emptyset': 823,
-     'intersection': 768,
-     'union': 768,
-     'propersuperset': 713,
-     'reflexsuperset': 713,
-     'notsubset': 713,
-     'propersubset': 713,
-     'reflexsubset': 713,
-     'element': 713,
-     'notelement': 713,
-     'angle': 768,
-     'gradient': 713,
-     'registerserif': 790,
-     'copyrightserif': 790,
-     'trademarkserif': 890,
-     'product': 823,
-     'radical': 549,
-     'dotmath': 250,
-     'logicalnot': 713,
-     'logicaland': 603,
-     'logicalor': 603,
-     'arrowdblboth': 1042,
-     'arrowdblleft': 987,
-     'arrowdblup': 603,
-     'arrowdblright': 987,
-     'arrowdbldown': 603,
-     'lozenge': 494,
-     'angleleft': 329,
-     'registersans': 790,
-     'copyrightsans': 790,
-     'trademarksans': 786,
-     'summation': 713,
-     'parenlefttp': 384,
-     'parenleftex': 384,
-     'parenleftbt': 384,
-     'bracketlefttp': 384,
-     'bracketleftex': 384,
-     'bracketleftbt': 384,
-     'bracelefttp': 494,
-     'braceleftmid': 494,
-     'braceleftbt': 494,
-     'braceex': 494,
-     'angleright': 329,
-     'integral': 274,
-     'integraltp': 686,
-     'integralex': 686,
-     'integralbt': 686,
-     'parenrighttp': 384,
-     'parenrightex': 384,
-     'parenrightbt': 384,
-     'bracketrighttp': 384,
-     'bracketrightex': 384,
-     'bracketrightbt': 384,
-     'bracerighttp': 494,
-     'bracerightmid': 494,
-     'bracerightbt': 494,
-     'apple': 790
-   },
-   'Times-Roman': {
-     'space': 250,
-     'exclam': 333,
-     'quotedbl': 408,
-     'numbersign': 500,
-     'dollar': 500,
-     'percent': 833,
-     'ampersand': 778,
-     'quoteright': 333,
-     'parenleft': 333,
-     'parenright': 333,
-     'asterisk': 500,
-     'plus': 564,
-     'comma': 250,
-     'hyphen': 333,
-     'period': 250,
-     'slash': 278,
-     'zero': 500,
-     'one': 500,
-     'two': 500,
-     'three': 500,
-     'four': 500,
-     'five': 500,
-     'six': 500,
-     'seven': 500,
-     'eight': 500,
-     'nine': 500,
-     'colon': 278,
-     'semicolon': 278,
-     'less': 564,
-     'equal': 564,
-     'greater': 564,
-     'question': 444,
-     'at': 921,
-     'A': 722,
-     'B': 667,
-     'C': 667,
-     'D': 722,
-     'E': 611,
-     'F': 556,
-     'G': 722,
-     'H': 722,
-     'I': 333,
-     'J': 389,
-     'K': 722,
-     'L': 611,
-     'M': 889,
-     'N': 722,
-     'O': 722,
-     'P': 556,
-     'Q': 722,
-     'R': 667,
-     'S': 556,
-     'T': 611,
-     'U': 722,
-     'V': 722,
-     'W': 944,
-     'X': 722,
-     'Y': 722,
-     'Z': 611,
-     'bracketleft': 333,
-     'backslash': 278,
-     'bracketright': 333,
-     'asciicircum': 469,
-     'underscore': 500,
-     'quoteleft': 333,
-     'a': 444,
-     'b': 500,
-     'c': 444,
-     'd': 500,
-     'e': 444,
-     'f': 333,
-     'g': 500,
-     'h': 500,
-     'i': 278,
-     'j': 278,
-     'k': 500,
-     'l': 278,
-     'm': 778,
-     'n': 500,
-     'o': 500,
-     'p': 500,
-     'q': 500,
-     'r': 333,
-     's': 389,
-     't': 278,
-     'u': 500,
-     'v': 500,
-     'w': 722,
-     'x': 500,
-     'y': 500,
-     'z': 444,
-     'braceleft': 480,
-     'bar': 200,
-     'braceright': 480,
-     'asciitilde': 541,
-     'exclamdown': 333,
-     'cent': 500,
-     'sterling': 500,
-     'fraction': 167,
-     'yen': 500,
-     'florin': 500,
-     'section': 500,
-     'currency': 500,
-     'quotesingle': 180,
-     'quotedblleft': 444,
-     'guillemotleft': 500,
-     'guilsinglleft': 333,
-     'guilsinglright': 333,
-     'fi': 556,
-     'fl': 556,
-     'endash': 500,
-     'dagger': 500,
-     'daggerdbl': 500,
-     'periodcentered': 250,
-     'paragraph': 453,
-     'bullet': 350,
-     'quotesinglbase': 333,
-     'quotedblbase': 444,
-     'quotedblright': 444,
-     'guillemotright': 500,
-     'ellipsis': 1000,
-     'perthousand': 1000,
-     'questiondown': 444,
-     'grave': 333,
-     'acute': 333,
-     'circumflex': 333,
-     'tilde': 333,
-     'macron': 333,
-     'breve': 333,
-     'dotaccent': 333,
-     'dieresis': 333,
-     'ring': 333,
-     'cedilla': 333,
-     'hungarumlaut': 333,
-     'ogonek': 333,
-     'caron': 333,
-     'emdash': 1000,
-     'AE': 889,
-     'ordfeminine': 276,
-     'Lslash': 611,
-     'Oslash': 722,
-     'OE': 889,
-     'ordmasculine': 310,
-     'ae': 667,
-     'dotlessi': 278,
-     'lslash': 278,
-     'oslash': 500,
-     'oe': 722,
-     'germandbls': 500,
-     'Idieresis': 333,
-     'eacute': 444,
-     'abreve': 444,
-     'uhungarumlaut': 500,
-     'ecaron': 444,
-     'Ydieresis': 722,
-     'divide': 564,
-     'Yacute': 722,
-     'Acircumflex': 722,
-     'aacute': 444,
-     'Ucircumflex': 722,
-     'yacute': 500,
-     'scommaaccent': 389,
-     'ecircumflex': 444,
-     'Uring': 722,
-     'Udieresis': 722,
-     'aogonek': 444,
-     'Uacute': 722,
-     'uogonek': 500,
-     'Edieresis': 611,
-     'Dcroat': 722,
-     'commaaccent': 250,
-     'copyright': 760,
-     'Emacron': 611,
-     'ccaron': 444,
-     'aring': 444,
-     'Ncommaaccent': 722,
-     'lacute': 278,
-     'agrave': 444,
-     'Tcommaaccent': 611,
-     'Cacute': 667,
-     'atilde': 444,
-     'Edotaccent': 611,
-     'scaron': 389,
-     'scedilla': 389,
-     'iacute': 278,
-     'lozenge': 471,
-     'Rcaron': 667,
-     'Gcommaaccent': 722,
-     'ucircumflex': 500,
-     'acircumflex': 444,
-     'Amacron': 722,
-     'rcaron': 333,
-     'ccedilla': 444,
-     'Zdotaccent': 611,
-     'Thorn': 556,
-     'Omacron': 722,
-     'Racute': 667,
-     'Sacute': 556,
-     'dcaron': 588,
-     'Umacron': 722,
-     'uring': 500,
-     'threesuperior': 300,
-     'Ograve': 722,
-     'Agrave': 722,
-     'Abreve': 722,
-     'multiply': 564,
-     'uacute': 500,
-     'Tcaron': 611,
-     'partialdiff': 476,
-     'ydieresis': 500,
-     'Nacute': 722,
-     'icircumflex': 278,
-     'Ecircumflex': 611,
-     'adieresis': 444,
-     'edieresis': 444,
-     'cacute': 444,
-     'nacute': 500,
-     'umacron': 500,
-     'Ncaron': 722,
-     'Iacute': 333,
-     'plusminus': 564,
-     'brokenbar': 200,
-     'registered': 760,
-     'Gbreve': 722,
-     'Idotaccent': 333,
-     'summation': 600,
-     'Egrave': 611,
-     'racute': 333,
-     'omacron': 500,
-     'Zacute': 611,
-     'Zcaron': 611,
-     'greaterequal': 549,
-     'Eth': 722,
-     'Ccedilla': 667,
-     'lcommaaccent': 278,
-     'tcaron': 326,
-     'eogonek': 444,
-     'Uogonek': 722,
-     'Aacute': 722,
-     'Adieresis': 722,
-     'egrave': 444,
-     'zacute': 444,
-     'iogonek': 278,
-     'Oacute': 722,
-     'oacute': 500,
-     'amacron': 444,
-     'sacute': 389,
-     'idieresis': 278,
-     'Ocircumflex': 722,
-     'Ugrave': 722,
-     'Delta': 612,
-     'thorn': 500,
-     'twosuperior': 300,
-     'Odieresis': 722,
-     'mu': 500,
-     'igrave': 278,
-     'ohungarumlaut': 500,
-     'Eogonek': 611,
-     'dcroat': 500,
-     'threequarters': 750,
-     'Scedilla': 556,
-     'lcaron': 344,
-     'Kcommaaccent': 722,
-     'Lacute': 611,
-     'trademark': 980,
-     'edotaccent': 444,
-     'Igrave': 333,
-     'Imacron': 333,
-     'Lcaron': 611,
-     'onehalf': 750,
-     'lessequal': 549,
-     'ocircumflex': 500,
-     'ntilde': 500,
-     'Uhungarumlaut': 722,
-     'Eacute': 611,
-     'emacron': 444,
-     'gbreve': 500,
-     'onequarter': 750,
-     'Scaron': 556,
-     'Scommaaccent': 556,
-     'Ohungarumlaut': 722,
-     'degree': 400,
-     'ograve': 500,
-     'Ccaron': 667,
-     'ugrave': 500,
-     'radical': 453,
-     'Dcaron': 722,
-     'rcommaaccent': 333,
-     'Ntilde': 722,
-     'otilde': 500,
-     'Rcommaaccent': 667,
-     'Lcommaaccent': 611,
-     'Atilde': 722,
-     'Aogonek': 722,
-     'Aring': 722,
-     'Otilde': 722,
-     'zdotaccent': 444,
-     'Ecaron': 611,
-     'Iogonek': 333,
-     'kcommaaccent': 500,
-     'minus': 564,
-     'Icircumflex': 333,
-     'ncaron': 500,
-     'tcommaaccent': 278,
-     'logicalnot': 564,
-     'odieresis': 500,
-     'udieresis': 500,
-     'notequal': 549,
-     'gcommaaccent': 500,
-     'eth': 500,
-     'zcaron': 444,
-     'ncommaaccent': 500,
-     'onesuperior': 300,
-     'imacron': 278,
-     'Euro': 500
-   },
-   'Times-Bold': {
-     'space': 250,
-     'exclam': 333,
-     'quotedbl': 555,
-     'numbersign': 500,
-     'dollar': 500,
-     'percent': 1000,
-     'ampersand': 833,
-     'quoteright': 333,
-     'parenleft': 333,
-     'parenright': 333,
-     'asterisk': 500,
-     'plus': 570,
-     'comma': 250,
-     'hyphen': 333,
-     'period': 250,
-     'slash': 278,
-     'zero': 500,
-     'one': 500,
-     'two': 500,
-     'three': 500,
-     'four': 500,
-     'five': 500,
-     'six': 500,
-     'seven': 500,
-     'eight': 500,
-     'nine': 500,
-     'colon': 333,
-     'semicolon': 333,
-     'less': 570,
-     'equal': 570,
-     'greater': 570,
-     'question': 500,
-     'at': 930,
-     'A': 722,
-     'B': 667,
-     'C': 722,
-     'D': 722,
-     'E': 667,
-     'F': 611,
-     'G': 778,
-     'H': 778,
-     'I': 389,
-     'J': 500,
-     'K': 778,
-     'L': 667,
-     'M': 944,
-     'N': 722,
-     'O': 778,
-     'P': 611,
-     'Q': 778,
-     'R': 722,
-     'S': 556,
-     'T': 667,
-     'U': 722,
-     'V': 722,
-     'W': 1000,
-     'X': 722,
-     'Y': 722,
-     'Z': 667,
-     'bracketleft': 333,
-     'backslash': 278,
-     'bracketright': 333,
-     'asciicircum': 581,
-     'underscore': 500,
-     'quoteleft': 333,
-     'a': 500,
-     'b': 556,
-     'c': 444,
-     'd': 556,
-     'e': 444,
-     'f': 333,
-     'g': 500,
-     'h': 556,
-     'i': 278,
-     'j': 333,
-     'k': 556,
-     'l': 278,
-     'm': 833,
-     'n': 556,
-     'o': 500,
-     'p': 556,
-     'q': 556,
-     'r': 444,
-     's': 389,
-     't': 333,
-     'u': 556,
-     'v': 500,
-     'w': 722,
-     'x': 500,
-     'y': 500,
-     'z': 444,
-     'braceleft': 394,
-     'bar': 220,
-     'braceright': 394,
-     'asciitilde': 520,
-     'exclamdown': 333,
-     'cent': 500,
-     'sterling': 500,
-     'fraction': 167,
-     'yen': 500,
-     'florin': 500,
-     'section': 500,
-     'currency': 500,
-     'quotesingle': 278,
-     'quotedblleft': 500,
-     'guillemotleft': 500,
-     'guilsinglleft': 333,
-     'guilsinglright': 333,
-     'fi': 556,
-     'fl': 556,
-     'endash': 500,
-     'dagger': 500,
-     'daggerdbl': 500,
-     'periodcentered': 250,
-     'paragraph': 540,
-     'bullet': 350,
-     'quotesinglbase': 333,
-     'quotedblbase': 500,
-     'quotedblright': 500,
-     'guillemotright': 500,
-     'ellipsis': 1000,
-     'perthousand': 1000,
-     'questiondown': 500,
-     'grave': 333,
-     'acute': 333,
-     'circumflex': 333,
-     'tilde': 333,
-     'macron': 333,
-     'breve': 333,
-     'dotaccent': 333,
-     'dieresis': 333,
-     'ring': 333,
-     'cedilla': 333,
-     'hungarumlaut': 333,
-     'ogonek': 333,
-     'caron': 333,
-     'emdash': 1000,
-     'AE': 1000,
-     'ordfeminine': 300,
-     'Lslash': 667,
-     'Oslash': 778,
-     'OE': 1000,
-     'ordmasculine': 330,
-     'ae': 722,
-     'dotlessi': 278,
-     'lslash': 278,
-     'oslash': 500,
-     'oe': 722,
-     'germandbls': 556,
-     'Idieresis': 389,
-     'eacute': 444,
-     'abreve': 500,
-     'uhungarumlaut': 556,
-     'ecaron': 444,
-     'Ydieresis': 722,
-     'divide': 570,
-     'Yacute': 722,
-     'Acircumflex': 722,
-     'aacute': 500,
-     'Ucircumflex': 722,
-     'yacute': 500,
-     'scommaaccent': 389,
-     'ecircumflex': 444,
-     'Uring': 722,
-     'Udieresis': 722,
-     'aogonek': 500,
-     'Uacute': 722,
-     'uogonek': 556,
-     'Edieresis': 667,
-     'Dcroat': 722,
-     'commaaccent': 250,
-     'copyright': 747,
-     'Emacron': 667,
-     'ccaron': 444,
-     'aring': 500,
-     'Ncommaaccent': 722,
-     'lacute': 278,
-     'agrave': 500,
-     'Tcommaaccent': 667,
-     'Cacute': 722,
-     'atilde': 500,
-     'Edotaccent': 667,
-     'scaron': 389,
-     'scedilla': 389,
-     'iacute': 278,
-     'lozenge': 494,
-     'Rcaron': 722,
-     'Gcommaaccent': 778,
-     'ucircumflex': 556,
-     'acircumflex': 500,
-     'Amacron': 722,
-     'rcaron': 444,
-     'ccedilla': 444,
-     'Zdotaccent': 667,
-     'Thorn': 611,
-     'Omacron': 778,
-     'Racute': 722,
-     'Sacute': 556,
-     'dcaron': 672,
-     'Umacron': 722,
-     'uring': 556,
-     'threesuperior': 300,
-     'Ograve': 778,
-     'Agrave': 722,
-     'Abreve': 722,
-     'multiply': 570,
-     'uacute': 556,
-     'Tcaron': 667,
-     'partialdiff': 494,
-     'ydieresis': 500,
-     'Nacute': 722,
-     'icircumflex': 278,
-     'Ecircumflex': 667,
-     'adieresis': 500,
-     'edieresis': 444,
-     'cacute': 444,
-     'nacute': 556,
-     'umacron': 556,
-     'Ncaron': 722,
-     'Iacute': 389,
-     'plusminus': 570,
-     'brokenbar': 220,
-     'registered': 747,
-     'Gbreve': 778,
-     'Idotaccent': 389,
-     'summation': 600,
-     'Egrave': 667,
-     'racute': 444,
-     'omacron': 500,
-     'Zacute': 667,
-     'Zcaron': 667,
-     'greaterequal': 549,
-     'Eth': 722,
-     'Ccedilla': 722,
-     'lcommaaccent': 278,
-     'tcaron': 416,
-     'eogonek': 444,
-     'Uogonek': 722,
-     'Aacute': 722,
-     'Adieresis': 722,
-     'egrave': 444,
-     'zacute': 444,
-     'iogonek': 278,
-     'Oacute': 778,
-     'oacute': 500,
-     'amacron': 500,
-     'sacute': 389,
-     'idieresis': 278,
-     'Ocircumflex': 778,
-     'Ugrave': 722,
-     'Delta': 612,
-     'thorn': 556,
-     'twosuperior': 300,
-     'Odieresis': 778,
-     'mu': 556,
-     'igrave': 278,
-     'ohungarumlaut': 500,
-     'Eogonek': 667,
-     'dcroat': 556,
-     'threequarters': 750,
-     'Scedilla': 556,
-     'lcaron': 394,
-     'Kcommaaccent': 778,
-     'Lacute': 667,
-     'trademark': 1000,
-     'edotaccent': 444,
-     'Igrave': 389,
-     'Imacron': 389,
-     'Lcaron': 667,
-     'onehalf': 750,
-     'lessequal': 549,
-     'ocircumflex': 500,
-     'ntilde': 556,
-     'Uhungarumlaut': 722,
-     'Eacute': 667,
-     'emacron': 444,
-     'gbreve': 500,
-     'onequarter': 750,
-     'Scaron': 556,
-     'Scommaaccent': 556,
-     'Ohungarumlaut': 778,
-     'degree': 400,
-     'ograve': 500,
-     'Ccaron': 722,
-     'ugrave': 556,
-     'radical': 549,
-     'Dcaron': 722,
-     'rcommaaccent': 444,
-     'Ntilde': 722,
-     'otilde': 500,
-     'Rcommaaccent': 722,
-     'Lcommaaccent': 667,
-     'Atilde': 722,
-     'Aogonek': 722,
-     'Aring': 722,
-     'Otilde': 778,
-     'zdotaccent': 444,
-     'Ecaron': 667,
-     'Iogonek': 389,
-     'kcommaaccent': 556,
-     'minus': 570,
-     'Icircumflex': 389,
-     'ncaron': 556,
-     'tcommaaccent': 333,
-     'logicalnot': 570,
-     'odieresis': 500,
-     'udieresis': 556,
-     'notequal': 549,
-     'gcommaaccent': 500,
-     'eth': 500,
-     'zcaron': 444,
-     'ncommaaccent': 556,
-     'onesuperior': 300,
-     'imacron': 278,
-     'Euro': 500
-   },
-   'Times-BoldItalic': {
-     'space': 250,
-     'exclam': 389,
-     'quotedbl': 555,
-     'numbersign': 500,
-     'dollar': 500,
-     'percent': 833,
-     'ampersand': 778,
-     'quoteright': 333,
-     'parenleft': 333,
-     'parenright': 333,
-     'asterisk': 500,
-     'plus': 570,
-     'comma': 250,
-     'hyphen': 333,
-     'period': 250,
-     'slash': 278,
-     'zero': 500,
-     'one': 500,
-     'two': 500,
-     'three': 500,
-     'four': 500,
-     'five': 500,
-     'six': 500,
-     'seven': 500,
-     'eight': 500,
-     'nine': 500,
-     'colon': 333,
-     'semicolon': 333,
-     'less': 570,
-     'equal': 570,
-     'greater': 570,
-     'question': 500,
-     'at': 832,
-     'A': 667,
-     'B': 667,
-     'C': 667,
-     'D': 722,
-     'E': 667,
-     'F': 667,
-     'G': 722,
-     'H': 778,
-     'I': 389,
-     'J': 500,
-     'K': 667,
-     'L': 611,
-     'M': 889,
-     'N': 722,
-     'O': 722,
-     'P': 611,
-     'Q': 722,
-     'R': 667,
-     'S': 556,
-     'T': 611,
-     'U': 722,
-     'V': 667,
-     'W': 889,
-     'X': 667,
-     'Y': 611,
-     'Z': 611,
-     'bracketleft': 333,
-     'backslash': 278,
-     'bracketright': 333,
-     'asciicircum': 570,
-     'underscore': 500,
-     'quoteleft': 333,
-     'a': 500,
-     'b': 500,
-     'c': 444,
-     'd': 500,
-     'e': 444,
-     'f': 333,
-     'g': 500,
-     'h': 556,
-     'i': 278,
-     'j': 278,
-     'k': 500,
-     'l': 278,
-     'm': 778,
-     'n': 556,
-     'o': 500,
-     'p': 500,
-     'q': 500,
-     'r': 389,
-     's': 389,
-     't': 278,
-     'u': 556,
-     'v': 444,
-     'w': 667,
-     'x': 500,
-     'y': 444,
-     'z': 389,
-     'braceleft': 348,
-     'bar': 220,
-     'braceright': 348,
-     'asciitilde': 570,
-     'exclamdown': 389,
-     'cent': 500,
-     'sterling': 500,
-     'fraction': 167,
-     'yen': 500,
-     'florin': 500,
-     'section': 500,
-     'currency': 500,
-     'quotesingle': 278,
-     'quotedblleft': 500,
-     'guillemotleft': 500,
-     'guilsinglleft': 333,
-     'guilsinglright': 333,
-     'fi': 556,
-     'fl': 556,
-     'endash': 500,
-     'dagger': 500,
-     'daggerdbl': 500,
-     'periodcentered': 250,
-     'paragraph': 500,
-     'bullet': 350,
-     'quotesinglbase': 333,
-     'quotedblbase': 500,
-     'quotedblright': 500,
-     'guillemotright': 500,
-     'ellipsis': 1000,
-     'perthousand': 1000,
-     'questiondown': 500,
-     'grave': 333,
-     'acute': 333,
-     'circumflex': 333,
-     'tilde': 333,
-     'macron': 333,
-     'breve': 333,
-     'dotaccent': 333,
-     'dieresis': 333,
-     'ring': 333,
-     'cedilla': 333,
-     'hungarumlaut': 333,
-     'ogonek': 333,
-     'caron': 333,
-     'emdash': 1000,
-     'AE': 944,
-     'ordfeminine': 266,
-     'Lslash': 611,
-     'Oslash': 722,
-     'OE': 944,
-     'ordmasculine': 300,
-     'ae': 722,
-     'dotlessi': 278,
-     'lslash': 278,
-     'oslash': 500,
-     'oe': 722,
-     'germandbls': 500,
-     'Idieresis': 389,
-     'eacute': 444,
-     'abreve': 500,
-     'uhungarumlaut': 556,
-     'ecaron': 444,
-     'Ydieresis': 611,
-     'divide': 570,
-     'Yacute': 611,
-     'Acircumflex': 667,
-     'aacute': 500,
-     'Ucircumflex': 722,
-     'yacute': 444,
-     'scommaaccent': 389,
-     'ecircumflex': 444,
-     'Uring': 722,
-     'Udieresis': 722,
-     'aogonek': 500,
-     'Uacute': 722,
-     'uogonek': 556,
-     'Edieresis': 667,
-     'Dcroat': 722,
-     'commaaccent': 250,
-     'copyright': 747,
-     'Emacron': 667,
-     'ccaron': 444,
-     'aring': 500,
-     'Ncommaaccent': 722,
-     'lacute': 278,
-     'agrave': 500,
-     'Tcommaaccent': 611,
-     'Cacute': 667,
-     'atilde': 500,
-     'Edotaccent': 667,
-     'scaron': 389,
-     'scedilla': 389,
-     'iacute': 278,
-     'lozenge': 494,
-     'Rcaron': 667,
-     'Gcommaaccent': 722,
-     'ucircumflex': 556,
-     'acircumflex': 500,
-     'Amacron': 667,
-     'rcaron': 389,
-     'ccedilla': 444,
-     'Zdotaccent': 611,
-     'Thorn': 611,
-     'Omacron': 722,
-     'Racute': 667,
-     'Sacute': 556,
-     'dcaron': 608,
-     'Umacron': 722,
-     'uring': 556,
-     'threesuperior': 300,
-     'Ograve': 722,
-     'Agrave': 667,
-     'Abreve': 667,
-     'multiply': 570,
-     'uacute': 556,
-     'Tcaron': 611,
-     'partialdiff': 494,
-     'ydieresis': 444,
-     'Nacute': 722,
-     'icircumflex': 278,
-     'Ecircumflex': 667,
-     'adieresis': 500,
-     'edieresis': 444,
-     'cacute': 444,
-     'nacute': 556,
-     'umacron': 556,
-     'Ncaron': 722,
-     'Iacute': 389,
-     'plusminus': 570,
-     'brokenbar': 220,
-     'registered': 747,
-     'Gbreve': 722,
-     'Idotaccent': 389,
-     'summation': 600,
-     'Egrave': 667,
-     'racute': 389,
-     'omacron': 500,
-     'Zacute': 611,
-     'Zcaron': 611,
-     'greaterequal': 549,
-     'Eth': 722,
-     'Ccedilla': 667,
-     'lcommaaccent': 278,
-     'tcaron': 366,
-     'eogonek': 444,
-     'Uogonek': 722,
-     'Aacute': 667,
-     'Adieresis': 667,
-     'egrave': 444,
-     'zacute': 389,
-     'iogonek': 278,
-     'Oacute': 722,
-     'oacute': 500,
-     'amacron': 500,
-     'sacute': 389,
-     'idieresis': 278,
-     'Ocircumflex': 722,
-     'Ugrave': 722,
-     'Delta': 612,
-     'thorn': 500,
-     'twosuperior': 300,
-     'Odieresis': 722,
-     'mu': 576,
-     'igrave': 278,
-     'ohungarumlaut': 500,
-     'Eogonek': 667,
-     'dcroat': 500,
-     'threequarters': 750,
-     'Scedilla': 556,
-     'lcaron': 382,
-     'Kcommaaccent': 667,
-     'Lacute': 611,
-     'trademark': 1000,
-     'edotaccent': 444,
-     'Igrave': 389,
-     'Imacron': 389,
-     'Lcaron': 611,
-     'onehalf': 750,
-     'lessequal': 549,
-     'ocircumflex': 500,
-     'ntilde': 556,
-     'Uhungarumlaut': 722,
-     'Eacute': 667,
-     'emacron': 444,
-     'gbreve': 500,
-     'onequarter': 750,
-     'Scaron': 556,
-     'Scommaaccent': 556,
-     'Ohungarumlaut': 722,
-     'degree': 400,
-     'ograve': 500,
-     'Ccaron': 667,
-     'ugrave': 556,
-     'radical': 549,
-     'Dcaron': 722,
-     'rcommaaccent': 389,
-     'Ntilde': 722,
-     'otilde': 500,
-     'Rcommaaccent': 667,
-     'Lcommaaccent': 611,
-     'Atilde': 667,
-     'Aogonek': 667,
-     'Aring': 667,
-     'Otilde': 722,
-     'zdotaccent': 389,
-     'Ecaron': 667,
-     'Iogonek': 389,
-     'kcommaaccent': 500,
-     'minus': 606,
-     'Icircumflex': 389,
-     'ncaron': 556,
-     'tcommaaccent': 278,
-     'logicalnot': 606,
-     'odieresis': 500,
-     'udieresis': 556,
-     'notequal': 549,
-     'gcommaaccent': 500,
-     'eth': 500,
-     'zcaron': 389,
-     'ncommaaccent': 556,
-     'onesuperior': 300,
-     'imacron': 278,
-     'Euro': 500
-   },
-   'Times-Italic': {
-     'space': 250,
-     'exclam': 333,
-     'quotedbl': 420,
-     'numbersign': 500,
-     'dollar': 500,
-     'percent': 833,
-     'ampersand': 778,
-     'quoteright': 333,
-     'parenleft': 333,
-     'parenright': 333,
-     'asterisk': 500,
-     'plus': 675,
-     'comma': 250,
-     'hyphen': 333,
-     'period': 250,
-     'slash': 278,
-     'zero': 500,
-     'one': 500,
-     'two': 500,
-     'three': 500,
-     'four': 500,
-     'five': 500,
-     'six': 500,
-     'seven': 500,
-     'eight': 500,
-     'nine': 500,
-     'colon': 333,
-     'semicolon': 333,
-     'less': 675,
-     'equal': 675,
-     'greater': 675,
-     'question': 500,
-     'at': 920,
-     'A': 611,
-     'B': 611,
-     'C': 667,
-     'D': 722,
-     'E': 611,
-     'F': 611,
-     'G': 722,
-     'H': 722,
-     'I': 333,
-     'J': 444,
-     'K': 667,
-     'L': 556,
-     'M': 833,
-     'N': 667,
-     'O': 722,
-     'P': 611,
-     'Q': 722,
-     'R': 611,
-     'S': 500,
-     'T': 556,
-     'U': 722,
-     'V': 611,
-     'W': 833,
-     'X': 611,
-     'Y': 556,
-     'Z': 556,
-     'bracketleft': 389,
-     'backslash': 278,
-     'bracketright': 389,
-     'asciicircum': 422,
-     'underscore': 500,
-     'quoteleft': 333,
-     'a': 500,
-     'b': 500,
-     'c': 444,
-     'd': 500,
-     'e': 444,
-     'f': 278,
-     'g': 500,
-     'h': 500,
-     'i': 278,
-     'j': 278,
-     'k': 444,
-     'l': 278,
-     'm': 722,
-     'n': 500,
-     'o': 500,
-     'p': 500,
-     'q': 500,
-     'r': 389,
-     's': 389,
-     't': 278,
-     'u': 500,
-     'v': 444,
-     'w': 667,
-     'x': 444,
-     'y': 444,
-     'z': 389,
-     'braceleft': 400,
-     'bar': 275,
-     'braceright': 400,
-     'asciitilde': 541,
-     'exclamdown': 389,
-     'cent': 500,
-     'sterling': 500,
-     'fraction': 167,
-     'yen': 500,
-     'florin': 500,
-     'section': 500,
-     'currency': 500,
-     'quotesingle': 214,
-     'quotedblleft': 556,
-     'guillemotleft': 500,
-     'guilsinglleft': 333,
-     'guilsinglright': 333,
-     'fi': 500,
-     'fl': 500,
-     'endash': 500,
-     'dagger': 500,
-     'daggerdbl': 500,
-     'periodcentered': 250,
-     'paragraph': 523,
-     'bullet': 350,
-     'quotesinglbase': 333,
-     'quotedblbase': 556,
-     'quotedblright': 556,
-     'guillemotright': 500,
-     'ellipsis': 889,
-     'perthousand': 1000,
-     'questiondown': 500,
-     'grave': 333,
-     'acute': 333,
-     'circumflex': 333,
-     'tilde': 333,
-     'macron': 333,
-     'breve': 333,
-     'dotaccent': 333,
-     'dieresis': 333,
-     'ring': 333,
-     'cedilla': 333,
-     'hungarumlaut': 333,
-     'ogonek': 333,
-     'caron': 333,
-     'emdash': 889,
-     'AE': 889,
-     'ordfeminine': 276,
-     'Lslash': 556,
-     'Oslash': 722,
-     'OE': 944,
-     'ordmasculine': 310,
-     'ae': 667,
-     'dotlessi': 278,
-     'lslash': 278,
-     'oslash': 500,
-     'oe': 667,
-     'germandbls': 500,
-     'Idieresis': 333,
-     'eacute': 444,
-     'abreve': 500,
-     'uhungarumlaut': 500,
-     'ecaron': 444,
-     'Ydieresis': 556,
-     'divide': 675,
-     'Yacute': 556,
-     'Acircumflex': 611,
-     'aacute': 500,
-     'Ucircumflex': 722,
-     'yacute': 444,
-     'scommaaccent': 389,
-     'ecircumflex': 444,
-     'Uring': 722,
-     'Udieresis': 722,
-     'aogonek': 500,
-     'Uacute': 722,
-     'uogonek': 500,
-     'Edieresis': 611,
-     'Dcroat': 722,
-     'commaaccent': 250,
-     'copyright': 760,
-     'Emacron': 611,
-     'ccaron': 444,
-     'aring': 500,
-     'Ncommaaccent': 667,
-     'lacute': 278,
-     'agrave': 500,
-     'Tcommaaccent': 556,
-     'Cacute': 667,
-     'atilde': 500,
-     'Edotaccent': 611,
-     'scaron': 389,
-     'scedilla': 389,
-     'iacute': 278,
-     'lozenge': 471,
-     'Rcaron': 611,
-     'Gcommaaccent': 722,
-     'ucircumflex': 500,
-     'acircumflex': 500,
-     'Amacron': 611,
-     'rcaron': 389,
-     'ccedilla': 444,
-     'Zdotaccent': 556,
-     'Thorn': 611,
-     'Omacron': 722,
-     'Racute': 611,
-     'Sacute': 500,
-     'dcaron': 544,
-     'Umacron': 722,
-     'uring': 500,
-     'threesuperior': 300,
-     'Ograve': 722,
-     'Agrave': 611,
-     'Abreve': 611,
-     'multiply': 675,
-     'uacute': 500,
-     'Tcaron': 556,
-     'partialdiff': 476,
-     'ydieresis': 444,
-     'Nacute': 667,
-     'icircumflex': 278,
-     'Ecircumflex': 611,
-     'adieresis': 500,
-     'edieresis': 444,
-     'cacute': 444,
-     'nacute': 500,
-     'umacron': 500,
-     'Ncaron': 667,
-     'Iacute': 333,
-     'plusminus': 675,
-     'brokenbar': 275,
-     'registered': 760,
-     'Gbreve': 722,
-     'Idotaccent': 333,
-     'summation': 600,
-     'Egrave': 611,
-     'racute': 389,
-     'omacron': 500,
-     'Zacute': 556,
-     'Zcaron': 556,
-     'greaterequal': 549,
-     'Eth': 722,
-     'Ccedilla': 667,
-     'lcommaaccent': 278,
-     'tcaron': 300,
-     'eogonek': 444,
-     'Uogonek': 722,
-     'Aacute': 611,
-     'Adieresis': 611,
-     'egrave': 444,
-     'zacute': 389,
-     'iogonek': 278,
-     'Oacute': 722,
-     'oacute': 500,
-     'amacron': 500,
-     'sacute': 389,
-     'idieresis': 278,
-     'Ocircumflex': 722,
-     'Ugrave': 722,
-     'Delta': 612,
-     'thorn': 500,
-     'twosuperior': 300,
-     'Odieresis': 722,
-     'mu': 500,
-     'igrave': 278,
-     'ohungarumlaut': 500,
-     'Eogonek': 611,
-     'dcroat': 500,
-     'threequarters': 750,
-     'Scedilla': 500,
-     'lcaron': 300,
-     'Kcommaaccent': 667,
-     'Lacute': 556,
-     'trademark': 980,
-     'edotaccent': 444,
-     'Igrave': 333,
-     'Imacron': 333,
-     'Lcaron': 611,
-     'onehalf': 750,
-     'lessequal': 549,
-     'ocircumflex': 500,
-     'ntilde': 500,
-     'Uhungarumlaut': 722,
-     'Eacute': 611,
-     'emacron': 444,
-     'gbreve': 500,
-     'onequarter': 750,
-     'Scaron': 500,
-     'Scommaaccent': 500,
-     'Ohungarumlaut': 722,
-     'degree': 400,
-     'ograve': 500,
-     'Ccaron': 667,
-     'ugrave': 500,
-     'radical': 453,
-     'Dcaron': 722,
-     'rcommaaccent': 389,
-     'Ntilde': 667,
-     'otilde': 500,
-     'Rcommaaccent': 611,
-     'Lcommaaccent': 556,
-     'Atilde': 611,
-     'Aogonek': 611,
-     'Aring': 611,
-     'Otilde': 722,
-     'zdotaccent': 389,
-     'Ecaron': 611,
-     'Iogonek': 333,
-     'kcommaaccent': 444,
-     'minus': 675,
-     'Icircumflex': 333,
-     'ncaron': 500,
-     'tcommaaccent': 278,
-     'logicalnot': 675,
-     'odieresis': 500,
-     'udieresis': 500,
-     'notequal': 549,
-     'gcommaaccent': 500,
-     'eth': 500,
-     'zcaron': 389,
-     'ncommaaccent': 500,
-     'onesuperior': 300,
-     'imacron': 278,
-     'Euro': 500
-   },
-   'ZapfDingbats': {
-     'space': 278,
-     'a1': 974,
-     'a2': 961,
-     'a202': 974,
-     'a3': 980,
-     'a4': 719,
-     'a5': 789,
-     'a119': 790,
-     'a118': 791,
-     'a117': 690,
-     'a11': 960,
-     'a12': 939,
-     'a13': 549,
-     'a14': 855,
-     'a15': 911,
-     'a16': 933,
-     'a105': 911,
-     'a17': 945,
-     'a18': 974,
-     'a19': 755,
-     'a20': 846,
-     'a21': 762,
-     'a22': 761,
-     'a23': 571,
-     'a24': 677,
-     'a25': 763,
-     'a26': 760,
-     'a27': 759,
-     'a28': 754,
-     'a6': 494,
-     'a7': 552,
-     'a8': 537,
-     'a9': 577,
-     'a10': 692,
-     'a29': 786,
-     'a30': 788,
-     'a31': 788,
-     'a32': 790,
-     'a33': 793,
-     'a34': 794,
-     'a35': 816,
-     'a36': 823,
-     'a37': 789,
-     'a38': 841,
-     'a39': 823,
-     'a40': 833,
-     'a41': 816,
-     'a42': 831,
-     'a43': 923,
-     'a44': 744,
-     'a45': 723,
-     'a46': 749,
-     'a47': 790,
-     'a48': 792,
-     'a49': 695,
-     'a50': 776,
-     'a51': 768,
-     'a52': 792,
-     'a53': 759,
-     'a54': 707,
-     'a55': 708,
-     'a56': 682,
-     'a57': 701,
-     'a58': 826,
-     'a59': 815,
-     'a60': 789,
-     'a61': 789,
-     'a62': 707,
-     'a63': 687,
-     'a64': 696,
-     'a65': 689,
-     'a66': 786,
-     'a67': 787,
-     'a68': 713,
-     'a69': 791,
-     'a70': 785,
-     'a71': 791,
-     'a72': 873,
-     'a73': 761,
-     'a74': 762,
-     'a203': 762,
-     'a75': 759,
-     'a204': 759,
-     'a76': 892,
-     'a77': 892,
-     'a78': 788,
-     'a79': 784,
-     'a81': 438,
-     'a82': 138,
-     'a83': 277,
-     'a84': 415,
-     'a97': 392,
-     'a98': 392,
-     'a99': 668,
-     'a100': 668,
-     'a89': 390,
-     'a90': 390,
-     'a93': 317,
-     'a94': 317,
-     'a91': 276,
-     'a92': 276,
-     'a205': 509,
-     'a85': 509,
-     'a206': 410,
-     'a86': 410,
-     'a87': 234,
-     'a88': 234,
-     'a95': 334,
-     'a96': 334,
-     'a101': 732,
-     'a102': 544,
-     'a103': 544,
-     'a104': 910,
-     'a106': 667,
-     'a107': 760,
-     'a108': 760,
-     'a112': 776,
-     'a111': 595,
-     'a110': 694,
-     'a109': 626,
-     'a120': 788,
-     'a121': 788,
-     'a122': 788,
-     'a123': 788,
-     'a124': 788,
-     'a125': 788,
-     'a126': 788,
-     'a127': 788,
-     'a128': 788,
-     'a129': 788,
-     'a130': 788,
-     'a131': 788,
-     'a132': 788,
-     'a133': 788,
-     'a134': 788,
-     'a135': 788,
-     'a136': 788,
-     'a137': 788,
-     'a138': 788,
-     'a139': 788,
-     'a140': 788,
-     'a141': 788,
-     'a142': 788,
-     'a143': 788,
-     'a144': 788,
-     'a145': 788,
-     'a146': 788,
-     'a147': 788,
-     'a148': 788,
-     'a149': 788,
-     'a150': 788,
-     'a151': 788,
-     'a152': 788,
-     'a153': 788,
-     'a154': 788,
-     'a155': 788,
-     'a156': 788,
-     'a157': 788,
-     'a158': 788,
-     'a159': 788,
-     'a160': 894,
-     'a161': 838,
-     'a163': 1016,
-     'a164': 458,
-     'a196': 748,
-     'a165': 924,
-     'a192': 748,
-     'a166': 918,
-     'a167': 927,
-     'a168': 928,
-     'a169': 928,
-     'a170': 834,
-     'a171': 873,
-     'a172': 828,
-     'a173': 924,
-     'a162': 924,
-     'a174': 917,
-     'a175': 930,
-     'a176': 931,
-     'a177': 463,
-     'a178': 883,
-     'a179': 836,
-     'a193': 836,
-     'a180': 867,
-     'a199': 867,
-     'a181': 696,
-     'a200': 696,
-     'a182': 874,
-     'a201': 874,
-     'a183': 760,
-     'a184': 946,
-     'a197': 771,
-     'a185': 865,
-     'a194': 771,
-     'a198': 888,
-     'a186': 967,
-     'a195': 888,
-     'a187': 831,
-     'a188': 873,
-     'a189': 927,
-     'a190': 970,
-     'a191': 918
-   }
- };
- 
- 
- 
- var EOF = {};
- 
- function isEOF(v) {
-   return v == EOF;
- }
++/**
++ * Page text content part.
++ *
++ * @typedef {Object} BidiText
++ * @property {string} str - text content.
++ * @property {string} dir - text direction: 'ttb', 'ltr' or 'rtl'.
++ * @property {number} x - x position of the text on the page.
++ * @property {number} y - y position of the text on the page.
++ * @property {number} angle - text rotation.
++ * @property {number} size - font size.
++ */
 +
- var Parser = (function ParserClosure() {
-   function Parser(lexer, allowStreams, xref) {
-     this.lexer = lexer;
-     this.allowStreams = allowStreams;
-     this.xref = xref;
-     this.refill();
++/**
++ * Proxy to a PDFPage in the worker thread.
++ * @class
++ */
++var PDFPageProxy = (function PDFPageProxyClosure() {
++  function PDFPageProxy(pageInfo, transport) {
++    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.cleanupAfterRender = false;
++    this.pendingDestroy = false;
++    this.intentStates = {};
 +  }
- 
-   Parser.prototype = {
-     refill: function Parser_refill() {
-       this.buf1 = this.lexer.getObj();
-       this.buf2 = this.lexer.getObj();
-     },
-     shift: function Parser_shift() {
-       if (isCmd(this.buf2, 'ID')) {
-         this.buf1 = this.buf2;
-         this.buf2 = null;
-         // skip byte after ID
-         this.lexer.skip();
-       } else {
-         this.buf1 = this.buf2;
-         this.buf2 = this.lexer.getObj();
-       }
++  PDFPageProxy.prototype = /** @lends PDFPageProxy.prototype */ {
++    /**
++     * @return {number} Page number of the page. First page is 1.
++     */
++    get pageNumber() {
++      return this.pageInfo.pageIndex + 1;
 +    },
-     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))
-             error('Dictionary key must be a name object');
- 
-           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;
-         }
-         this.shift();
-         return dict;
-       }
-       if (isInt(this.buf1)) { // indirect reference or integer
-         var num = this.buf1;
-         this.shift();
-         if (isInt(this.buf1) && isCmd(this.buf2, 'R')) {
-           var ref = new Ref(num, this.buf1);
-           this.shift();
-           this.shift();
-           return ref;
-         }
-         return num;
-       }
-       if (isString(this.buf1)) { // string
-         var str = this.buf1;
-         this.shift();
-         if (cipherTransform)
-           str = cipherTransform.decryptString(str);
-         return str;
-       }
- 
-       // simple object
-       var obj = this.buf1;
-       this.shift();
-       return obj;
++    /**
++     * @return {number} The number of degrees the page is rotated clockwise.
++     */
++    get rotate() {
++      return this.pageInfo.rotate;
 +    },
-     makeInlineImage: function Parser_makeInlineImage(cipherTransform) {
-       var lexer = this.lexer;
-       var stream = lexer.stream;
- 
-       // parse dictionary
-       var dict = new Dict();
-       while (!isCmd(this.buf1, 'ID') && !isEOF(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))
-           break;
-         dict.set(key, this.getObj(cipherTransform));
-       }
- 
-       // parse image stream
-       var startPos = stream.pos;
- 
-       // searching for the /EI\s/
-       var state = 0, ch;
-       while (state != 4 &&
-              (ch = stream.getByte()) !== null && ch !== undefined) {
-         switch (ch) {
-           case 0x20:
-           case 0x0D:
-           case 0x0A:
-             state = state === 3 ? 4 : 0;
-             break;
-           case 0x45:
-             state = 2;
-             break;
-           case 0x49:
-             state = state === 2 ? 3 : 0;
-             break;
-           default:
-             state = 0;
-             break;
-         }
-       }
- 
-       var length = (stream.pos - 4) - startPos;
-       var imageStream = stream.makeSubStream(startPos, length, dict);
-       if (cipherTransform)
-         imageStream = cipherTransform.createStream(imageStream);
-       imageStream = this.filter(imageStream, dict, length);
-       imageStream.parameters = dict;
- 
-       this.buf2 = Cmd.get('EI');
-       this.shift();
- 
-       return imageStream;
++    /**
++     * @return {Object} The reference that points to this page. It has 'num' and
++     * 'gen' properties.
++     */
++    get ref() {
++      return this.pageInfo.ref;
 +    },
-     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 {Array} An array of the visible portion of the PDF page in the
++     * user space units - [x1, y1, x2, y2].
++     */
++    get view() {
++      return this.pageInfo.view;
 +    },
-     makeStream: function Parser_makeStream(dict, cipherTransform) {
-       var lexer = this.lexer;
-       var stream = lexer.stream;
- 
-       // get stream start position
-       lexer.skipToNextLine();
-       var pos = stream.pos;
- 
-       // get length
-       var length = this.fetchIfRef(dict.get('Length'));
-       if (!isInt(length))
-         error('Bad ' + length + ' attribute in stream');
- 
-       // skip over the stream data
-       stream.pos = pos + length;
-       this.shift(); // '>>'
-       this.shift(); // 'stream'
-       if (!isCmd(this.buf1, 'endstream'))
-         error('Missing endstream');
-       this.shift();
- 
-       stream = stream.makeSubStream(pos, length, dict);
-       if (cipherTransform)
-         stream = cipherTransform.createStream(stream);
-       stream = this.filter(stream, dict, length);
-       stream.parameters = dict;
-       return stream;
++    /**
++     * @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.
++     */
++    getViewport: function PDFPageProxy_getViewport(scale, rotate) {
++      if (arguments.length < 2)
++        rotate = this.rotate;
++      return new PDFJS.PageViewport(this.view, scale, rotate, 0, 0);
 +    },
-     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))
-         return this.makeFilter(stream, filter.name, length, params);
-       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))
-             error('Bad filter name: ' + filter);
- 
-           params = null;
-           if (isArray(paramsArray) && (i in paramsArray))
-             params = paramsArray[i];
-           stream = this.makeFilter(stream, filter.name, length, params);
-           // after the first stream the length variable is invalid
-           length = null;
-         }
-       }
-       return stream;
++    /**
++     * @return {Promise} A promise that is resolved with an {Array} of the
++     * annotation objects.
++     */
++    getAnnotations: function PDFPageProxy_getAnnotations() {
++      if (this.annotationsPromise)
++        return this.annotationsPromise;
++
++      var promise = new PDFJS.LegacyPromise();
++      this.annotationsPromise = promise;
++      this.transport.getAnnotations(this.pageInfo.pageIndex);
++      return promise;
 +    },
-     makeFilter: function Parser_makeFilter(stream, name, length, params) {
-       if (stream.dict.get('Length') === 0) {
-         return new NullStream(stream);
-       }
-       if (name == 'FlateDecode' || name == 'Fl') {
-         if (params) {
-           return new PredictorStream(new FlateStream(stream), 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);
-         }
-         return new LZWStream(stream, earlyChange);
-       }
-       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;
-     }
-   };
++    /**
++     * 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).
++     */
++    render: function PDFPageProxy_render(params) {
++      var stats = this.stats;
++      stats.time('Overall');
 +
-   return Parser;
- })();
++      // If there was a pending destroy cancel it so no cleanup happens during
++      // this call to render.
++      this.pendingDestroy = false;
 +
- var Lexer = (function LexerClosure() {
-   function Lexer(stream, knownCommands) {
-     this.stream = stream;
-     // 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:
-     // if there a command that is a prefix of the other valid command or
-     // literal (e.g. 'f' and 'false') the following prefixes must be included,
-     // 'fa', 'fal', 'fals'. The prefixes are not needed, if the command has no
-     // other commands or literals as a prefix. The knowCommands is optional.
-     this.knownCommands = knownCommands;
-   }
++      var renderingIntent = 'intent' in params ?
++        (params.intent == 'print' ? 'print' : 'display') :
++        'display';
 +
-   Lexer.isSpace = function Lexer_isSpace(ch) {
-     return ch == ' ' || ch == '\t' || ch == '\x0d' || ch == '\x0a';
-   };
++      if (!this.intentStates[renderingIntent]) {
++        this.intentStates[renderingIntent] = {};
++      }
++      var intentState = this.intentStates[renderingIntent];
 +
-   // 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
-   ];
- 
-   function toHexDigit(ch) {
-     if (ch >= '0' && ch <= '9')
-       return ch.charCodeAt(0) - 48;
-     ch = ch.toUpperCase();
-     if (ch >= 'A' && ch <= 'F')
-       return ch.charCodeAt(0) - 55;
-     return -1;
-   }
++      // If there is no displayReadyPromise yet, then the operatorList was never
++      // requested before. Make the request and create the promise.
++      if (!intentState.displayReadyPromise) {
++        intentState.receivingOperatorList = true;
++        intentState.displayReadyPromise = new LegacyPromise();
++        intentState.operatorList = {
++          fnArray: [],
++          argsArray: [],
++          lastChunk: false
++        };
 +
-   Lexer.prototype = {
-     getNumber: function Lexer_getNumber(ch) {
-       var floating = false;
-       var str = ch;
-       var stream = this.stream;
-       while ((ch = stream.lookChar())) {
-         if (ch == '.' && !floating) {
-           str += ch;
-           floating = true;
-         } else if (ch == '-') {
-           // ignore minus signs in the middle of numbers to match
-           // Adobe's behavior
-           warn('Badly formated number');
-         } else if (ch >= '0' && ch <= '9') {
-           str += ch;
-         } else if (ch == 'e' || ch == 'E') {
-           floating = true;
-         } else {
-           // the last character doesn't belong to us
-           break;
-         }
-         stream.skip();
++        this.stats.time('Page Request');
++        this.transport.messageHandler.send('RenderPageRequest', {
++          pageIndex: this.pageNumber - 1,
++          intent: renderingIntent
++        });
 +      }
-       var value = parseFloat(str);
-       if (isNaN(value))
-         error('Invalid floating point number: ' + value);
-       return value;
-     },
-     getString: function Lexer_getString() {
-       var numParen = 1;
-       var done = false;
-       var str = '';
-       var stream = this.stream;
-       var ch;
-       do {
-         ch = stream.getChar();
-         switch (ch) {
-           case null:
-           case undefined:
-             warn('Unterminated string');
-             done = true;
-             break;
-           case '(':
-             ++numParen;
-             str += ch;
-             break;
-           case ')':
-             if (--numParen === 0) {
-               done = true;
-             } else {
-               str += ch;
-             }
-             break;
-           case '\\':
-             ch = stream.getChar();
-             switch (ch) {
-               case null:
-               case undefined:
-                 warn('Unterminated string');
-                 done = true;
-                 break;
-               case 'n':
-                 str += '\n';
-                 break;
-               case 'r':
-                 str += '\r';
-                 break;
-               case 't':
-                 str += '\t';
-                 break;
-               case 'b':
-                 str += '\b';
-                 break;
-               case 'f':
-                 str += '\f';
-                 break;
-               case '\\':
-               case '(':
-               case ')':
-                 str += ch;
-                 break;
-               case '0': case '1': case '2': case '3':
-               case '4': case '5': case '6': case '7':
-                 var x = ch - '0';
-                 ch = stream.lookChar();
-                 if (ch >= '0' && ch <= '7') {
-                   stream.skip();
-                   x = (x << 3) + (ch - '0');
-                   ch = stream.lookChar();
-                   if (ch >= '0' && ch <= '7') {
-                     stream.skip();
-                     x = (x << 3) + (ch - '0');
-                   }
-                 }
 +
-                 str += String.fromCharCode(x);
-                 break;
-               case '\r':
-                 ch = stream.lookChar();
-                 if (ch == '\n')
-                   stream.skip();
-                 break;
-               case '\n':
-                 break;
-               default:
-                 str += ch;
-                 break;
-             }
-             break;
-           default:
-             str += ch;
-             break;
-         }
-       } while (!done);
-       return str;
-     },
-     getName: function Lexer_getName(ch) {
-       var str = '';
-       var stream = this.stream;
-       while (!!(ch = stream.lookChar()) && !specialChars[ch.charCodeAt(0)]) {
-         stream.skip();
-         if (ch == '#') {
-           ch = stream.lookChar();
-           var x = toHexDigit(ch);
-           if (x != -1) {
-             stream.skip();
-             var x2 = toHexDigit(stream.getChar());
-             if (x2 == -1)
-               error('Illegal digit in hex char in name: ' + x2);
-             str += String.fromCharCode((x << 4) | x2);
-           } else {
-             str += '#';
-             str += ch;
-           }
-         } else {
-           str += ch;
-         }
++      var internalRenderTask = new InternalRenderTask(complete, params,
++                                       this.objs, this.commonObjs,
++                                       intentState.operatorList,
++                                       this.pageNumber);
++      if (!intentState.renderTasks) {
++        intentState.renderTasks = [];
 +      }
-       if (str.length > 128)
-         error('Warning: name token is longer than allowed by the spec: ' +
-               str.length);
-       return new Name(str);
-     },
-     getHexString: function Lexer_getHexString(ch) {
-       var str = '';
-       var stream = this.stream;
-       var isFirstHex = true;
-       var firstDigit;
-       var secondDigit;
-       while (true) {
-         ch = stream.getChar();
-         if (!ch) {
-           warn('Unterminated hex string');
-           break;
-         } else if (ch === '>') {
-           break;
-         } else if (specialChars[ch.charCodeAt(0)] === 1) {
-           continue;
-         } else {
-           if (isFirstHex) {
-             firstDigit = toHexDigit(ch);
-             if (firstDigit === -1) {
-               warn('Ignoring invalid character "' + ch + '" in hex string');
-               continue;
-             }
-           } else {
-             secondDigit = toHexDigit(ch);
-             if (secondDigit === -1) {
-               warn('Ignoring invalid character "' + ch + '" in hex string');
-               continue;
-             }
-             str += String.fromCharCode((firstDigit << 4) | secondDigit);
++      intentState.renderTasks.push(internalRenderTask);
++      var renderTask = new RenderTask(internalRenderTask);
++
++      var self = this;
++      intentState.displayReadyPromise.then(
++        function pageDisplayReadyPromise(transparency) {
++          if (self.pendingDestroy) {
++            complete();
++            return;
 +          }
-           isFirstHex = !isFirstHex;
++          stats.time('Rendering');
++          internalRenderTask.initalizeGraphics(transparency);
++          internalRenderTask.operatorListChanged();
++        },
++        function pageDisplayReadPromiseError(reason) {
++          complete(reason);
 +        }
-       }
-       return str;
-     },
-     getObj: function Lexer_getObj() {
-       // skip whitespace and comments
-       var comment = false;
-       var stream = this.stream;
-       var ch;
-       while (true) {
-         if (!(ch = stream.getChar()))
-           return EOF;
-         if (comment) {
-           if (ch == '\r' || ch == '\n')
-             comment = false;
-         } else if (ch == '%') {
-           comment = true;
-         } else if (specialChars[ch.charCodeAt(0)] != 1) {
-           break;
++      );
++
++      function complete(error) {
++        var i = intentState.renderTasks.indexOf(internalRenderTask);
++        if (i >= 0) {
++          intentState.renderTasks.splice(i, 1);
 +        }
-       }
 +
-       // start reading token
-       switch (ch) {
-         case '0': case '1': case '2': case '3': case '4':
-         case '5': case '6': case '7': case '8': case '9':
-         case '+': case '-': case '.':
-           return this.getNumber(ch);
-         case '(':
-           return this.getString();
-         case '/':
-           return this.getName(ch);
-         // array punctuation
-         case '[':
-         case ']':
-           return Cmd.get(ch);
-         // hex string or dict punctuation
-         case '<':
-           ch = stream.lookChar();
-           if (ch == '<') {
-             // dict punctuation
-             stream.skip();
-             return Cmd.get('<<');
-           }
-           return this.getHexString(ch);
-         // dict punctuation
-         case '>':
-           ch = stream.lookChar();
-           if (ch == '>') {
-             stream.skip();
-             return Cmd.get('>>');
-           }
-           return Cmd.get(ch);
-         case '{':
-         case '}':
-           return Cmd.get(ch);
-         // fall through
-         case ')':
-           error('Illegal character: ' + ch);
-       }
++        if (self.cleanupAfterRender) {
++          self.pendingDestroy = true;
++        }
++        self._tryDestroy();
 +
-       // command
-       var str = ch;
-       var knownCommands = this.knownCommands;
-       var knownCommandFound = knownCommands && (str in knownCommands);
-       while (!!(ch = stream.lookChar()) && !specialChars[ch.charCodeAt(0)]) {
-         // stop if known command is found and next character does not make
-         // the str a command
-         if (knownCommandFound && !((str + ch) in knownCommands))
-           break;
-         stream.skip();
-         if (str.length == 128)
-           error('Command token too long: ' + str.length);
-         str += ch;
-         knownCommandFound = knownCommands && (str in knownCommands);
-       }
-       if (str == 'true')
-         return true;
-       if (str == 'false')
-         return false;
-       if (str == 'null')
-         return null;
-       return Cmd.get(str);
-     },
-     skipToNextLine: function Lexer_skipToNextLine() {
-       var stream = this.stream;
-       while (true) {
-         var ch = stream.getChar();
-         if (!ch || ch == '\n')
-           return;
-         if (ch == '\r') {
-           if ((ch = stream.lookChar()) == '\n')
-             stream.skip();
-           return;
++        if (error) {
++          renderTask.promise.reject(error);
++        } else {
++          renderTask.promise.resolve();
 +        }
++        stats.timeEnd('Rendering');
++        stats.timeEnd('Overall');
 +      }
-     },
-     skip: function Lexer_skip() {
-       this.stream.skip();
-     }
-   };
- 
-   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) {
-         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;
-       }
-       error('Hints table in linearization table is invalid: ' + index);
-     },
-     get length() {
-       if (!isDict(this.linDict))
-         return 0;
-       return this.getInt('L');
-     },
-     get hintsOffset() {
-       return this.getHint(0);
++      return renderTask;
 +    },
-     get hintsLength() {
-       return this.getHint(1);
-     },
-     get hintsOffset2() {
-       return this.getHint(2);
-     },
-     get hintsLenth2() {
-       return this.getHint(3);
-     },
-     get objectNumberFirst() {
-       return this.getInt('O');
++    /**
++     * @return {Promise} That is resolved with the array of {@link BidiText}
++     * objects 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;
 +    },
-     get endFirst() {
-       return this.getInt('E');
++    /**
++     * Destroys resources allocated by the page.
++     */
++    destroy: function PDFPageProxy_destroy() {
++      this.pendingDestroy = true;
++      this._tryDestroy();
 +    },
-     get numPages() {
-       return this.getInt('N');
++    /**
++     * 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 ||
++          Object.keys(this.intentStates).some(function(intent) {
++            var intentState = this.intentStates[intent];
++            return intentState.renderTasks.length !== 0 ||
++                   intentState.receivingOperatorList;
++          }, this)) {
++        return;
++      }
++
++      Object.keys(this.intentStates).forEach(function(intent) {
++        delete this.intentStates[intent];
++      }, this);
++      this.objs.clear();
++      this.pendingDestroy = false;
 +    },
-     get mainXRefEntriesOffset() {
-       return this.getInt('T');
++    /**
++     * For internal use only.
++     * @ignore
++     */
++    _startRenderPage: function PDFPageProxy_startRenderPage(transparency,
++                                                            intent) {
++      var intentState = this.intentStates[intent];
++      intentState.displayReadyPromise.resolve(transparency);
 +    },
-     get pageFirst() {
-       return this.getInt('P');
-     }
-   };
- 
-   return Linearization;
- })();
- 
- 
- 
- 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) {
++    /**
++     * For internal use only.
++     * @ignore
++     */
++    _renderPageChunk: function PDFPageProxy_renderPageChunk(operatorListChunk,
++                                                            intent) {
++      var intentState = this.intentStates[intent];
++      // Add the new chunk to the current operator list.
++      for (var i = 0, ii = operatorListChunk.length; i < ii; i++) {
++        intentState.operatorList.fnArray.push(operatorListChunk.fnArray[i]);
++        intentState.operatorList.argsArray.push(
++          operatorListChunk.argsArray[i]);
++      }
++      intentState.operatorList.lastChunk = operatorListChunk.lastChunk;
 +
-     var dict = isStream(shading) ? shading.dict : shading;
-     var type = dict.get('ShadingType');
++      // Notify all the rendering tasks there are more operators to be consumed.
++      for (var i = 0; i < intentState.renderTasks.length; i++) {
++        intentState.renderTasks[i].operatorListChanged();
++      }
 +
-     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:
-         TODO('Unsupported shading type: ' + type);
-         return new Shadings.Dummy();
++      if (operatorListChunk.lastChunk) {
++        intentState.receivingOperatorList = false;
++        this._tryDestroy();
++      }
 +    }
 +  };
-   return Pattern;
++  return PDFPageProxy;
 +})();
 +
- 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];
-     }
++/**
++ * For internal use only.
++ * @ignore
++ */
++var WorkerTransport = (function WorkerTransportClosure() {
++  function WorkerTransport(workerInitializedPromise, workerReadyPromise,
++      pdfDataRangeTransport, progressCallback) {
++    this.pdfDataRangeTransport = pdfDataRangeTransport;
 +
-     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.workerReadyPromise = workerReadyPromise;
++    this.progressCallback = progressCallback;
++    this.commonObjs = new PDFObjects();
 +
-     this.extendStart = extendStart;
-     this.extendEnd = extendEnd;
++    this.pageCache = [];
++    this.pagePromises = [];
++    this.downloadInfoPromise = new PDFJS.LegacyPromise();
++    this.passwordCallback = null;
 +
-     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');
++    // If worker support isn't disabled explicit and the browser has worker
++    // support, create a new web worker and test if it/the browser fullfills
++    // all requirements to run parts of pdf.js in a web worker.
++    // Right now, the requirement is, that an Uint8Array is still an Uint8Array
++    // as it arrives on the worker. Chrome added this with version 15.
++    if (!globalScope.PDFJS.disableWorker && typeof Worker !== 'undefined') {
++      var workerSrc = PDFJS.workerSrc;
++      if (!workerSrc) {
++        error('No PDFJS.workerSrc specified');
 +      }
-       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 = [];
++      try {
++        // Some versions of FF can't create a worker on localhost, see:
++        // https://bugzilla.mozilla.org/show_bug.cgi?id=683280
++        var worker = new Worker(workerSrc);
++        var messageHandler = new MessageHandler('main', worker);
++        this.messageHandler = messageHandler;
 +
-     // 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;
-     }
++        messageHandler.on('test', function transportTest(data) {
++          var supportTypedArray = data && data.supportTypedArray;
++          if (supportTypedArray) {
++            this.worker = worker;
++            if (!data.supportTransfers) {
++              PDFJS.postMessageTransfers = false;
++            }
++            this.setupMessageHandler(messageHandler);
++            workerInitializedPromise.resolve();
++          } else {
++            globalScope.PDFJS.disableWorker = true;
++            this.loadFakeWorkerFiles().then(function() {
++              this.setupFakeWorker();
++              workerInitializedPromise.resolve();
++            }.bind(this));
++          }
++        }.bind(this));
 +
-     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 testObj = new Uint8Array([PDFJS.postMessageTransfers ? 255 : 0]);
++        // 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]);
++        } catch (ex) {
++          info('Cannot use postMessage transfers');
++          testObj[0] = 0;
++          messageHandler.send('test', testObj);
++        }
++        return;
++      } catch (e) {
++        info('The worker has been disabled.');
++      }
 +    }
++    // 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));
++  }
++  WorkerTransport.prototype = {
++    destroy: function WorkerTransport_destroy() {
++      this.pageCache = [];
++      this.pagePromises = [];
++      var self = this;
++      this.messageHandler.send('Terminate', null, function () {
++        FontLoader.clear();
++        if (self.worker) {
++          self.worker.terminate();
++        }
++      });
++    },
 +
-     var background = 'transparent';
-     if (dict.has('Background')) {
-       var rgbColor = cs.getRgb(dict.get('Background'), 0);
-       background = Util.makeCssRgb(rgbColor);
-     }
++    loadFakeWorkerFiles: function WorkerTransport_loadFakeWorkerFiles() {
++      if (!PDFJS.fakeWorkerFilesLoadedPromise) {
++        PDFJS.fakeWorkerFilesLoadedPromise = new LegacyPromise();
++        // 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();
++        });
++      }
++      return PDFJS.fakeWorkerFilesLoadedPromise;
++    },
 +
-     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]);
-     }
++    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() {}
++      };
 +
-     this.colorStops = colorStops;
-   }
++      var messageHandler = new MessageHandler('main', fakeWorker);
++      this.setupMessageHandler(messageHandler);
 +
-   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);
++      // If the main thread is our worker, setup the handling for the messages
++      // the main thread sends to it self.
++      PDFJS.WorkerMessageHandler.setup(messageHandler);
++    },
 +
-         for (var i = 0, ii = colorStops.length; i < ii; ++i) {
-           var c = colorStops[i];
-           grad.addColorStop(c[0], c[1]);
-         }
-         return grad;
-       }
-     };
-   };
++    setupMessageHandler:
++      function WorkerTransport_setupMessageHandler(messageHandler) {
++      this.messageHandler = messageHandler;
 +
-   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);
++      function updatePassword(password) {
++        messageHandler.send('UpdatePassword', password);
 +      }
 +
-       var matrix = this.matrix;
-       if (matrix) {
-         p0 = Util.applyTransform(p0, matrix);
-         p1 = Util.applyTransform(p1, matrix);
++      var pdfDataRangeTransport = this.pdfDataRangeTransport;
++      if (pdfDataRangeTransport) {
++        pdfDataRangeTransport.addRangeListener(function(begin, chunk) {
++          messageHandler.send('OnDataRange', {
++            begin: begin,
++            chunk: chunk
++          });
++        });
++
++        pdfDataRangeTransport.addProgressListener(function(loaded) {
++          messageHandler.send('OnDataProgress', {
++            loaded: loaded
++          });
++        });
++
++        messageHandler.on('RequestDataRange',
++          function transportDataRange(data) {
++            pdfDataRangeTransport.requestDataRange(data.begin, data.end);
++          }, this);
 +      }
 +
-       return ['RadialAxial', type, this.colorStops, p0, p1, r0, r1];
-     }
-   };
++      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);
 +
-   return RadialAxial;
- })();
++      messageHandler.on('NeedPassword', function transportPassword(data) {
++        if (this.passwordCallback) {
++          return this.passwordCallback(updatePassword,
++                                       PasswordResponses.NEED_PASSWORD);
++        }
++        this.workerReadyPromise.reject(data.exception.message, data.exception);
++      }, this);
 +
- Shadings.Dummy = (function DummyClosure() {
-   function Dummy() {
-     this.type = 'Pattern';
-   }
++      messageHandler.on('IncorrectPassword', function transportBadPass(data) {
++        if (this.passwordCallback) {
++          return this.passwordCallback(updatePassword,
++                                       PasswordResponses.INCORRECT_PASSWORD);
++        }
++        this.workerReadyPromise.reject(data.exception.message, data.exception);
++      }, this);
 +
-   Dummy.fromIR = function Dummy_fromIR() {
-     return {
-       type: 'Pattern',
-       getPattern: function Dummy_fromIR_getPattern() {
-         return 'hotpink';
-       }
-     };
-   };
++      messageHandler.on('InvalidPDF', function transportInvalidPDF(data) {
++        this.workerReadyPromise.reject(data.exception.name, data.exception);
++      }, this);
 +
-   Dummy.prototype = {
-     getIR: function Dummy_getIR() {
-       return ['Dummy'];
-     }
-   };
-   return Dummy;
- })();
++      messageHandler.on('MissingPDF', function transportMissingPDF(data) {
++        this.workerReadyPromise.reject(data.exception.message, data.exception);
++      }, this);
 +
- var TilingPattern = (function TilingPatternClosure() {
-   var PaintType = {
-     COLORED: 1,
-     UNCOLORED: 2
-   };
-   var MAX_PATTERN_SIZE = 4096;
++      messageHandler.on('UnknownError', function transportUnknownError(data) {
++        this.workerReadyPromise.reject(data.exception.message, data.exception);
++      }, this);
 +
-   function TilingPattern(IR, color, ctx, objs, commonObjs) {
-     var operatorList = IR[2];
-     this.matrix = IR[3] || [1, 0, 0, 1, 0, 0];
-     var bbox = IR[4];
-     var xstep = IR[5];
-     var ystep = IR[6];
-     var paintType = IR[7];
-     var tilingType = IR[8];
++      messageHandler.on('DataLoaded', function transportPage(data) {
++        this.downloadInfoPromise.resolve(data);
++      }, this);
 +
-     TODO('TilingType: ' + tilingType);
++      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);
++      }, this);
 +
-     this.curMatrix = ctx.mozCurrentTransform;
-     this.ctx = ctx;
-     this.type = 'Pattern';
++      messageHandler.on('GetAnnotations', function transportAnnotations(data) {
++        var annotations = data.annotations;
++        var promise = this.pageCache[data.pageIndex].annotationsPromise;
++        promise.resolve(annotations);
++      }, this);
 +
-     var x0 = bbox[0], y0 = bbox[1], x1 = bbox[2], y1 = bbox[3];
++      messageHandler.on('StartRenderPage', function transportRender(data) {
++        var page = this.pageCache[data.pageIndex];
 +
-     var topLeft = [x0, y0];
-     // we want the canvas to be as large as the step size
-     var botRight = [x0 + xstep, y0 + ystep];
++        page.stats.timeEnd('Page Request');
++        page._startRenderPage(data.transparency, data.intent);
++      }, this);
 +
-     var width = botRight[0] - topLeft[0];
-     var height = botRight[1] - topLeft[1];
++      messageHandler.on('RenderPageChunk', function transportRender(data) {
++        var page = this.pageCache[data.pageIndex];
 +
-     // Obtain scale from matrix and current transformation matrix.
-     var matrixScale = Util.singularValueDecompose2dScale(this.matrix);
-     var curMatrixScale = Util.singularValueDecompose2dScale(this.curMatrix);
-     var combinedScale = [matrixScale[0] * curMatrixScale[0],
-                          matrixScale[1] * curMatrixScale[1]];
++        page._renderPageChunk(data.operatorList, data.intent);
++      }, this);
 +
-     // 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);
++      messageHandler.on('commonobj', function transportObj(data) {
++        var id = data[0];
++        var type = data[1];
++        if (this.commonObjs.hasData(id))
++          return;
 +
-     height = Math.min(Math.ceil(Math.abs(height * combinedScale[1])),
-                       MAX_PATTERN_SIZE);
++        switch (type) {
++          case 'Font':
++            var exportedData = data[2];
 +
-     var tmpCanvas = createScratchCanvas(width, height);
++            var font;
++            if ('error' in exportedData) {
++              var error = exportedData.error;
++              warn('Error during font loading: ' + error);
++              this.commonObjs.resolve(id, error);
++              break;
++            } else {
++              font = new FontFace(exportedData);
++            }
 +
-     // set the new canvas element context as the graphics context
-     var tmpCtx = tmpCanvas.getContext('2d');
-     var graphics = new CanvasGraphics(tmpCtx, commonObjs, objs);
++            FontLoader.bind(
++              [font],
++              function fontReady(fontObjs) {
++                this.commonObjs.resolve(id, font);
++              }.bind(this)
++            );
++            break;
++          case 'FontPath':
++            this.commonObjs.resolve(id, data[2]);
++            break;
++          default:
++            error('Got unknown common object type ' + type);
++        }
++      }, this);
 +
-     this.setFillAndStrokeStyleToContext(tmpCtx, paintType, color);
++      messageHandler.on('obj', function transportObj(data) {
++        var id = data[0];
++        var pageIndex = data[1];
++        var type = data[2];
++        var pageProxy = this.pageCache[pageIndex];
++        if (pageProxy.objs.hasData(id)) {
++          return;
++        }
 +
-     this.setScale(width, height, xstep, ystep);
-     this.transformToScale(graphics);
++        switch (type) {
++          case 'JpegStream':
++            var imageData = data[3];
++            loadJpegStream(id, imageData, pageProxy.objs);
++            break;
++          case 'Image':
++            var imageData = data[3];
++            pageProxy.objs.resolve(id, imageData);
 +
-     // transform coordinates to pattern space
-     var tmpTranslate = [1, 0, 0, 1, -topLeft[0], -topLeft[1]];
-     graphics.transform.apply(graphics, tmpTranslate);
++            // heuristics that will allow not to store large data
++            var MAX_IMAGE_SIZE_TO_STORE = 8000000;
++            if ('data' in imageData &&
++                imageData.data.length > MAX_IMAGE_SIZE_TO_STORE) {
++              pageProxy.cleanupAfterRender = true;
++            }
++            break;
++          default:
++            error('Got unknown object type ' + type);
++        }
++      }, this);
 +
-     this.clipBbox(graphics, bbox, x0, y0, x1, y1);
++      messageHandler.on('DocProgress', function transportDocProgress(data) {
++        if (this.progressCallback) {
++          this.progressCallback({
++            loaded: data.loaded,
++            total: data.total
++          });
++        }
++      }, this);
 +
-     graphics.executeOperatorList(operatorList);
++      messageHandler.on('DocError', function transportDocError(data) {
++        this.workerReadyPromise.reject(data);
++      }, this);
 +
-     this.canvas = tmpCanvas;
-   }
++      messageHandler.on('PageError', function transportError(data, intent) {
++        var page = this.pageCache[data.pageNum - 1];
++        var intentState = page.intentStates[intent];
++        if (intentState.displayReadyPromise)
++          intentState.displayReadyPromise.reject(data.error);
++        else
++          error(data.error);
++      }, this);
 +
-   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');
++      messageHandler.on('JpegDecode', function(data, deferred) {
++        var imageUrl = data[0];
++        var components = data[1];
++        if (components != 3 && components != 1)
++          error('Only 3 component or 1 component can be returned');
 +
-     return [
-       'TilingPattern', args, operatorList, matrix, bbox, xstep, ystep,
-       paintType, tilingType
-     ];
-   };
++        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;
 +
-   TilingPattern.prototype = {
-     setScale: function TilingPattern_setScale(width, height, xstep, ystep) {
-       this.scale = [width / xstep, height / ystep];
++          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];
++            }
++          } 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;
++      });
 +    },
 +
-     transformToScale: function TilingPattern_transformToScale(graphics) {
-       var scale = this.scale;
-       var tmpScale = [scale[0], 0, 0, scale[1], 0, 0];
-       graphics.transform.apply(graphics, tmpScale);
++    fetchDocument: function WorkerTransport_fetchDocument(source) {
++      source.disableAutoFetch = PDFJS.disableAutoFetch;
++      source.chunkedViewerLoading = !!this.pdfDataRangeTransport;
++      this.messageHandler.send('GetDocRequest', {
++        source: source,
++        disableRange: PDFJS.disableRange,
++        maxImageSize: PDFJS.maxImageSize,
++        disableFontFace: PDFJS.disableFontFace,
++        disableCreateObjectURL: PDFJS.disableCreateObjectURL,
++        verbosity: PDFJS.verbosity
++      });
 +    },
 +
-     scaleToContext: function TilingPattern_scaleToContext() {
-       var scale = this.scale;
-       this.ctx.scale(1 / scale[0], 1 / scale[1]);
++    getData: function WorkerTransport_getData(promise) {
++      this.messageHandler.send('GetData', null, function(data) {
++        promise.resolve(data);
++      });
 +    },
 +
-     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();
++    getPage: function WorkerTransport_getPage(pageNumber, promise) {
++      if (pageNumber <= 0 || pageNumber > this.numPages ||
++          (pageNumber|0) !== pageNumber) {
++        var pagePromise = new PDFJS.LegacyPromise();
++        pagePromise.reject(new Error('Invalid page request'));
++        return pagePromise;
 +      }
++
++      var pageIndex = pageNumber - 1;
++      if (pageIndex in this.pagePromises)
++        return this.pagePromises[pageIndex];
++      var promise = new PDFJS.LegacyPromise();
++      this.pagePromises[pageIndex] = promise;
++      this.messageHandler.send('GetPageRequest', { pageIndex: pageIndex });
++      return promise;
 +    },
 +
-     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 = new DeviceRgbCS().getRgb(color, 0);
-           var cssColor = Util.makeCssRgb(rgbColor);
-           context.fillStyle = cssColor;
-           context.strokeStyle = cssColor;
-           break;
-         default:
-           error('Unsupported paint type: ' + paintType);
-       }
++    getPageIndex: function WorkerTransport_getPageIndexByRef(ref) {
++      var promise = new PDFJS.LegacyPromise();
++      this.messageHandler.send('GetPageIndex', { ref: ref },
++        function (pageIndex) {
++          promise.resolve(pageIndex);
++        }
++      );
++      return promise;
 +    },
 +
-     getPattern: function TilingPattern_getPattern() {
-       var matrix = this.matrix;
-       var curMatrix = this.curMatrix;
-       var ctx = this.ctx;
++    getAnnotations: function WorkerTransport_getAnnotations(pageIndex) {
++      this.messageHandler.send('GetAnnotationsRequest',
++        { pageIndex: pageIndex });
++    },
 +
-       ctx.setTransform.apply(ctx, curMatrix);
-       ctx.transform.apply(ctx, matrix);
-       this.scaleToContext();
++    getDestinations: function WorkerTransport_getDestinations() {
++      var promise = new PDFJS.LegacyPromise();
++      this.messageHandler.send('GetDestinations', null,
++        function transportDestinations(destinations) {
++          promise.resolve(destinations);
++        }
++      );
++      return promise;
++    },
 +
-       return ctx.createPattern(this.canvas, 'repeat');
++    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.commonObjs.clear();
++          FontLoader.clear();
++        }.bind(this)
++      );
 +    }
 +  };
++  return WorkerTransport;
 +
-   return TilingPattern;
 +})();
 +
++/**
++ * A PDF document and page is built of many objects. E.g. there are objects
++ * 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() {
++    this.objs = {};
++  }
 +
++  PDFObjects.prototype = {
++    /**
++     * Internal function.
++     * Ensures there is an object defined for `objId`.
++     */
++    ensureObj: function PDFObjects_ensureObj(objId) {
++      if (this.objs[objId])
++        return this.objs[objId];
 +
- var Stream = (function StreamClosure() {
-   function Stream(arrayBuffer, start, length, dict) {
-     this.bytes = arrayBuffer instanceof Uint8Array ? arrayBuffer :
-       new Uint8Array(arrayBuffer);
-     this.start = start || 0;
-     this.pos = this.start;
-     this.end = (start + length) || this.bytes.length;
-     this.dict = dict;
-   }
++      var obj = {
++        promise: new LegacyPromise(),
++        data: null,
++        resolved: false
++      };
++      this.objs[objId] = obj;
 +
-   // required methods for a stream. if a particular stream does not
-   // implement these, an error should be thrown
-   Stream.prototype = {
-     get length() {
-       return this.end - this.start;
-     },
-     getByte: function Stream_getByte() {
-       if (this.pos >= this.end)
-         return null;
-       return this.bytes[this.pos++];
-     },
-     // returns subarray of original buffer
-     // should only be read
-     getBytes: function Stream_getBytes(length) {
-       var bytes = this.bytes;
-       var pos = this.pos;
-       var strEnd = this.end;
- 
-       if (!length)
-         return bytes.subarray(pos, strEnd);
- 
-       var end = pos + length;
-       if (end > strEnd)
-         end = strEnd;
- 
-       this.pos = end;
-       return bytes.subarray(pos, end);
-     },
-     lookChar: function Stream_lookChar() {
-       if (this.pos >= this.end)
-         return null;
-       return String.fromCharCode(this.bytes[this.pos]);
-     },
-     getChar: function Stream_getChar() {
-       if (this.pos >= this.end)
-         return null;
-       return String.fromCharCode(this.bytes[this.pos++]);
-     },
-     skip: function Stream_skip(n) {
-       if (!n)
-         n = 1;
-       this.pos += n;
-     },
-     reset: function Stream_reset() {
-       this.pos = this.start;
-     },
-     moveStart: function Stream_moveStart() {
-       this.start = this.pos;
-     },
-     makeSubStream: function Stream_makeSubStream(start, length, dict) {
-       return new Stream(this.bytes.buffer, start, length, dict);
++      return obj;
 +    },
-     isStream: true
-   };
 +
-   return Stream;
- })();
++    /**
++     * If called *without* callback, this returns the data of `objId` but the
++     * object needs to be resolved. If it isn't, this function throws.
++     *
++     * If called *with* a callback, the callback is called with the data of the
++     * object once the object is resolved. That means, if you call this
++     * function and the object is already resolved, the callback gets called
++     * right away.
++     */
++    get: function PDFObjects_get(objId, callback) {
++      // 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);
++        return null;
++      }
 +
- var StringStream = (function StringStreamClosure() {
-   function StringStream(str) {
-     var length = str.length;
-     var bytes = new Uint8Array(length);
-     for (var n = 0; n < length; ++n)
-       bytes[n] = str.charCodeAt(n);
-     Stream.call(this, bytes);
-   }
++      // If there isn't a callback, the user expects to get the resolved data
++      // directly.
++      var obj = this.objs[objId];
 +
-   StringStream.prototype = Stream.prototype;
++      // If there isn't an object yet or the object isn't resolved, then the
++      // data isn't ready yet!
++      if (!obj || !obj.resolved)
++        error('Requesting object that isn\'t resolved yet ' + objId);
 +
-   return StringStream;
- })();
++      return obj.data;
++    },
 +
- // super class for the decoding streams
- var DecodeStream = (function DecodeStreamClosure() {
-   function DecodeStream() {
-     this.pos = 0;
-     this.bufferLength = 0;
-     this.eof = false;
-     this.buffer = null;
-   }
++    /**
++     * Resolves the object `objId` with optional `data`.
++     */
++    resolve: function PDFObjects_resolve(objId, data) {
++      var obj = this.ensureObj(objId);
 +
-   DecodeStream.prototype = {
-     ensureBuffer: function DecodeStream_ensureBuffer(requested) {
-       var buffer = this.buffer;
-       var current = buffer ? buffer.byteLength : 0;
-       if (requested < current)
-         return buffer;
-       var size = 512;
-       while (size < requested)
-         size <<= 1;
-       var buffer2 = new Uint8Array(size);
-       for (var i = 0; i < current; ++i)
-         buffer2[i] = buffer[i];
-       return (this.buffer = buffer2);
-     },
-     getByte: function DecodeStream_getByte() {
-       var pos = this.pos;
-       while (this.bufferLength <= pos) {
-         if (this.eof)
-           return null;
-         this.readBlock();
-       }
-       return this.buffer[this.pos++];
++      obj.resolved = true;
++      obj.data = data;
++      obj.promise.resolve(data);
 +    },
-     getBytes: function DecodeStream_getBytes(length) {
-       var end, pos = this.pos;
- 
-       if (length) {
-         this.ensureBuffer(pos + length);
-         end = pos + length;
 +
-         while (!this.eof && this.bufferLength < end)
-           this.readBlock();
++    isResolved: function PDFObjects_isResolved(objId) {
++      var objs = this.objs;
 +
-         var bufEnd = this.bufferLength;
-         if (end > bufEnd)
-           end = bufEnd;
++      if (!objs[objId]) {
++        return false;
 +      } else {
-         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);
++        return objs[objId].resolved;
 +      }
- 
-       this.pos = end;
-       return this.buffer.subarray(pos, end);
 +    },
-     lookChar: function DecodeStream_lookChar() {
-       var pos = this.pos;
-       while (this.bufferLength <= pos) {
-         if (this.eof)
-           return null;
-         this.readBlock();
-       }
-       return String.fromCharCode(this.buffer[this.pos]);
++
++    hasData: function PDFObjects_hasData(objId) {
++      return this.isResolved(objId);
 +    },
-     getChar: function DecodeStream_getChar() {
-       var pos = this.pos;
-       while (this.bufferLength <= pos) {
-         if (this.eof)
-           return null;
-         this.readBlock();
++
++    /**
++     * Returns the data of `objId` if object exists, null otherwise.
++     */
++    getData: function PDFObjects_getData(objId) {
++      var objs = this.objs;
++      if (!objs[objId] || !objs[objId].resolved) {
++        return null;
++      } else {
++        return objs[objId].data;
 +      }
-       return String.fromCharCode(this.buffer[this.pos++]);
-     },
-     makeSubStream: function DecodeStream_makeSubStream(start, length, dict) {
-       var end = start + length;
-       while (this.bufferLength <= end && !this.eof)
-         this.readBlock();
-       return new Stream(this.buffer, start, length, dict);
 +    },
-     skip: function DecodeStream_skip(n) {
-       if (!n)
-         n = 1;
-       this.pos += n;
-     },
-     reset: function DecodeStream_reset() {
-       this.pos = 0;
-     }
-   };
- 
-   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;
++    clear: function PDFObjects_clear() {
++      this.objs = {};
 +    }
- 
-     this.pos = end;
-     return this.buffer.subarray(pos, end);
 +  };
- 
-   return FakeStream;
++  return PDFObjects;
 +})();
 +
- var StreamsSequenceStream = (function StreamsSequenceStreamClosure() {
-   function StreamsSequenceStream(streams) {
-     this.streams = streams;
-     DecodeStream.call(this);
++/**
++ * Allows controlling of the rendering tasks.
++ * @class
++ */
++var RenderTask = (function RenderTaskClosure() {
++  function RenderTask(internalRenderTask) {
++    this.internalRenderTask = internalRenderTask;
++    /**
++     * Promise for rendering task completion.
++     * @type {Promise}
++     */
++    this.promise = new PDFJS.LegacyPromise();
 +  }
 +
-   StreamsSequenceStream.prototype = Object.create(DecodeStream.prototype);
- 
-   StreamsSequenceStream.prototype.readBlock =
-     function streamSequenceStreamReadBlock() {
- 
-     var streams = this.streams;
-     if (streams.length === 0) {
-       this.eof = true;
-       return;
++  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();
++      this.promise.reject(new Error('Rendering is cancelled'));
 +    }
-     var stream = streams.shift();
-     var chunk = stream.getBytes();
-     var bufferLength = this.bufferLength;
-     var newLength = bufferLength + chunk.length;
-     var buffer = this.ensureBuffer(newLength);
-     buffer.set(chunk, bufferLength);
-     this.bufferLength = newLength;
 +  };
 +
-   return StreamsSequenceStream;
++  return RenderTask;
 +})();
 +
- var FlateStream = (function FlateStreamClosure() {
-   var codeLenCodeMap = new Uint32Array([
-     16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
-   ]);
- 
-   var lengthDecode = new Uint32Array([
-     0x00003, 0x00004, 0x00005, 0x00006, 0x00007, 0x00008, 0x00009, 0x0000a,
-     0x1000b, 0x1000d, 0x1000f, 0x10011, 0x20013, 0x20017, 0x2001b, 0x2001f,
-     0x30023, 0x3002b, 0x30033, 0x3003b, 0x40043, 0x40053, 0x40063, 0x40073,
-     0x50083, 0x500a3, 0x500c3, 0x500e3, 0x00102, 0x00102, 0x00102
-   ]);
- 
-   var distDecode = new Uint32Array([
-     0x00001, 0x00002, 0x00003, 0x00004, 0x10005, 0x10007, 0x20009, 0x2000d,
-     0x30011, 0x30019, 0x40021, 0x40031, 0x50041, 0x50061, 0x60081, 0x600c1,
-     0x70101, 0x70181, 0x80201, 0x80301, 0x90401, 0x90601, 0xa0801, 0xa0c01,
-     0xb1001, 0xb1801, 0xc2001, 0xc3001, 0xd4001, 0xd6001
-   ]);
- 
-   var fixedLitCodeTab = [new Uint32Array([
-     0x70100, 0x80050, 0x80010, 0x80118, 0x70110, 0x80070, 0x80030, 0x900c0,
-     0x70108, 0x80060, 0x80020, 0x900a0, 0x80000, 0x80080, 0x80040, 0x900e0,
-     0x70104, 0x80058, 0x80018, 0x90090, 0x70114, 0x80078, 0x80038, 0x900d0,
-     0x7010c, 0x80068, 0x80028, 0x900b0, 0x80008, 0x80088, 0x80048, 0x900f0,
-     0x70102, 0x80054, 0x80014, 0x8011c, 0x70112, 0x80074, 0x80034, 0x900c8,
-     0x7010a, 0x80064, 0x80024, 0x900a8, 0x80004, 0x80084, 0x80044, 0x900e8,
-     0x70106, 0x8005c, 0x8001c, 0x90098, 0x70116, 0x8007c, 0x8003c, 0x900d8,
-     0x7010e, 0x8006c, 0x8002c, 0x900b8, 0x8000c, 0x8008c, 0x8004c, 0x900f8,
-     0x70101, 0x80052, 0x80012, 0x8011a, 0x70111, 0x80072, 0x80032, 0x900c4,
-     0x70109, 0x80062, 0x80022, 0x900a4, 0x80002, 0x80082, 0x80042, 0x900e4,
-     0x70105, 0x8005a, 0x8001a, 0x90094, 0x70115, 0x8007a, 0x8003a, 0x900d4,
-     0x7010d, 0x8006a, 0x8002a, 0x900b4, 0x8000a, 0x8008a, 0x8004a, 0x900f4,
-     0x70103, 0x80056, 0x80016, 0x8011e, 0x70113, 0x80076, 0x80036, 0x900cc,
-     0x7010b, 0x80066, 0x80026, 0x900ac, 0x80006, 0x80086, 0x80046, 0x900ec,
-     0x70107, 0x8005e, 0x8001e, 0x9009c, 0x70117, 0x8007e, 0x8003e, 0x900dc,
-     0x7010f, 0x8006e, 0x8002e, 0x900bc, 0x8000e, 0x8008e, 0x8004e, 0x900fc,
-     0x70100, 0x80051, 0x80011, 0x80119, 0x70110, 0x80071, 0x80031, 0x900c2,
-     0x70108, 0x80061, 0x80021, 0x900a2, 0x80001, 0x80081, 0x80041, 0x900e2,
-     0x70104, 0x80059, 0x80019, 0x90092, 0x70114, 0x80079, 0x80039, 0x900d2,
-     0x7010c, 0x80069, 0x80029, 0x900b2, 0x80009, 0x80089, 0x80049, 0x900f2,
-     0x70102, 0x80055, 0x80015, 0x8011d, 0x70112, 0x80075, 0x80035, 0x900ca,
-     0x7010a, 0x80065, 0x80025, 0x900aa, 0x80005, 0x80085, 0x80045, 0x900ea,
-     0x70106, 0x8005d, 0x8001d, 0x9009a, 0x70116, 0x8007d, 0x8003d, 0x900da,
-     0x7010e, 0x8006d, 0x8002d, 0x900ba, 0x8000d, 0x8008d, 0x8004d, 0x900fa,
-     0x70101, 0x80053, 0x80013, 0x8011b, 0x70111, 0x80073, 0x80033, 0x900c6,
-     0x70109, 0x80063, 0x80023, 0x900a6, 0x80003, 0x80083, 0x80043, 0x900e6,
-     0x70105, 0x8005b, 0x8001b, 0x90096, 0x70115, 0x8007b, 0x8003b, 0x900d6,
-     0x7010d, 0x8006b, 0x8002b, 0x900b6, 0x8000b, 0x8008b, 0x8004b, 0x900f6,
-     0x70103, 0x80057, 0x80017, 0x8011f, 0x70113, 0x80077, 0x80037, 0x900ce,
-     0x7010b, 0x80067, 0x80027, 0x900ae, 0x80007, 0x80087, 0x80047, 0x900ee,
-     0x70107, 0x8005f, 0x8001f, 0x9009e, 0x70117, 0x8007f, 0x8003f, 0x900de,
-     0x7010f, 0x8006f, 0x8002f, 0x900be, 0x8000f, 0x8008f, 0x8004f, 0x900fe,
-     0x70100, 0x80050, 0x80010, 0x80118, 0x70110, 0x80070, 0x80030, 0x900c1,
-     0x70108, 0x80060, 0x80020, 0x900a1, 0x80000, 0x80080, 0x80040, 0x900e1,
-     0x70104, 0x80058, 0x80018, 0x90091, 0x70114, 0x80078, 0x80038, 0x900d1,
-     0x7010c, 0x80068, 0x80028, 0x900b1, 0x80008, 0x80088, 0x80048, 0x900f1,
-     0x70102, 0x80054, 0x80014, 0x8011c, 0x70112, 0x80074, 0x80034, 0x900c9,
-     0x7010a, 0x80064, 0x80024, 0x900a9, 0x80004, 0x80084, 0x80044, 0x900e9,
-     0x70106, 0x8005c, 0x8001c, 0x90099, 0x70116, 0x8007c, 0x8003c, 0x900d9,
-     0x7010e, 0x8006c, 0x8002c, 0x900b9, 0x8000c, 0x8008c, 0x8004c, 0x900f9,
-     0x70101, 0x80052, 0x80012, 0x8011a, 0x70111, 0x80072, 0x80032, 0x900c5,
-     0x70109, 0x80062, 0x80022, 0x900a5, 0x80002, 0x80082, 0x80042, 0x900e5,
-     0x70105, 0x8005a, 0x8001a, 0x90095, 0x70115, 0x8007a, 0x8003a, 0x900d5,
-     0x7010d, 0x8006a, 0x8002a, 0x900b5, 0x8000a, 0x8008a, 0x8004a, 0x900f5,
-     0x70103, 0x80056, 0x80016, 0x8011e, 0x70113, 0x80076, 0x80036, 0x900cd,
-     0x7010b, 0x80066, 0x80026, 0x900ad, 0x80006, 0x80086, 0x80046, 0x900ed,
-     0x70107, 0x8005e, 0x8001e, 0x9009d, 0x70117, 0x8007e, 0x8003e, 0x900dd,
-     0x7010f, 0x8006e, 0x8002e, 0x900bd, 0x8000e, 0x8008e, 0x8004e, 0x900fd,
-     0x70100, 0x80051, 0x80011, 0x80119, 0x70110, 0x80071, 0x80031, 0x900c3,
-     0x70108, 0x80061, 0x80021, 0x900a3, 0x80001, 0x80081, 0x80041, 0x900e3,
-     0x70104, 0x80059, 0x80019, 0x90093, 0x70114, 0x80079, 0x80039, 0x900d3,
-     0x7010c, 0x80069, 0x80029, 0x900b3, 0x80009, 0x80089, 0x80049, 0x900f3,
-     0x70102, 0x80055, 0x80015, 0x8011d, 0x70112, 0x80075, 0x80035, 0x900cb,
-     0x7010a, 0x80065, 0x80025, 0x900ab, 0x80005, 0x80085, 0x80045, 0x900eb,
-     0x70106, 0x8005d, 0x8001d, 0x9009b, 0x70116, 0x8007d, 0x8003d, 0x900db,
-     0x7010e, 0x8006d, 0x8002d, 0x900bb, 0x8000d, 0x8008d, 0x8004d, 0x900fb,
-     0x70101, 0x80053, 0x80013, 0x8011b, 0x70111, 0x80073, 0x80033, 0x900c7,
-     0x70109, 0x80063, 0x80023, 0x900a7, 0x80003, 0x80083, 0x80043, 0x900e7,
-     0x70105, 0x8005b, 0x8001b, 0x90097, 0x70115, 0x8007b, 0x8003b, 0x900d7,
-     0x7010d, 0x8006b, 0x8002b, 0x900b7, 0x8000b, 0x8008b, 0x8004b, 0x900f7,
-     0x70103, 0x80057, 0x80017, 0x8011f, 0x70113, 0x80077, 0x80037, 0x900cf,
-     0x7010b, 0x80067, 0x80027, 0x900af, 0x80007, 0x80087, 0x80047, 0x900ef,
-     0x70107, 0x8005f, 0x8001f, 0x9009f, 0x70117, 0x8007f, 0x8003f, 0x900df,
-     0x7010f, 0x8006f, 0x8002f, 0x900bf, 0x8000f, 0x8008f, 0x8004f, 0x900ff
-   ]), 9];
- 
-   var fixedDistCodeTab = [new Uint32Array([
-     0x50000, 0x50010, 0x50008, 0x50018, 0x50004, 0x50014, 0x5000c, 0x5001c,
-     0x50002, 0x50012, 0x5000a, 0x5001a, 0x50006, 0x50016, 0x5000e, 0x00000,
-     0x50001, 0x50011, 0x50009, 0x50019, 0x50005, 0x50015, 0x5000d, 0x5001d,
-     0x50003, 0x50013, 0x5000b, 0x5001b, 0x50007, 0x50017, 0x5000f, 0x00000
-   ]), 5];
- 
-   function FlateStream(stream) {
-     var bytes = stream.getBytes();
-     var bytesPos = 0;
- 
-     this.dict = stream.dict;
-     var cmf = bytes[bytesPos++];
-     var flg = bytes[bytesPos++];
-     if (cmf == -1 || flg == -1)
-       error('Invalid header in flate stream: ' + cmf + ', ' + flg);
-     if ((cmf & 0x0f) != 0x08)
-       error('Unknown compression method in flate stream: ' + cmf + ', ' + flg);
-     if ((((cmf << 8) + flg) % 31) !== 0)
-       error('Bad FCHECK in flate stream: ' + cmf + ', ' + flg);
-     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);
-   }
- 
-   FlateStream.prototype = Object.create(DecodeStream.prototype);
- 
-   FlateStream.prototype.getBits = function FlateStream_getBits(bits) {
-     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')
-         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;
-   };
++/**
++ * For internal use only.
++ * @ignore
++ */
++var InternalRenderTask = (function InternalRenderTaskClosure() {
 +
-   FlateStream.prototype.getCode = function FlateStream_getCode(table) {
-     var codes = table[0];
-     var maxLen = table[1];
-     var codeSize = this.codeSize;
-     var codeBuf = this.codeBuf;
-     var bytes = this.bytes;
-     var bytesPos = this.bytesPos;
- 
-     while (codeSize < maxLen) {
-       var b;
-       if (typeof (b = bytes[bytesPos++]) == 'undefined')
-         error('Bad encoding in flate stream');
-       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)
-       error('Bad encoding in flate stream');
-     this.codeBuf = (codeBuf >> codeLen);
-     this.codeSize = (codeSize - codeLen);
-     this.bytesPos = bytesPos;
-     return codeVal;
-   };
++  function InternalRenderTask(callback, params, objs, commonObjs, operatorList,
++                              pageNumber) {
++    this.callback = callback;
++    this.params = params;
++    this.objs = objs;
++    this.commonObjs = commonObjs;
++    this.operatorListIdx = null;
++    this.operatorList = operatorList;
++    this.pageNumber = pageNumber;
++    this.running = false;
++    this.graphicsReadyCallback = null;
++    this.graphicsReady = false;
++    this.cancelled = false;
++  }
 +
-   FlateStream.prototype.generateHuffmanTable =
-     function flateStreamGenerateHuffmanTable(lengths) {
-     var n = lengths.length;
++  InternalRenderTask.prototype = {
 +
-     // find max code length
-     var maxLen = 0;
-     for (var i = 0; i < n; ++i) {
-       if (lengths[i] > maxLen)
-         maxLen = lengths[i];
-     }
++    initalizeGraphics:
++        function InternalRenderTask_initalizeGraphics(transparency) {
 +
-     // build the table
-     var size = 1 << maxLen;
-     var codes = new Uint32Array(size);
-     for (var len = 1, code = 0, skip = 2;
-          len <= maxLen;
-          ++len, code <<= 1, skip <<= 1) {
-       for (var val = 0; val < n; ++val) {
-         if (lengths[val] == len) {
-           // bit-reverse the code
-           var code2 = 0;
-           var t = code;
-           for (var i = 0; i < len; ++i) {
-             code2 = (code2 << 1) | (t & 1);
-             t >>= 1;
-           }
++      if (this.cancelled) {
++        return;
++      }
++      if (PDFJS.pdfBug && 'StepperManager' in globalScope &&
++          globalScope.StepperManager.enabled) {
++        this.stepper = globalScope.StepperManager.create(this.pageNumber - 1);
++        this.stepper.init(this.operatorList);
++        this.stepper.nextBreakPoint = this.stepper.getNextBreakPoint();
++      }
 +
-           // fill the table entries
-           for (var i = code2; i < size; i += skip)
-             codes[i] = (len << 16) | val;
++      var params = this.params;
++      this.gfx = new CanvasGraphics(params.canvasContext, this.commonObjs,
++                                    this.objs, params.textLayer,
++                                    params.imageLayer);
 +
-           ++code;
-         }
++      this.gfx.beginDrawing(params.viewport, transparency);
++      this.operatorListIdx = 0;
++      this.graphicsReady = true;
++      if (this.graphicsReadyCallback) {
++        this.graphicsReadyCallback();
 +      }
-     }
++    },
 +
-     return [codes, maxLen];
-   };
++    cancel: function InternalRenderTask_cancel() {
++      this.running = false;
++      this.cancelled = true;
++      this.callback('cancelled');
++    },
 +
-   FlateStream.prototype.readBlock = function FlateStream_readBlock() {
-     // read block header
-     var hdr = this.getBits(3);
-     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')
-         error('Bad block header in flate stream');
-       var blockLen = b;
-       if (typeof (b = bytes[bytesPos++]) == 'undefined')
-         error('Bad block header in flate stream');
-       blockLen |= (b << 8);
-       if (typeof (b = bytes[bytesPos++]) == 'undefined')
-         error('Bad block header in flate stream');
-       var check = b;
-       if (typeof (b = bytes[bytesPos++]) == 'undefined')
-         error('Bad block header in flate stream');
-       check |= (b << 8);
-       if (check != (~blockLen & 0xffff))
-         error('Bad uncompressed block length in flate stream');
- 
-       this.codeBuf = 0;
-       this.codeSize = 0;
- 
-       var bufferLength = this.bufferLength;
-       var buffer = this.ensureBuffer(bufferLength + blockLen);
-       var end = bufferLength + blockLen;
-       this.bufferLength = end;
-       for (var n = bufferLength; n < end; ++n) {
-         if (typeof (b = bytes[bytesPos++]) == 'undefined') {
-           this.eof = true;
-           break;
++    operatorListChanged: function InternalRenderTask_operatorListChanged() {
++      if (!this.graphicsReady) {
++        if (!this.graphicsReadyCallback) {
++          this.graphicsReadyCallback = this._continue.bind(this);
 +        }
-         buffer[n] = b;
++        return;
 +      }
-       this.bytesPos = bytesPos;
-       return;
-     }
- 
-     var litCodeTable;
-     var distCodeTable;
-     if (hdr == 1) { // compressed block, fixed codes
-       litCodeTable = fixedLitCodeTab;
-       distCodeTable = fixedDistCodeTab;
-     } 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;
- 
-       // build the code lengths code table
-       var codeLenCodeLengths = new Uint8Array(codeLenCodeMap.length);
- 
-       for (var 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;
-       var codes = numLitCodes + numDistCodes;
-       var codeLengths = new Uint8Array(codes);
-       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);
-         } else {
-           codeLengths[i++] = len = code;
-           continue;
-         }
 +
-         var repeatLength = this.getBits(bitsLength) + bitsOffset;
-         while (repeatLength-- > 0)
-           codeLengths[i++] = what;
++      if (this.stepper) {
++        this.stepper.updateOperatorList(this.operatorList);
 +      }
 +
-       litCodeTable =
-         this.generateHuffmanTable(codeLengths.subarray(0, numLitCodes));
-       distCodeTable =
-         this.generateHuffmanTable(codeLengths.subarray(numLitCodes, codes));
-     } else {
-       error('Unknown block type in flate stream');
-     }
++      if (this.running) {
++        return;
++      }
++      this._continue();
++    },
 +
-     var buffer = this.buffer;
-     var limit = buffer ? buffer.length : 0;
-     var pos = this.bufferLength;
-     while (true) {
-       var code1 = this.getCode(litCodeTable);
-       if (code1 < 256) {
-         if (pos + 1 >= limit) {
-           buffer = this.ensureBuffer(pos + 1);
-           limit = buffer.length;
-         }
-         buffer[pos++] = code1;
-         continue;
++    _continue: function InternalRenderTask__continue() {
++      this.running = true;
++      if (this.cancelled) {
++        return;
++      }
++      if (this.params.continueCallback) {
++        this.params.continueCallback(this._next.bind(this));
++      } else {
++        this._next();
 +      }
-       if (code1 == 256) {
-         this.bufferLength = pos;
++    },
++
++    _next: function InternalRenderTask__next() {
++      if (this.cancelled) {
 +        return;
 +      }
-       code1 -= 257;
-       code1 = lengthDecode[code1];
-       var code2 = code1 >> 16;
-       if (code2 > 0)
-         code2 = this.getBits(code2);
-       var len = (code1 & 0xffff) + code2;
-       code1 = this.getCode(distCodeTable);
-       code1 = distDecode[code1];
-       code2 = code1 >> 16;
-       if (code2 > 0)
-         code2 = this.getBits(code2);
-       var dist = (code1 & 0xffff) + code2;
-       if (pos + len >= limit) {
-         buffer = this.ensureBuffer(pos + len);
-         limit = buffer.length;
++      this.operatorListIdx = this.gfx.executeOperatorList(this.operatorList,
++                                        this.operatorListIdx,
++                                        this._continue.bind(this),
++                                        this.stepper);
++      if (this.operatorListIdx === this.operatorList.argsArray.length) {
++        this.running = false;
++        if (this.operatorList.lastChunk) {
++          this.gfx.endDrawing();
++          this.callback();
++        }
 +      }
-       for (var k = 0; k < len; ++k, ++pos)
-         buffer[pos] = buffer[pos - dist];
 +    }
++
 +  };
 +
-   return FlateStream;
++  return InternalRenderTask;
 +})();
 +
- var PredictorStream = (function PredictorStreamClosure() {
-   function PredictorStream(stream, params) {
-     var predictor = this.predictor = params.get('Predictor') || 1;
 +
-     if (predictor <= 1)
-       return stream; // no prediction
-     if (predictor !== 2 && (predictor < 10 || predictor > 15))
-       error('Unsupported predictor: ' + predictor);
- 
-     if (predictor === 2)
-       this.readBlock = this.readBlockTiff;
-     else
-       this.readBlock = this.readBlockPng;
- 
-     this.stream = stream;
-     this.dict = stream.dict;
++var Metadata = PDFJS.Metadata = (function MetadataClosure() {
++  function fixMetadata(meta) {
++    return meta.replace(/>\\376\\377([^<]+)/g, function(all, codes) {
++      var bytes = codes.replace(/\\([0-3])([0-7])([0-7])/g,
++                                function(code, d1, d2, d3) {
++        return String.fromCharCode(d1 * 64 + d2 * 8 + d3 * 1);
++      });
++      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) :
++          '&#x' + (0x10000 + code).toString(16).substring(1) + ';';
++      }
++      return '>' + chars;
++    });
++  }
 +
-     var colors = this.colors = params.get('Colors') || 1;
-     var bits = this.bits = params.get('BitsPerComponent') || 8;
-     var columns = this.columns = params.get('Columns') || 1;
++  function Metadata(meta) {
++    if (typeof meta === 'string') {
++      // Ghostscript produces invalid metadata
++      meta = fixMetadata(meta);
 +
-     this.pixBytes = (colors * bits + 7) >> 3;
-     this.rowBytes = (columns * colors * bits + 7) >> 3;
++      var parser = new DOMParser();
++      meta = parser.parseFromString(meta, 'application/xml');
++    } else if (!(meta instanceof Document)) {
++      error('Metadata: Invalid metadata object');
++    }
 +
-     DecodeStream.call(this);
-     return this;
++    this.metaDocument = meta;
++    this.metadata = {};
++    this.parse();
 +  }
 +
-   PredictorStream.prototype = Object.create(DecodeStream.prototype);
- 
-   PredictorStream.prototype.readBlockTiff =
-     function predictorStreamReadBlockTiff() {
-     var rowBytes = this.rowBytes;
++  Metadata.prototype = {
++    parse: function Metadata_parse() {
++      var doc = this.metaDocument;
++      var rdf = doc.documentElement;
 +
-     var bufferLength = this.bufferLength;
-     var buffer = this.ensureBuffer(bufferLength + rowBytes);
++      if (rdf.nodeName.toLowerCase() !== 'rdf:rdf') { // Wrapped in <xmpmeta>
++        rdf = rdf.firstChild;
++        while (rdf && rdf.nodeName.toLowerCase() !== 'rdf:rdf')
++          rdf = rdf.nextSibling;
++      }
 +
-     var bits = this.bits;
-     var colors = this.colors;
++      var nodeName = (rdf) ? rdf.nodeName.toLowerCase() : null;
++      if (!rdf || nodeName !== 'rdf:rdf' || !rdf.hasChildNodes())
++        return;
 +
-     var rawBytes = this.stream.getBytes(rowBytes);
++      var children = rdf.childNodes, desc, entry, name, i, ii, length, iLength;
 +
-     var inbuf = 0, outbuf = 0;
-     var inbits = 0, outbits = 0;
-     var pos = bufferLength;
++      for (i = 0, length = children.length; i < length; i++) {
++        desc = children[i];
++        if (desc.nodeName.toLowerCase() !== 'rdf:description')
++          continue;
 +
-     if (bits === 1) {
-       for (var i = 0; i < rowBytes; ++i) {
-         var c = rawBytes[i];
-         inbuf = (inbuf << 8) | c;
-         // bitwise addition is exclusive or
-         // first shift inbuf and then add
-         buffer[pos++] = (c ^ (inbuf >> colors)) & 0xFF;
-         // truncate inbuf (assumes colors < 16)
-         inbuf &= 0xFFFF;
-       }
-     } else if (bits === 8) {
-       for (var i = 0; i < colors; ++i)
-         buffer[pos++] = rawBytes[i];
-       for (; i < rowBytes; ++i) {
-         buffer[pos] = buffer[pos - colors] + rawBytes[i];
-         pos++;
-       }
-     } else {
-       var compArray = new Uint8Array(colors + 1);
-       var bitMask = (1 << bits) - 1;
-       var j = 0, k = bufferLength;
-       var columns = this.columns;
-       for (var i = 0; i < columns; ++i) {
-         for (var kk = 0; kk < colors; ++kk) {
-           if (inbits < bits) {
-             inbuf = (inbuf << 8) | (rawBytes[j++] & 0xFF);
-             inbits += 8;
-           }
-           compArray[kk] = (compArray[kk] +
-                            (inbuf >> (inbits - bits))) & bitMask;
-           inbits -= bits;
-           outbuf = (outbuf << bits) | compArray[kk];
-           outbits += bits;
-           if (outbits >= 8) {
-             buffer[k++] = (outbuf >> (outbits - 8)) & 0xFF;
-             outbits -= 8;
++        for (ii = 0, iLength = desc.childNodes.length; ii < iLength; ii++) {
++          if (desc.childNodes[ii].nodeName.toLowerCase() !== '#text') {
++            entry = desc.childNodes[ii];
++            name = entry.nodeName.toLowerCase();
++            this.metadata[name] = entry.textContent.trim();
 +          }
 +        }
 +      }
-       if (outbits > 0) {
-         buffer[k++] = (outbuf << (8 - outbits)) +
-         (inbuf & ((1 << (8 - outbits)) - 1));
-       }
++    },
++
++    get: function Metadata_get(name) {
++      return this.metadata[name] || null;
++    },
++
++    has: function Metadata_has(name) {
++      return typeof this.metadata[name] !== 'undefined';
 +    }
-     this.bufferLength += rowBytes;
 +  };
 +
-   PredictorStream.prototype.readBlockPng =
-     function predictorStreamReadBlockPng() {
++  return Metadata;
++})();
++
++
++// <canvas> contexts store most of the state we need natively.
++// However, PDF needs a bit more state, which we store here.
++
++// Minimal font size that would be used during canvas fillText operations.
++var MIN_FONT_SIZE = 16;
 +
-     var rowBytes = this.rowBytes;
-     var pixBytes = this.pixBytes;
++var COMPILE_TYPE3_GLYPHS = true;
 +
-     var predictor = this.stream.getByte();
-     var rawBytes = this.stream.getBytes(rowBytes);
++function createScratchCanvas(width, height) {
++  var canvas = document.createElement('canvas');
++  canvas.width = width;
++  canvas.height = height;
++  return canvas;
++}
 +
-     var bufferLength = this.bufferLength;
-     var buffer = this.ensureBuffer(bufferLength + rowBytes);
++function addContextCurrentTransform(ctx) {
++  // If the context doesn't expose a `mozCurrentTransform`, add a JS based on.
++  if (!ctx.mozCurrentTransform) {
++    // Store the original context
++    ctx._scaleX = ctx._scaleX || 1.0;
++    ctx._scaleY = ctx._scaleY || 1.0;
++    ctx._originalSave = ctx.save;
++    ctx._originalRestore = ctx.restore;
++    ctx._originalRotate = ctx.rotate;
++    ctx._originalScale = ctx.scale;
++    ctx._originalTranslate = ctx.translate;
++    ctx._originalTransform = ctx.transform;
++    ctx._originalSetTransform = ctx.setTransform;
 +
-     var prevRow = buffer.subarray(bufferLength - rowBytes, bufferLength);
-     if (prevRow.length === 0)
-       prevRow = new Uint8Array(rowBytes);
++    ctx._transformMatrix = [ctx._scaleX, 0, 0, ctx._scaleY, 0, 0];
++    ctx._transformStack = [];
 +
-     var j = bufferLength;
-     switch (predictor) {
-       case 0:
-         for (var i = 0; i < rowBytes; ++i)
-           buffer[j++] = rawBytes[i];
-         break;
-       case 1:
-         for (var 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)
-           buffer[j++] = (prevRow[i] + rawBytes[i]) & 0xFF;
-         break;
-       case 3:
-         for (var 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;
-           j++;
-         }
-         break;
-       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];
-           buffer[j++] = up + c;
-         }
-         for (; i < rowBytes; ++i) {
-           var 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)
-             pa = -pa;
-           var pb = p - up;
-           if (pb < 0)
-             pb = -pb;
-           var pc = p - upLeft;
-           if (pc < 0)
-             pc = -pc;
- 
-           var c = rawBytes[i];
-           if (pa <= pb && pa <= pc)
-             buffer[j++] = left + c;
-           else if (pb <= pc)
-             buffer[j++] = up + c;
-           else
-             buffer[j++] = upLeft + c;
-         }
-         break;
-       default:
-         error('Unsupported predictor: ' + predictor);
-     }
-     this.bufferLength += rowBytes;
-   };
++    Object.defineProperty(ctx, 'mozCurrentTransform', {
++      get: function getCurrentTransform() {
++        return this._transformMatrix;
++      }
++    });
 +
-   return PredictorStream;
- })();
++    Object.defineProperty(ctx, 'mozCurrentTransformInverse', {
++      get: function getCurrentTransformInverse() {
++        // Calculation done using WolframAlpha:
++        // http://www.wolframalpha.com/input/?
++        //   i=Inverse+{{a%2C+c%2C+e}%2C+{b%2C+d%2C+f}%2C+{0%2C+0%2C+1}}
 +
- /**
-  * Depending on the type of JPEG a JpegStream is handled in different ways. For
-  * JPEG's that are supported natively such as DeviceGray and DeviceRGB the image
-  * data is stored and then loaded by the browser.  For unsupported JPEG's we use
-  * a library to decode these images and the stream behaves like all the other
-  * DecodeStreams.
-  */
- var JpegStream = (function JpegStreamClosure() {
-   function isAdobeImage(bytes) {
-     var maxBytesScanned = Math.max(bytes.length - 16, 1024);
-     // Looking for APP14, 'Adobe'
-     for (var i = 0; i < maxBytesScanned; ++i) {
-       if (bytes[i] == 0xFF && bytes[i + 1] == 0xEE &&
-           bytes[i + 2] === 0x00 && bytes[i + 3] == 0x0E &&
-           bytes[i + 4] == 0x41 && bytes[i + 5] == 0x64 &&
-           bytes[i + 6] == 0x6F && bytes[i + 7] == 0x62 &&
-           bytes[i + 8] == 0x65 && bytes[i + 9] === 0x00)
-           return true;
-       // scanning until frame tag
-       if (bytes[i] == 0xFF && bytes[i + 1] == 0xC0)
-         break;
-     }
-     return false;
-   }
++        var m = this._transformMatrix;
++        var a = m[0], b = m[1], c = m[2], d = m[3], e = m[4], f = m[5];
++
++        var ad_bc = a * d - b * c;
++        var bc_ad = b * c - a * d;
++
++        return [
++          d / ad_bc,
++          b / bc_ad,
++          c / bc_ad,
++          a / ad_bc,
++          (d * e - c * f) / bc_ad,
++          (b * e - a * f) / ad_bc
++        ];
++      }
++    });
 +
-   function fixAdobeImage(bytes) {
-     // Inserting 'EMBED' marker after JPEG signature
-     var embedMarker = new Uint8Array([0xFF, 0xEC, 0, 8, 0x45, 0x4D, 0x42, 0x45,
-                                       0x44, 0]);
-     var newBytes = new Uint8Array(bytes.length + embedMarker.length);
-     newBytes.set(bytes, embedMarker.length);
-     // copy JPEG header
-     newBytes[0] = bytes[0];
-     newBytes[1] = bytes[1];
-     newBytes.set(embedMarker, 2);
-     return newBytes;
-   }
++    ctx.save = function ctxSave() {
++      var old = this._transformMatrix;
++      this._transformStack.push(old);
++      this._transformMatrix = old.slice(0, 6);
 +
-   function JpegStream(bytes, dict, xref) {
-     // TODO: per poppler, some images may have 'junk' before that
-     // need to be removed
-     this.dict = dict;
++      this._originalSave();
++    };
 +
-     this.isAdobeImage = false;
-     this.colorTransform = dict.get('ColorTransform') || -1;
++    ctx.restore = function ctxRestore() {
++      var prev = this._transformStack.pop();
++      if (prev) {
++        this._transformMatrix = prev;
++        this._originalRestore();
++      }
++    };
 +
-     if (isAdobeImage(bytes)) {
-       this.isAdobeImage = true;
-       bytes = fixAdobeImage(bytes);
-     }
++    ctx.translate = function ctxTranslate(x, y) {
++      var m = this._transformMatrix;
++      m[4] = m[0] * x + m[2] * y + m[4];
++      m[5] = m[1] * x + m[3] * y + m[5];
 +
-     this.bytes = bytes;
++      this._originalTranslate(x, y);
++    };
 +
-     DecodeStream.call(this);
-   }
++    ctx.scale = function ctxScale(x, y) {
++      var m = this._transformMatrix;
++      m[0] = m[0] * x;
++      m[1] = m[1] * x;
++      m[2] = m[2] * y;
++      m[3] = m[3] * y;
 +
-   JpegStream.prototype = Object.create(DecodeStream.prototype);
++      this._originalScale(x, y);
++    };
 +
-   JpegStream.prototype.ensureBuffer = function JpegStream_ensureBuffer(req) {
-     if (this.bufferLength)
-       return;
-     try {
-       var jpegImage = new JpegImage();
-       if (this.colorTransform != -1)
-         jpegImage.colorTransform = this.colorTransform;
-       jpegImage.parse(this.bytes);
-       var width = jpegImage.width;
-       var height = jpegImage.height;
-       var data = jpegImage.getData(width, height);
-       this.buffer = data;
-       this.bufferLength = data.length;
-     } catch (e) {
-       error('JPEG error: ' + e);
-     }
-   };
-   JpegStream.prototype.getIR = function JpegStream_getIR() {
-     return bytesToString(this.bytes);
-   };
-   JpegStream.prototype.getChar = function JpegStream_getChar() {
-     error('internal error: getChar is not valid on JpegStream');
-   };
-   /**
-    * Checks if the image can be decoded and displayed by the browser without any
-    * further processing such as color space conversions.
-    */
-   JpegStream.prototype.isNativelySupported =
-     function JpegStream_isNativelySupported(xref, res) {
-     var cs = ColorSpace.parse(this.dict.get('ColorSpace', 'CS'), xref, res);
-     // when bug 674619 lands, let's check if browser can do
-     // normal cmyk and then we won't need to decode in JS
-     if (cs.name === 'DeviceGray' || cs.name === 'DeviceRGB')
-       return true;
-     if (cs.name === 'DeviceCMYK' && !this.isAdobeImage &&
-         this.colorTransform < 1)
-       return true;
-     return false;
-   };
-   /**
-    * Checks if the image can be decoded by the browser.
-    */
-   JpegStream.prototype.isNativelyDecodable =
-     function JpegStream_isNativelyDecodable(xref, res) {
-     var cs = ColorSpace.parse(this.dict.get('ColorSpace', 'CS'), xref, res);
-     var numComps = cs.numComps;
-     if (numComps == 1 || numComps == 3)
-       return true;
++    ctx.transform = function ctxTransform(a, b, c, d, e, f) {
++      var m = this._transformMatrix;
++      this._transformMatrix = [
++        m[0] * a + m[2] * b,
++        m[1] * a + m[3] * b,
++        m[0] * c + m[2] * d,
++        m[1] * c + m[3] * d,
++        m[0] * e + m[2] * f + m[4],
++        m[1] * e + m[3] * f + m[5]
++      ];
 +
-     return false;
-   };
++      ctx._originalTransform(a, b, c, d, e, f);
++    };
 +
-   return JpegStream;
- })();
++    ctx.setTransform = function ctxSetTransform(a, b, c, d, e, f) {
++      this._transformMatrix = [a, b, c, d, e, f];
 +
- /**
-  * For JPEG 2000's we use a library to decode these images and
-  * the stream behaves like all the other DecodeStreams.
-  */
- var JpxStream = (function JpxStreamClosure() {
-   function JpxStream(bytes, dict) {
-     this.dict = dict;
-     this.bytes = bytes;
++      ctx._originalSetTransform(a, b, c, d, e, f);
++    };
 +
-     DecodeStream.call(this);
-   }
++    ctx.rotate = function ctxRotate(angle) {
++      var cosValue = Math.cos(angle);
++      var sinValue = Math.sin(angle);
 +
-   JpxStream.prototype = Object.create(DecodeStream.prototype);
++      var m = this._transformMatrix;
++      this._transformMatrix = [
++        m[0] * cosValue + m[2] * sinValue,
++        m[1] * cosValue + m[3] * sinValue,
++        m[0] * (-sinValue) + m[2] * cosValue,
++        m[1] * (-sinValue) + m[3] * cosValue,
++        m[4],
++        m[5]
++      ];
 +
-   JpxStream.prototype.ensureBuffer = function JpxStream_ensureBuffer(req) {
-     if (this.bufferLength)
-       return;
++      this._originalRotate(angle);
++    };
++  }
++}
 +
-     var jpxImage = new JpxImage();
-     jpxImage.parse(this.bytes);
- 
-     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 data = new Uint8Array(width * height * componentsCount);
- 
-     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 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;
++var CachedCanvases = (function CachedCanvasesClosure() {
++  var cache = {};
++  return {
++    getCanvas: function CachedCanvases_getCanvas(id, width, height,
++                                                 trackTransform) {
++      var canvasEntry;
++      if (id in cache) {
++        canvasEntry = cache[id];
++        canvasEntry.canvas.width = width;
++        canvasEntry.canvas.height = height;
++        // reset canvas transform for emulated mozCurrentTransform, if needed
++        canvasEntry.context.setTransform(1, 0, 0, 1, 0, 0);
++      } else {
++        var canvas = createScratchCanvas(width, height);
++        var ctx = canvas.getContext('2d');
++        if (trackTransform) {
++          addContextCurrentTransform(ctx);
++        }
++        cache[id] = canvasEntry = {canvas: canvas, context: ctx};
 +      }
++      return canvasEntry;
++    },
++    clear: function () {
++      cache = {};
 +    }
- 
-     this.buffer = data;
-     this.bufferLength = data.length;
-   };
-   JpxStream.prototype.getChar = function JpxStream_getChar() {
-     error('internal error: getChar is not valid on JpxStream');
 +  };
- 
-   return JpxStream;
 +})();
 +
- /**
-  * For JBIG2's we use a library to decode these images and
-  * the stream behaves like all the other DecodeStreams.
-  */
- var Jbig2Stream = (function Jbig2StreamClosure() {
-   function Jbig2Stream(bytes, dict) {
-     this.dict = dict;
-     this.bytes = bytes;
- 
-     DecodeStream.call(this);
++function compileType3Glyph(imgData) {
++  var POINT_TO_PROCESS_LIMIT = 1000;
++
++  var width = imgData.width, height = imgData.height;
++  var i, j, j0, width1 = width + 1;
++  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:
++  //   4 | 8
++  //   --P--
++  //   2 | 1
++  // We are interested only in points with the flags:
++  //   - outside corners: 1, 2, 4, 8;
++  //   - inside corners: 7, 11, 13, 14;
++  //   - and, intersections: 5, 10.
++  var count = 0;
++  pos = 0;
++  if (data[pos] !== 0) {
++    points[0] = 1;
++    ++count;
++  }
++  for (j = 1; j < width; j++) {
++    if (data[pos] !== data[pos + 1]) {
++      points[j] = data[pos] ? 2 : 1;
++      ++count;
++    }
++    pos++;
++  }
++  if (data[pos] !== 0) {
++    points[j] = 2;
++    ++count;
++  }
++  for (i = 1; i < height; i++) {
++    pos = i * lineSize;
++    j0 = i * width1;
++    if (data[pos - lineSize] !== data[pos]) {
++      points[j0] = data[pos] ? 1 : 8;
++      ++count;
++    }
++    // 'sum' is the position of the current pixel configuration in the 'TYPES'
++    // 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 + 1] ? 4 : 0) +
++            (data[pos - lineSize + 1] ? 8 : 0);
++      if (POINT_TYPES[sum]) {
++        points[j0 + j] = POINT_TYPES[sum];
++        ++count;
++      }
++      pos++;
++    }
++    if (data[pos - lineSize] !== data[pos]) {
++      points[j0 + j] = data[pos] ? 2 : 4;
++      ++count;
++    }
++
++    if (count > POINT_TO_PROCESS_LIMIT) {
++      return null;
++    }
 +  }
 +
-   Jbig2Stream.prototype = Object.create(DecodeStream.prototype);
- 
-   Jbig2Stream.prototype.ensureBuffer = function Jbig2Stream_ensureBuffer(req) {
-     if (this.bufferLength)
-       return;
- 
-     var jbig2Image = new Jbig2Image();
- 
-     var chunks = [], decodeParams = this.dict.get('DecodeParms');
-     if (decodeParams && decodeParams.has('JBIG2Globals')) {
-       var globalsStream = decodeParams.get('JBIG2Globals');
-       var globals = globalsStream.getBytes();
-       chunks.push({data: globals, start: 0, end: globals.length});
++  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 + 1]) {
++      points[j0 + j] = data[pos] ? 4 : 8;
++      ++count;
 +    }
-     chunks.push({data: this.bytes, start: 0, end: this.bytes.length});
-     var data = jbig2Image.parseChunks(chunks);
-     var dataLength = data.length;
- 
-     // JBIG2 had black as 1 and white as 0, inverting the colors
-     for (var i = 0; i < dataLength; i++)
-       data[i] ^= 0xFF;
- 
-     this.buffer = data;
-     this.bufferLength = dataLength;
-   };
-   Jbig2Stream.prototype.getChar = function Jbig2Stream_getChar() {
-     error('internal error: getChar is not valid on Jbig2Stream');
-   };
++    pos++;
++  }
++  if (data[pos] !== 0) {
++    points[j0 + j] = 4;
++    ++count;
++  }
++  if (count > POINT_TO_PROCESS_LIMIT) {
++    return null;
++  }
 +
-   return Jbig2Stream;
- })();
++  // building outlines
++  var steps = new Int32Array([0, width1, -1, 0, -width1, 0, 0, 0, 1]);
++  var outlines = [];
++  for (i = 0; count && i <= height; i++) {
++    var p = i * width1;
++    var end = p + width;
++    while (p < end && !points[p]) {
++      p++;
++    }
++    if (p === end) {
++      continue;
++    }
++    var coords = [p % width1, i];
++
++    var type = points[p], p0 = p, pp;
++    do {
++      var step = steps[type];
++      do { p += step; } while (!points[p]);
++
++      pp = points[p];
++      if (pp !== 5 && pp !== 10) {
++        // set new direction
++        type = pp;
++        // delete mark
++        points[p] = 0;
++      } else { // type is 5 or 10, ie, a crossing
++        // set new direction
++        type = pp & ((0x33 * type) >> 4);
++        // set new type for "future hit"
++        points[p] &= (type >> 2 | type << 2);
++      }
++
++      coords.push(p % width1);
++      coords.push((p / width1) | 0);
++      --count;
++    } while (p0 !== p);
++    outlines.push(coords);
++    --i;
++  }
++
++  var drawOutline = function(c) {
++    c.save();
++    // the path shall be painted in [0..1]x[0..1] space
++    c.scale(1 / width, -1 / height);
++    c.translate(0, -height);
++    c.beginPath();
++    for (var i = 0, ii = outlines.length; i < ii; i++) {
++      var o = outlines[i];
++      c.moveTo(o[0], o[1]);
++      for (var j = 2, jj = o.length; j < jj; j += 2) {
++        c.lineTo(o[j], o[j+1]);
++      }
++    }
++    c.fill();
++    c.beginPath();
++    c.restore();
++  };
++
++  return drawOutline;
++}
 +
- var DecryptStream = (function DecryptStreamClosure() {
-   function DecryptStream(str, decrypt) {
-     this.str = str;
-     this.dict = str.dict;
-     this.decrypt = decrypt;
++var CanvasExtraState = (function CanvasExtraStateClosure() {
++  function CanvasExtraState(old) {
++    // Are soft masks and alpha values shapes or opacities?
++    this.alphaIsShape = false;
++    this.fontSize = 0;
++    this.fontSizeScale = 1;
++    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.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';
++    // Note: fill alpha applies to all non-stroking operations
++    this.fillAlpha = 1;
++    this.strokeAlpha = 1;
++    this.lineWidth = 1;
++    this.activeSMask = null; // nonclonable field (see the save method below)
 +
-     DecodeStream.call(this);
++    this.old = old;
 +  }
 +
-   var chunkSize = 512;
- 
-   DecryptStream.prototype = Object.create(DecodeStream.prototype);
- 
-   DecryptStream.prototype.readBlock = function DecryptStream_readBlock() {
-     var chunk = this.str.getBytes(chunkSize);
-     if (!chunk || chunk.length === 0) {
-       this.eof = true;
-       return;
++  CanvasExtraState.prototype = {
++    clone: function CanvasExtraState_clone() {
++      return Object.create(this);
++    },
++    setCurrentPoint: function CanvasExtraState_setCurrentPoint(x, y) {
++      this.x = x;
++      this.y = y;
 +    }
-     var decrypt = this.decrypt;
-     chunk = decrypt(chunk);
- 
-     var bufferLength = this.bufferLength;
-     var i, n = chunk.length;
-     var buffer = this.ensureBuffer(bufferLength + n);
-     for (i = 0; i < n; i++)
-       buffer[bufferLength++] = chunk[i];
-     this.bufferLength = bufferLength;
 +  };
- 
-   return DecryptStream;
++  return CanvasExtraState;
 +})();
 +
- var Ascii85Stream = (function Ascii85StreamClosure() {
-   function Ascii85Stream(str) {
-     this.str = str;
-     this.dict = str.dict;
-     this.input = new Uint8Array(5);
++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;
 +
-     DecodeStream.call(this);
++  function CanvasGraphics(canvasCtx, commonObjs, objs, textLayer, imageLayer) {
++    this.ctx = canvasCtx;
++    this.current = new CanvasExtraState();
++    this.stateStack = [];
++    this.pendingClip = null;
++    this.pendingEOFill = false;
++    this.res = null;
++    this.xobjs = null;
++    this.commonObjs = commonObjs;
++    this.objs = objs;
++    this.textLayer = textLayer;
++    this.imageLayer = imageLayer;
++    this.groupStack = [];
++    this.processingType3 = null;
++    // Patterns are painted relative to the initial page/form transform, see pdf
++    // spec 8.7.2 NOTE 1.
++    this.baseTransform = null;
++    this.baseTransformStack = [];
++    this.groupLevel = 0;
++    this.smaskStack = [];
++    this.smaskCounter = 0;
++    this.tempSMask = null;
++    if (canvasCtx) {
++      addContextCurrentTransform(canvasCtx);
++    }
 +  }
 +
-   Ascii85Stream.prototype = Object.create(DecodeStream.prototype);
- 
-   Ascii85Stream.prototype.readBlock = function Ascii85Stream_readBlock() {
-     var tildaCode = '~'.charCodeAt(0);
-     var zCode = 'z'.charCodeAt(0);
-     var str = this.str;
- 
-     var c = str.getByte();
-     while (Lexer.isSpace(String.fromCharCode(c)))
-       c = str.getByte();
- 
-     if (!c || c === tildaCode) {
-       this.eof = true;
++  function putBinaryImageData(ctx, imgData) {
++    if (typeof ImageData !== 'undefined' && imgData instanceof ImageData) {
++      ctx.putImageData(imgData, 0, 0);
 +      return;
 +    }
 +
-     var bufferLength = this.bufferLength, buffer;
++    // 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 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;
++
++    // 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 destDataLength = dest.length;
++      var srcLength = src.byteLength;
++      for (var i = 3; i < destDataLength; i += 4) {
++        dest[i] = 255;
++      }
++      for (var i = 0; i < totalChunks; i++) {
++        var thisChunkHeight =
++          (i < fullChunks) ? fullChunkHeight : partialChunkHeight;
++        var destPos = 0;
++        for (var j = 0; j < thisChunkHeight; j++) {
++          var mask = 0;
++          var srcByte = 0;
++          for (var k = 0; k < width; k++, destPos += 4) {
++            if (mask === 0) {
++              if (srcPos >= srcLength) {
++                break;
++              }
++              srcByte = src[srcPos++];
++              mask = 128;
++            }
 +
-     // special code for z
-     if (c == zCode) {
-       buffer = this.ensureBuffer(bufferLength + 4);
-       for (var 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) {
-         c = str.getByte();
-         while (Lexer.isSpace(String.fromCharCode(c)))
-           c = str.getByte();
++            if ((srcByte & mask)) {
++              dest[destPos] = 255;
++              dest[destPos + 1] = 255;
++              dest[destPos + 2] = 255;
++            } else {
++              dest[destPos] = 0;
++              dest[destPos + 1] = 0;
++              dest[destPos + 2] = 0;
++            }
 +
-         input[i] = c;
++            mask >>= 1;
++          }
++        }
++        if (destPos < destDataLength) {
++          // We ran out of input. Make all remaining pixels transparent.
++          destPos += 3;
++          do {
++            dest[destPos] = 0;
++            destPos += 4;
++          } while (destPos < destDataLength);
++        }
 +
-         if (!c || c == tildaCode)
-           break;
++        ctx.putImageData(chunkImgData, 0, i * fullChunkHeight);
 +      }
-       buffer = this.ensureBuffer(bufferLength + i - 1);
-       this.bufferLength += i - 1;
- 
-       // partial ending;
-       if (i < 5) {
-         for (; i < 5; ++i)
-           input[i] = 0x21 + 84;
-         this.eof = true;
-       }
-       var t = 0;
-       for (var i = 0; i < 5; ++i)
-         t = t * 85 + (input[i] - 0x21);
 +
-       for (var i = 3; i >= 0; --i) {
-         buffer[bufferLength + i] = t & 0xFF;
-         t >>= 8;
-       }
-     }
-   };
++    } else if (imgData.kind === ImageKind.RGBA_32BPP) {
++      // RGBA, 32-bits per pixel.
++      var haveSetAndSubarray = 'set' in dest && 'subarray' in src;
 +
-   return Ascii85Stream;
- })();
++      for (var i = 0; i < totalChunks; i++) {
++        var thisChunkHeight =
++          (i < fullChunks) ? fullChunkHeight : partialChunkHeight;
++        var elemsInThisChunk = imgData.width * thisChunkHeight * 4;
++        if (haveSetAndSubarray) {
++          dest.set(src.subarray(srcPos, srcPos + elemsInThisChunk));
++          srcPos += elemsInThisChunk;
++        } else {
++          for (var j = 0; j < elemsInThisChunk; j++) {
++            dest[j] = src[srcPos++];
++          }
++        }
++        ctx.putImageData(chunkImgData, 0, i * fullChunkHeight);
++      }
 +
- var AsciiHexStream = (function AsciiHexStreamClosure() {
-   function AsciiHexStream(str) {
-     this.str = str;
-     this.dict = str.dict;
++    } else if (imgData.kind === ImageKind.RGB_24BPP) {
++      // RGB, 24-bits per pixel.
++      for (var i = 0; i < totalChunks; i++) {
++        var thisChunkHeight =
++          (i < fullChunks) ? fullChunkHeight : partialChunkHeight;
++        var elemsInThisChunk = imgData.width * thisChunkHeight * 3;
++        var destPos = 0;
++        for (var j = 0; j < elemsInThisChunk; j += 3) {
++          dest[destPos++] = src[srcPos++];
++          dest[destPos++] = src[srcPos++];
++          dest[destPos++] = src[srcPos++];
++          dest[destPos++] = 255;
++        }
++        ctx.putImageData(chunkImgData, 0, i * fullChunkHeight);
++      }
 +
-     DecodeStream.call(this);
++    } else {
++        error('bad image kind: ' + imgData.kind);
++    }
 +  }
 +
-   var hexvalueMap = {
-       9: -1, // \t
-       32: -1, // space
-       48: 0,
-       49: 1,
-       50: 2,
-       51: 3,
-       52: 4,
-       53: 5,
-       54: 6,
-       55: 7,
-       56: 8,
-       57: 9,
-       65: 10,
-       66: 11,
-       67: 12,
-       68: 13,
-       69: 14,
-       70: 15,
-       97: 10,
-       98: 11,
-       99: 12,
-       100: 13,
-       101: 14,
-       102: 15
-   };
- 
-   AsciiHexStream.prototype = Object.create(DecodeStream.prototype);
- 
-   AsciiHexStream.prototype.readBlock = function AsciiHexStream_readBlock() {
-     var gtCode = '>'.charCodeAt(0), bytes = this.str.getBytes(), c, n,
-         decodeLength, buffer, bufferLength, i, length;
++  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;
 +
-     decodeLength = (bytes.length + 1) >> 1;
-     buffer = this.ensureBuffer(this.bufferLength + decodeLength);
-     bufferLength = this.bufferLength;
++    var chunkImgData = ctx.createImageData(width, fullChunkHeight);
++    var srcPos = 0;
++    var src = imgData.data;
++    var dest = chunkImgData.data;
 +
-     for (i = 0, length = bytes.length; i < length; i++) {
-       c = hexvalueMap[bytes[i]];
-       while (c == -1 && (i + 1) < length) {
-         c = hexvalueMap[bytes[++i]];
-       }
++    for (var i = 0; i < totalChunks; i++) {
++      var thisChunkHeight =
++        (i < fullChunks) ? fullChunkHeight : partialChunkHeight;
 +
-       if ((i + 1) < length && (bytes[i + 1] !== gtCode)) {
-         n = hexvalueMap[bytes[++i]];
-         buffer[bufferLength++] = c * 16 + n;
-       } else {
-         // EOD marker at an odd number, behave as if a 0 followed the last
-         // digit.
-         if (bytes[i] !== gtCode) {
-           buffer[bufferLength++] = c * 16;
++      // 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);
 +    }
- 
-     this.bufferLength = bufferLength;
-     this.eof = true;
-   };
- 
-   return AsciiHexStream;
- })();
- 
- var RunLengthStream = (function RunLengthStreamClosure() {
-   function RunLengthStream(str) {
-     this.str = str;
-     this.dict = str.dict;
- 
-     DecodeStream.call(this);
 +  }
 +
-   RunLengthStream.prototype = Object.create(DecodeStream.prototype);
++  function copyCtxState(sourceCtx, destCtx) {
++    var properties = ['strokeStyle', 'fillStyle', 'fillRule', 'globalAlpha',
++                      'lineWidth', 'lineCap', 'lineJoin', 'miterLimit',
++                      'globalCompositeOperation', 'font'];
++    for (var i = 0, ii = properties.length; i < ii; i++) {
++      var property = properties[i];
++      if (property in sourceCtx) {
++        destCtx[property] = sourceCtx[property];
++      }
++    }
++    if ('setLineDash' in sourceCtx) {
++      destCtx.setLineDash(sourceCtx.getLineDash());
++      destCtx.lineDashOffset =  sourceCtx.lineDashOffset;
++    } else if ('mozDash' in sourceCtx) {
++      destCtx.mozDash = sourceCtx.mozDash;
++      destCtx.mozDashOffset = sourceCtx.mozDashOffset;
++    }
++  }
 +
-   RunLengthStream.prototype.readBlock = function RunLengthStream_readBlock() {
-     // The repeatHeader has following format. The first byte defines type of run
-     // and amount of bytes to repeat/copy: n = 0 through 127 - copy next n bytes
-     // (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) {
-       this.eof = true;
-       return;
++  function composeSMask(ctx, smask, layerCtx) {
++    var mask = smask.canvas;
++    var maskCtx = smask.context;
++    var width = mask.width, height = mask.height;
++
++    var addBackdropFn;
++    if (smask.backdrop) {
++      var cs = smask.colorSpace || ColorSpace.singletons.rgb;
++      var backdrop = cs.getRgb(smask.backdrop, 0);
++      addBackdropFn = function (r0, g0, b0, bytes) {
++        var length = bytes.length;
++        for (var i = 3; i < length; i += 4) {
++          var alpha = bytes[i] / 255;
++          if (alpha === 0) {
++            bytes[i - 3] = r0;
++            bytes[i - 2] = g0;
++            bytes[i - 1] = b0;
++          } else if (alpha < 1) {
++            var alpha_ = 1 - alpha;
++            bytes[i - 3] = (bytes[i - 3] * alpha + r0 * alpha_) | 0;
++            bytes[i - 2] = (bytes[i - 2] * alpha + g0 * alpha_) | 0;
++            bytes[i - 1] = (bytes[i - 1] * alpha + b0 * alpha_) | 0;
++          }
++        }
++      }.bind(null, backdrop[0], backdrop[1], backdrop[2]);
++    } else {
++      addBackdropFn = function () {};
 +    }
 +
-     var bufferLength = this.bufferLength;
-     var n = repeatHeader[0];
-     if (n < 128) {
-       // copy n bytes
-       var buffer = this.ensureBuffer(bufferLength + n + 1);
-       buffer[bufferLength++] = repeatHeader[1];
-       if (n > 0) {
-         var source = this.str.getBytes(n);
-         buffer.set(source, bufferLength);
-         bufferLength += n;
-       }
++    var composeFn;
++    if (smask.subtype === 'Luminosity') {
++      composeFn = function (maskDataBytes, layerDataBytes) {
++        var length = maskDataBytes.length;
++        for (var i = 3; i < length; i += 4) {
++          var y = ((maskDataBytes[i - 3] * 77) +     // * 0.3 / 255 * 0x10000
++                   (maskDataBytes[i - 2] * 152) +    // * 0.59 ....
++                   (maskDataBytes[i - 1] * 28)) | 0; // * 0.11 ....
++          layerDataBytes[i] = (layerDataBytes[i] * y) >> 16;
++        }
++      };
 +    } else {
-       n = 257 - n;
-       var b = repeatHeader[1];
-       var buffer = this.ensureBuffer(bufferLength + n + 1);
-       for (var i = 0; i < n; i++)
-         buffer[bufferLength++] = b;
++      composeFn = function (maskDataBytes, layerDataBytes) {
++        var length = maskDataBytes.length;
++        for (var i = 3; i < length; i += 4) {
++          var alpha = maskDataBytes[i];
++          layerDataBytes[i] = (layerDataBytes[i] * alpha / 255) | 0;
++        }
++      };
 +    }
-     this.bufferLength = bufferLength;
-   };
 +
-   return RunLengthStream;
- })();
++    // processing image in chunks to save memory
++    var chunkSize = 16;
++    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);
 +
- var CCITTFaxStream = (function CCITTFaxStreamClosure() {
- 
-   var ccittEOL = -2;
-   var twoDimPass = 0;
-   var twoDimHoriz = 1;
-   var twoDimVert0 = 2;
-   var twoDimVertR1 = 3;
-   var twoDimVertL1 = 4;
-   var twoDimVertR2 = 5;
-   var twoDimVertL2 = 6;
-   var twoDimVertR3 = 7;
-   var twoDimVertL3 = 8;
- 
-   var twoDimTable = [
-     [-1, -1], [-1, -1],                   // 000000x
-     [7, twoDimVertL3],                    // 0000010
-     [7, twoDimVertR3],                    // 0000011
-     [6, twoDimVertL2], [6, twoDimVertL2], // 000010x
-     [6, twoDimVertR2], [6, twoDimVertR2], // 000011x
-     [4, twoDimPass], [4, twoDimPass],     // 0001xxx
-     [4, twoDimPass], [4, twoDimPass],
-     [4, twoDimPass], [4, twoDimPass],
-     [4, twoDimPass], [4, twoDimPass],
-     [3, twoDimHoriz], [3, twoDimHoriz],   // 001xxxx
-     [3, twoDimHoriz], [3, twoDimHoriz],
-     [3, twoDimHoriz], [3, twoDimHoriz],
-     [3, twoDimHoriz], [3, twoDimHoriz],
-     [3, twoDimHoriz], [3, twoDimHoriz],
-     [3, twoDimHoriz], [3, twoDimHoriz],
-     [3, twoDimHoriz], [3, twoDimHoriz],
-     [3, twoDimHoriz], [3, twoDimHoriz],
-     [3, twoDimVertL1], [3, twoDimVertL1], // 010xxxx
-     [3, twoDimVertL1], [3, twoDimVertL1],
-     [3, twoDimVertL1], [3, twoDimVertL1],
-     [3, twoDimVertL1], [3, twoDimVertL1],
-     [3, twoDimVertL1], [3, twoDimVertL1],
-     [3, twoDimVertL1], [3, twoDimVertL1],
-     [3, twoDimVertL1], [3, twoDimVertL1],
-     [3, twoDimVertL1], [3, twoDimVertL1],
-     [3, twoDimVertR1], [3, twoDimVertR1], // 011xxxx
-     [3, twoDimVertR1], [3, twoDimVertR1],
-     [3, twoDimVertR1], [3, twoDimVertR1],
-     [3, twoDimVertR1], [3, twoDimVertR1],
-     [3, twoDimVertR1], [3, twoDimVertR1],
-     [3, twoDimVertR1], [3, twoDimVertR1],
-     [3, twoDimVertR1], [3, twoDimVertR1],
-     [3, twoDimVertR1], [3, twoDimVertR1],
-     [1, twoDimVert0], [1, twoDimVert0],   // 1xxxxxx
-     [1, twoDimVert0], [1, twoDimVert0],
-     [1, twoDimVert0], [1, twoDimVert0],
-     [1, twoDimVert0], [1, twoDimVert0],
-     [1, twoDimVert0], [1, twoDimVert0],
-     [1, twoDimVert0], [1, twoDimVert0],
-     [1, twoDimVert0], [1, twoDimVert0],
-     [1, twoDimVert0], [1, twoDimVert0],
-     [1, twoDimVert0], [1, twoDimVert0],
-     [1, twoDimVert0], [1, twoDimVert0],
-     [1, twoDimVert0], [1, twoDimVert0],
-     [1, twoDimVert0], [1, twoDimVert0],
-     [1, twoDimVert0], [1, twoDimVert0],
-     [1, twoDimVert0], [1, twoDimVert0],
-     [1, twoDimVert0], [1, twoDimVert0],
-     [1, twoDimVert0], [1, twoDimVert0],
-     [1, twoDimVert0], [1, twoDimVert0],
-     [1, twoDimVert0], [1, twoDimVert0],
-     [1, twoDimVert0], [1, twoDimVert0],
-     [1, twoDimVert0], [1, twoDimVert0],
-     [1, twoDimVert0], [1, twoDimVert0],
-     [1, twoDimVert0], [1, twoDimVert0],
-     [1, twoDimVert0], [1, twoDimVert0],
-     [1, twoDimVert0], [1, twoDimVert0],
-     [1, twoDimVert0], [1, twoDimVert0],
-     [1, twoDimVert0], [1, twoDimVert0],
-     [1, twoDimVert0], [1, twoDimVert0],
-     [1, twoDimVert0], [1, twoDimVert0],
-     [1, twoDimVert0], [1, twoDimVert0],
-     [1, twoDimVert0], [1, twoDimVert0],
-     [1, twoDimVert0], [1, twoDimVert0],
-     [1, twoDimVert0], [1, twoDimVert0]
-   ];
- 
-   var whiteTable1 = [
-     [-1, -1],                               // 00000
-     [12, ccittEOL],                         // 00001
-     [-1, -1], [-1, -1],                     // 0001x
-     [-1, -1], [-1, -1], [-1, -1], [-1, -1], // 001xx
-     [-1, -1], [-1, -1], [-1, -1], [-1, -1], // 010xx
-     [-1, -1], [-1, -1], [-1, -1], [-1, -1], // 011xx
-     [11, 1792], [11, 1792],                 // 1000x
-     [12, 1984],                             // 10010
-     [12, 2048],                             // 10011
-     [12, 2112],                             // 10100
-     [12, 2176],                             // 10101
-     [12, 2240],                             // 10110
-     [12, 2304],                             // 10111
-     [11, 1856], [11, 1856],                 // 1100x
-     [11, 1920], [11, 1920],                 // 1101x
-     [12, 2368],                             // 11100
-     [12, 2432],                             // 11101
-     [12, 2496],                             // 11110
-     [12, 2560]                              // 11111
-   ];
- 
-   var whiteTable2 = [
-     [-1, -1], [-1, -1], [-1, -1], [-1, -1],     // 0000000xx
-     [8, 29], [8, 29],                           // 00000010x
-     [8, 30], [8, 30],                           // 00000011x
-     [8, 45], [8, 45],                           // 00000100x
-     [8, 46], [8, 46],                           // 00000101x
-     [7, 22], [7, 22], [7, 22], [7, 22],         // 0000011xx
-     [7, 23], [7, 23], [7, 23], [7, 23],         // 0000100xx
-     [8, 47], [8, 47],                           // 00001010x
-     [8, 48], [8, 48],                           // 00001011x
-     [6, 13], [6, 13], [6, 13], [6, 13],         // 000011xxx
-     [6, 13], [6, 13], [6, 13], [6, 13],
-     [7, 20], [7, 20], [7, 20], [7, 20],         // 0001000xx
-     [8, 33], [8, 33],                           // 00010010x
-     [8, 34], [8, 34],                           // 00010011x
-     [8, 35], [8, 35],                           // 00010100x
-     [8, 36], [8, 36],                           // 00010101x
-     [8, 37], [8, 37],                           // 00010110x
-     [8, 38], [8, 38],                           // 00010111x
-     [7, 19], [7, 19], [7, 19], [7, 19],         // 0001100xx
-     [8, 31], [8, 31],                           // 00011010x
-     [8, 32], [8, 32],                           // 00011011x
-     [6, 1], [6, 1], [6, 1], [6, 1],             // 000111xxx
-     [6, 1], [6, 1], [6, 1], [6, 1],
-     [6, 12], [6, 12], [6, 12], [6, 12],         // 001000xxx
-     [6, 12], [6, 12], [6, 12], [6, 12],
-     [8, 53], [8, 53],                           // 00100100x
-     [8, 54], [8, 54],                           // 00100101x
-     [7, 26], [7, 26], [7, 26], [7, 26],         // 0010011xx
-     [8, 39], [8, 39],                           // 00101000x
-     [8, 40], [8, 40],                           // 00101001x
-     [8, 41], [8, 41],                           // 00101010x
-     [8, 42], [8, 42],                           // 00101011x
-     [8, 43], [8, 43],                           // 00101100x
-     [8, 44], [8, 44],                           // 00101101x
-     [7, 21], [7, 21], [7, 21], [7, 21],         // 0010111xx
-     [7, 28], [7, 28], [7, 28], [7, 28],         // 0011000xx
-     [8, 61], [8, 61],                           // 00110010x
-     [8, 62], [8, 62],                           // 00110011x
-     [8, 63], [8, 63],                           // 00110100x
-     [8, 0], [8, 0],                             // 00110101x
-     [8, 320], [8, 320],                         // 00110110x
-     [8, 384], [8, 384],                         // 00110111x
-     [5, 10], [5, 10], [5, 10], [5, 10],         // 00111xxxx
-     [5, 10], [5, 10], [5, 10], [5, 10],
-     [5, 10], [5, 10], [5, 10], [5, 10],
-     [5, 10], [5, 10], [5, 10], [5, 10],
-     [5, 11], [5, 11], [5, 11], [5, 11],         // 01000xxxx
-     [5, 11], [5, 11], [5, 11], [5, 11],
-     [5, 11], [5, 11], [5, 11], [5, 11],
-     [5, 11], [5, 11], [5, 11], [5, 11],
-     [7, 27], [7, 27], [7, 27], [7, 27],         // 0100100xx
-     [8, 59], [8, 59],                           // 01001010x
-     [8, 60], [8, 60],                           // 01001011x
-     [9, 1472],                                  // 010011000
-     [9, 1536],                                  // 010011001
-     [9, 1600],                                  // 010011010
-     [9, 1728],                                  // 010011011
-     [7, 18], [7, 18], [7, 18], [7, 18],         // 0100111xx
-     [7, 24], [7, 24], [7, 24], [7, 24],         // 0101000xx
-     [8, 49], [8, 49],                           // 01010010x
-     [8, 50], [8, 50],                           // 01010011x
-     [8, 51], [8, 51],                           // 01010100x
-     [8, 52], [8, 52],                           // 01010101x
-     [7, 25], [7, 25], [7, 25], [7, 25],         // 0101011xx
-     [8, 55], [8, 55],                           // 01011000x
-     [8, 56], [8, 56],                           // 01011001x
-     [8, 57], [8, 57],                           // 01011010x
-     [8, 58], [8, 58],                           // 01011011x
-     [6, 192], [6, 192], [6, 192], [6, 192],     // 010111xxx
-     [6, 192], [6, 192], [6, 192], [6, 192],
-     [6, 1664], [6, 1664], [6, 1664], [6, 1664], // 011000xxx
-     [6, 1664], [6, 1664], [6, 1664], [6, 1664],
-     [8, 448], [8, 448],                         // 01100100x
-     [8, 512], [8, 512],                         // 01100101x
-     [9, 704],                                   // 011001100
-     [9, 768],                                   // 011001101
-     [8, 640], [8, 640],                         // 01100111x
-     [8, 576], [8, 576],                         // 01101000x
-     [9, 832],                                   // 011010010
-     [9, 896],                                   // 011010011
-     [9, 960],                                   // 011010100
-     [9, 1024],                                  // 011010101
-     [9, 1088],                                  // 011010110
-     [9, 1152],                                  // 011010111
-     [9, 1216],                                  // 011011000
-     [9, 1280],                                  // 011011001
-     [9, 1344],                                  // 011011010
-     [9, 1408],                                  // 011011011
-     [7, 256], [7, 256], [7, 256], [7, 256],     // 0110111xx
-     [4, 2], [4, 2], [4, 2], [4, 2],             // 0111xxxxx
-     [4, 2], [4, 2], [4, 2], [4, 2],
-     [4, 2], [4, 2], [4, 2], [4, 2],
-     [4, 2], [4, 2], [4, 2], [4, 2],
-     [4, 2], [4, 2], [4, 2], [4, 2],
-     [4, 2], [4, 2], [4, 2], [4, 2],
-     [4, 2], [4, 2], [4, 2], [4, 2],
-     [4, 2], [4, 2], [4, 2], [4, 2],
-     [4, 3], [4, 3], [4, 3], [4, 3],             // 1000xxxxx
-     [4, 3], [4, 3], [4, 3], [4, 3],
-     [4, 3], [4, 3], [4, 3], [4, 3],
-     [4, 3], [4, 3], [4, 3], [4, 3],
-     [4, 3], [4, 3], [4, 3], [4, 3],
-     [4, 3], [4, 3], [4, 3], [4, 3],
-     [4, 3], [4, 3], [4, 3], [4, 3],
-     [4, 3], [4, 3], [4, 3], [4, 3],
-     [5, 128], [5, 128], [5, 128], [5, 128],     // 10010xxxx
-     [5, 128], [5, 128], [5, 128], [5, 128],
-     [5, 128], [5, 128], [5, 128], [5, 128],
-     [5, 128], [5, 128], [5, 128], [5, 128],
-     [5, 8], [5, 8], [5, 8], [5, 8],             // 10011xxxx
-     [5, 8], [5, 8], [5, 8], [5, 8],
-     [5, 8], [5, 8], [5, 8], [5, 8],
-     [5, 8], [5, 8], [5, 8], [5, 8],
-     [5, 9], [5, 9], [5, 9], [5, 9],             // 10100xxxx
-     [5, 9], [5, 9], [5, 9], [5, 9],
-     [5, 9], [5, 9], [5, 9], [5, 9],
-     [5, 9], [5, 9], [5, 9], [5, 9],
-     [6, 16], [6, 16], [6, 16], [6, 16],         // 101010xxx
-     [6, 16], [6, 16], [6, 16], [6, 16],
-     [6, 17], [6, 17], [6, 17], [6, 17],         // 101011xxx
-     [6, 17], [6, 17], [6, 17], [6, 17],
-     [4, 4], [4, 4], [4, 4], [4, 4],             // 1011xxxxx
-     [4, 4], [4, 4], [4, 4], [4, 4],
-     [4, 4], [4, 4], [4, 4], [4, 4],
-     [4, 4], [4, 4], [4, 4], [4, 4],
-     [4, 4], [4, 4], [4, 4], [4, 4],
-     [4, 4], [4, 4], [4, 4], [4, 4],
-     [4, 4], [4, 4], [4, 4], [4, 4],
-     [4, 4], [4, 4], [4, 4], [4, 4],
-     [4, 5], [4, 5], [4, 5], [4, 5],             // 1100xxxxx
-     [4, 5], [4, 5], [4, 5], [4, 5],
-     [4, 5], [4, 5], [4, 5], [4, 5],
-     [4, 5], [4, 5], [4, 5], [4, 5],
-     [4, 5], [4, 5], [4, 5], [4, 5],
-     [4, 5], [4, 5], [4, 5], [4, 5],
-     [4, 5], [4, 5], [4, 5], [4, 5],
-     [4, 5], [4, 5], [4, 5], [4, 5],
-     [6, 14], [6, 14], [6, 14], [6, 14],         // 110100xxx
-     [6, 14], [6, 14], [6, 14], [6, 14],
-     [6, 15], [6, 15], [6, 15], [6, 15],         // 110101xxx
-     [6, 15], [6, 15], [6, 15], [6, 15],
-     [5, 64], [5, 64], [5, 64], [5, 64],         // 11011xxxx
-     [5, 64], [5, 64], [5, 64], [5, 64],
-     [5, 64], [5, 64], [5, 64], [5, 64],
-     [5, 64], [5, 64], [5, 64], [5, 64],
-     [4, 6], [4, 6], [4, 6], [4, 6],             // 1110xxxxx
-     [4, 6], [4, 6], [4, 6], [4, 6],
-     [4, 6], [4, 6], [4, 6], [4, 6],
-     [4, 6], [4, 6], [4, 6], [4, 6],
-     [4, 6], [4, 6], [4, 6], [4, 6],
-     [4, 6], [4, 6], [4, 6], [4, 6],
-     [4, 6], [4, 6], [4, 6], [4, 6],
-     [4, 6], [4, 6], [4, 6], [4, 6],
-     [4, 7], [4, 7], [4, 7], [4, 7],             // 1111xxxxx
-     [4, 7], [4, 7], [4, 7], [4, 7],
-     [4, 7], [4, 7], [4, 7], [4, 7],
-     [4, 7], [4, 7], [4, 7], [4, 7],
-     [4, 7], [4, 7], [4, 7], [4, 7],
-     [4, 7], [4, 7], [4, 7], [4, 7],
-     [4, 7], [4, 7], [4, 7], [4, 7],
-     [4, 7], [4, 7], [4, 7], [4, 7]
-   ];
- 
-   var blackTable1 = [
-     [-1, -1], [-1, -1],                             // 000000000000x
-     [12, ccittEOL], [12, ccittEOL],                 // 000000000001x
-     [-1, -1], [-1, -1], [-1, -1], [-1, -1],         // 00000000001xx
-     [-1, -1], [-1, -1], [-1, -1], [-1, -1],         // 00000000010xx
-     [-1, -1], [-1, -1], [-1, -1], [-1, -1],         // 00000000011xx
-     [-1, -1], [-1, -1], [-1, -1], [-1, -1],         // 00000000100xx
-     [-1, -1], [-1, -1], [-1, -1], [-1, -1],         // 00000000101xx
-     [-1, -1], [-1, -1], [-1, -1], [-1, -1],         // 00000000110xx
-     [-1, -1], [-1, -1], [-1, -1], [-1, -1],         // 00000000111xx
-     [11, 1792], [11, 1792], [11, 1792], [11, 1792], // 00000001000xx
-     [12, 1984], [12, 1984],                         // 000000010010x
-     [12, 2048], [12, 2048],                         // 000000010011x
-     [12, 2112], [12, 2112],                         // 000000010100x
-     [12, 2176], [12, 2176],                         // 000000010101x
-     [12, 2240], [12, 2240],                         // 000000010110x
-     [12, 2304], [12, 2304],                         // 000000010111x
-     [11, 1856], [11, 1856], [11, 1856], [11, 1856], // 00000001100xx
-     [11, 1920], [11, 1920], [11, 1920], [11, 1920], // 00000001101xx
-     [12, 2368], [12, 2368],                         // 000000011100x
-     [12, 2432], [12, 2432],                         // 000000011101x
-     [12, 2496], [12, 2496],                         // 000000011110x
-     [12, 2560], [12, 2560],                         // 000000011111x
-     [10, 18], [10, 18], [10, 18], [10, 18],         // 0000001000xxx
-     [10, 18], [10, 18], [10, 18], [10, 18],
-     [12, 52], [12, 52],                             // 000000100100x
-     [13, 640],                                      // 0000001001010
-     [13, 704],                                      // 0000001001011
-     [13, 768],                                      // 0000001001100
-     [13, 832],                                      // 0000001001101
-     [12, 55], [12, 55],                             // 000000100111x
-     [12, 56], [12, 56],                             // 000000101000x
-     [13, 1280],                                     // 0000001010010
-     [13, 1344],                                     // 0000001010011
-     [13, 1408],                                     // 0000001010100
-     [13, 1472],                                     // 0000001010101
-     [12, 59], [12, 59],                             // 000000101011x
-     [12, 60], [12, 60],                             // 000000101100x
-     [13, 1536],                                     // 0000001011010
-     [13, 1600],                                     // 0000001011011
-     [11, 24], [11, 24], [11, 24], [11, 24],         // 00000010111xx
-     [11, 25], [11, 25], [11, 25], [11, 25],         // 00000011000xx
-     [13, 1664],                                     // 0000001100100
-     [13, 1728],                                     // 0000001100101
-     [12, 320], [12, 320],                           // 000000110011x
-     [12, 384], [12, 384],                           // 000000110100x
-     [12, 448], [12, 448],                           // 000000110101x
-     [13, 512],                                      // 0000001101100
-     [13, 576],                                      // 0000001101101
-     [12, 53], [12, 53],                             // 000000110111x
-     [12, 54], [12, 54],                             // 000000111000x
-     [13, 896],                                      // 0000001110010
-     [13, 960],                                      // 0000001110011
-     [13, 1024],                                     // 0000001110100
-     [13, 1088],                                     // 0000001110101
-     [13, 1152],                                     // 0000001110110
-     [13, 1216],                                     // 0000001110111
-     [10, 64], [10, 64], [10, 64], [10, 64],         // 0000001111xxx
-     [10, 64], [10, 64], [10, 64], [10, 64]
-   ];
- 
-   var blackTable2 = [
-     [8, 13], [8, 13], [8, 13], [8, 13],     // 00000100xxxx
-     [8, 13], [8, 13], [8, 13], [8, 13],
-     [8, 13], [8, 13], [8, 13], [8, 13],
-     [8, 13], [8, 13], [8, 13], [8, 13],
-     [11, 23], [11, 23],                     // 00000101000x
-     [12, 50],                               // 000001010010
-     [12, 51],                               // 000001010011
-     [12, 44],                               // 000001010100
-     [12, 45],                               // 000001010101
-     [12, 46],                               // 000001010110
-     [12, 47],                               // 000001010111
-     [12, 57],                               // 000001011000
-     [12, 58],                               // 000001011001
-     [12, 61],                               // 000001011010
-     [12, 256],                              // 000001011011
-     [10, 16], [10, 16], [10, 16], [10, 16], // 0000010111xx
-     [10, 17], [10, 17], [10, 17], [10, 17], // 0000011000xx
-     [12, 48],                               // 000001100100
-     [12, 49],                               // 000001100101
-     [12, 62],                               // 000001100110
-     [12, 63],                               // 000001100111
-     [12, 30],                               // 000001101000
-     [12, 31],                               // 000001101001
-     [12, 32],                               // 000001101010
-     [12, 33],                               // 000001101011
-     [12, 40],                               // 000001101100
-     [12, 41],                               // 000001101101
-     [11, 22], [11, 22],                     // 00000110111x
-     [8, 14], [8, 14], [8, 14], [8, 14],     // 00000111xxxx
-     [8, 14], [8, 14], [8, 14], [8, 14],
-     [8, 14], [8, 14], [8, 14], [8, 14],
-     [8, 14], [8, 14], [8, 14], [8, 14],
-     [7, 10], [7, 10], [7, 10], [7, 10],     // 0000100xxxxx
-     [7, 10], [7, 10], [7, 10], [7, 10],
-     [7, 10], [7, 10], [7, 10], [7, 10],
-     [7, 10], [7, 10], [7, 10], [7, 10],
-     [7, 10], [7, 10], [7, 10], [7, 10],
-     [7, 10], [7, 10], [7, 10], [7, 10],
-     [7, 10], [7, 10], [7, 10], [7, 10],
-     [7, 10], [7, 10], [7, 10], [7, 10],
-     [7, 11], [7, 11], [7, 11], [7, 11],     // 0000101xxxxx
-     [7, 11], [7, 11], [7, 11], [7, 11],
-     [7, 11], [7, 11], [7, 11], [7, 11],
-     [7, 11], [7, 11], [7, 11], [7, 11],
-     [7, 11], [7, 11], [7, 11], [7, 11],
-     [7, 11], [7, 11], [7, 11], [7, 11],
-     [7, 11], [7, 11], [7, 11], [7, 11],
-     [7, 11], [7, 11], [7, 11], [7, 11],
-     [9, 15], [9, 15], [9, 15], [9, 15],     // 000011000xxx
-     [9, 15], [9, 15], [9, 15], [9, 15],
-     [12, 128],                              // 000011001000
-     [12, 192],                              // 000011001001
-     [12, 26],                               // 000011001010
-     [12, 27],                               // 000011001011
-     [12, 28],                               // 000011001100
-     [12, 29],                               // 000011001101
-     [11, 19], [11, 19],                     // 00001100111x
-     [11, 20], [11, 20],                     // 00001101000x
-     [12, 34],                               // 000011010010
-     [12, 35],                               // 000011010011
-     [12, 36],                               // 000011010100
-     [12, 37],                               // 000011010101
-     [12, 38],                               // 000011010110
-     [12, 39],                               // 000011010111
-     [11, 21], [11, 21],                     // 00001101100x
-     [12, 42],                               // 000011011010
-     [12, 43],                               // 000011011011
-     [10, 0], [10, 0], [10, 0], [10, 0],     // 0000110111xx
-     [7, 12], [7, 12], [7, 12], [7, 12],     // 0000111xxxxx
-     [7, 12], [7, 12], [7, 12], [7, 12],
-     [7, 12], [7, 12], [7, 12], [7, 12],
-     [7, 12], [7, 12], [7, 12], [7, 12],
-     [7, 12], [7, 12], [7, 12], [7, 12],
-     [7, 12], [7, 12], [7, 12], [7, 12],
-     [7, 12], [7, 12], [7, 12], [7, 12],
-     [7, 12], [7, 12], [7, 12], [7, 12]
-   ];
- 
-   var blackTable3 = [
-     [-1, -1], [-1, -1], [-1, -1], [-1, -1], // 0000xx
-     [6, 9],                                 // 000100
-     [6, 8],                                 // 000101
-     [5, 7], [5, 7],                         // 00011x
-     [4, 6], [4, 6], [4, 6], [4, 6],         // 0010xx
-     [4, 5], [4, 5], [4, 5], [4, 5],         // 0011xx
-     [3, 1], [3, 1], [3, 1], [3, 1],         // 010xxx
-     [3, 1], [3, 1], [3, 1], [3, 1],
-     [3, 4], [3, 4], [3, 4], [3, 4],         // 011xxx
-     [3, 4], [3, 4], [3, 4], [3, 4],
-     [2, 3], [2, 3], [2, 3], [2, 3],         // 10xxxx
-     [2, 3], [2, 3], [2, 3], [2, 3],
-     [2, 3], [2, 3], [2, 3], [2, 3],
-     [2, 3], [2, 3], [2, 3], [2, 3],
-     [2, 2], [2, 2], [2, 2], [2, 2],         // 11xxxx
-     [2, 2], [2, 2], [2, 2], [2, 2],
-     [2, 2], [2, 2], [2, 2], [2, 2],
-     [2, 2], [2, 2], [2, 2], [2, 2]
-   ];
- 
-   function CCITTFaxStream(str, params) {
-     this.str = str;
-     this.dict = str.dict;
- 
-     params = params || new Dict();
- 
-     this.encoding = params.get('K') || 0;
-     this.eoline = params.get('EndOfLine') || false;
-     this.byteAlign = params.get('EncodedByteAlign') || false;
-     this.columns = params.get('Columns') || 1728;
-     this.rows = params.get('Rows') || 0;
-     var eoblock = params.get('EndOfBlock');
-     if (eoblock === null || eoblock === undefined)
-       eoblock = true;
-     this.eoblock = eoblock;
-     this.black = params.get('BlackIs1') || false;
- 
-     this.codingLine = new Uint32Array(this.columns + 1);
-     this.refLine = new Uint32Array(this.columns + 2);
- 
-     this.codingLine[0] = this.columns;
-     this.codingPos = 0;
- 
-     this.row = 0;
-     this.nextLine2D = this.encoding < 0;
-     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) {
-       this.eatBits(12);
-     }
-     if (this.encoding > 0) {
-       this.nextLine2D = !this.lookBits(1);
-       this.eatBits(1);
++      addBackdropFn(maskData.data);
++      composeFn(maskData.data, layerData.data);
++
++      maskCtx.putImageData(layerData, 0, row);
 +    }
 +
-     DecodeStream.call(this);
++    ctx.setTransform(1, 0, 0, 1, 0, 0);
++    ctx.drawImage(mask, smask.offsetX, smask.offsetY);
 +  }
 +
-   CCITTFaxStream.prototype = Object.create(DecodeStream.prototype);
- 
-   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;
-     }
-   };
++  var LINE_CAP_STYLES = ['butt', 'round', 'square'];
++  var LINE_JOIN_STYLES = ['miter', 'round', 'bevel'];
++  var NORMAL_CLIP = {};
++  var EO_CLIP = {};
 +
-   CCITTFaxStream.prototype.addPixels =
-     function ccittFaxStreamAddPixels(a1, blackPixels) {
-     var codingLine = this.codingLine;
-     var codingPos = this.codingPos;
++  CanvasGraphics.prototype = {
 +
-     if (a1 > codingLine[codingPos]) {
-       if (a1 > this.columns) {
-         info('row is wrong length');
-         this.err = true;
-         a1 = this.columns;
-       }
-       if ((codingPos & 1) ^ blackPixels) {
-         ++codingPos;
++    beginDrawing: function CanvasGraphics_beginDrawing(viewport, transparency) {
++      // For pdfs that use blend modes we have to clear the canvas else certain
++      // blend modes can look wrong since we'd be blending with a white
++      // backdrop. The problem with a transparent backdrop though is we then
++      // don't get sub pixel anti aliasing on text, so we fill with white if
++      // we can.
++      var width = this.ctx.canvas.width;
++      var height = this.ctx.canvas.height;
++      if (transparency) {
++        this.ctx.clearRect(0, 0, width, height);
++      } else {
++        this.ctx.mozOpaque = true;
++        this.ctx.save();
++        this.ctx.fillStyle = 'rgb(255, 255, 255)';
++        this.ctx.fillRect(0, 0, width, height);
++        this.ctx.restore();
 +      }
 +
-       codingLine[codingPos] = a1;
-     }
-     this.codingPos = codingPos;
-   };
++      var transform = viewport.transform;
++
++      this.ctx.save();
++      this.ctx.transform.apply(this.ctx, transform);
 +
-   CCITTFaxStream.prototype.addPixelsNeg =
-     function ccittFaxStreamAddPixelsNeg(a1, blackPixels) {
-     var codingLine = this.codingLine;
-     var codingPos = this.codingPos;
++      this.baseTransform = this.ctx.mozCurrentTransform.slice();
 +
-     if (a1 > codingLine[codingPos]) {
-       if (a1 > this.columns) {
-         info('row is wrong length');
-         this.err = true;
-         a1 = this.columns;
++      if (this.textLayer) {
++        this.textLayer.beginLayout();
 +      }
-       if ((codingPos & 1) ^ blackPixels)
-         ++codingPos;
- 
-       codingLine[codingPos] = a1;
-     } else if (a1 < codingLine[codingPos]) {
-       if (a1 < 0) {
-         info('invalid code');
-         this.err = true;
-         a1 = 0;
++      if (this.imageLayer) {
++        this.imageLayer.beginLayout();
 +      }
-       while (codingPos > 0 && a1 < codingLine[codingPos - 1])
-         --codingPos;
-       codingLine[codingPos] = a1;
-     }
- 
-     this.codingPos = codingPos;
-   };
++    },
 +
-   CCITTFaxStream.prototype.lookChar = function CCITTFaxStream_lookChar() {
-     if (this.buf != EOF)
-       return this.buf;
++    executeOperatorList: function CanvasGraphics_executeOperatorList(
++                                    operatorList,
++                                    executionStartIdx, continueCallback,
++                                    stepper) {
++      var argsArray = operatorList.argsArray;
++      var fnArray = operatorList.fnArray;
++      var i = executionStartIdx || 0;
++      var argsArrayLen = argsArray.length;
 +
-     var refLine = this.refLine;
-     var codingLine = this.codingLine;
-     var columns = this.columns;
++      // Sometimes the OperatorList to execute is empty.
++      if (argsArrayLen == i) {
++        return i;
++      }
 +
-     var refPos, blackPixels, bits;
++      var executionEndIdx;
++      var endTime = Date.now() + EXECUTION_TIME;
 +
-     if (this.outputBits === 0) {
-       if (this.eof)
-         return null;
++      var commonObjs = this.commonObjs;
++      var objs = this.objs;
++      var fnId;
++      var deferred = Promise.resolve();
 +
-       this.err = false;
- 
-       var code1, code2, code3;
-       if (this.nextLine2D) {
-         for (var i = 0; codingLine[i] < columns; ++i)
-           refLine[i] = codingLine[i];
- 
-         refLine[i++] = columns;
-         refLine[i] = columns;
-         codingLine[0] = 0;
-         this.codingPos = 0;
-         refPos = 0;
-         blackPixels = 0;
- 
-         while (codingLine[this.codingPos] < columns) {
-           code1 = this.getTwoDimCode();
-           switch (code1) {
-             case twoDimPass:
-               this.addPixels(refLine[refPos + 1], blackPixels);
-               if (refLine[refPos + 1] < columns)
-                 refPos += 2;
-               break;
-             case twoDimHoriz:
-               code1 = code2 = 0;
-               if (blackPixels) {
-                 do {
-                   code1 += (code3 = this.getBlackCode());
-                 } while (code3 >= 64);
-                 do {
-                   code2 += (code3 = this.getWhiteCode());
-                 } while (code3 >= 64);
-               } else {
-                 do {
-                   code1 += (code3 = this.getWhiteCode());
-                 } while (code3 >= 64);
-                 do {
-                   code2 += (code3 = this.getBlackCode());
-                 } while (code3 >= 64);
-               }
-               this.addPixels(codingLine[this.codingPos] +
-                              code1, blackPixels);
-               if (codingLine[this.codingPos] < columns) {
-                 this.addPixels(codingLine[this.codingPos] + code2,
-                                blackPixels ^ 1);
-               }
-               while (refLine[refPos] <= codingLine[this.codingPos] &&
-                      refLine[refPos] < columns) {
-                 refPos += 2;
-               }
-               break;
-             case twoDimVertR3:
-               this.addPixels(refLine[refPos] + 3, blackPixels);
-               blackPixels ^= 1;
-               if (codingLine[this.codingPos] < columns) {
-                 ++refPos;
-                 while (refLine[refPos] <= codingLine[this.codingPos] &&
-                        refLine[refPos] < columns)
-                   refPos += 2;
-               }
-               break;
-             case twoDimVertR2:
-               this.addPixels(refLine[refPos] + 2, blackPixels);
-               blackPixels ^= 1;
-               if (codingLine[this.codingPos] < columns) {
-                 ++refPos;
-                 while (refLine[refPos] <= codingLine[this.codingPos] &&
-                        refLine[refPos] < columns) {
-                   refPos += 2;
-                 }
-               }
-               break;
-             case twoDimVertR1:
-               this.addPixels(refLine[refPos] + 1, blackPixels);
-               blackPixels ^= 1;
-               if (codingLine[this.codingPos] < columns) {
-                 ++refPos;
-                 while (refLine[refPos] <= codingLine[this.codingPos] &&
-                        refLine[refPos] < columns)
-                   refPos += 2;
-               }
-               break;
-             case twoDimVert0:
-               this.addPixels(refLine[refPos], blackPixels);
-               blackPixels ^= 1;
-               if (codingLine[this.codingPos] < columns) {
-                 ++refPos;
-                 while (refLine[refPos] <= codingLine[this.codingPos] &&
-                        refLine[refPos] < columns)
-                   refPos += 2;
-               }
-               break;
-             case twoDimVertL3:
-               this.addPixelsNeg(refLine[refPos] - 3, blackPixels);
-               blackPixels ^= 1;
-               if (codingLine[this.codingPos] < columns) {
-                 if (refPos > 0)
-                   --refPos;
-                 else
-                   ++refPos;
-                 while (refLine[refPos] <= codingLine[this.codingPos] &&
-                        refLine[refPos] < columns)
-                   refPos += 2;
-               }
-               break;
-             case twoDimVertL2:
-               this.addPixelsNeg(refLine[refPos] - 2, blackPixels);
-               blackPixels ^= 1;
-               if (codingLine[this.codingPos] < columns) {
-                 if (refPos > 0)
-                   --refPos;
-                 else
-                   ++refPos;
-                 while (refLine[refPos] <= codingLine[this.codingPos] &&
-                        refLine[refPos] < columns)
-                   refPos += 2;
-               }
-               break;
-             case twoDimVertL1:
-               this.addPixelsNeg(refLine[refPos] - 1, blackPixels);
-               blackPixels ^= 1;
-               if (codingLine[this.codingPos] < columns) {
-                 if (refPos > 0)
-                   --refPos;
-                 else
-                   ++refPos;
- 
-                 while (refLine[refPos] <= codingLine[this.codingPos] &&
-                        refLine[refPos] < columns)
-                   refPos += 2;
-               }
-               break;
-             case EOF:
-               this.addPixels(columns, 0);
-               this.eof = true;
-               break;
-             default:
-               info('bad 2d code');
-               this.addPixels(columns, 0);
-               this.err = true;
-           }
++      while (true) {
++        if (stepper && i === stepper.nextBreakPoint) {
++          stepper.breakIt(i, continueCallback);
++          return i;
 +        }
-       } else {
-         codingLine[0] = 0;
-         this.codingPos = 0;
-         blackPixels = 0;
-         while (codingLine[this.codingPos] < columns) {
-           code1 = 0;
-           if (blackPixels) {
-             do {
-               code1 += (code3 = this.getBlackCode());
-             } while (code3 >= 64);
-           } else {
-             do {
-               code1 += (code3 = this.getWhiteCode());
-             } while (code3 >= 64);
++
++        fnId = fnArray[i];
++
++        if (fnId !== OPS.dependency) {
++          this[fnId].apply(this, argsArray[i]);
++        } else {
++          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_';
++
++            // 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);
++              return i;
++            }
 +          }
-           this.addPixels(codingLine[this.codingPos] + code1, blackPixels);
-           blackPixels ^= 1;
 +        }
-       }
 +
-       if (this.byteAlign)
-         this.inputBits &= ~7;
- 
-       var gotEOL = false;
++        i++;
 +
-       if (!this.eoblock && this.row == this.rows - 1) {
-         this.eof = true;
-       } else {
-         code1 = this.lookBits(12);
-         while (code1 === 0) {
-           this.eatBits(1);
-           code1 = this.lookBits(12);
++        // If the entire operatorList was executed, stop as were done.
++        if (i == argsArrayLen) {
++          return i;
 +        }
-         if (code1 == 1) {
-           this.eatBits(12);
-           gotEOL = true;
-         } else if (code1 == EOF) {
-           this.eof = true;
++
++        // 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 operatorList isn't executed completely yet OR the execution
++        // time was short enough, do another execution round.
 +      }
++    },
 +
-       if (!this.eof && this.encoding > 0) {
-         this.nextLine2D = !this.lookBits(1);
-         this.eatBits(1);
++    endDrawing: function CanvasGraphics_endDrawing() {
++      this.ctx.restore();
++      CachedCanvases.clear();
++
++      if (this.textLayer) {
++        this.textLayer.endLayout();
++      }
++      if (this.imageLayer) {
++        this.imageLayer.endLayout();
 +      }
++    },
 +
-       if (this.eoblock && gotEOL) {
-         code1 = this.lookBits(12);
-         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) {
-               code1 = this.lookBits(12);
-               if (code1 != 1)
-                 info('bad rtc code: ' + code1);
-               this.eatBits(12);
-               if (this.encoding > 0) {
-                 this.lookBits(1);
-                 this.eatBits(1);
++    // Graphics state
++    setLineWidth: function CanvasGraphics_setLineWidth(width) {
++      this.current.lineWidth = width;
++      this.ctx.lineWidth = width;
++    },
++    setLineCap: function CanvasGraphics_setLineCap(style) {
++      this.ctx.lineCap = LINE_CAP_STYLES[style];
++    },
++    setLineJoin: function CanvasGraphics_setLineJoin(style) {
++      this.ctx.lineJoin = LINE_JOIN_STYLES[style];
++    },
++    setMiterLimit: function CanvasGraphics_setMiterLimit(limit) {
++      this.ctx.miterLimit = limit;
++    },
++    setDash: function CanvasGraphics_setDash(dashArray, dashPhase) {
++      var ctx = this.ctx;
++      if ('setLineDash' in ctx) {
++        ctx.setLineDash(dashArray);
++        ctx.lineDashOffset = dashPhase;
++      } else {
++        ctx.mozDash = dashArray;
++        ctx.mozDashOffset = dashPhase;
++      }
++    },
++    setRenderingIntent: function CanvasGraphics_setRenderingIntent(intent) {
++      // Maybe if we one day fully support color spaces this will be important
++      // for now we can ignore.
++      // TODO set rendering intent?
++    },
++    setFlatness: function CanvasGraphics_setFlatness(flatness) {
++      // There's no way to control this with canvas, but we can safely ignore.
++      // TODO set flatness?
++    },
++    setGState: function CanvasGraphics_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':
++            this.setRenderingIntent(value);
++            break;
++          case 'FL':
++            this.setFlatness(value);
++            break;
++          case 'Font':
++            this.setFont(value[0], value[1]);
++            break;
++          case 'CA':
++            this.current.strokeAlpha = state[1];
++            break;
++          case 'ca':
++            this.current.fillAlpha = state[1];
++            this.ctx.globalAlpha = state[1];
++            break;
++          case 'BM':
++            if (value && value.name && (value.name !== 'Normal')) {
++              var mode = value.name.replace(/([A-Z])/g,
++                function(c) {
++                  return '-' + c.toLowerCase();
++                }
++              ).substring(1);
++              this.ctx.globalCompositeOperation = mode;
++              if (this.ctx.globalCompositeOperation !== mode) {
++                warn('globalCompositeOperation "' + mode +
++                     '" is not supported');
 +              }
++            } else {
++              this.ctx.globalCompositeOperation = 'source-over';
 +            }
-           }
-           this.eof = true;
-         }
-       } else if (this.err && this.eoline) {
-         while (true) {
-           code1 = this.lookBits(13);
-           if (code1 == EOF) {
-             this.eof = true;
-             return null;
-           }
-           if ((code1 >> 1) == 1) {
 +            break;
-           }
-           this.eatBits(1);
-         }
-         this.eatBits(12);
-         if (this.encoding > 0) {
-           this.eatBits(1);
-           this.nextLine2D = !(code1 & 1);
++          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() {
 +
-       if (codingLine[0] > 0)
-         this.outputBits = codingLine[this.codingPos = 0];
-       else
-         this.outputBits = codingLine[this.codingPos = 1];
-       this.row++;
-     }
++      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);
 +
-     if (this.outputBits >= 8) {
-       this.buf = (this.codingPos & 1) ? 0 : 0xFF;
-       this.outputBits -= 8;
-       if (this.outputBits === 0 && codingLine[this.codingPos] < columns) {
-         this.codingPos++;
-         this.outputBits = (codingLine[this.codingPos] -
-                            codingLine[this.codingPos - 1]);
-       }
-     } else {
-       var bits = 8;
-       this.buf = 0;
-       do {
-         if (this.outputBits > bits) {
-           this.buf <<= bits;
-           if (!(this.codingPos & 1)) {
-             this.buf |= 0xFF >> (8 - bits);
-           }
-           this.outputBits -= bits;
-           bits = 0;
-         } else {
-           this.buf <<= this.outputBits;
-           if (!(this.codingPos & 1)) {
-             this.buf |= 0xFF >> (8 - this.outputBits);
-           }
-           bits -= this.outputBits;
-           this.outputBits = 0;
-           if (codingLine[this.codingPos] < columns) {
-             this.codingPos++;
-             this.outputBits = (codingLine[this.codingPos] -
-                                codingLine[this.codingPos - 1]);
-           } else if (bits > 0) {
-             this.buf <<= bits;
-             bits = 0;
-           }
-         }
-       } while (bits);
-     }
-     if (this.black) {
-       this.buf ^= 0xFF;
-     }
-     return this.buf;
-   };
++      var currentCtx = this.ctx;
++      var currentTransform = currentCtx.mozCurrentTransform;
++      this.ctx.save();
 +
-   // This functions returns the code found from the table.
-   // The start and end parameters set the boundaries for searching the table.
-   // The limit parameter is optional. Function returns an array with three
-   // values. The first array element indicates whether a valid code is being
-   // 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) {
- 
-     var limitValue = limit || 0;
-     for (var i = start; i <= end; ++i) {
-       var code = this.lookBits(i);
-       if (code == EOF)
-         return [true, 1, false];
-       if (i < end)
-         code <<= end - i;
-       if (!limitValue || code >= limitValue) {
-         var p = table[code - limitValue];
-         if (p[0] == i) {
-           this.eatBits(i);
-           return [true, p[1], true];
-         }
-       }
-     }
-     return [false, 0, false];
-   };
++      var groupCtx = scratchCanvas.context;
++      groupCtx.translate(-activeSMask.offsetX, -activeSMask.offsetY);
++      groupCtx.transform.apply(groupCtx, currentTransform);
 +
-   CCITTFaxStream.prototype.getTwoDimCode =
-     function ccittFaxStreamGetTwoDimCode() {
- 
-     var code = 0;
-     var p;
-     if (this.eoblock) {
-       code = this.lookBits(7);
-       p = twoDimTable[code];
-       if (p && p[0] > 0) {
-         this.eatBits(p[0]);
-         return p[1];
-       }
-     } else {
-       var result = this.findTableCode(1, 7, twoDimTable);
-       if (result[0] && result[2])
-         return result[1];
-     }
-     info('Bad two dim code');
-     return EOF;
-   };
++      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();
 +
-   CCITTFaxStream.prototype.getWhiteCode =
-     function ccittFaxStreamGetWhiteCode() {
- 
-     var code = 0;
-     var p;
-     var n;
-     if (this.eoblock) {
-       code = this.lookBits(12);
-       if (code == EOF)
-         return 1;
- 
-       if ((code >> 5) === 0)
-         p = whiteTable1[code];
-       else
-         p = whiteTable2[code >> 3];
- 
-       if (p[0] > 0) {
-         this.eatBits(p[0]);
-         return p[1];
++      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();
++      if (this.current.activeSMask) {
++        this.current.activeSMask = null;
 +      }
-     } else {
-       var result = this.findTableCode(1, 9, whiteTable2);
-       if (result[0])
-         return result[1];
- 
-       result = this.findTableCode(11, 12, whiteTable1);
-       if (result[0])
-         return result[1];
-     }
-     info('bad white code');
-     this.eatBits(1);
-     return 1;
-   };
++    },
++    restore: function CanvasGraphics_restore() {
++      var prev = this.stateStack.pop();
++      if (prev) {
++        if (this.current.activeSMask) {
++          this.endSMaskGroup();
++        }
 +
-   CCITTFaxStream.prototype.getBlackCode =
-     function ccittFaxStreamGetBlackCode() {
- 
-     var code, p;
-     if (this.eoblock) {
-       code = this.lookBits(13);
-       if (code == EOF)
-         return 1;
-       if ((code >> 7) === 0)
-         p = blackTable1[code];
-       else if ((code >> 9) === 0 && (code >> 7) !== 0)
-         p = blackTable2[(code >> 1) - 64];
-       else
-         p = blackTable3[code >> 7];
- 
-       if (p[0] > 0) {
-         this.eatBits(p[0]);
-         return p[1];
++        this.current = prev;
++        this.ctx.restore();
 +      }
-     } else {
-       var result = this.findTableCode(2, 6, blackTable3);
-       if (result[0])
-         return result[1];
- 
-       result = this.findTableCode(7, 12, blackTable2, 64);
-       if (result[0])
-         return result[1];
- 
-       result = this.findTableCode(10, 13, blackTable1);
-       if (result[0])
-         return result[1];
-     }
-     info('bad black code');
-     this.eatBits(1);
-     return 1;
-   };
++    },
++    transform: function CanvasGraphics_transform(a, b, c, d, e, f) {
++      this.ctx.transform(a, b, c, d, e, f);
++    },
 +
-   CCITTFaxStream.prototype.lookBits = function CCITTFaxStream_lookBits(n) {
-     var c;
-     while (this.inputBits < n) {
-       if ((c = this.str.getByte()) === null || c === undefined) {
-         if (this.inputBits === 0)
-           return EOF;
-         return ((this.inputBuf << (n - this.inputBits)) &
-                 (0xFFFF >> (16 - n)));
++    // 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) {
++      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);
++    },
++    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)
++        ctx.lineWidth = this.getSinglePixelWidth();
++      // For stroke we want to temporarily change the global alpha to the
++      // stroking alpha.
++      ctx.globalAlpha = this.current.strokeAlpha;
++      if (strokeColor && strokeColor.hasOwnProperty('type') &&
++          strokeColor.type === 'Pattern') {
++        // for patterns, we transform to pattern space, calculate
++        // the pattern, call stroke, and restore to user space
++        ctx.save();
++        ctx.strokeStyle = strokeColor.getPattern(ctx, this);
++        ctx.stroke();
++        ctx.restore();
++      } else {
++        ctx.stroke();
 +      }
-       this.inputBuf = (this.inputBuf << 8) + c;
-       this.inputBits += 8;
-     }
-     return (this.inputBuf >> (this.inputBits - n)) & (0xFFFF >> (16 - n));
-   };
- 
-   CCITTFaxStream.prototype.eatBits = function CCITTFaxStream_eatBits(n) {
-     if ((this.inputBits -= n) < 0)
-       this.inputBits = 0;
-   };
- 
-   return CCITTFaxStream;
- })();
- 
- var LZWStream = (function LZWStreamClosure() {
-   function LZWStream(str, earlyChange) {
-     this.str = str;
-     this.dict = str.dict;
-     this.cachedData = 0;
-     this.bitsCached = 0;
- 
-     var maxLzwDictionarySize = 4096;
-     var lzwState = {
-       earlyChange: earlyChange,
-       codeLength: 9,
-       nextCode: 258,
-       dictionaryValues: new Uint8Array(maxLzwDictionarySize),
-       dictionaryLengths: new Uint16Array(maxLzwDictionarySize),
-       dictionaryPrevCodes: new Uint16Array(maxLzwDictionarySize),
-       currentSequence: new Uint8Array(maxLzwDictionarySize),
-       currentSequenceLength: 0
-     };
-     for (var i = 0; i < 256; ++i) {
-       lzwState.dictionaryValues[i] = i;
-       lzwState.dictionaryLengths[i] = 1;
-     }
-     this.lzwState = lzwState;
- 
-     DecodeStream.call(this);
-   }
- 
-   LZWStream.prototype = Object.create(DecodeStream.prototype);
++      if (consumePath)
++        this.consumePath();
++      // Restore the global alpha to the fill alpha
++      ctx.globalAlpha = this.current.fillAlpha;
++    },
++    closeStroke: function CanvasGraphics_closeStroke() {
++      this.closePath();
++      this.stroke();
++    },
++    fill: function CanvasGraphics_fill(consumePath) {
++      consumePath = typeof consumePath !== 'undefined' ? consumePath : true;
++      var ctx = this.ctx;
++      var fillColor = this.current.fillColor;
++      var needRestore = false;
 +
-   LZWStream.prototype.readBits = function LZWStream_readBits(n) {
-     var bitsCached = this.bitsCached;
-     var cachedData = this.cachedData;
-     while (bitsCached < n) {
-       var c = this.str.getByte();
-       if (c === null || c === undefined) {
-         this.eof = true;
-         return null;
++      if (fillColor && fillColor.hasOwnProperty('type') &&
++          fillColor.type === 'Pattern') {
++        ctx.save();
++        ctx.fillStyle = fillColor.getPattern(ctx, this);
++        needRestore = true;
 +      }
-       cachedData = (cachedData << 8) | c;
-       bitsCached += 8;
-     }
-     this.bitsCached = (bitsCached -= n);
-     this.cachedData = cachedData;
-     this.lastCode = null;
-     return (cachedData >>> bitsCached) & ((1 << n) - 1);
-   };
 +
-   LZWStream.prototype.readBlock = function LZWStream_readBlock() {
-     var blockSize = 512;
-     var estimatedDecodedSize = blockSize * 2, decodedSizeDelta = blockSize;
-     var i, j, q;
- 
-     var lzwState = this.lzwState;
-     if (!lzwState)
-       return; // eof was found
- 
-     var earlyChange = lzwState.earlyChange;
-     var nextCode = lzwState.nextCode;
-     var dictionaryValues = lzwState.dictionaryValues;
-     var dictionaryLengths = lzwState.dictionaryLengths;
-     var dictionaryPrevCodes = lzwState.dictionaryPrevCodes;
-     var codeLength = lzwState.codeLength;
-     var prevCode = lzwState.prevCode;
-     var currentSequence = lzwState.currentSequence;
-     var currentSequenceLength = lzwState.currentSequenceLength;
- 
-     var decodedLength = 0;
-     var currentBufferLength = this.bufferLength;
-     var buffer = this.ensureBuffer(this.bufferLength + estimatedDecodedSize);
- 
-     for (i = 0; i < blockSize; i++) {
-       var code = this.readBits(codeLength);
-       var hasPrev = currentSequenceLength > 0;
-       if (code < 256) {
-         currentSequence[0] = code;
-         currentSequenceLength = 1;
-       } else if (code >= 258) {
-         if (code < nextCode) {
-           currentSequenceLength = dictionaryLengths[code];
-           for (j = currentSequenceLength - 1, q = code; j >= 0; j--) {
-             currentSequence[j] = dictionaryValues[q];
-             q = dictionaryPrevCodes[q];
-           }
++      if (this.pendingEOFill) {
++        if ('mozFillRule' in this.ctx) {
++          this.ctx.mozFillRule = 'evenodd';
++          this.ctx.fill();
++          this.ctx.mozFillRule = 'nonzero';
 +        } else {
-           currentSequence[currentSequenceLength++] = currentSequence[0];
++          try {
++            this.ctx.fill('evenodd');
++          } catch (ex) {
++            // shouldn't really happen, but browsers might think differently
++            this.ctx.fill();
++          }
 +        }
-       } else if (code == 256) {
-         codeLength = 9;
-         nextCode = 258;
-         currentSequenceLength = 0;
-         continue;
++        this.pendingEOFill = false;
 +      } else {
-         this.eof = true;
-         delete this.lzwState;
-         break;
++        this.ctx.fill();
 +      }
 +
-       if (hasPrev) {
-         dictionaryPrevCodes[nextCode] = prevCode;
-         dictionaryLengths[nextCode] = dictionaryLengths[prevCode] + 1;
-         dictionaryValues[nextCode] = currentSequence[0];
-         nextCode++;
-         codeLength = (nextCode + earlyChange) & (nextCode + earlyChange - 1) ?
-           codeLength : Math.min(Math.log(nextCode + earlyChange) /
-           0.6931471805599453 + 1, 12) | 0;
++      if (needRestore) {
++        ctx.restore();
 +      }
-       prevCode = code;
- 
-       decodedLength += currentSequenceLength;
-       if (estimatedDecodedSize < decodedLength) {
-         do {
-           estimatedDecodedSize += decodedSizeDelta;
-         } while (estimatedDecodedSize < decodedLength);
-         buffer = this.ensureBuffer(this.bufferLength + estimatedDecodedSize);
++      if (consumePath) {
++        this.consumePath();
 +      }
-       for (j = 0; j < currentSequenceLength; j++)
-         buffer[currentBufferLength++] = currentSequence[j];
-     }
-     lzwState.nextCode = nextCode;
-     lzwState.codeLength = codeLength;
-     lzwState.prevCode = prevCode;
-     lzwState.currentSequenceLength = currentSequenceLength;
- 
-     this.bufferLength = currentBufferLength;
-   };
- 
-   return LZWStream;
- })();
- 
- var NullStream = (function NullStreamClosure() {
-   function NullStream() {
-     Stream.call(this, new Uint8Array(0));
-   }
- 
-   NullStream.prototype = Stream.prototype;
- 
-   return NullStream;
- })();
- 
++    },
++    eoFill: function CanvasGraphics_eoFill() {
++      this.pendingEOFill = true;
++      this.fill();
++    },
++    fillStroke: function CanvasGraphics_fillStroke() {
++      this.fill(false);
++      this.stroke(false);
 +
- function MessageHandler(name, comObj) {
-   this.name = name;
-   this.comObj = comObj;
-   this.callbackIndex = 1;
-   var callbacks = this.callbacks = {};
-   var ah = this.actionHandler = {};
++      this.consumePath();
++    },
++    eoFillStroke: function CanvasGraphics_eoFillStroke() {
++      this.pendingEOFill = true;
++      this.fillStroke();
++    },
++    closeFillStroke: function CanvasGraphics_closeFillStroke() {
++      this.closePath();
++      this.fillStroke();
++    },
++    closeEOFillStroke: function CanvasGraphics_closeEOFillStroke() {
++      this.pendingEOFill = true;
++      this.closePath();
++      this.fillStroke();
++    },
++    endPath: function CanvasGraphics_endPath() {
++      this.consumePath();
++    },
 +
-   ah['console_log'] = [function ahConsoleLog(data) {
-     log.apply(null, 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['_warn'] = [function ah_Warn(data) {
-     warn(data);
-   }];
++    // Clipping
++    clip: function CanvasGraphics_clip() {
++      this.pendingClip = NORMAL_CLIP;
++    },
++    eoClip: function CanvasGraphics_eoClip() {
++      this.pendingClip = EO_CLIP;
++    },
 +
-   comObj.onmessage = function messageHandlerComObjOnMessage(event) {
-     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);
-       } else {
-         error('Cannot resolve callback ' + callbackId);
-       }
-     } else if (data.action in ah) {
-       var action = ah[data.action];
-       if (data.callbackId) {
-         var promise = new Promise();
-         promise.then(function(resolvedData) {
-           comObj.postMessage({
-             isReply: true,
-             callbackId: data.callbackId,
-             data: resolvedData
-           });
-         });
-         action[0].call(action[1], data.data, promise);
-       } else {
-         action[0].call(action[1], data.data);
++    // Text
++    beginText: function CanvasGraphics_beginText() {
++      this.current.textMatrix = IDENTITY_MATRIX;
++      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;
 +      }
-     } else {
-       error('Unkown action from worker: ' + data.action);
-     }
-   };
- }
- 
- MessageHandler.prototype = {
-   on: function messageHandlerOn(actionName, handler, scope) {
-     var ah = this.actionHandler;
-     if (ah[actionName]) {
-       error('There is already an actionName called "' + actionName + '"');
-     }
-     ah[actionName] = [handler, scope];
-   },
-   /**
-    * 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.
-    */
-   send: function messageHandlerSend(actionName, data, callback) {
-     var message = {
-       action: actionName,
-       data: data
-     };
-     if (callback) {
-       var callbackId = this.callbackIndex++;
-       this.callbacks[callbackId] = callback;
-       message.callbackId = callbackId;
-     }
-     this.comObj.postMessage(message);
-   }
- };
- 
- var WorkerMessageHandler = {
-   setup: function wphSetup(handler) {
-     var pdfModel = null;
- 
-     function loadDocument(pdfData, pdfModelSource) {
-       // Create only the model of the PDFDoc, which is enough for
-       // processing the content of the pdf.
-       var pdfPassword = pdfModelSource.password;
-       try {
-         pdfModel = new PDFDocument(new Stream(pdfData), pdfPassword);
-       } catch (e) {
-         if (e instanceof PasswordException) {
-           if (e.code === 'needpassword') {
-             handler.send('NeedPassword', {
-               exception: e
-             });
-           } else if (e.code === 'incorrectpassword') {
-             handler.send('IncorrectPassword', {
-               exception: e
-             });
-           }
- 
-           return;
-         } else if (e instanceof InvalidPDFException) {
-           handler.send('InvalidPDF', {
-             exception: e
-           });
++      var paths = this.pendingTextPaths;
++      var ctx = this.ctx;
 +
-           return;
-         } else if (e instanceof MissingPDFException) {
-           handler.send('MissingPDF', {
-             exception: e
-           });
++      ctx.save();
++      ctx.beginPath();
++      for (var i = 0; i < paths.length; i++) {
++        var path = paths[i];
++        ctx.setTransform.apply(ctx, path.transform);
++        ctx.translate(path.x, path.y);
++        path.addToPath(ctx, path.fontSize);
++      }
++      ctx.restore();
++      ctx.clip();
++      ctx.beginPath();
++      delete this.pendingTextPaths;
++    },
++    setCharSpacing: function CanvasGraphics_setCharSpacing(spacing) {
++      this.current.charSpacing = spacing;
++    },
++    setWordSpacing: function CanvasGraphics_setWordSpacing(spacing) {
++      this.current.wordSpacing = spacing;
++    },
++    setHScale: function CanvasGraphics_setHScale(scale) {
++      this.current.textHScale = scale / 100;
++    },
++    setLeading: function CanvasGraphics_setLeading(leading) {
++      this.current.leading = -leading;
++    },
++    setFont: function CanvasGraphics_setFont(fontRefName, size) {
++      var fontObj = this.commonObjs.get(fontRefName);
++      var current = this.current;
 +
-           return;
-         } else {
-           handler.send('UnknownError', {
-             exception: new UnknownErrorException(e.message, e.toString())
-           });
++      if (!fontObj)
++        error('Can\'t find font for ' + fontRefName);
 +
-           return;
-         }
-       }
-       var doc = {
-         numPages: pdfModel.numPages,
-         fingerprint: pdfModel.getFingerprint(),
-         destinations: pdfModel.catalog.destinations,
-         javaScript: pdfModel.catalog.javaScript,
-         outline: pdfModel.catalog.documentOutline,
-         info: pdfModel.getDocumentInfo(),
-         metadata: pdfModel.catalog.metadata,
-         encrypted: !!pdfModel.xref.encrypt
-       };
-       handler.send('GetDoc', {pdfInfo: doc});
-     }
++      current.fontMatrix = fontObj.fontMatrix ? fontObj.fontMatrix :
++                                                FONT_IDENTITY_MATRIX;
 +
-     handler.on('test', function wphSetupTest(data) {
-       // check if Uint8Array can be sent to worker
-       if (!(data instanceof Uint8Array)) {
-         handler.send('test', false);
-         return;
-       }
-       // check if the response property is supported by xhr
-       var xhr = new XMLHttpRequest();
-       var responseExists = 'response' in xhr;
-       // check if the property is actually implemented
-       try {
-         var dummy = xhr.responseType;
-       } catch (e) {
-         responseExists = false;
-       }
-       if (!responseExists) {
-         handler.send('test', false);
-         return;
++      // A valid matrix needs all main diagonal elements to be non-zero
++      // This also ensures we bypass FF bugzilla bug #719844.
++      if (current.fontMatrix[0] === 0 ||
++          current.fontMatrix[3] === 0) {
++        warn('Invalid font matrix for font ' + fontRefName);
 +      }
-       handler.send('test', true);
-     });
 +
-     handler.on('GetDocRequest', function wphSetupDoc(data) {
-       var source = data.source;
-       if (source.data) {
-         // the data is array, instantiating directly from it
-         loadDocument(source.data, source);
-         return;
++      // The spec for Tf (setFont) says that 'size' specifies the font 'scale',
++      // and in some docs this can be negative (inverted x-y axes).
++      if (size < 0) {
++        size = -size;
++        current.fontDirection = -1;
++      } else {
++        current.fontDirection = 1;
 +      }
 +
-       PDFJS.getPdf(
-         {
-           url: source.url,
-           progress: function getPDFProgress(evt) {
-             handler.send('DocProgress', {
-               loaded: evt.loaded,
-               total: evt.lengthComputable ? evt.total : void(0)
-             });
-           },
-           error: function getPDFError(e) {
-             if (e.target.status == 404) {
-               handler.send('MissingPDF', {
-                 exception: new MissingPDFException(
-                   'Missing PDF \"' + source.url + '\".')});
-             } else {
-               handler.send('DocError', 'Unexpected server response (' +
-                             e.target.status + ') while retrieving PDF \"' +
-                             source.url + '\".');
-             }
-           },
-           headers: source.httpHeaders
-         },
-         function getPDFLoad(data) {
-           loadDocument(data, source);
-         });
-     });
++      this.current.font = fontObj;
++      this.current.fontSize = size;
 +
-     handler.on('GetPageRequest', function wphSetupGetPage(data) {
-       var pageNumber = data.pageIndex + 1;
-       var pdfPage = pdfModel.getPage(pageNumber);
-       var page = {
-         pageIndex: data.pageIndex,
-         rotate: pdfPage.rotate,
-         ref: pdfPage.ref,
-         view: pdfPage.view
-       };
-       handler.send('GetPage', {pageInfo: page});
-     });
++      if (fontObj.coded)
++        return; // we don't need ctx.font for Type3 fonts
 +
-     handler.on('GetData', function wphSetupGetData(data, promise) {
-       promise.resolve(pdfModel.stream.bytes);
-     });
++      var name = fontObj.loadedName || 'sans-serif';
++      var bold = fontObj.black ? (fontObj.bold ? 'bolder' : 'bold') :
++                                 (fontObj.bold ? 'bold' : 'normal');
 +
-     handler.on('GetAnnotationsRequest', function wphSetupGetAnnotations(data) {
-       var pdfPage = pdfModel.getPage(data.pageIndex + 1);
-       handler.send('GetAnnotations', {
-         pageIndex: data.pageIndex,
-         annotations: pdfPage.getAnnotations()
-       });
-     });
++      var italic = fontObj.italic ? 'italic' : 'normal';
++      var typeface = '"' + name + '", ' + fontObj.fallbackName;
 +
-     handler.on('RenderPageRequest', function wphSetupRenderPage(data) {
-       var pageNum = data.pageIndex + 1;
++      // Some font backends cannot handle fonts below certain size.
++      // Keeping the font at minimal size and using the fontSizeScale to change
++      // 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 :
++                                   size / MIN_FONT_SIZE;
 +
-       // The following code does quite the same as
-       // Page.prototype.startRendering, but stops at one point and sends the
-       // result back to the main thread.
-       var gfx = new CanvasGraphics(null);
++      var rule = italic + ' ' + bold + ' ' + browserFontSize + 'px ' + typeface;
++      this.ctx.font = rule;
++    },
++    setTextRenderingMode: function CanvasGraphics_setTextRenderingMode(mode) {
++      this.current.textRenderingMode = mode;
++    },
++    setTextRise: function CanvasGraphics_setTextRise(rise) {
++      this.current.textRise = rise;
++    },
++    moveText: function CanvasGraphics_moveText(x, y) {
++      this.current.x = this.current.lineX += x;
++      this.current.y = this.current.lineY += y;
++    },
++    setLeadingMoveText: function CanvasGraphics_setLeadingMoveText(x, y) {
++      this.setLeading(-y);
++      this.moveText(x, y);
++    },
++    setTextMatrix: function CanvasGraphics_setTextMatrix(a, b, c, d, e, f) {
++      this.current.textMatrix = [a, b, c, d, e, f];
 +
-       var start = Date.now();
++      this.current.x = this.current.lineX = 0;
++      this.current.y = this.current.lineY = 0;
++    },
++    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;
++      geometry.ascent = font.ascent;
++      geometry.descent = font.descent;
++      return geometry;
++    },
 +
-       var dependency = [];
-       var operatorList = null;
-       try {
-         var page = pdfModel.getPage(pageNum);
-         // Pre compile the pdf page and fetch the fonts/images.
-         operatorList = page.getOperatorList(handler, dependency);
-       } catch (e) {
-         var minimumStackMessage =
-             'worker.js: while trying to getPage() and getOperatorList()';
- 
-         var wrappedException;
- 
-         // Turn the error into an obj that can be serialized
-         if (typeof e === 'string') {
-           wrappedException = {
-             message: e,
-             stack: minimumStackMessage
-           };
-         } else if (typeof e === 'object') {
-           wrappedException = {
-             message: e.message || e.toString(),
-             stack: e.stack || minimumStackMessage
-           };
-         } else {
-           wrappedException = {
-             message: 'Unknown exception type: ' + (typeof e),
-             stack: minimumStackMessage
-           };
-         }
++    paintChar: function (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 fillStrokeMode = textRenderingMode &
++        TextRenderingMode.FILL_STROKE_MASK;
++      var isAddToPathSet = !!(textRenderingMode &
++        TextRenderingMode.ADD_TO_PATH_FLAG);
 +
-         handler.send('PageError', {
-           pageNum: pageNum,
-           error: wrappedException
-         });
-         return;
++      var addToPath;
++      if (font.disableFontFace || isAddToPathSet) {
++        addToPath = font.getPathGenerator(this.commonObjs, character);
 +      }
 +
-       log('page=%d - getOperatorList: time=%dms, len=%d', pageNum,
-                               Date.now() - start, operatorList.fnArray.length);
- 
-       // Filter the dependecies for fonts.
-       var fonts = {};
-       for (var i = 0, ii = dependency.length; i < ii; i++) {
-         var dep = dependency[i];
-         if (dep.indexOf('g_font_') === 0) {
-           fonts[dep] = true;
++      if (font.disableFontFace) {
++        ctx.save();
++        ctx.translate(x, y);
++        ctx.beginPath();
++        addToPath(ctx, fontSize);
++        if (fillStrokeMode === TextRenderingMode.FILL ||
++            fillStrokeMode === TextRenderingMode.FILL_STROKE) {
++          ctx.fill();
++        }
++        if (fillStrokeMode === TextRenderingMode.STROKE ||
++            fillStrokeMode === TextRenderingMode.FILL_STROKE) {
++          ctx.stroke();
++        }
++        ctx.restore();
++      } else {
++        if (fillStrokeMode === TextRenderingMode.FILL ||
++            fillStrokeMode === TextRenderingMode.FILL_STROKE) {
++          ctx.fillText(character, x, y);
++        }
++        if (fillStrokeMode === TextRenderingMode.STROKE ||
++            fillStrokeMode === TextRenderingMode.FILL_STROKE) {
++          ctx.strokeText(character, x, y);
 +        }
 +      }
-       handler.send('RenderPage', {
-         pageIndex: data.pageIndex,
-         operatorList: operatorList,
-         depFonts: Object.keys(fonts)
-       });
-     }, this);
- 
-     handler.on('GetTextContent', function wphExtractText(data, promise) {
-       var pageNum = data.pageIndex + 1;
-       var start = Date.now();
 +
-       var textContent = '';
-       try {
-         var page = pdfModel.getPage(pageNum);
-         textContent = page.extractTextContent();
-         promise.resolve(textContent);
-       } catch (e) {
-         // Skip errored pages
-         promise.reject(e);
++      if (isAddToPathSet) {
++        var paths = this.pendingTextPaths || (this.pendingTextPaths = []);
++        paths.push({
++          transform: ctx.mozCurrentTransform,
++          x: x,
++          y: y,
++          fontSize: fontSize,
++          addToPath: addToPath
++        });
 +      }
++    },
 +
-       log('text indexing: page=%d - time=%dms',
-                       pageNum, Date.now() - start);
-     });
-   }
- };
- 
- var consoleTimer = {};
- 
- var workerConsole = {
-   log: function log() {
-     var args = Array.prototype.slice.call(arguments);
-     globalScope.postMessage({
-       action: 'console_log',
-       data: args
-     });
-   },
- 
-   error: function error() {
-     var args = Array.prototype.slice.call(arguments);
-     globalScope.postMessage({
-       action: 'console_error',
-       data: args
-     });
-     throw 'pdf.js execution error';
-   },
- 
-   time: function time(name) {
-     consoleTimer[name] = Date.now();
-   },
- 
-   timeEnd: function timeEnd(name) {
-     var time = consoleTimer[name];
-     if (!time) {
-       error('Unkown timer name ' + name);
-     }
-     this.log('Timer:', name, Date.now() - time);
-   }
- };
++    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);
++    },
 +
- // Worker thread?
- if (typeof window === 'undefined') {
-   globalScope.console = workerConsole;
- 
-   // Add a logger so we can pass warnings on to the main thread, errors will
-   // throw an exception which will be forwarded on automatically.
-   PDFJS.LogManager.addLogger({
-     warn: function(msg) {
-       globalScope.postMessage({
-         action: '_warn',
-         data: msg
-       });
-     }
-   });
++    showText: function CanvasGraphics_showText(glyphs, skipTextSelection) {
++      var ctx = this.ctx;
++      var current = this.current;
++      var font = current.font;
++      var fontSize = current.fontSize;
++      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 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 handler = new MessageHandler('worker_processor', this);
-   WorkerMessageHandler.setup(handler);
- }
++      // 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);
 +
++        ctx.scale(textHScale, 1);
 +
- var JpxImage = (function JpxImageClosure() {
-   // Table E.1
-   var SubbandsGainLog2 = {
-     'LL': 0,
-     'LH': 1,
-     'HL': 1,
-     'HH': 2
-   };
-   function JpxImage() {
-     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 position = 0, length = data.length;
-       while (position < length) {
-         var headerSize = 8;
-         var lbox = readUint(data, position, 4);
-         var tbox = readUint(data, position + 4, 4);
-         position += headerSize;
-         if (lbox == 1) {
-           lbox = readUint(data, position, 8);
-           position += 8;
-           headerSize += 8;
-         }
-         if (lbox === 0)
-           lbox = length - position + headerSize;
-         if (lbox < headerSize)
-           error('JPX error: Invalid box field size');
-         var dataLength = lbox - headerSize;
-         var jumpDataLength = true;
-         switch (tbox) {
-           case 0x6A501A1A: // 'jP\032\032'
-             // TODO
-             break;
-           case 0x6A703268: // 'jp2h'
-             jumpDataLength = false; // parsing child boxes
-             break;
-           case 0x636F6C72: // 'colr'
-             // TODO
-             break;
-           case 0x6A703263: // 'jp2c'
-             this.parseCodestream(data, position, position + dataLength);
-             break;
++        if (textSelection) {
++          this.save();
++          ctx.scale(1, -1);
++          geom = this.createTextGeometry();
++          this.restore();
 +        }
-         if (jumpDataLength)
-           position += dataLength;
-       }
-     },
-     parseCodestream: function JpxImage_parseCodestream(data, start, end) {
-       var context = {};
-       try {
-         var position = start;
-         while (position < end) {
-           var code = readUint16(data, position);
-           position += 2;
- 
-           var length = 0, j;
-           switch (code) {
-             case 0xFF4F: // Start of codestream (SOC)
-               context.mainHeader = true;
-               break;
-             case 0xFFD9: // End of codestream (EOC)
-               break;
-             case 0xFF51: // Image and tile size (SIZ)
-               length = readUint16(data, position);
-               var siz = {};
-               siz.Xsiz = readUint32(data, position + 4);
-               siz.Ysiz = readUint32(data, position + 8);
-               siz.XOsiz = readUint32(data, position + 12);
-               siz.YOsiz = readUint32(data, position + 16);
-               siz.XTsiz = readUint32(data, position + 20);
-               siz.YTsiz = readUint32(data, position + 24);
-               siz.XTOsiz = readUint32(data, position + 28);
-               siz.YTOsiz = readUint32(data, position + 32);
-               var componentsCount = readUint16(data, position + 36);
-               siz.Csiz = componentsCount;
-               var components = [];
-               j = position + 38;
-               for (var i = 0; i < componentsCount; i++) {
-                 var component = {
-                   precision: (data[j] & 0x7F) + 1,
-                   isSigned: !!(data[j] & 0x80),
-                   XRsiz: data[j + 1],
-                   YRsiz: data[j + 1]
-                 };
-                 calculateComponentDimensions(component, siz);
-                 components.push(component);
-               }
-               context.SIZ = siz;
-               context.components = components;
-               calculateTileGrids(context, components);
-               context.QCC = [];
-               context.COC = [];
-               break;
-             case 0xFF5C: // Quantization default (QCD)
-               length = readUint16(data, position);
-               var qcd = {};
-               j = position + 2;
-               var sqcd = data[j++];
-               var spqcdSize, scalarExpounded;
-               switch (sqcd & 0x1F) {
-                 case 0:
-                   spqcdSize = 8;
-                   scalarExpounded = true;
-                   break;
-                 case 1:
-                   spqcdSize = 16;
-                   scalarExpounded = false;
-                   break;
-                 case 2:
-                   spqcdSize = 16;
-                   scalarExpounded = true;
-                   break;
-                 default:
-                   throw 'Invalid SQcd value ' + sqcd;
-               }
-               qcd.noQuantization = spqcdSize == 8;
-               qcd.scalarExpounded = scalarExpounded;
-               qcd.guardBits = sqcd >> 5;
-               var spqcds = [];
-               while (j < length + position) {
-                 var spqcd = {};
-                 if (spqcdSize == 8) {
-                   spqcd.epsilon = data[j++] >> 3;
-                   spqcd.mu = 0;
-                 } else {
-                   spqcd.epsilon = data[j] >> 3;
-                   spqcd.mu = ((data[j] & 0x7) << 8) | data[j + 1];
-                   j += 2;
-                 }
-                 spqcds.push(spqcd);
-               }
-               qcd.SPqcds = spqcds;
-               if (context.mainHeader)
-                 context.QCD = qcd;
-               else {
-                 context.currentTile.QCD = qcd;
-                 context.currentTile.QCC = [];
-               }
-               break;
-             case 0xFF5D: // Quantization component (QCC)
-               length = readUint16(data, position);
-               var qcc = {};
-               j = position + 2;
-               var cqcc;
-               if (context.SIZ.Csiz < 257)
-                 cqcc = data[j++];
-               else {
-                 cqcc = readUint16(data, j);
-                 j += 2;
-               }
-               var sqcd = data[j++];
-               var spqcdSize, scalarExpounded;
-               switch (sqcd & 0x1F) {
-                 case 0:
-                   spqcdSize = 8;
-                   scalarExpounded = true;
-                   break;
-                 case 1:
-                   spqcdSize = 16;
-                   scalarExpounded = false;
-                   break;
-                 case 2:
-                   spqcdSize = 16;
-                   scalarExpounded = true;
-                   break;
-                 default:
-                   throw 'Invalid SQcd value ' + sqcd;
-               }
-               qcc.noQuantization = spqcdSize == 8;
-               qcc.scalarExpounded = scalarExpounded;
-               qcc.guardBits = sqcd >> 5;
-               var spqcds = [];
-               while (j < length + position) {
-                 var spqcd = {};
-                 if (spqcdSize == 8) {
-                   spqcd.epsilon = data[j++] >> 3;
-                   spqcd.mu = 0;
-                 } else {
-                   spqcd.epsilon = data[j] >> 3;
-                   spqcd.mu = ((data[j] & 0x7) << 8) | data[j + 1];
-                   j += 2;
-                 }
-                 spqcds.push(spqcd);
-               }
-               qcc.SPqcds = spqcds;
-               if (context.mainHeader)
-                 context.QCC[cqcc] = qcc;
-               else
-                 context.currentTile.QCC[cqcc] = qcc;
-               break;
-             case 0xFF52: // Coding style default (COD)
-               length = readUint16(data, position);
-               var cod = {};
-               j = position + 2;
-               var scod = data[j++];
-               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;
-               cod.multipleComponentTransform = data[j++];
- 
-               cod.decompositionLevelsCount = data[j++];
-               cod.xcb = (data[j++] & 0xF) + 2;
-               cod.ycb = (data[j++] & 0xF) + 2;
-               var blockStyle = data[j++];
-               cod.selectiveArithmeticCodingBypass = !!(blockStyle & 1);
-               cod.resetContextProbabilities = !!(blockStyle & 2);
-               cod.terminationOnEachCodingPass = !!(blockStyle & 4);
-               cod.verticalyStripe = !!(blockStyle & 8);
-               cod.predictableTermination = !!(blockStyle & 16);
-               cod.segmentationSymbolUsed = !!(blockStyle & 32);
-               cod.transformation = data[j++];
-               if (cod.entropyCoderWithCustomPrecincts) {
-                 var precinctsSizes = {};
-                 while (j < length + position) {
-                   var precinctsSize = data[j];
-                   precinctsSizes.push({
-                     PPx: precinctsSize & 0xF,
-                     PPy: precinctsSize >> 4
-                   });
-                 }
-                 cod.precinctsSizes = precinctsSizes;
-               }
++        for (var i = 0; i < glyphsLength; ++i) {
 +
-               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)
-                 context.COD = cod;
-               else {
-                 context.currentTile.COD = cod;
-                 context.currentTile.COC = [];
-               }
-               break;
-             case 0xFF90: // Start of tile-part (SOT)
-               length = readUint16(data, position);
-               var tile = {};
-               tile.index = readUint16(data, position + 2);
-               tile.length = readUint32(data, position + 4);
-               tile.dataEnd = tile.length + position - 2;
-               tile.partIndex = data[position + 8];
-               tile.partsCount = data[position + 9];
- 
-               context.mainHeader = false;
-               if (tile.partIndex === 0) {
-                 // reset component specific settings
-                 tile.COD = context.COD;
-                 tile.COC = context.COC.slice(0); // clone of the global COC
-                 tile.QCD = context.QCD;
-                 tile.QCC = context.QCC.slice(0); // clone of the global COC
-               }
-               context.currentTile = tile;
-               break;
-             case 0xFF93: // Start of data (SOD)
-               var tile = context.currentTile;
-               if (tile.partIndex === 0) {
-                 initializeTile(context, tile.index);
-                 buildPackets(context);
-               }
++          var glyph = glyphs[i];
++          if (glyph === null) {
++            // word break
++            this.ctx.translate(wordSpacing, 0);
++            current.x += wordSpacing * textHScale;
++            continue;
++          }
 +
-               // moving to the end of the data
-               length = tile.dataEnd - position;
++          this.processingType3 = glyph;
++          this.save();
++          ctx.scale(fontSize, fontSize);
++          ctx.transform.apply(ctx, fontMatrix);
++          this.executeOperatorList(glyph.operatorList);
++          this.restore();
 +
-               parseTilePackets(context, data, position, length);
-               break;
-             case 0xFF64: // Comment (COM)
-               length = readUint16(data, position);
-               // skipping content
-               break;
-             default:
-               throw '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');
-       }
-       this.tiles = transformComponents(context);
-       this.width = context.SIZ.Xsiz - context.SIZ.XOsiz;
-       this.height = context.SIZ.Ysiz - context.SIZ.YOsiz;
-       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);
-     component.x1 = Math.ceil(siz.Xsiz / component.XRsiz);
-     component.y0 = Math.ceil(siz.YOsiz / component.YRsiz);
-     component.y1 = Math.ceil(siz.Ysiz / component.YRsiz);
-     component.width = component.x1 - component.x0;
-     component.height = component.y1 - component.y0;
-   }
-   function calculateTileGrids(context, components) {
-     var siz = context.SIZ;
-     // Section B.3 Division into tile and tile-components
-     var 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.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);
-         tile.ty1 = Math.min(siz.YTOsiz + (q + 1) * siz.YTsiz, siz.Ysiz);
-         tile.width = tile.tx1 - tile.tx0;
-         tile.height = tile.ty1 - tile.ty0;
-         tile.components = [];
-         tiles.push(tile);
-       }
-     }
-     context.tiles = tiles;
- 
-     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];
-         tileComponent.tcx0 = Math.ceil(tile.tx0 / component.XRsiz);
-         tileComponent.tcy0 = Math.ceil(tile.ty0 / component.YRsiz);
-         tileComponent.tcx1 = Math.ceil(tile.tx1 / component.XRsiz);
-         tileComponent.tcy1 = Math.ceil(tile.ty1 / component.YRsiz);
-         tileComponent.width = tileComponent.tcx1 - tileComponent.tcx0;
-         tileComponent.height = tileComponent.tcy1 - tileComponent.tcy0;
-         tile.components[i] = tileComponent;
-       }
-     }
-   }
-   function getBlocksDimensions(context, component, r) {
-     var codOrCoc = component.codingStyleParameters;
-     var result = {};
-     if (!codOrCoc.entropyCoderWithCustomPrecincts) {
-       result.PPx = 15;
-       result.PPy = 15;
-     } else {
-       result.PPx = codOrCoc.precinctsSizes[r].PPx;
-       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);
-     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 ?
-       Math.ceil(resolution.trx1 / precinctWidth) -
-       Math.floor(resolution.trx0 / precinctWidth) : 0;
-     var numprecinctshigh = resolution.try1 > resolution.try0 ?
-       Math.ceil(resolution.try1 / precinctHeight) -
-       Math.floor(resolution.try0 / precinctHeight) : 0;
-     var numprecincts = numprecinctswide * numprecinctshigh;
-     var precinctXOffset = Math.floor(resolution.trx0 / precinctWidth) *
-       precinctWidth;
-     var precinctYOffset = Math.floor(resolution.try0 / precinctHeight) *
-       precinctHeight;
-     resolution.precinctParameters = {
-       precinctXOffset: precinctXOffset,
-       precinctYOffset: precinctYOffset,
-       precinctWidth: precinctWidth,
-       precinctHeight: precinctHeight,
-       numprecinctswide: numprecinctswide,
-       numprecinctshigh: numprecinctshigh,
-       numprecincts: numprecincts
-     };
-   }
-   function buildCodeblocks(context, subband, dimensions) {
-     // Section B.7 Division sub-band into code-blocks
-     var xcb_ = dimensions.xcb_;
-     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 precinctParameters = subband.resolution.precinctParameters;
-     var codeblocks = [];
-     var precincts = [];
-     for (var j = cby0; j < cby1; j++) {
-       for (var i = cbx0; i < cbx1; i++) {
-         var codeblock = {
-           cbx: i,
-           cby: j,
-           tbx0: codeblockWidth * i,
-           tby0: codeblockHeight * j,
-           tbx1: codeblockWidth * (i + 1),
-           tby1: codeblockHeight * (j + 1)
-         };
-         // calculate precinct number
-         var pi = Math.floor((codeblock.tbx0 -
-           precinctParameters.precinctXOffset) /
-           precinctParameters.precinctWidth);
-         var pj = Math.floor((codeblock.tby0 -
-           precinctParameters.precinctYOffset) /
-           precinctParameters.precinctHeight);
-         var 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);
-         } else {
-           precincts[precinctNumber] = precinct = {
-             cbxMin: i,
-             cbyMin: j,
-             cbxMax: i,
-             cbyMax: j
-           };
-         }
-         codeblock.precinct = precinct;
-       }
-     }
-     subband.codeblockParameters = {
-       codeblockWidth: xcb_,
-       codeblockHeight: ycb_,
-       numcodeblockwide: cbx1 - cbx0 + 1,
-       numcodeblockhigh: cby1 - cby1 + 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) {
-     var precinctCodeblocks = [];
-     // Section B.10.8 Order of info in packet
-     var subbands = resolution.subbands;
-     // sub-bands already ordered in 'LL', 'HL', 'LH', and 'HH' sequence
-     for (var i = 0, ii = subbands.length; i < ii; i++) {
-       var subband = subbands[i];
-       var codeblocks = subband.codeblocks;
-       for (var j = 0, jj = codeblocks.length; j < jj; j++) {
-         var codeblock = codeblocks[j];
-         if (codeblock.precinctNumber != precinctNumber)
-           continue;
-         precinctCodeblocks.push(codeblock);
-       }
-     }
-     return {
-       layerNumber: layerNumber,
-       codeblocks: precinctCodeblocks
-     };
-   }
-   function LayerResolutionComponentPositionIterator(context) {
-     var siz = context.SIZ;
-     var tileIndex = context.currentTile.index;
-     var tile = context.tiles[tileIndex];
-     var layersCount = tile.codingStyleDefaultParameters.layersCount;
-     var componentsCount = siz.Csiz;
-     var maxDecompositionLevelsCount = 0;
-     for (var q = 0; q < componentsCount; q++) {
-       maxDecompositionLevelsCount = Math.max(maxDecompositionLevelsCount,
-         tile.components[q].codingStyleParameters.decompositionLevelsCount);
-     }
++          var transformed = Util.applyTransform([glyph.width, 0], fontMatrix);
++          var width = (transformed[0] * fontSize + charSpacing) *
++                      current.fontDirection;
 +
-     var l = 0, r = 0, i = 0, k = 0;
- 
-     this.nextPacket = function JpxImage_nextPacket() {
-       // Section B.12.1.1 Layer-resolution-component-position
-       for (; l < layersCount; l++) {
-         for (; r <= maxDecompositionLevelsCount; r++) {
-           for (; i < componentsCount; i++) {
-             var component = tile.components[i];
-             if (r > component.codingStyleParameters.decompositionLevelsCount)
-               continue;
- 
-             var resolution = component.resolutions[r];
-             var numprecincts = resolution.precinctParameters.numprecincts;
-             for (; k < numprecincts;) {
-               var packet = createPacket(resolution, k, l);
-               k++;
-               return packet;
-             }
-             k = 0;
-           }
-           i = 0;
-         }
-         r = 0;
-       }
-       throw 'Out of packets';
-     };
-   }
-   function ResolutionLayerComponentPositionIterator(context) {
-     var siz = context.SIZ;
-     var tileIndex = context.currentTile.index;
-     var tile = context.tiles[tileIndex];
-     var layersCount = tile.codingStyleDefaultParameters.layersCount;
-     var componentsCount = siz.Csiz;
-     var maxDecompositionLevelsCount = 0;
-     for (var q = 0; q < componentsCount; q++) {
-       maxDecompositionLevelsCount = Math.max(maxDecompositionLevelsCount,
-         tile.components[q].codingStyleParameters.decompositionLevelsCount);
-     }
++          ctx.translate(width, 0);
++          current.x += width * textHScale;
 +
-     var r = 0, l = 0, i = 0, k = 0;
- 
-     this.nextPacket = function JpxImage_nextPacket() {
-       // Section B.12.1.2 Resolution-layer-component-position
-       for (; r <= maxDecompositionLevelsCount; r++) {
-         for (; l < layersCount; l++) {
-           for (; i < componentsCount; i++) {
-             var component = tile.components[i];
-             if (r > component.codingStyleParameters.decompositionLevelsCount)
-               continue;
- 
-             var resolution = component.resolutions[r];
-             var numprecincts = resolution.precinctParameters.numprecincts;
-             for (; k < numprecincts;) {
-               var packet = createPacket(resolution, k, l);
-               k++;
-               return packet;
-             }
-             k = 0;
-           }
-           i = 0;
-         }
-         l = 0;
-       }
-       throw 'Out of packets';
-     };
-   }
-   function buildPackets(context) {
-     var siz = context.SIZ;
-     var tileIndex = context.currentTile.index;
-     var tile = context.tiles[tileIndex];
-     var componentsCount = siz.Csiz;
-     // Creating resolutions and sub-bands for each component
-     for (var c = 0; c < componentsCount; c++) {
-       var component = tile.components[c];
-       var decompositionLevelsCount =
-         component.codingStyleParameters.decompositionLevelsCount;
-       // Section B.5 Resolution levels and sub-bands
-       var resolutions = [];
-       var subbands = [];
-       for (var r = 0; r <= decompositionLevelsCount; r++) {
-         var blocksDimensions = getBlocksDimensions(context, component, r);
-         var resolution = {};
-         var scale = 1 << (decompositionLevelsCount - r);
-         resolution.trx0 = Math.ceil(component.tcx0 / scale);
-         resolution.try0 = Math.ceil(component.tcy0 / scale);
-         resolution.trx1 = Math.ceil(component.tcx1 / scale);
-         resolution.try1 = Math.ceil(component.tcy1 / scale);
-         buildPrecincts(context, resolution, blocksDimensions);
-         resolutions.push(resolution);
- 
-         var subband;
-         if (r === 0) {
-           // one sub-band (LL) with last decomposition
-           subband = {};
-           subband.type = 'LL';
-           subband.tbx0 = Math.ceil(component.tcx0 / scale);
-           subband.tby0 = Math.ceil(component.tcy0 / scale);
-           subband.tbx1 = Math.ceil(component.tcx1 / scale);
-           subband.tby1 = Math.ceil(component.tcy1 / scale);
-           subband.resolution = resolution;
-           buildCodeblocks(context, subband, blocksDimensions);
-           subbands.push(subband);
-           resolution.subbands = [subband];
-         } else {
-           var bscale = 1 << (decompositionLevelsCount - r + 1);
-           var resolutionSubbands = [];
-           // three sub-bands (HL, LH and HH) with rest of decompositions
-           subband = {};
-           subband.type = 'HL';
-           subband.tbx0 = Math.ceil(component.tcx0 / bscale - 0.5);
-           subband.tby0 = Math.ceil(component.tcy0 / bscale);
-           subband.tbx1 = Math.ceil(component.tcx1 / bscale - 0.5);
-           subband.tby1 = Math.ceil(component.tcy1 / bscale);
-           subband.resolution = resolution;
-           buildCodeblocks(context, subband, blocksDimensions);
-           subbands.push(subband);
-           resolutionSubbands.push(subband);
- 
-           subband = {};
-           subband.type = 'LH';
-           subband.tbx0 = Math.ceil(component.tcx0 / bscale);
-           subband.tby0 = Math.ceil(component.tcy0 / bscale - 0.5);
-           subband.tbx1 = Math.ceil(component.tcx1 / bscale);
-           subband.tby1 = Math.ceil(component.tcy1 / bscale - 0.5);
-           subband.resolution = resolution;
-           buildCodeblocks(context, subband, blocksDimensions);
-           subbands.push(subband);
-           resolutionSubbands.push(subband);
- 
-           subband = {};
-           subband.type = 'HH';
-           subband.tbx0 = Math.ceil(component.tcx0 / bscale - 0.5);
-           subband.tby0 = Math.ceil(component.tcy0 / bscale - 0.5);
-           subband.tbx1 = Math.ceil(component.tcx1 / bscale - 0.5);
-           subband.tby1 = Math.ceil(component.tcy1 / bscale - 0.5);
-           subband.resolution = resolution;
-           buildCodeblocks(context, subband, blocksDimensions);
-           subbands.push(subband);
-           resolutionSubbands.push(subband);
- 
-           resolution.subbands = resolutionSubbands;
-         }
-       }
-       component.resolutions = resolutions;
-       component.subbands = subbands;
-     }
-     // Generate the packets sequence
-     var progressionOrder = tile.codingStyleDefaultParameters.progressionOrder;
-     var packetsIterator;
-     switch (progressionOrder) {
-       case 0:
-         tile.packetsIterator =
-           new LayerResolutionComponentPositionIterator(context);
-         break;
-       case 1:
-         tile.packetsIterator =
-           new ResolutionLayerComponentPositionIterator(context);
-         break;
-       default:
-         throw 'Unsupported progression order ' + progressionOrder;
-     }
-   }
-   function parseTilePackets(context, data, offset, dataLength) {
-     var position = 0;
-     var buffer, bufferSize = 0, skipNextBit = false;
-     function readBits(count) {
-       while (bufferSize < count) {
-         var b = data[offset + position];
-         position++;
-         if (skipNextBit) {
-           buffer = (buffer << 7) | b;
-           bufferSize += 7;
-           skipNextBit = false;
-         } else {
-           buffer = (buffer << 8) | b;
-           bufferSize += 8;
++          canvasWidth += width;
 +        }
-         if (b == 0xFF) {
-           skipNextBit = true;
++        ctx.restore();
++        this.processingType3 = null;
++      } else {
++        ctx.save();
++        this.applyTextTransforms();
++
++        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;
++
++        if (textSelection)
++          geom = this.createTextGeometry();
++
++        if (fontSizeScale != 1.0) {
++          ctx.scale(fontSizeScale, fontSizeScale);
++          lineWidth /= fontSizeScale;
 +        }
-       }
-       bufferSize -= count;
-       return (buffer >>> bufferSize) & ((1 << count) - 1);
-     }
-     function alignToByte() {
-       bufferSize = 0;
-       if (skipNextBit) {
-         position++;
-         skipNextBit = false;
-       }
-     }
-     function readCodingpasses() {
-       var value = readBits(1);
-       if (value === 0)
-         return 1;
-       value = (value << 1) | readBits(1);
-       if (value == 0x02)
-         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 tileIndex = context.currentTile.index;
-     var tile = context.tiles[tileIndex];
-     var packetsIterator = tile.packetsIterator;
-     while (position < dataLength) {
-       var packet = packetsIterator.nextPacket();
-       if (!readBits(1)) {
-         alignToByte();
-         continue;
-       }
-       var layerNumber = packet.layerNumber;
-       var queue = [];
-       for (var i = 0, ii = packet.codeblocks.length; i < ii; i++) {
-         var 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;
-         if ('included' in codeblock) {
-           codeblockIncluded = !!readBits(1);
-         } else {
-           // reading inclusion tree
-           var precinct = codeblock.precinct;
-           var inclusionTree, zeroBitPlanesTree;
-           if ('inclusionTree' in precinct) {
-             inclusionTree = precinct.inclusionTree;
-           } else {
-             // building inclusion and zero bit-planes trees
-             var width = precinct.cbxMax - precinct.cbxMin + 1;
-             var height = precinct.cbyMax - precinct.cbyMin + 1;
-             inclusionTree = new InclusionTree(width, height, layerNumber);
-             zeroBitPlanesTree = new TagTree(width, height);
-             precinct.inclusionTree = inclusionTree;
-             precinct.zeroBitPlanesTree = zeroBitPlanesTree;
++
++        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;
 +          }
 +
-           if (inclusionTree.reset(codeblockColumn, codeblockRow, layerNumber)) {
-             while (true) {
-               if (readBits(1)) {
-                 var valueReady = !inclusionTree.nextLevel();
-                 if (valueReady) {
-                   codeblock.included = true;
-                   codeblockIncluded = firstTimeInclusion = true;
-                   break;
-                 }
-               } else {
-                 inclusionTree.incrementValue(layerNumber);
-                 break;
++          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 && this.isFontSubpixelAAEnabled) {
++              // 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);
++            }
 +          }
-         }
-         if (!codeblockIncluded)
-           continue;
-         if (firstTimeInclusion) {
-           zeroBitPlanesTree = precinct.zeroBitPlanesTree;
-           zeroBitPlanesTree.reset(codeblockColumn, codeblockRow);
-           while (true) {
-             if (readBits(1)) {
-               var valueReady = !zeroBitPlanesTree.nextLevel();
-               if (valueReady)
-                 break;
-             } else
-               zeroBitPlanesTree.incrementValue();
++
++          x += charWidth;
++
++          canvasWidth += charWidth;
++
++          if (restoreNeeded) {
++            ctx.restore();
 +          }
-           codeblock.zeroBitPlanes = zeroBitPlanesTree.value;
 +        }
-         var codingpasses = readCodingpasses();
-         while (readBits(1))
-           codeblock.Lblock++;
-         var codingpassesLog2 = log2(codingpasses);
-         // rounding down log2
-         var bits = ((codingpasses < (1 << codingpassesLog2)) ?
-           codingpassesLog2 - 1 : codingpassesLog2) + codeblock.Lblock;
-         var codedDataLength = readBits(bits);
-         queue.push({
-           codeblock: codeblock,
-           codingpasses: codingpasses,
-           dataLength: codedDataLength
-         });
-       }
-       alignToByte();
-       while (queue.length > 0) {
-         var packetItem = queue.shift();
-         var codeblock = packetItem.codeblock;
-         if (!('data' in codeblock))
-           codeblock.data = [];
-         codeblock.data.push({
-           data: data,
-           start: offset + position,
-           end: offset + position + packetItem.dataLength,
-           codingpasses: packetItem.codingpasses
-         });
-         position += packetItem.dataLength;
-       }
-     }
-     return position;
-   }
-   function copyCoefficients(coefficients, x0, y0, width, height,
-                             delta, mb, codeblocks, transformation,
-                             segmentationSymbolUsed) {
-     var r = 0.5; // formula (E-6)
-     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)
-         continue;
-       if (!('data' in codeblock))
-         continue;
- 
-       var bitModel, currentCodingpassType;
-       bitModel = new BitModel(blockWidth, blockHeight, codeblock.subbandType,
-         codeblock.zeroBitPlanes);
-       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];
-         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 chunk = dataItem.data.subarray(dataItem.start, dataItem.end);
-         encodedData.set(chunk, k);
-         k += chunk.length;
-       }
-       // decoding the item
-       var decoder = new ArithmeticDecoder(encodedData, 0, totalLength);
-       bitModel.setDecoder(decoder);
- 
-       for (var q = 0; q < codingpasses; q++) {
-         switch (currentCodingpassType) {
-           case 0:
-             bitModel.runSignificancePropogationPass();
-             break;
-           case 1:
-             bitModel.runMagnitudeRefinementPass();
-             break;
-           case 2:
-             bitModel.runCleanupPass();
-             if (segmentationSymbolUsed)
-               bitModel.checkSegmentationSymbol();
-             break;
++        if (vertical) {
++          current.y -= x * textHScale;
++        } else {
++          current.x += x * textHScale;
 +        }
-         currentCodingpassType = (currentCodingpassType + 1) % 3;
++        ctx.restore();
 +      }
 +
-       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;
-           position++;
++      if (textSelection) {
++        geom.canvasWidth = canvasWidth;
++        if (vertical) {
++          var VERTICAL_TEXT_ROTATION = Math.PI / 2;
++          geom.angle += VERTICAL_TEXT_ROTATION;
 +        }
-         offset += width - blockWidth;
++        this.textLayer.appendText(geom);
 +      }
-     }
-   }
-   function transformTile(context, tile, c) {
-     var component = tile.components[c];
-     var codingStyleParameters = component.codingStyleParameters;
-     var quantizationParameters = component.quantizationParameters;
-     var decompositionLevelsCount =
-       codingStyleParameters.decompositionLevelsCount;
-     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 subbandCoefficients = [];
-     var k = 0, b = 0;
-     for (var i = 0; i <= decompositionLevelsCount; i++) {
-       var resolution = component.resolutions[i];
- 
-       for (var j = 0, jj = resolution.subbands.length; j < jj; j++) {
-         var mu, epsilon;
-         if (!scalarExpounded) {
-           // formula E-5
-           mu = spqcds[0].mu;
-           epsilon = spqcds[0].epsilon + (i > 0 ? 1 - i : 0);
-         } else {
-           mu = spqcds[b].mu;
-           epsilon = spqcds[b].epsilon;
-         }
- 
-         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 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++;
-       }
-     }
++      return canvasWidth;
++    },
++    showSpacedText: function CanvasGraphics_showSpacedText(arr) {
++      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 transformation = codingStyleParameters.transformation;
-     var transform = transformation === 0 ? new IrreversibleTransform() :
-       new ReversibleTransform();
-     var result = transform.calculate(subbandCoefficients,
-       component.tcx0, component.tcy0);
-     return {
-       left: component.tcx0,
-       top: component.tcy0,
-       width: result.width,
-       height: result.height,
-       items: result.items
-     };
-   }
-   function transformComponents(context) {
-     var siz = context.SIZ;
-     var components = context.components;
-     var componentsCount = siz.Csiz;
-     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);
++      if (textSelection) {
++        ctx.save();
++        this.applyTextTransforms();
++        geom = this.createTextGeometry();
++        ctx.restore();
 +      }
 +
-       // Section G.2.2 Inverse multi component transform
-       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;
-         }
-       }
++      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;
++          }
 +
-       // 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;
++          if (textSelection)
++            spacingAccumulator += spacingLength;
++        } else {
++          var shownCanvasWidth = this.showText(e, true);
 +
-         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;
++          if (textSelection) {
++            canvasWidth += spacingAccumulator + shownCanvasWidth;
++            spacingAccumulator = 0;
++          }
++        }
 +      }
 +
-       // 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;
++      if (textSelection) {
++        geom.canvasWidth = canvasWidth;
++        if (vertical) {
++          var VERTICAL_TEXT_ROTATION = Math.PI / 2;
++          geom.angle += VERTICAL_TEXT_ROTATION;
 +        }
-         result[c].items = data;
++        this.textLayer.appendText(geom);
 +      }
++    },
++    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);
++    },
 +
-       resultImages.push(result);
-     }
-     return resultImages;
-   }
-   function initializeTile(context, tileIndex) {
-     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;
-       component.quantizationParameters = qcdOrQcc;
-       var codOrCoc = c in context.currentTile.COC ?
-         context.currentTile.COC[c] : context.currentTile.COD;
-       component.codingStyleParameters = codOrCoc;
-     }
-     tile.codingStyleDefaultParameters = context.currentTile.COD;
-   }
++    // Type3 fonts
++    setCharWidth: function CanvasGraphics_setCharWidth(xWidth, yWidth) {
++      // We can safely ignore this since the width should be the same
++      // as the width in the Widths array.
++    },
++    setCharWidthAndBounds: function CanvasGraphics_setCharWidthAndBounds(xWidth,
++                                                                        yWidth,
++                                                                        llx,
++                                                                        lly,
++                                                                        urx,
++                                                                        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.clip();
++      this.endPath();
++    },
 +
-   // Section B.10.2 Tag trees
-   var TagTree = (function TagTreeClosure() {
-     function TagTree(width, height) {
-       var levelsLength = log2(Math.max(width, height)) + 1;
-       this.levels = [];
-       for (var i = 0; i < levelsLength; i++) {
-         var level = {
-           width: width,
-           height: height,
-           items: []
-         };
-         this.levels.push(level);
-         width = Math.ceil(width / 2);
-         height = Math.ceil(height / 2);
-       }
-     }
-     TagTree.prototype = {
-       reset: function TagTree_reset(i, j) {
-         var currentLevel = 0, value = 0;
-         while (currentLevel < this.levels.length) {
-           var level = this.levels[currentLevel];
-           var index = i + j * level.width;
-           if (index in level.items) {
-             value = level.items[index];
-             break;
-           }
-           level.index = index;
-           i >>= 1;
-           j >>= 1;
-           currentLevel++;
-         }
-         currentLevel--;
-         var level = this.levels[currentLevel];
-         level.items[level.index] = value;
-         this.currentLevel = currentLevel;
-         delete this.value;
-       },
-       incrementValue: function TagTree_incrementValue() {
-         var level = this.levels[this.currentLevel];
-         level.items[level.index]++;
-       },
-       nextLevel: function TagTree_nextLevel() {
-         var currentLevel = this.currentLevel;
-         var level = this.levels[currentLevel];
-         var value = level.items[level.index];
-         currentLevel--;
-         if (currentLevel < 0) {
-           this.value = value;
-           return false;
-         }
++    // 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;
 +
-         this.currentLevel = currentLevel;
-         var level = this.levels[currentLevel];
-         level.items[level.index] = value;
-         return true;
++          color = base.getRgb(args, 0);
++        }
++        var pattern = new TilingPattern(IR, color, this.ctx, this.objs,
++                                        this.commonObjs, this.baseTransform);
++      } else {
++        var pattern = getShadingPatternFromIR(IR);
 +      }
-     };
-     return TagTree;
-   })();
- 
-   var InclusionTree = (function InclusionTreeClosure() {
-     function InclusionTree(width, height,  defaultValue) {
-       var levelsLength = log2(Math.max(width, height)) + 1;
-       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++)
-           items[j] = defaultValue;
- 
-         var level = {
-           width: width,
-           height: height,
-           items: items
-         };
-         this.levels.push(level);
++      return pattern;
++    },
++    setStrokeColorN: function CanvasGraphics_setStrokeColorN(/*...*/) {
++      var cs = this.current.strokeColorSpace;
 +
-         width = Math.ceil(width / 2);
-         height = Math.ceil(height / 2);
++      if (cs.name == 'Pattern') {
++        this.current.strokeColor = this.getColorN_Pattern(arguments, cs);
++      } else {
++        this.setStrokeColor.apply(this, arguments);
 +      }
-     }
-     InclusionTree.prototype = {
-       reset: function InclusionTree_reset(i, j, stopValue) {
-         var currentLevel = 0;
-         while (currentLevel < this.levels.length) {
-           var level = this.levels[currentLevel];
-           var index = i + j * level.width;
-           level.index = index;
-           var value = level.items[index];
- 
-           if (value == 0xFF)
-             break;
- 
-           if (value > stopValue) {
-             this.currentLevel = currentLevel;
-             // already know about this one, propagating the value to top levels
-             this.propagateValues();
-             return false;
-           }
++    },
++    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;
++    },
++    setFillColorN: function CanvasGraphics_setFillColorN(/*...*/) {
++      var cs = this.current.fillColorSpace;
 +
-           i >>= 1;
-           j >>= 1;
-           currentLevel++;
-         }
-         this.currentLevel = currentLevel - 1;
-         return true;
-       },
-       incrementValue: function InclusionTree_incrementValue(stopValue) {
-         var level = this.levels[this.currentLevel];
-         level.items[level.index] = stopValue + 1;
-         this.propagateValues();
-       },
-       propagateValues: function InclusionTree_propagateValues() {
-         var levelIndex = this.currentLevel;
-         var level = this.levels[levelIndex];
-         var currentValue = level.items[level.index];
-         while (--levelIndex >= 0) {
-           var level = this.levels[levelIndex];
-           level.items[level.index] = currentValue;
-         }
-       },
-       nextLevel: function InclusionTree_nextLevel() {
-         var currentLevel = this.currentLevel;
-         var level = this.levels[currentLevel];
-         var value = level.items[level.index];
-         level.items[level.index] = 0xFF;
-         currentLevel--;
-         if (currentLevel < 0)
-           return false;
- 
-         this.currentLevel = currentLevel;
-         var level = this.levels[currentLevel];
-         level.items[level.index] = value;
-         return true;
++      if (cs.name == 'Pattern') {
++        this.current.fillColor = this.getColorN_Pattern(arguments, cs);
++      } else {
++        this.setFillColor.apply(this, arguments);
 +      }
-     };
-     return InclusionTree;
-   })();
++    },
++    setStrokeGray: function CanvasGraphics_setStrokeGray(gray) {
++      this.current.strokeColorSpace = ColorSpace.singletons.gray;
 +
-   // 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}
-     ];
++      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;
 +
-     function ArithmeticDecoder(data, start, end) {
-       this.data = data;
-       this.bp = start;
-       this.dataEnd = end;
++      var rgbColor = this.current.fillColorSpace.getRgb(arguments, 0);
++      var color = Util.makeCssRgb(rgbColor);
++      this.ctx.fillStyle = color;
++      this.current.fillColor = color;
++    },
++    setStrokeRGBColor: function CanvasGraphics_setStrokeRGBColor(r, g, b) {
++      this.current.strokeColorSpace = ColorSpace.singletons.rgb;
 +
-       this.chigh = data[start];
-       this.clow = 0;
++      var rgbColor = this.current.strokeColorSpace.getRgb(arguments, 0);
++      var color = Util.makeCssRgb(rgbColor);
++      this.ctx.strokeStyle = color;
++      this.current.strokeColor = color;
++    },
++    setFillRGBColor: function CanvasGraphics_setFillRGBColor(r, g, b) {
++      this.current.fillColorSpace = ColorSpace.singletons.rgb;
 +
-       this.byteIn();
++      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;
 +
-       this.chigh = ((this.chigh << 7) & 0xFFFF) | ((this.clow >> 9) & 0x7F);
-       this.clow = (this.clow << 7) & 0xFFFF;
-       this.ct -= 7;
-       this.a = 0x8000;
-     }
++      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;
 +
-     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;
++      var color = Util.makeCssCmyk(arguments);
++      this.ctx.fillStyle = color;
++      this.current.fillColor = color;
++    },
 +
-           if (qeTableIcx.switchFlag == 1) {
-             cx.mps = 1 - cx.mps;
-           }
-           cx.index = qeTableIcx.nlps;
-         }
-         return d;
-       }
-     };
++    shadingFill: function CanvasGraphics_shadingFill(patternIR) {
++      var ctx = this.ctx;
 +
-     return ArithmeticDecoder;
-   })();
++      this.save();
++      var pattern = getShadingPatternFromIR(patternIR);
++      ctx.fillStyle = pattern.getPattern(ctx, this, true);
 +
-   // Section D. Coefficient bit modeling
-   var BitModel = (function BitModelClosure() {
-     // 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)
-     var LLAndLHContextsLabel = new Uint8Array([
-       0, 5, 8, 0, 3, 7, 8, 0, 4, 7, 8, 0, 0, 0, 0, 0, 1, 6, 8, 0, 3, 7, 8, 0, 4,
-       7, 8, 0, 0, 0, 0, 0, 2, 6, 8, 0, 3, 7, 8, 0, 4, 7, 8, 0, 0, 0, 0, 0, 2, 6,
-       8, 0, 3, 7, 8, 0, 4, 7, 8, 0, 0, 0, 0, 0, 2, 6, 8, 0, 3, 7, 8, 0, 4, 7, 8
-     ]);
-     var HLContextLabel = new Uint8Array([
-       0, 3, 4, 0, 5, 7, 7, 0, 8, 8, 8, 0, 0, 0, 0, 0, 1, 3, 4, 0, 6, 7, 7, 0, 8,
-       8, 8, 0, 0, 0, 0, 0, 2, 3, 4, 0, 6, 7, 7, 0, 8, 8, 8, 0, 0, 0, 0, 0, 2, 3,
-       4, 0, 6, 7, 7, 0, 8, 8, 8, 0, 0, 0, 0, 0, 2, 3, 4, 0, 6, 7, 7, 0, 8, 8, 8
-     ]);
-     var HHContextLabel = new Uint8Array([
-       0, 1, 2, 0, 1, 2, 2, 0, 2, 2, 2, 0, 0, 0, 0, 0, 3, 4, 5, 0, 4, 5, 5, 0, 5,
-       5, 5, 0, 0, 0, 0, 0, 6, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 0, 0, 0, 0, 8, 8,
-       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}
-     ];
++      var inv = ctx.mozCurrentTransformInverse;
++      if (inv) {
++        var canvas = ctx.canvas;
++        var width = canvas.width;
++        var height = canvas.height;
 +
-     function BitModel(width, height, subband, zeroBitPlanes) {
-       this.width = width;
-       this.height = height;
++        var bl = Util.applyTransform([0, 0], inv);
++        var br = Util.applyTransform([0, height], inv);
++        var ul = Util.applyTransform([width, 0], inv);
++        var ur = Util.applyTransform([width, height], inv);
 +
-       this.contextLabelTable = subband == 'HH' ? HHContextLabel :
-         subband == 'HL' ? HLContextLabel : LLAndLHContextsLabel;
++        var x0 = Math.min(bl[0], br[0], ul[0], ur[0]);
++        var y0 = Math.min(bl[1], br[1], ul[1], ur[1]);
++        var x1 = Math.max(bl[0], br[0], ul[0], ur[0]);
++        var y1 = Math.max(bl[1], br[1], ul[1], ur[1]);
 +
-       var coefficientCount = width * height;
++        this.ctx.fillRect(x0, y0, x1 - x0, y1 - y0);
++      } else {
++        // HACK to draw the gradient onto an infinite rectangle.
++        // PDF gradients are drawn across the entire image while
++        // Canvas only allows gradients to be drawn in a rectangle
++        // The following bug should allow us to remove this.
++        // https://bugzilla.mozilla.org/show_bug.cgi?id=664884
 +
-       // coefficients outside the encoding region treated as insignificant
-       // add border state cells for significanceState
-       this.neighborsSignificance = new Uint8Array(coefficientCount);
-       this.coefficentsSign = new Uint8Array(coefficientCount);
-       this.coefficentsMagnitude = new Uint32Array(coefficientCount);
-       this.processingFlags = new Uint8Array(coefficientCount);
++        this.ctx.fillRect(-1e10, -1e10, 2e10, 2e10);
++      }
 +
-       var bitsDecoded = new Uint8Array(this.width * this.height);
-       for (var i = 0, ii = bitsDecoded.length; i < ii; i++)
-         bitsDecoded[i] = zeroBitPlanes;
-       this.bitsDecoded = bitsDecoded;
++      this.restore();
++    },
 +
-       this.reset();
-     }
++    // Images
++    beginInlineImage: function CanvasGraphics_beginInlineImage() {
++      error('Should not call beginInlineImage');
++    },
++    beginImageData: function CanvasGraphics_beginImageData() {
++      error('Should not call beginImageData');
++    },
 +
-     BitModel.prototype = {
-       setDecoder: function BitModel_setDecoder(decoder) {
-         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});
-       },
-       setNeighborsSignificance:
-         function BitModel_setNeighborsSignificance(row, column) {
-         var neighborsSignificance = this.neighborsSignificance;
-         var width = this.width, height = this.height;
-         var index = row * width + column;
-         if (row > 0) {
-           if (column > 0)
-             neighborsSignificance[index - width - 1] += 0x10;
-           if (column + 1 < width)
-             neighborsSignificance[index - width + 1] += 0x10;
-           neighborsSignificance[index - width] += 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;
-         }
-         if (column > 0)
-           neighborsSignificance[index - 1] += 0x01;
-         if (column + 1 < width)
-           neighborsSignificance[index + 1] += 0x01;
-         neighborsSignificance[index] |= 0x80;
-       },
-       runSignificancePropogationPass:
-         function BitModel_runSignificancePropogationPass() {
-         var decoder = this.decoder;
-         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)
-                 break;
++    paintFormXObjectBegin: function CanvasGraphics_paintFormXObjectBegin(matrix,
++                                                                        bbox) {
++      this.save();
++      this.baseTransformStack.push(this.baseTransform);
 +
-               if (coefficentsMagnitude[index] || !neighborsSignificance[index])
-                 continue;
- 
-               var contextLabel = labels[neighborsSignificance[index]];
-               var cx = contexts[contextLabel];
-               var decision = decoder.readBit(cx);
-               if (decision) {
-                 var sign = this.decodeSignBit(i, j);
-                 coefficentsSign[index] = sign;
-                 coefficentsMagnitude[index] = 1;
-                 this.setNeighborsSignificance(i, j);
-                 processingFlags[index] |= firstMagnitudeBitMask;
-               }
-               bitsDecoded[index]++;
-               processingFlags[index] |= processedMask;
-             }
-           }
-         }
-       },
-       decodeSignBit: function BitModel_decodeSignBit(row, column) {
-         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 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;
-       },
-       runMagnitudeRefinementPass:
-         function BitModel_runMagnitudeRefinementPass() {
-         var decoder = this.decoder;
-         var width = this.width, height = this.height;
-         var coefficentsMagnitude = this.coefficentsMagnitude;
-         var neighborsSignificance = this.neighborsSignificance;
-         var contexts = this.contexts;
-         var bitsDecoded = this.bitsDecoded;
-         var processingFlags = this.processingFlags;
-         var processedMask = 1;
-         var firstMagnitudeBitMask = 2;
-         for (var i0 = 0; i0 < height; i0 += 4) {
-           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;
- 
-               // significant but not those that have just become
-               if (!coefficentsMagnitude[index] ||
-                 (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;
-               }
++      if (matrix && isArray(matrix) && 6 == matrix.length)
++        this.transform.apply(this, matrix);
 +
-               var cx = contexts[contextLabel];
-               var bit = decoder.readBit(cx);
-               coefficentsMagnitude[index] =
-                 (coefficentsMagnitude[index] << 1) | bit;
-               bitsDecoded[index]++;
-               processingFlags[index] |= processedMask;
-             }
-           }
-         }
-       },
-       runCleanupPass: function BitModel_runCleanupPass() {
-         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;
-         var labels = this.contextLabelTable;
-         var bitsDecoded = this.bitsDecoded;
-         var processingFlags = this.processingFlags;
-         var processedMask = 1;
-         var firstMagnitudeBitMask = 2;
-         var oneRowDown = width;
-         var twoRowsDown = width * 2;
-         var threeRowsDown = width * 3;
-         for (var i0 = 0; i0 < height; i0 += 4) {
-           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 &&
-               processingFlags[index0] === 0 &&
-               processingFlags[index0 + oneRowDown] === 0 &&
-               processingFlags[index0 + twoRowsDown] === 0 &&
-               processingFlags[index0 + threeRowsDown] === 0 &&
-               neighborsSignificance[index0] === 0 &&
-               neighborsSignificance[index0 + oneRowDown] === 0 &&
-               neighborsSignificance[index0 + twoRowsDown] === 0 &&
-               neighborsSignificance[index0 + threeRowsDown] === 0;
-             var i1 = 0, index = index0;
-             var cx, i;
-             if (allEmpty) {
-               cx = this.runLengthContext;
-               var hasSignificantCoefficent = decoder.readBit(cx);
-               if (!hasSignificantCoefficent) {
-                 bitsDecoded[index0]++;
-                 bitsDecoded[index0 + oneRowDown]++;
-                 bitsDecoded[index0 + twoRowsDown]++;
-                 bitsDecoded[index0 + threeRowsDown]++;
-                 continue; // next column
-               }
-               cx = this.uniformContext;
-               i1 = (decoder.readBit(cx) << 1) | decoder.readBit(cx);
-               i = i0 + i1;
-               index += i1 * width;
- 
-               var sign = this.decodeSignBit(i, j);
-               coefficentsSign[index] = sign;
-               coefficentsMagnitude[index] = 1;
-               this.setNeighborsSignificance(i, j);
-               processingFlags[index] |= firstMagnitudeBitMask;
- 
-               index = index0;
-               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;
++      this.baseTransform = this.ctx.mozCurrentTransform;
 +
-               if (coefficentsMagnitude[index] ||
-                 (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);
-                 coefficentsSign[index] = sign;
-                 coefficentsMagnitude[index] = 1;
-                 this.setNeighborsSignificance(i, j);
-                 processingFlags[index] |= firstMagnitudeBitMask;
-               }
-               bitsDecoded[index]++;
-             }
-           }
-         }
-       },
-       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';
++      if (bbox && 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.clip();
++        this.endPath();
 +      }
-     };
++    },
 +
-     return BitModel;
-   })();
++    paintFormXObjectEnd: function CanvasGraphics_paintFormXObjectEnd() {
++      this.restore();
++      this.baseTransform = this.baseTransformStack.pop();
++    },
 +
-   // Section F, Discrete wavelet transofrmation
-   var Transform = (function TransformClosure() {
-     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);
-       }
-       return ll;
-     };
-     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;
- 
-       // 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)
-           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];
++    beginGroup: function CanvasGraphics_beginGroup(group) {
++      this.save();
++      var currentCtx = this.ctx;
++      // TODO non-isolated groups - according to Rik at adobe non-isolated
++      // group results aren't usually that different and they even have tools
++      // that ignore this setting. Notes from Rik on implmenting:
++      // - When you encounter an transparency group, create a new canvas with
++      // the dimensions of the bbox
++      // - copy the content from the previous canvas to the new canvas
++      // - draw as usual
++      // - remove the backdrop alpha:
++      // alphaNew = 1 - (1 - alpha)/(1 - alphaBackdrop) with 'alpha' the alpha
++      // value of your transparency group and 'alphaBackdrop' the alpha of the
++      // backdrop
++      // - remove background color:
++      // colorNew = color - alphaNew *colorBackdrop /(1 - alphaNew)
++      if (!group.isolated) {
++        info('TODO: Support non-isolated groups.');
 +      }
 +
-       var bufferPadding = 4;
-       var bufferLength = new Float32Array(Math.max(width, height) +
-         2 * bufferPadding);
-       var buffer = new Float32Array(bufferLength);
-       var bufferOut = new Float32Array(bufferLength);
- 
-       // 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;
-           }
-           continue;
-         }
++      // TODO knockout - supposedly possible with the clever use of compositing
++      // modes.
++      if (group.knockout) {
++        warn('Knockout groups not supported.');
++      }
 +
-         var k = v * width;
-         var l = bufferPadding;
-         for (var u = 0; u < width; u++, k++, l++)
-           buffer[l] = items[k];
- 
-         // Section F.3.7 extending... using max extension of 4
-         var i1 = bufferPadding - 1, j1 = bufferPadding + 1;
-         var i2 = bufferPadding + width - 2, j2 = bufferPadding + width;
-         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--];
- 
-         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];
++      var currentTransform = currentCtx.mozCurrentTransform;
++      if (group.matrix) {
++        currentCtx.transform.apply(currentCtx, group.matrix);
 +      }
++      assert(group.bbox, 'Bounding box is required.');
 +
-       // Section F.3.5 VER_SR
-       for (var u = 0; u < width; u++) {
-         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;
-           }
-           continue;
-         }
++      // Based on the current transform figure out how big the bounding box
++      // will actually be.
++      var bounds = Util.getAxialAlignedBoundingBox(
++                    group.bbox,
++                    currentCtx.mozCurrentTransform);
++      // Clip the bounding box to the current canvas.
++      var canvasBounds = [0,
++                          0,
++                          currentCtx.canvas.width,
++                          currentCtx.canvas.height];
++      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 k = u;
-         var l = bufferPadding;
-         for (var v = 0; v < height; v++, k += width, l++)
-           buffer[l] = items[k];
- 
-         // Section F.3.7 extending... using max extension of 4
-         var i1 = bufferPadding - 1, j1 = bufferPadding + 1;
-         var i2 = bufferPadding + height - 2, j2 = bufferPadding + height;
-         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--];
- 
-         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];
++      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);
 +      }
-       return {
-         width: width,
-         height: height,
-         items: items
-       };
-     };
-     return Transform;
-   })();
- 
-   // Section 3.8.2 Irreversible 9-7 filter
-   var IrreversibleTransform = (function IrreversibleTransformClosure() {
-     function IrreversibleTransform() {
-       Transform.call(this);
-     }
++      var scratchCanvas = CachedCanvases.getCanvas(
++        cacheId, drawnWidth, drawnHeight, true);
++      var groupCtx = scratchCanvas.context;
 +
-     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);
- 
-       var alpha = -1.586134342059924;
-       var beta = -0.052980118572961;
-       var gamma = 0.882911075530934;
-       var delta = 0.443506852043971;
-       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 2
-       var j = offset_ - 3;
-       for (var n = i0_ - 2, nn = i1_ + 2; n < nn; n++, j += 2)
-         x[j] = K_ * y[j];
- 
-       // 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 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]);
- 
-       // 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]);
- 
-       // 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]);
-     };
++      // 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.translate(-offsetX, -offsetY);
++      groupCtx.transform.apply(groupCtx, currentTransform);
 +
-     return IrreversibleTransform;
-   })();
++      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,
++          subtype: group.smask.subtype,
++          backdrop: group.smask.backdrop,
++          colorSpace: group.colorSpace && ColorSpace.fromIR(group.colorSpace)
++        });
++      } 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);
++      }
++      // 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([
++        ['BM', 'Normal'],
++        ['ca', 1],
++        ['CA', 1]
++      ]);
++      this.groupStack.push(currentCtx);
++      this.groupLevel++;
++    },
 +
-   // Section 3.8.1 Reversible 5-3 filter
-   var ReversibleTransform = (function ReversibleTransformClosure() {
-     function ReversibleTransform() {
-       Transform.call(this);
-     }
++    endGroup: function CanvasGraphics_endGroup(group) {
++      this.groupLevel--;
++      var groupCtx = this.ctx;
++      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) {
++        this.ctx.imageSmoothingEnabled = false;
++      } else {
++        this.ctx.mozImageSmoothingEnabled = false;
++      }
++      if (group.smask) {
++        this.tempSMask = this.smaskStack.pop();
++      } else {
++        this.ctx.drawImage(groupCtx.canvas, 0, 0);
++      }
++      this.restore();
++    },
 +
-     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);
++    beginAnnotations: function CanvasGraphics_beginAnnotations() {
++      this.save();
++      this.current = new CanvasExtraState();
++    },
 +
-       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);
++    endAnnotations: function CanvasGraphics_endAnnotations() {
++      this.restore();
++    },
 +
-       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);
-     };
++    beginAnnotation: function CanvasGraphics_beginAnnotation(rect, transform,
++                                                             matrix) {
++      this.save();
 +
-     return ReversibleTransform;
-   })();
++      if (rect && 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.clip();
++        this.endPath();
++      }
 +
-   return JpxImage;
- })();
++      this.transform.apply(this, transform);
++      this.transform.apply(this, matrix);
++    },
 +
++    endAnnotation: function CanvasGraphics_endAnnotation() {
++      this.restore();
++    },
 +
++    paintJpegXObject: function CanvasGraphics_paintJpegXObject(objId, w, h) {
++      var domImage = this.objs.get(objId);
++      if (!domImage) {
++        error('Dependent image isn\'t ready yet');
++      }
 +
- 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}
-     ];
++      this.save();
 +
-     function ArithmeticDecoder(data, start, end) {
-       this.data = data;
-       this.bp = start;
-       this.dataEnd = end;
++      var ctx = this.ctx;
++      // scale the image to the unit square
++      ctx.scale(1 / w, -1 / h);
 +
-       this.chigh = data[start];
-       this.clow = 0;
++      ctx.drawImage(domImage, 0, 0, domImage.width, domImage.height,
++                    0, -h, w, h);
++      if (this.imageLayer) {
++        var currentTransform = ctx.mozCurrentTransformInverse;
++        var position = this.getCanvasPosition(0, 0);
++        this.imageLayer.appendImage({
++          objId: objId,
++          left: position[0],
++          top: position[1],
++          width: w / currentTransform[0],
++          height: h / currentTransform[3]
++        });
++      }
++      this.restore();
++    },
 +
-       this.byteIn();
++    paintImageMaskXObject: function CanvasGraphics_paintImageMaskXObject(img) {
++      var ctx = this.ctx;
++      var width = img.width, height = img.height;
 +
-       this.chigh = ((this.chigh << 7) & 0xFFFF) | ((this.clow >> 9) & 0x7F);
-       this.clow = (this.clow << 7) & 0xFFFF;
-       this.ct -= 7;
-       this.a = 0x8000;
-     }
++      var glyph = this.processingType3;
 +
-     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;
++      if (COMPILE_TYPE3_GLYPHS && glyph && !('compiled' in glyph)) {
++        var MAX_SIZE_TO_COMPILE = 1000;
++        if (width <= MAX_SIZE_TO_COMPILE && height <= MAX_SIZE_TO_COMPILE) {
++          glyph.compiled =
++            compileType3Glyph({data: img.data, width: width, height: height});
 +        } else {
-           this.a = qeTableIcx.qe;
-           d = 1 - cx.mps;
- 
-           if (qeTableIcx.switchFlag == 1) {
-             cx.mps = 1 - cx.mps;
-           }
-           cx.index = qeTableIcx.nlps;
++          glyph.compiled = null;
 +        }
-         return d;
 +      }
-     };
 +
-     return ArithmeticDecoder;
-   })();
- 
-   // Utility data structures
-   function ContextCache() {}
++      if (glyph && glyph.compiled) {
++        glyph.compiled(ctx);
++        return;
++      }
 +
-   ContextCache.prototype = {
-     getContexts: function(id) {
-       if (id in this)
-         return this[id];
-       return (this[id] = []);
-     }
-   };
++      var maskCanvas = CachedCanvases.getCanvas('maskCanvas', width, height);
++      var maskCtx = maskCanvas.context;
++      maskCtx.save();
 +
-   function DecodingContext(data, start, end) {
-     this.data = data;
-     this.start = start;
-     this.end = end;
-   }
++      putBinaryImageMask(maskCtx, img);
 +
-   DecodingContext.prototype = {
-     get decoder() {
-       var decoder = new ArithmeticDecoder(this.data, this.start, this.end);
-       return shadow(this, 'decoder', decoder);
-     },
-     get contextCache() {
-       var cache = new ContextCache();
-       return shadow(this, 'contextCache', cache);
-     }
-   };
++      maskCtx.globalCompositeOperation = 'source-in';
 +
-   // Annex A. Arithmetic Integer Decoding Procedure
-   // 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 cx = contexts[prev];
-       if (!cx)
-         contexts[prev] = cx = {index: 0, mps: 0};
-       var bit = decoder.readBit(cx);
-       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;
-       }
-       state++;
-     }
-     v += offset;
-     return !s ? v : v > 0 ? -v : null;
-   }
++      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);
 +
-   // A.3 The IAID decoding procedure
-   function decodeIAID(contextCache, decoder, codeLength) {
-     var contexts = contextCache.getContexts('IAID');
- 
-     var prev = 1;
-     for (var i = 0; i < codeLength; i++) {
-       var cx = contexts[prev];
-       if (!cx)
-         contexts[prev] = cx = {index: 0, mps: 0};
-       var bit = decoder.readBit(cx);
-       prev = (prev * 2) + bit;
-     }
-     if (codeLength < 31)
-       return prev & ((1 << codeLength) - 1);
-     else
-       return prev - Math.pow(2, codeLength);
-   }
++      maskCtx.restore();
 +
-   // 7.3 Segment types
-   var SegmentTypes = [
-     'SymbolDictionary', null, null, null, 'IntermediateTextRegion', null,
-     'ImmediateTextRegion', 'ImmediateLosslessTextRegion', null, null, null,
-     null, null, null, null, null, 'patternDictionary', null, null, null,
-     'IntermediateHalftoneRegion', null, 'ImmediateHalftoneRegion',
-     'ImmediateLosslessHalftoneRegion', null, null, null, null, null, null, null,
-     null, null, null, null, null, 'IntermediateGenericRegion', null,
-     'ImmediateGenericRegion', 'ImmediateLosslessGenericRegion',
-     'IntermediateGenericRefinementRegion', null,
-     'ImmediateGenericRefinementRegion',
-     'ImmediateLosslessGenericRefinementRegion', null, null, null, null,
-     'PageInformation', 'EndOfPage', 'EndOfStripe', 'EndOfFile', 'Profiles',
-     'Tables', null, null, null, null, null, null, null, null,
-     'Extension'
-   ];
- 
-   var CodingTemplates = [
-     [{x: -1, y: -2}, {x: 0, y: -2}, {x: 1, y: -2}, {x: -2, y: -1},
-      {x: -1, y: -1}, {x: 0, y: -1}, {x: 1, y: -1}, {x: 2, y: -1},
-      {x: -4, y: 0}, {x: -3, y: 0}, {x: -2, y: 0}, {x: -1, y: 0}],
-     [{x: -1, y: -2}, {x: 0, y: -2}, {x: 1, y: -2}, {x: 2, y: -2},
-      {x: -2, y: -1}, {x: -1, y: -1}, {x: 0, y: -1}, {x: 1, y: -1},
-      {x: 2, y: -1}, {x: -3, y: 0}, {x: -2, y: 0}, {x: -1, y: 0}],
-     [{x: -1, y: -2}, {x: 0, y: -2}, {x: 1, y: -2}, {x: -2, y: -1},
-      {x: -1, y: -1}, {x: 0, y: -1}, {x: 1, y: -1}, {x: -2, y: 0},
-      {x: -1, y: 0}],
-     [{x: -3, y: -1}, {x: -2, y: -1}, {x: -1, y: -1}, {x: 0, y: -1},
-      {x: 1, y: -1}, {x: -4, y: 0}, {x: -3, y: 0}, {x: -2, y: 0}, {x: -1, y: 0}]
-   ];
- 
-   var RefinementTemplates = [
-     {
-       coding: [{x: 0, y: -1}, {x: 1, y: -1}, {x: -1, y: 0}],
-       reference: [{x: 0, y: -1}, {x: 1, y: -1}, {x: -1, y: 0}, {x: 0, y: 0},
-                   {x: 1, y: 0}, {x: -1, y: 1}, {x: 0, y: 1}, {x: 1, y: 1}]
++      this.paintInlineImageXObject(maskCanvas.canvas);
 +    },
-     {
-       coding: [{x: -1, y: -1}, {x: 0, y: -1}, {x: 1, y: -1}, {x: -1, y: 0}],
-       reference: [{x: 0, y: -1}, {x: -1, y: 0}, {x: 0, y: 0}, {x: 1, y: 0},
-                   {x: 0, y: 1}, {x: 1, y: 1}]
-     }
-   ];
- 
-   var ReusedContexts = [
-     0x1CD3, // '00111001101' (template) + '0011' (at),
-     0x079A, // '001111001101' + '0',
-     0x00E3, // '001110001' + '1',
-     0x018B  // '011000101' + '1'
-   ];
- 
-   var RefinementReusedContexts = [
-     0x0020, // '000' + '0' (coding) + '00010000' + '0' (reference)
-     0x0008  // '0000' + '001000'
-   ];
- 
-   function log2(x) {
-     var n = 1, i = 0;
-     while (x > n) {
-       n <<= 1;
-       i++;
-     }
-     return i;
-   }
 +
-   function readInt32(data, start) {
-     return (data[start] << 24) | (data[start + 1] << 16) |
-            (data[start + 2] << 8) | data[start + 3];
-   }
++    paintImageMaskXObjectGroup:
++      function CanvasGraphics_paintImageMaskXObjectGroup(images) {
++      var ctx = this.ctx;
 +
-   function readUint32(data, start) {
-     var value = readInt32(data, start);
-     return value & 0x80000000 ? (value + 4294967296) : value;
-   }
++      for (var i = 0, ii = images.length; i < ii; i++) {
++        var image = images[i];
++        var width = image.width, height = image.height;
 +
-   function readUint16(data, start) {
-     return (data[start] << 8) | data[start + 1];
-   }
++        var maskCanvas = CachedCanvases.getCanvas('maskCanvas', width, height);
++        var maskCtx = maskCanvas.context;
++        maskCtx.save();
 +
-   function readInt8(data, start) {
-     return (data[start] << 24) >> 24;
-   }
++        putBinaryImageMask(maskCtx, image);
 +
-   // 6.2 Generic Region Decoding Procedure
-   function decodeBitmap(mmr, width, height, templateIndex, prediction, skip, at,
-                         decodingContext) {
-     if (mmr)
-       error('JBIG2 error: MMR encoding is not supported');
- 
-     var useskip = !!skip;
-     var template = CodingTemplates[templateIndex].concat(at);
-     var templateLength = template.length;
-     var templateX = new Int32Array(templateLength);
-     var templateY = new Int32Array(templateLength);
-     for (var k = 0; k < templateLength; k++) {
-       templateX[k] = template[k].x;
-       templateY[k] = template[k].y;
-     }
++        maskCtx.globalCompositeOperation = 'source-in';
 +
-     var pseudoPixelContext = ReusedContexts[templateIndex];
-     var bitmap = [];
++        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);
 +
-     var decoder = decodingContext.decoder;
-     var contexts = decodingContext.contextCache.getContexts('GB');
++        maskCtx.restore();
 +
-     var ltp = 0;
-     for (var i = 0; i < height; i++) {
-       if (prediction) {
-         var cx = contexts[pseudoPixelContext];
-         if (!cx)
-           contexts[pseudoPixelContext] = cx = {index: 0, mps: 0};
-         var sltp = decoder.readBit(cx);
-         ltp ^= sltp;
-       }
-       if (ltp) {
-         bitmap.push(bitmap[bitmap.length - 1]); // duplicate previous row
-         continue;
-       }
-       var row = new Uint8Array(width);
-       bitmap.push(row);
-       for (var 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];
-         }
-         var cx = contexts[contextLabel];
-         if (!cx)
-           contexts[contextLabel] = cx = {index: 0, mps: 0};
-         var pixel = decoder.readBit(cx);
-         row[j] = pixel;
++        ctx.save();
++        ctx.transform.apply(ctx, image.transform);
++        ctx.scale(1, -1);
++        ctx.drawImage(maskCanvas.canvas, 0, 0, width, height,
++                      0, -1, 1, 1);
++        ctx.restore();
 +      }
-     }
-     return bitmap;
-   }
++    },
 +
-   // 6.3.2 Generic Refinement Region Decoding Procedure
-   function decodeRefinement(width, height, templateIndex, referenceBitmap,
-                             offsetX, offsetY, prediction, at,
-                             decodingContext) {
-     var codingTemplate = RefinementTemplates[templateIndex].coding;
-     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++) {
-       codingTemplateX[k] = codingTemplate[k].x;
-       codingTemplateY[k] = codingTemplate[k].y;
-     }
-     var referenceTemplate = RefinementTemplates[templateIndex].reference;
-     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++) {
-       referenceTemplateX[k] = referenceTemplate[k].x;
-       referenceTemplateY[k] = referenceTemplate[k].y;
-     }
-     var referenceWidth = referenceBitmap[0].length;
-     var referenceHeight = referenceBitmap.length;
- 
-     var pseudoPixelContext = RefinementReusedContexts[templateIndex];
-     var bitmap = [];
- 
-     var decoder = decodingContext.decoder;
-     var contexts = decodingContext.contextCache.getContexts('GR');
- 
-     var ltp = 0;
-     for (var i = 0; i < height; i++) {
-       if (prediction) {
-         var cx = contexts[pseudoPixelContext];
-         if (!cx)
-           contexts[pseudoPixelContext] = cx = {index: 0, mps: 0};
-         var sltp = decoder.readBit(cx);
-         ltp ^= sltp;
-       }
-       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 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)
-             contextLabel <<= 1; // out of bound pixel
-           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)
-             contextLabel <<= 1; // out of bound pixel
-           else
-             contextLabel = (contextLabel << 1) | referenceBitmap[i0][j0];
-         }
-         var cx = contexts[contextLabel];
-         if (!cx)
-           contexts[contextLabel] = cx = {index: 0, mps: 0};
-         var pixel = decoder.readBit(cx);
-         row[j] = pixel;
-       }
-     }
++    paintImageXObject: function CanvasGraphics_paintImageXObject(objId) {
++      var imgData = this.objs.get(objId);
++      if (!imgData)
++        error('Dependent image isn\'t ready yet');
 +
-     return bitmap;
-   }
++      this.paintInlineImageXObject(imgData);
++    },
 +
-   // 6.5.5 Decoding the symbol dictionary
-   function decodeSymbolDictionary(huffman, refinement, symbols,
-                                   numberOfNewSymbols, numberOfExportedSymbols,
-                                   huffmanTables, templateIndex, at,
-                                   refinementTemplateIndex, refinementAt,
-                                   decodingContext) {
-     if (huffman)
-       error('JBIG2 error: huffman is not supported');
- 
-     var newSymbols = [];
-     var currentHeight = 0;
-     var symbolCodeLength = log2(symbols.length + numberOfNewSymbols);
- 
-     var decoder = decodingContext.decoder;
-     var contextCache = decodingContext.contextCache;
- 
-     while (newSymbols.length < numberOfNewSymbols) {
-       var deltaHeight = decodeInteger(contextCache, 'IADH', decoder); // 6.5.6
-       currentHeight += deltaHeight;
-       var currentWidth = 0;
-       var totalWidth = 0;
-       while (true) {
-         var deltaWidth = decodeInteger(contextCache, 'IADW', decoder); // 6.5.7
-         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,
-             refinementTemplateIndex, symbol, rdx, rdy, false, refinementAt,
-             decodingContext);
-         } else {
-           // 6.5.8.1 Direct-coded symbol bitmap
-           bitmap = decodeBitmap(false, currentWidth, currentHeight,
-             templateIndex, false, null, at, decodingContext);
-         }
-         newSymbols.push(bitmap);
-       }
-     }
-     // 6.5.10 Exported symbols
-     var exportedSymbols = [];
-     var flags = [], currentFlag = false;
-     var totalSymbolsLength = symbols.length + numberOfNewSymbols;
-     while (flags.length < totalSymbolsLength) {
-       var runLength = decodeInteger(contextCache, 'IAEX', decoder);
-       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]);
-     return exportedSymbols;
-   }
++    paintInlineImageXObject:
++      function CanvasGraphics_paintInlineImageXObject(imgData) {
++      var width = imgData.width;
++      var height = imgData.height;
++      var ctx = this.ctx;
 +
-   function decodeTextRegion(huffman, refinement, width, height,
-                             defaultPixelValue, numberOfSymbolInstances,
-                             stripSize, inputSymbols, symbolCodeLength,
-                             transposed, dsOffset, referenceCorner,
-                             combinationOperator, huffmanTables,
-                             refinementTemplateIndex, refinementAt,
-                             decodingContext) {
-     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);
-       if (defaultPixelValue) {
-         for (var j = 0; j < width; j++)
-           row[j] = defaultPixelValue;
-       }
-       bitmap.push(row);
-     }
++      this.save();
++      // scale the image to the unit square
++      ctx.scale(1 / width, -1 / height);
 +
-     var decoder = decodingContext.decoder;
-     var contextCache = decodingContext.contextCache;
- 
-     if (transposed)
-       error('JBIG2 error: transposed is not supported');
- 
-     var stripT = -decodeInteger(contextCache, 'IADT', decoder); // 6.4.6
-     var firstS = 0;
-     var i = 0;
-     while (i < numberOfSymbolInstances) {
-       var deltaT = decodeInteger(contextCache, 'IADT', decoder); // 6.4.6
-       stripT += deltaT;
- 
-       var deltaFirstS = decodeInteger(contextCache, 'IAFS', decoder); // 6.4.7
-       firstS += deltaFirstS;
-       var currentS = firstS;
-       do {
-         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 symbolBitmap = inputSymbols[symbolId];
-         var symbolWidth = symbolBitmap[0].length;
-         var symbolHeight = symbolBitmap.length;
-         if (applyRefinement) {
-           var rdw = decodeInteger(contextCache, 'IARDW', decoder); // 6.4.11.1
-           var rdh = decodeInteger(contextCache, 'IARDH', decoder); // 6.4.11.2
-           var rdx = decodeInteger(contextCache, 'IARDX', decoder); // 6.4.11.3
-           var rdy = decodeInteger(contextCache, 'IARDY', decoder); // 6.4.11.4
-           symbolWidth += rdw;
-           symbolHeight += rdh;
-           symbolBitmap = decodeRefinement(symbolWidth, symbolHeight,
-             refinementTemplateIndex, symbolBitmap, (rdw >> 1) + rdx,
-             (rdh >> 1) + rdy, false, refinementAt,
-             decodingContext);
-         }
-         var offsetT = t - ((referenceCorner & 1) ? 0 : symbolHeight);
-         var offsetS = currentS - ((referenceCorner & 2) ? symbolWidth : 0);
-         for (var t2 = 0; t2 < symbolHeight; t2++) {
-           var row = bitmap[offsetT + t2];
-           if (!row) continue;
-           var symbolRow = symbolBitmap[t2];
-           switch (combinationOperator) {
-             case 0: // OR
-               for (var s2 = 0; s2 < symbolWidth; s2++)
-                 row[offsetS + s2] |= symbolRow[s2];
-               break;
-             case 2: // XOR
-               for (var s2 = 0; s2 < symbolWidth; s2++)
-                 row[offsetS + s2] ^= symbolRow[s2];
-               break;
-             default:
-               error('JBIG2 error: operator ' + combinationOperator +
-                     ' is not supported');
-           }
-         }
++      var currentTransform = ctx.mozCurrentTransformInverse;
++      var a = currentTransform[0], b = currentTransform[1];
++      var widthScale = Math.max(Math.sqrt(a * a + b * b), 1);
++      var c = currentTransform[2], d = currentTransform[3];
++      var heightScale = Math.max(Math.sqrt(c * c + d * d), 1);
++
++      var imgToPaint;
++      // 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);
++        var tmpCtx = tmpCanvas.context;
++        putBinaryImageData(tmpCtx, imgData);
++        imgToPaint = tmpCanvas.canvas;
++      }
++
++      var paintWidth = width, paintHeight = height;
++      var tmpCanvasId = 'prescale1';
++      // Vertial or horizontal scaling shall not be more than 2 to not loose the
++      // pixels during drawImage operation, painting on the temporary canvas(es)
++      // that are twice smaller in size
++      while ((widthScale > 2 && paintWidth > 1) ||
++             (heightScale > 2 && paintHeight > 1)) {
++        var newWidth = paintWidth, newHeight = paintHeight;
++        if (widthScale > 2 && paintWidth > 1) {
++          newWidth = Math.ceil(paintWidth / 2);
++          widthScale /= paintWidth / newWidth;
++        }
++        if (heightScale > 2 && paintHeight > 1) {
++          newHeight = Math.ceil(paintHeight / 2);
++          heightScale /= paintHeight / newHeight;
++        }
++        var tmpCanvas = CachedCanvases.getCanvas(tmpCanvasId,
++                                                 newWidth, newHeight);
++        tmpCtx = tmpCanvas.context;
++        tmpCtx.clearRect(0, 0, newWidth, newHeight);
++        tmpCtx.drawImage(imgToPaint, 0, 0, paintWidth, paintHeight,
++                                     0, 0, newWidth, newHeight);
++        imgToPaint = tmpCanvas.canvas;
++        paintWidth = newWidth;
++        paintHeight = newHeight;
++        tmpCanvasId = tmpCanvasId === 'prescale1' ? 'prescale2' : 'prescale1';
++      }
++      ctx.drawImage(imgToPaint, 0, 0, paintWidth, paintHeight,
++                                0, -height, width, height);
 +
-         currentS += symbolWidth - 1;
-         i++;
++      if (this.imageLayer) {
++        var position = this.getCanvasPosition(0, -height);
++        this.imageLayer.appendImage({
++          imgData: imgData,
++          left: position[0],
++          top: position[1],
++          width: width / currentTransform[0],
++          height: height / currentTransform[3]
++        });
++      }
++      this.restore();
++    },
 +
-         var deltaS = decodeInteger(contextCache, 'IADS', decoder); // 6.4.8
-         if (deltaS === null)
-           break; // OOB
-         currentS += deltaS + dsOffset;
-       } while (true);
-     }
-     return bitmap;
-   }
++    paintInlineImageXObjectGroup:
++      function CanvasGraphics_paintInlineImageXObjectGroup(imgData, map) {
++      var ctx = this.ctx;
++      var w = imgData.width;
++      var h = imgData.height;
 +
-   function readSegmentHeader(data, start) {
-     var segmentHeader = {};
-     segmentHeader.number = readUint32(data, start);
-     var flags = data[start + 4];
-     var segmentType = flags & 0x3F;
-     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;
-       position += 3;
-       var bytes = (referredToCount + 7) >> 3;
-       retainBits[0] = data[position++];
-       while (--bytes > 0) {
-         retainBits.push(data[position++]);
-       }
-     } 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 referredTo = [];
-     for (var 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)
-       segmentHeader.pageAssociation = data[position++];
-     else {
-       segmentHeader.pageAssociation = readUint32(data, position);
-       position += 4;
-     }
-     segmentHeader.length = readUint32(data, position);
-     position += 4;
-     if (segmentHeader.length == 0xFFFFFFFF) {
-       // 7.2.7 Segment data length, unknown segment length
-       if (segmentType === 38) { // ImmediateGenericRegion
-         var genericRegionInfo = readRegionSegmentInformation(data, position);
-         var genericRegionSegmentFlags = data[position +
-           RegionSegmentInformationFieldLength];
-         var genericRegionMmr = !!(genericRegionSegmentFlags & 1);
-         // searching for the segment end
-         var searchPatternLength = 6;
-         var searchPattern = new Uint8Array(searchPatternLength);
-         if (!genericRegionMmr) {
-           searchPattern[0] = 0xFF;
-           searchPattern[1] = 0xAC;
-         }
-         searchPattern[2] = (genericRegionInfo.height >>> 24) & 0xFF;
-         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++) {
-           var j = 0;
-           while (j < searchPatternLength && searchPattern[j] === data[i + j]) {
-             j++;
-           }
-           if (j == searchPatternLength) {
-             segmentHeader.length = i + searchPatternLength;
-             break;
-           }
-         }
-         if (segmentHeader.length == 0xFFFFFFFF) {
-           error('JBIG2 error: segment end was not found');
++      var tmpCanvas = CachedCanvases.getCanvas('inlineImage', w, h);
++      var tmpCtx = tmpCanvas.context;
++      putBinaryImageData(tmpCtx, imgData);
++
++      for (var i = 0, ii = map.length; i < ii; i++) {
++        var entry = map[i];
++        ctx.save();
++        ctx.transform.apply(ctx, entry.transform);
++        ctx.scale(1, -1);
++        ctx.drawImage(tmpCanvas.canvas, entry.x, entry.y, entry.w, entry.h,
++                      0, -1, 1, 1);
++        if (this.imageLayer) {
++          var position = this.getCanvasPosition(entry.x, entry.y);
++          this.imageLayer.appendImage({
++            imgData: imgData,
++            left: position[0],
++            top: position[1],
++            width: w,
++            height: h
++          });
 +        }
-       } else {
-         error('JBIG2 error: invalid unknown segment length');
++        ctx.restore();
 +      }
-     }
-     segmentHeader.headerEnd = position;
-     return segmentHeader;
-   }
++    },
 +
-   function readSegments(header, data, start, end) {
-     var segments = [];
-     var position = start;
-     while (position < end) {
-       var segmentHeader = readSegmentHeader(data, position);
-       position = segmentHeader.headerEnd;
-       var segment = {
-         header: segmentHeader,
-         data: data
-       };
-       if (!header.randomAccess) {
-         segment.start = position;
-         position += segmentHeader.length;
-         segment.end = position;
-       }
-       segments.push(segment);
-       if (segmentHeader.type == 51)
-         break; // end of file is found
-     }
-     if (header.randomAccess) {
-       for (var i = 0, ii = segments.length; i < ii; i++) {
-         segments[i].start = position;
-         position += segments[i].header.length;
-         segments[i].end = position;
-       }
-     }
-     return segments;
-   }
++    // Marked content
 +
-   // 7.4.1 Region segment information field
-   function readRegionSegmentInformation(data, start) {
-     return {
-       width: readUint32(data, start),
-       height: readUint32(data, start + 4),
-       x: readUint32(data, start + 8),
-       y: readUint32(data, start + 12),
-       combinationOperator: data[start + 16] & 7
-     };
-   }
-   var RegionSegmentInformationFieldLength = 17;
- 
-   function processSegment(segment, visitor) {
-     var header = segment.header;
- 
-     var data = segment.data, position = segment.start, end = segment.end;
-     var args;
-     switch (header.type) {
-       case 0: // SymbolDictionary
-         // 7.4.2 Symbol dictionary segment syntax
-         var dictionary = {};
-         var dictionaryFlags = readUint16(data, position); // 7.4.2.1.1
-         dictionary.huffman = !!(dictionaryFlags & 1);
-         dictionary.refinement = !!(dictionaryFlags & 2);
-         dictionary.huffmanDHSelector = (dictionaryFlags >> 2) & 3;
-         dictionary.huffmanDWSelector = (dictionaryFlags >> 4) & 3;
-         dictionary.bitmapSizeSelector = (dictionaryFlags >> 6) & 1;
-         dictionary.aggregationInstancesSelector = (dictionaryFlags >> 7) & 1;
-         dictionary.bitmapCodingContextUsed = !!(dictionaryFlags & 256);
-         dictionary.bitmapCodingContextRetained = !!(dictionaryFlags & 512);
-         dictionary.template = (dictionaryFlags >> 10) & 3;
-         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++) {
-             at.push({
-               x: readInt8(data, position),
-               y: readInt8(data, position + 1)
-             });
-             position += 2;
-           }
-           dictionary.at = at;
-         }
-         if (dictionary.refinement && !dictionary.refinementTemplate) {
-           var at = [];
-           for (var i = 0; i < 2; i++) {
-             at.push({
-               x: readInt8(data, position),
-               y: readInt8(data, position + 1)
-             });
-             position += 2;
-           }
-           dictionary.refinementAt = at;
-         }
-         dictionary.numberOfExportedSymbols = readUint32(data, position);
-         position += 4;
-         dictionary.numberOfNewSymbols = readUint32(data, position);
-         position += 4;
-         args = [dictionary, header.number, header.referredTo,
-                 data, position, end];
-         break;
-       case 6: // ImmediateTextRegion
-       case 7: // ImmediateLosslessTextRegion
-         var textRegion = {};
-         textRegion.info = readRegionSegmentInformation(data, position);
-         position += RegionSegmentInformationFieldLength;
-         var textRegionSegmentFlags = readUint16(data, position);
-         position += 2;
-         textRegion.huffman = !!(textRegionSegmentFlags & 1);
-         textRegion.refinement = !!(textRegionSegmentFlags & 2);
-         textRegion.stripSize = 1 << ((textRegionSegmentFlags >> 2) & 3);
-         textRegion.referenceCorner = (textRegionSegmentFlags >> 4) & 3;
-         textRegion.transposed = !!(textRegionSegmentFlags & 64);
-         textRegion.combinationOperator = (textRegionSegmentFlags >> 7) & 3;
-         textRegion.defaultPixelValue = (textRegionSegmentFlags >> 9) & 1;
-         textRegion.dsOffset = (textRegionSegmentFlags << 17) >> 27;
-         textRegion.refinementTemplate = (textRegionSegmentFlags >> 15) & 1;
-         if (textRegion.huffman) {
-           var textRegionHuffmanFlags = readUint16(data, position);
-           position += 2;
-           textRegion.huffmanFS = (textRegionHuffmanFlags) & 3;
-           textRegion.huffmanDS = (textRegionHuffmanFlags >> 2) & 3;
-           textRegion.huffmanDT = (textRegionHuffmanFlags >> 4) & 3;
-           textRegion.huffmanRefinementDW = (textRegionHuffmanFlags >> 6) & 3;
-           textRegion.huffmanRefinementDH = (textRegionHuffmanFlags >> 8) & 3;
-           textRegion.huffmanRefinementDX = (textRegionHuffmanFlags >> 10) & 3;
-           textRegion.huffmanRefinementDY = (textRegionHuffmanFlags >> 12) & 3;
-           textRegion.huffmanRefinementSizeSelector =
-             !!(textRegionHuffmanFlags & 14);
-         }
-         if (textRegion.refinement && !textRegion.refinementTemplate) {
-           var at = [];
-           for (var i = 0; i < 2; i++) {
-             at.push({
-               x: readInt8(data, position),
-               y: readInt8(data, position + 1)
-             });
-             position += 2;
-           }
-           textRegion.refinementAt = at;
-         }
-         textRegion.numberOfSymbolInstances = readUint32(data, position);
-         position += 4;
-         // TODO 7.4.3.1.7 Symbol ID Huffman table decoding
-         if (textRegion.huffman)
-           error('JBIG2 error: huffman is not supported');
-         args = [textRegion, header.referredTo, data, position, end];
-         break;
-       case 38: // ImmediateGenericRegion
-       case 39: // ImmediateLosslessGenericRegion
-         var genericRegion = {};
-         genericRegion.info = readRegionSegmentInformation(data, position);
-         position += RegionSegmentInformationFieldLength;
-         var genericRegionSegmentFlags = data[position++];
-         genericRegion.mmr = !!(genericRegionSegmentFlags & 1);
-         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++) {
-             at.push({
-               x: readInt8(data, position),
-               y: readInt8(data, position + 1)
-             });
-             position += 2;
-           }
-           genericRegion.at = at;
-         }
-         args = [genericRegion, data, position, end];
-         break;
-       case 48: // PageInformation
-         var pageInfo = {
-           width: readUint32(data, position),
-           height: readUint32(data, position + 4),
-           resolutionX: readUint32(data, position + 8),
-           resolutionY: readUint32(data, position + 12)
-         };
-         if (pageInfo.height == 0xFFFFFFFF)
-           delete pageInfo.height;
-         var pageSegmentFlags = data[position + 16];
-         var pageStripingInformatiom = readUint16(data, position + 17);
-         pageInfo.lossless = !!(pageSegmentFlags & 1);
-         pageInfo.refinement = !!(pageSegmentFlags & 2);
-         pageInfo.defaultPixelValue = (pageSegmentFlags >> 2) & 1;
-         pageInfo.combinationOperator = (pageSegmentFlags >> 3) & 3;
-         pageInfo.requiresBuffer = !!(pageSegmentFlags & 32);
-         pageInfo.combinationOperatorOverride = !!(pageSegmentFlags & 64);
-         args = [pageInfo];
-         break;
-       case 49: // EndOfPage
-         break;
-       case 50: // EndOfStripe
-         break;
-       case 51: // EndOfFile
-         break;
-       default:
-         error('JBIG2 error: segment type ' + header.typeName + '(' +
-               header.type + ') is not implemented');
-     }
-     var callbackName = 'on' + header.typeName;
-     if (callbackName in visitor)
-       visitor[callbackName].apply(visitor, args);
-   }
++    markPoint: function CanvasGraphics_markPoint(tag) {
++      // TODO Marked content.
++    },
++    markPointProps: function CanvasGraphics_markPointProps(tag, properties) {
++      // TODO Marked content.
++    },
++    beginMarkedContent: function CanvasGraphics_beginMarkedContent(tag) {
++      // TODO Marked content.
++    },
++    beginMarkedContentProps: function CanvasGraphics_beginMarkedContentProps(
++                                        tag, properties) {
++      // TODO Marked content.
++    },
++    endMarkedContent: function CanvasGraphics_endMarkedContent() {
++      // TODO Marked content.
++    },
 +
-   function processSegments(segments, visitor) {
-     for (var i = 0, ii = segments.length; i < ii; i++)
-       processSegment(segments[i], visitor);
-   }
++    // Compatibility
 +
-   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)
-       error('JBIG2 error: invalid header');
-     var header = {};
-     position += 8;
-     var flags = data[position++];
-     header.randomAccess = !(flags & 1);
-     if (!(flags & 2)) {
-       header.numberOfPages = readUint32(data, position);
-       position += 4;
-     }
-     var segments = readSegments(header, data, position, end);
-     error('Not implemented');
-     // processSegments(segments, new SimpleSegmentVisitor());
-   }
++    beginCompat: function CanvasGraphics_beginCompat() {
++      // TODO ignore undefined operators (should we do that anyway?)
++    },
++    endCompat: function CanvasGraphics_endCompat() {
++      // TODO stop ignoring undefined operators
++    },
 +
-   function parseJbig2Chunks(chunks) {
-     var visitor = new SimpleSegmentVisitor();
-     for (var i = 0, ii = chunks.length; i < ii; i++) {
-       var chunk = chunks[i];
-       var segments = readSegments({}, chunk.data, chunk.start, chunk.end);
-       processSegments(segments, visitor);
-     }
-     return visitor.buffer;
-   }
++    // Helper functions
 +
-   function SimpleSegmentVisitor() {}
- 
-   SimpleSegmentVisitor.prototype = {
-     onPageInformation: function SimpleSegmentVisitor_onPageInformation(info) {
-       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;
-       this.buffer = buffer;
-     },
-     drawBitmap: function SimpleSegmentVisitor_drawBitmap(regionInfo, bitmap) {
-       var pageInfo = this.currentPageInfo;
-       var width = regionInfo.width, height = regionInfo.height;
-       var rowSize = (pageInfo.width + 7) >> 3;
-       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;
-               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;
-               mask >>= 1;
-               if (!mask) {
-                 mask = 128;
-                 offset++;
-               }
++    consumePath: function CanvasGraphics_consumePath() {
++      if (this.pendingClip) {
++        if (this.pendingClip == EO_CLIP) {
++          if ('mozFillRule' in this.ctx) {
++            this.ctx.mozFillRule = 'evenodd';
++            this.ctx.clip();
++            this.ctx.mozFillRule = 'nonzero';
++          } else {
++            try {
++              this.ctx.clip('evenodd');
++            } catch (ex) {
++              // shouldn't really happen, but browsers might think differently
++              this.ctx.clip();
 +            }
-             break;
-           default:
-             error('JBIG2 error: operator ' + combinationOperator +
-                   ' is not supported');
++          }
++        } else {
++          this.ctx.clip();
 +        }
++        this.pendingClip = null;
 +      }
++      this.ctx.beginPath();
 +    },
-     onImmediateGenericRegion:
-       function SimpleSegmentVisitor_onImmediateGenericRegion(region, data,
-                                                              start, end) {
-       var regionInfo = region.info;
-       var decodingContext = new DecodingContext(data, start, end);
-       var bitmap = decodeBitmap(region.mmr, regionInfo.width, regionInfo.height,
-                                 region.template, region.prediction, null,
-                                 region.at, decodingContext);
-       this.drawBitmap(regionInfo, bitmap);
-     },
-     onImmediateLosslessGenericRegion:
-       function SimpleSegmentVisitor_onImmediateLosslessGenericRegion() {
-       this.onImmediateGenericRegion.apply(this, arguments);
-     },
-     onSymbolDictionary:
-       function SimpleSegmentVisitor_onSymbolDictionary(dictionary,
-                                                        currentSegment,
-                                                        referredSegments,
-                                                        data, start, end) {
-       var huffmanTables;
-       if (dictionary.huffman)
-         error('JBIG2 error: huffman is not supported');
- 
-       // Combines exported symbols from all referred segments
-       var symbols = this.symbols;
-       if (!symbols)
-         this.symbols = symbols = {};
- 
-       var inputSymbols = [];
-       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,
-         dictionary.refinement, inputSymbols, dictionary.numberOfNewSymbols,
-         dictionary.numberOfExportedSymbols, huffmanTables,
-         dictionary.template, dictionary.at,
-         dictionary.refinementTemplate, dictionary.refinementAt,
-         decodingContext);
-     },
-     onImmediateTextRegion:
-       function SimpleSegmentVisitor_onImmediateTextRegion(region,
-                                                           referredSegments,
-                                                           data, start, end) {
-       var regionInfo = region.info;
-       var huffmanTables;
- 
-       // Combines exported symbols from all referred segments
-       var symbols = this.symbols;
-       var inputSymbols = [];
-       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);
-       var bitmap = decodeTextRegion(region.huffman, region.refinement,
-         regionInfo.width, regionInfo.height, region.defaultPixelValue,
-         region.numberOfSymbolInstances, region.stripSize, inputSymbols,
-         symbolCodeLength, region.transposed, region.dsOffset,
-         region.referenceCorner, region.combinationOperator, huffmanTables,
-         region.refinementTemplate, region.refinementAt, decodingContext);
-       this.drawBitmap(regionInfo, bitmap);
++    getSinglePixelWidth: function CanvasGraphics_getSinglePixelWidth(scale) {
++      var inverse = this.ctx.mozCurrentTransformInverse;
++      // max of the current horizontal and vertical scale
++      return Math.sqrt(Math.max(
++        (inverse[0] * inverse[0] + inverse[1] * inverse[1]),
++        (inverse[2] * inverse[2] + inverse[3] * inverse[3])));
 +    },
-     onImmediateLosslessTextRegion:
-       function SimpleSegmentVisitor_onImmediateLosslessTextRegion() {
-         this.onImmediateTextRegion.apply(this, arguments);
++    getCanvasPosition: function CanvasGraphics_getCanvasPosition(x, y) {
++        var transform = this.ctx.mozCurrentTransform;
++        return [
++          transform[0] * x + transform[2] * y + transform[4],
++          transform[1] * x + transform[3] * y + transform[5]
++        ];
 +    }
 +  };
 +
-   function Jbig2Image() {}
- 
-   Jbig2Image.prototype = {
-     parseChunks: function Jbig2Image_parseChunks(chunks) {
-       return parseJbig2Chunks(chunks);
-     }
-   };
++  for (var op in OPS) {
++    CanvasGraphics.prototype[OPS[op]] = CanvasGraphics.prototype[op];
++  }
 +
-   return Jbig2Image;
++  return CanvasGraphics;
 +})();
 +
 +
- var bidi = PDFJS.bidi = (function bidiClosure() {
-   // Character types for symbols from 0000 to 00FF.
-   var baseTypes = [
-     'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'S', 'B', 'S', 'WS',
-     'B', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN',
-     'BN', 'BN', 'B', 'B', 'B', 'S', 'WS', 'ON', 'ON', 'ET', 'ET', 'ET', 'ON',
-     'ON', 'ON', 'ON', 'ON', 'ON', 'CS', 'ON', 'CS', 'ON', 'EN', 'EN', 'EN',
-     'EN', 'EN', 'EN', 'EN', 'EN', 'EN', 'EN', 'ON', 'ON', 'ON', 'ON', 'ON',
-     'ON', 'ON', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L',
-     'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'ON', 'ON',
-     'ON', 'ON', 'ON', 'ON', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L',
-     'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L',
-     'L', 'ON', 'ON', 'ON', 'ON', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'B', 'BN',
-     'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN',
-     'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN',
-     'BN', 'CS', 'ON', 'ET', 'ET', 'ET', 'ET', 'ON', 'ON', 'ON', 'ON', 'L', 'ON',
-     'ON', 'ON', 'ON', 'ON', 'ET', 'ET', 'EN', 'EN', 'ON', 'L', 'ON', 'ON', 'ON',
-     'EN', 'L', 'ON', 'ON', 'ON', 'ON', 'ON', 'L', 'L', 'L', 'L', 'L', 'L', 'L',
-     'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L',
-     'L', 'ON', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L',
-     'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L',
-     'L', 'L', 'L', 'ON', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L'
-   ];
- 
-   // Character types for symbols from 0600 to 06FF
-   var arabicTypes = [
-     'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
-     'CS', 'AL', 'ON', 'ON', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'AL',
-     'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
-     'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
-     'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
-     'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
-     'AL', 'AL', 'AL', 'AL', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM',
-     'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'AL', 'AL', 'AL', 'AL',
-     'AL', 'AL', 'AL', 'AN', 'AN', 'AN', 'AN', 'AN', 'AN', 'AN', 'AN', 'AN',
-     'AN', 'ET', 'AN', 'AN', 'AL', 'AL', 'AL', 'NSM', 'AL', 'AL', 'AL', 'AL',
-     'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
-     'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
-     'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
-     'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
-     'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
-     'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
-     'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
-     'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
-     'AL', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM',
-     'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'ON', 'NSM',
-     'NSM', 'NSM', 'NSM', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
-     'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL'
-   ];
- 
-   function isOdd(i) {
-     return (i & 1) !== 0;
-   }
 +
-   function isEven(i) {
-     return (i & 1) === 0;
-   }
++var ShadingIRs = {};
 +
-   function findUnequal(arr, start, value) {
-     var j;
-     for (var j = start, jj = arr.length; j < jj; ++j) {
-       if (arr[j] != value)
-         return j;
-     }
-     return j;
-   }
++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);
++        }
 +
-   function setValues(arr, start, end, value) {
-     for (var j = start; j < end; ++j) {
-       arr[j] = value;
-     }
++        for (var i = 0, ii = colorStops.length; i < ii; ++i) {
++          var c = colorStops[i];
++          grad.addColorStop(c[0], c[1]);
++        }
++        return grad;
++      }
++    };
 +  }
++};
 +
-   function reverseValues(arr, start, end) {
-     for (var i = start, j = end - 1; i < j; ++i, --j) {
-       var temp = arr[i];
-       arr[i] = arr[j];
-       arr[j] = temp;
++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 * 2 + 1] > coords[p2 * 2 + 1]) {
++      tmp = p1; p1 = p2; p2 = tmp; tmp = c1; c1 = c2; c2 = tmp;
++    }
++    if (coords[p2 * 2 + 1] > coords[p3 * 2 + 1]) {
++      tmp = p2; p2 = p3; p3 = tmp; tmp = c2; c2 = c3; c3 = tmp;
++    }
++    if (coords[p1 * 2 + 1] > coords[p2 * 2 + 1]) {
++      tmp = p1; p1 = p2; p2 = tmp; tmp = c1; c1 = c2; c2 = tmp;
++    }
++    var x1 = (coords[p1 * 2] + context.offsetX) * context.scaleX;
++    var y1 = (coords[p1 * 2 + 1] + context.offsetY) * context.scaleY;
++    var x2 = (coords[p2 * 2] + context.offsetX) * context.scaleX;
++    var y2 = (coords[p2 * 2 + 1] + context.offsetY) * context.scaleY;
++    var x3 = (coords[p3 * 2] + context.offsetX) * context.scaleX;
++    var y3 = (coords[p3 * 2 + 1] + context.offsetY) * context.scaleY;
++    if (y1 >= y3) {
++      return;
 +    }
-   }
- 
-   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';
++    var c1i = c1 * 3, c2i = c2 * 3, c3i = c3 * 3;
++    var c1r = colors[c1i], c1g = colors[c1i + 1], c1b = colors[c1i + 2];
++    var c2r = colors[c2i], c2g = colors[c2i + 1], c2b = colors[c2i + 2];
++    var c3r = colors[c3i], c3g = colors[c3i + 1], c3b = colors[c3i + 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;
++    switch (figure.type) {
++      case 'lattice':
++        var verticesPerRow = figure.verticesPerRow;
++        var rows = Math.floor(ps.length / verticesPerRow) - 1;
++        var cols = verticesPerRow - 1;
++        for (var 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 (var 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:
-         return c;
++        error('illigal figure');
++        break;
 +    }
 +  }
 +
-   function BidiResult(str, isLTR, vertical) {
-     this.str = str;
-     this.dir = vertical ? 'ttb' : isLTR ? 'ltr' : 'rtl';
-   }
- 
-   function bidi(str, startLevel, vertical) {
-     var isLTR = true;
-     var strLength = str.length;
-     if (strLength === 0 || vertical)
-       return new BidiResult(str, isLTR, vertical);
- 
-     // get types, fill arrays
- 
-     var chars = [];
-     var types = [];
-     var oldtypes = [];
-     var numBidi = 0;
- 
-     for (var i = 0; i < strLength; ++i) {
-       chars[i] = str.charAt(i);
- 
-       var charCode = str.charCodeAt(i);
-       var charType = 'L';
-       if (charCode <= 0x00ff)
-         charType = baseTypes[charCode];
-       else if (0x0590 <= charCode && charCode <= 0x05f4)
-         charType = 'R';
-       else if (0x0600 <= charCode && charCode <= 0x06ff)
-         charType = arabicTypes[charCode & 0xff];
-       else if (0x0700 <= charCode && charCode <= 0x08AC)
-         charType = 'AL';
- 
-       if (charType == 'R' || charType == 'AL' || charType == 'AN')
-         numBidi++;
- 
-       oldtypes[i] = 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
-     if (numBidi === 0) {
-       isLTR = true;
-       return new BidiResult(str, isLTR);
-     }
- 
-     if (startLevel == -1) {
-       if ((strLength / numBidi) < 0.3) {
-         isLTR = true;
-         startLevel = 0;
-       } else {
-         isLTR = false;
-         startLevel = 1;
-       }
-     }
- 
-     var levels = [];
- 
-     for (var 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 sor = e;
-     var eor = sor;
- 
-     /*
-      W1. Examine each non-spacing mark (NSM) in the level run, and change the
-      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')
-         types[i] = lastType;
-       else
-         lastType = types[i];
-     }
- 
-     /*
-      W2. Search backwards from each instance of a European number until the
-      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 = t;
-     }
- 
-     /*
-      W3. Change all ALs to R.
-      */
- 
-     for (var i = 0; i < strLength; ++i) {
-       var t = types[i];
-       if (t == 'AL')
-         types[i] = 'R';
++  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 boundsWidth = bounds[2] - bounds[0];
++    var boundsHeight = bounds[3] - bounds[1];
++
++    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 = width / boundsWidth;
++    var scaleY = height / boundsHeight;
++
++    var tmpCanvas = CachedCanvases.getCanvas('mesh', width, height, false);
++    var tmpCtx = tmpCanvas.context;
++    if (backgroundColor) {
++      tmpCtx.fillStyle = makeCssRgb(backgroundColor);
++      tmpCtx.fillRect(0, 0, width, height);
 +    }
 +
-     /*
-      W4. A single European separator between two European numbers changes to a
-      European number. A single common separator between two numbers of the same
-      type changes to that type:
-      */
++    var context = {
++      coords: coords,
++      colors: colors,
++      offsetX: -bounds[0],
++      offsetY: -bounds[1],
++      scaleX: scaleX,
++      scaleY: scaleY
++    };
 +
-     for (var 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])
-         types[i] = types[i - 1];
++    var data = tmpCtx.getImageData(0, 0, width, height);
++    for (var i = 0; i < figures.length; i++) {
++      drawFigure(data, figures[i], context);
 +    }
++    tmpCtx.putImageData(data, 0, 0);
 +
-     /*
-      W5. A sequence of European terminators adjacent to European numbers changes
-      to all European numbers:
-      */
++    return {canvas: tmpCanvas.canvas, scaleX: 1 / scaleX, scaleY: 1 / scaleY};
++  }
++  return createMeshCanvas;
++})();
 +
-     for (var i = 0; i < strLength; ++i) {
-       if (types[i] == 'EN') {
-         // do before
-         for (var 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')
-             break;
-           types[j] = 'EN';
++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 combinedScale;
++        // Obtain scale from matrix and current transformation matrix.
++        if (shadingFill) {
++          combinedScale = Util.singularValueDecompose2dScale(
++            ctx.mozCurrentTransform);
++        } else {
++          var matrixScale = Util.singularValueDecompose2dScale(matrix);
++          var curMatrixScale = Util.singularValueDecompose2dScale(
++            owner.baseTransform);
++          combinedScale = [matrixScale[0] * curMatrixScale[0],
++            matrixScale[1] * curMatrixScale[1]];
 +        }
-       }
-     }
- 
-     /*
-      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')
-         types[i] = 'ON';
-     }
 +
-     /*
-      W7. Search backwards from each instance of a European number until the
-      first strong type (R, L, or sor) is found. If an L is found,  then change
-      the type of the European number to L.
-      */
++        // Rasterizing on the main thread since sending/queue large canvases
++        // might cause OOM.
++        // TODO consider using WebGL or asm.js to perform rasterization
++        var temporaryPatternCanvas = createMeshCanvas(bounds, combinedScale,
++          coords, colors, figures, shadingFill ? null : background);
 +
-     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 = t;
-     }
++        if (!shadingFill) {
++          ctx.setTransform.apply(ctx, owner.baseTransform);
++          if (matrix) {
++            ctx.transform.apply(ctx, matrix);
++          }
++        }
 +
-     /*
-      N1. A sequence of neutrals takes the direction of the surrounding strong
-      text if the text on both sides has the same direction. European and Arabic
-      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.
-      */
++        ctx.translate(bounds[0], bounds[1]);
++        ctx.scale(temporaryPatternCanvas.scaleX,
++                  temporaryPatternCanvas.scaleY);
 +
-     for (var i = 0; i < strLength; ++i) {
-       if (types[i] == 'ON') {
-         var end = findUnequal(types, i + 1, 'ON');
-         var before = sor;
-         if (i > 0)
-           before = types[i - 1];
-         var after = eor;
-         if (end + 1 < strLength)
-           after = types[end + 1];
-         if (before != 'L')
-           before = 'R';
-         if (after != 'L')
-           after = 'R';
-         if (before == after)
-           setValues(types, i, end, before);
-         i = end - 1; // reset to end (-1 so next iteration is ok)
++        return ctx.createPattern(temporaryPatternCanvas.canvas, 'no-repeat');
 +      }
-     }
- 
-     /*
-      N2. Any remaining neutrals take the embedding direction.
-      */
- 
-     for (var i = 0; i < strLength; ++i) {
-       if (types[i] == 'ON')
-         types[i] = e;
-     }
- 
-     /*
-      I1. For all characters with an even (left-to-right) embedding direction,
-      those of type R go up one level and those of type AN or EN go up two
-      levels.
-      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];
-       if (isEven(levels[i])) {
-         if (t == 'R') {
-           levels[i] += 1;
-         } else if (t == 'AN' || t == 'EN') {
-           levels[i] += 2;
-         }
-       } else { // isOdd, so
-         if (t == 'L' || t == 'AN' || t == 'EN') {
-           levels[i] += 1;
-         }
++ShadingIRs.Dummy = {
++  fromIR: function Dummy_fromIR() {
++    return {
++      type: 'Pattern',
++      getPattern: function Dummy_fromIR_getPattern() {
++        return 'hotpink';
 +      }
-     }
- 
-     /*
-      L1. On each line, reset the embedding level of the following characters to
-      the paragraph embedding level:
- 
-      segment separators,
-      paragraph separators,
-      any sequence of whitespace characters preceding a segment separator or
-      paragraph separator, and any sequence of white space characters at the end
-      of the line.
-      */
- 
-     // don't bother as text is only single line
- 
-     /*
-      L2. From the highest level found in the text to the lowest odd level on
-      each line, reverse any contiguous sequence of characters that are at that
-      level or higher.
-      */
- 
-     // 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)
-         highestLevel = level;
-       if (lowestOddLevel > level && isOdd(level))
-         lowestOddLevel = level;
-     }
++    };
++  }
++};
 +
-     // now reverse between those limits
++function getShadingPatternFromIR(raw) {
++  var shadingIR = ShadingIRs[raw[0]];
++  if (!shadingIR) {
++    error('Unknown IR type: ' + raw[0]);
++  }
++  return shadingIR.fromIR(raw);
++}
 +
-     for (var level = highestLevel; level >= lowestOddLevel; --level) {
-       // find segments to reverse
-       var start = -1;
-       for (var i = 0, ii = levels.length; i < ii; ++i) {
-         if (levels[i] < level) {
-           if (start >= 0) {
-             reverseValues(chars, start, i);
-             start = -1;
-           }
-         } else if (start < 0) {
-           start = i;
-         }
-       }
-       if (start >= 0) {
-         reverseValues(chars, start, levels.length);
-       }
-     }
++var TilingPattern = (function TilingPatternClosure() {
++  var PaintType = {
++    COLORED: 1,
++    UNCOLORED: 2
++  };
 +
-     /*
-      L3. Combining marks applied to a right-to-left base character will at this
-      point precede their base character. If the rendering engine expects them to
-      follow the base characters in the final display process, then the ordering
-      of the marks and the base character must be reversed.
-      */
++  var MAX_PATTERN_SIZE = 3000; // 10in @ 300dpi shall be enough
 +
-     // don't bother for now
++  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;
++  }
 +
-     /*
-      L4. A character that possesses the mirrored property as specified by
-      Section 4.7, Mirrored, must be depicted by a mirrored glyph if the resolved
-      directionality of that character is R.
-      */
++  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;
 +
-     // don't mirror as characters are already mirrored in the pdf
++      info('TilingType: ' + tilingType);
 +
-     // Finally, return string
++      var x0 = bbox[0], y0 = bbox[1], x1 = bbox[2], y1 = bbox[3];
 +
-     var result = '';
-     for (var i = 0, ii = chars.length; i < ii; ++i) {
-       var ch = chars[i];
-       if (ch != '<' && ch != '>')
-         result += ch;
-     }
++      var topLeft = [x0, y0];
++      // we want the canvas to be as large as the step size
++      var botRight = [x0 + xstep, y0 + ystep];
 +
-     return new BidiResult(result, isLTR);
-   }
++      var width = botRight[0] - topLeft[0];
++      var height = botRight[1] - topLeft[1];
 +
-   return bidi;
- })();
++      // 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 Metadata = PDFJS.Metadata = (function MetadataClosure() {
-   function fixMetadata(meta) {
-     return meta.replace(/>\\376\\377([^<]+)/g, function(all, codes) {
-       var bytes = codes.replace(/\\([0-3])([0-7])([0-7])/g,
-                                 function(code, d1, d2, d3) {
-         return String.fromCharCode(d1 * 64 + d2 * 8 + d3 * 1);
-       });
-       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) :
-           '&#x' + (0x10000 + code).toString(16).substring(1) + ';';
-       }
-       return '>' + chars;
-     });
-   }
++      var tmpCanvas = CachedCanvases.getCanvas('pattern', width, height, true);
++      var tmpCtx = tmpCanvas.context;
++      var graphics = new CanvasGraphics(tmpCtx, commonObjs, objs);
++      graphics.groupLevel = owner.groupLevel;
 +
-   function Metadata(meta) {
-     if (typeof meta === 'string') {
-       // Ghostscript produces invalid metadata
-       meta = fixMetadata(meta);
++      this.setFillAndStrokeStyleToContext(tmpCtx, paintType, color);
 +
-       var parser = new DOMParser();
-       meta = parser.parseFromString(meta, 'application/xml');
-     } else if (!(meta instanceof Document)) {
-       error('Metadata: Invalid metadata object');
-     }
++      this.setScale(width, height, xstep, ystep);
++      this.transformToScale(graphics);
 +
-     this.metaDocument = meta;
-     this.metadata = {};
-     this.parse();
-   }
++      // transform coordinates to pattern space
++      var tmpTranslate = [1, 0, 0, 1, -topLeft[0], -topLeft[1]];
++      graphics.transform.apply(graphics, tmpTranslate);
 +
-   Metadata.prototype = {
-     parse: function Metadata_parse() {
-       var doc = this.metaDocument;
-       var rdf = doc.documentElement;
++      this.clipBbox(graphics, bbox, x0, y0, x1, y1);
 +
-       if (rdf.nodeName.toLowerCase() !== 'rdf:rdf') { // Wrapped in <xmpmeta>
-         rdf = rdf.firstChild;
-         while (rdf && rdf.nodeName.toLowerCase() !== 'rdf:rdf')
-           rdf = rdf.nextSibling;
-       }
++      graphics.executeOperatorList(operatorList);
++      return tmpCanvas.canvas;
++    },
 +
-       var nodeName = (rdf) ? rdf.nodeName.toLowerCase() : null;
-       if (!rdf || nodeName !== 'rdf:rdf' || !rdf.hasChildNodes())
-         return;
++    setScale: function TilingPattern_setScale(width, height, xstep, ystep) {
++      this.scale = [width / xstep, height / ystep];
++    },
 +
-       var children = rdf.childNodes, desc, entry, name, i, ii, length, iLength;
++    transformToScale: function TilingPattern_transformToScale(graphics) {
++      var scale = this.scale;
++      var tmpScale = [scale[0], 0, 0, scale[1], 0, 0];
++      graphics.transform.apply(graphics, tmpScale);
++    },
 +
-       for (i = 0, length = children.length; i < length; i++) {
-         desc = children[i];
-         if (desc.nodeName.toLowerCase() !== 'rdf:description')
-           continue;
++    scaleToContext: function TilingPattern_scaleToContext() {
++      var scale = this.scale;
++      this.ctx.scale(1 / scale[0], 1 / scale[1]);
++    },
 +
-         for (ii = 0, iLength = desc.childNodes.length; ii < iLength; ii++) {
-           if (desc.childNodes[ii].nodeName.toLowerCase() !== '#text') {
-             entry = desc.childNodes[ii];
-             name = entry.nodeName.toLowerCase();
-             this.metadata[name] = entry.textContent.trim();
-           }
-         }
++    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();
 +      }
 +    },
 +
-     get: function Metadata_get(name) {
-       return this.metadata[name] || null;
-     },
++    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);
++        }
++      },
 +
-     has: function Metadata_has(name) {
-       return typeof this.metadata[name] !== 'undefined';
++    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 Metadata;
++  return TilingPattern;
 +})();
- /* -*- 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
- 
-        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.
- */
- 
- // - 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 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 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;
++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);
 +    }
-     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 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);
 +    }
-     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;
++  },
++  get loadTestFont() {
++    // This is a CFF font with 1 glyph for '.' that fills its entire width and
++    // height.
++    return shadow(this, 'loadTestFont', atob(
++      'T1RUTwALAIAAAwAwQ0ZGIDHtZg4AAAOYAAAAgUZGVE1lkzZwAAAEHAAAABxHREVGABQAFQ' +
++      'AABDgAAAAeT1MvMlYNYwkAAAEgAAAAYGNtYXABDQLUAAACNAAAAUJoZWFk/xVFDQAAALwA' +
++      'AAA2aGhlYQdkA+oAAAD0AAAAJGhtdHgD6AAAAAAEWAAAAAZtYXhwAAJQAAAAARgAAAAGbm' +
++      'FtZVjmdH4AAAGAAAAAsXBvc3T/hgAzAAADeAAAACAAAQAAAAEAALZRFsRfDzz1AAsD6AAA' +
++      'AADOBOTLAAAAAM4KHDwAAAAAA+gDIQAAAAgAAgAAAAAAAAABAAADIQAAAFoD6AAAAAAD6A' +
++      'ABAAAAAAAAAAAAAAAAAAAAAQAAUAAAAgAAAAQD6AH0AAUAAAKKArwAAACMAooCvAAAAeAA' +
++      'MQECAAACAAYJAAAAAAAAAAAAAQAAAAAAAAAAAAAAAFBmRWQAwAAuAC4DIP84AFoDIQAAAA' +
++      'AAAQAAAAAAAAAAACAAIAABAAAADgCuAAEAAAAAAAAAAQAAAAEAAAAAAAEAAQAAAAEAAAAA' +
++      'AAIAAQAAAAEAAAAAAAMAAQAAAAEAAAAAAAQAAQAAAAEAAAAAAAUAAQAAAAEAAAAAAAYAAQ' +
++      'AAAAMAAQQJAAAAAgABAAMAAQQJAAEAAgABAAMAAQQJAAIAAgABAAMAAQQJAAMAAgABAAMA' +
++      'AQQJAAQAAgABAAMAAQQJAAUAAgABAAMAAQQJAAYAAgABWABYAAAAAAAAAwAAAAMAAAAcAA' +
++      'EAAAAAADwAAwABAAAAHAAEACAAAAAEAAQAAQAAAC7//wAAAC7////TAAEAAAAAAAABBgAA' +
++      'AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAA' +
++      'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' +
++      'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' +
++      'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' +
++      'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAA' +
++      'AAAAD/gwAyAAAAAQAAAAAAAAAAAAAAAAAAAAABAAQEAAEBAQJYAAEBASH4DwD4GwHEAvgc' +
++      'A/gXBIwMAYuL+nz5tQXkD5j3CBLnEQACAQEBIVhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWF' +
++      'hYWFhYWFhYAAABAQAADwACAQEEE/t3Dov6fAH6fAT+fPp8+nwHDosMCvm1Cvm1DAz6fBQA' +
++      'AAAAAAABAAAAAMmJbzEAAAAAzgTjFQAAAADOBOQpAAEAAAAAAAAADAAUAAQAAAABAAAAAg' +
++      'ABAAAAAAAAAAAD6AAAAAAAAA=='
++    ));
++  },
++
++  loadTestFontId: 0,
++
++  loadingContext: {
++    requests: [],
++    nextRequestId: 0
++  },
++
++  isSyncFontLoadingSupported: (function detectSyncFontLoadingSupport() {
++    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)
++      return true;
++    // TODO other browsers
++    return false;
++  })(),
++
++  bind: function fontLoaderBind(fonts, callback) {
++    assert(!isWorker, 'bind() shall be called from main thread');
++
++    var rules = [], fontsToLoad = [];
++    for (var i = 0, ii = fonts.length; i < ii; i++) {
++      var font = fonts[i];
++
++      // Add the font to the DOM only once or skip if the font
++      // is already loaded.
++      if (font.attached || font.loading === false) {
++        continue;
 +      }
-     }
-     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]);
-     }
++      font.attached = true;
 +
-     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 rule = font.bindDOM();
++      if (rule) {
++        rules.push(rule);
++        fontsToLoad.push(font);
++      }
 +    }
 +
-     var mcu = 0, marker;
-     var mcuExpected;
-     if (componentsLength == 1) {
-       mcuExpected = components[0].blocksPerLine * components[0].blocksPerColumn;
++    var request = FontLoader.queueLoadingCallback(callback);
++    if (rules.length > 0 && !this.isSyncFontLoadingSupported) {
++      FontLoader.prepareFontLoadEvent(rules, fontsToLoad, request);
 +    } else {
-       mcuExpected = mcusPerLine * frame.mcusPerColumn;
++      request.complete();
 +    }
-     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";
-       }
++  queueLoadingCallback: function FontLoader_queueLoadingCallback(callback) {
++    function LoadLoader_completeRequest() {
++      assert(!request.end, 'completeRequest() cannot be called twice');
++      request.end = Date.now();
 +
-       if (marker >= 0xFFD0 && marker <= 0xFFD7) { // RSTx
-         offset += 2;
++      // sending all completed requests in order how they were queued
++      while (context.requests.length > 0 && context.requests[0].end) {
++        var otherRequest = context.requests.shift();
++        setTimeout(otherRequest.callback, 0);
 +      }
-       else
-         break;
 +    }
 +
-     return offset - startOffset;
-   }
++    var context = FontLoader.loadingContext;
++    var requestId = 'pdfjs-font-loading-' + (context.nextRequestId++);
++    var request = {
++      id: requestId,
++      complete: LoadLoader_completeRequest,
++      callback: callback,
++      started: Date.now()
++    };
++    context.requests.push(request);
++    return request;
++  },
 +
-   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;
-       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;
-         }
++  prepareFontLoadEvent: function fontLoaderPrepareFontLoadEvent(rules,
++                                                                fonts,
++                                                                request) {
++      /** Hack begin */
++      // There's currently no event when a font has finished downloading so the
++      // following code is a dirty hack to 'guess' when a font is
++      // ready. It's assumed fonts are loaded in order, so add a known test
++      // font after the desired fonts and then test for the loading of that
++      // test font.
 +
-         // 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;
++      function int32(data, offset) {
++        return (data.charCodeAt(offset) << 24) |
++               (data.charCodeAt(offset + 1) << 16) |
++               (data.charCodeAt(offset + 2) << 8) |
++               (data.charCodeAt(offset + 3) & 0xff);
 +      }
 +
-       // 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;
++      function string32(value) {
++        return String.fromCharCode((value >> 24) & 0xff) +
++               String.fromCharCode((value >> 16) & 0xff) +
++               String.fromCharCode((value >> 8) & 0xff) +
++               String.fromCharCode(value & 0xff);
 +      }
 +
-       // 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;
++      function spliceString(s, offset, remove, insert) {
++        var chunk1 = data.substr(0, offset);
++        var chunk2 = data.substr(offset + remove);
++        return chunk1 + insert + chunk2;
 +      }
-     }
 +
-     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;
-   }
++      var i, ii;
 +
-   function clampTo8bit(a) {
-     return a < 0 ? 0 : a > 255 ? 255 : a;
-   }
++      var canvas = document.createElement('canvas');
++      canvas.width = 1;
++      canvas.height = 1;
++      var ctx = canvas.getContext('2d');
 +
-   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;
-           }
++      var called = 0;
++      function isFontReady(name, callback) {
++        called++;
++        // With setTimeout clamping this gives the font ~100ms to load.
++        if(called > 30) {
++          warn('Load test font never loaded.');
++          callback();
++          return;
 +        }
-         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;
-           }
++        ctx.font = '30px ' + name;
++        ctx.fillText('.', 0, 20);
++        var imageData = ctx.getImageData(0, 0, 1, 1);
++        if (imageData.data[3] > 0) {
++          callback();
++          return;
 +        }
-         frame.maxH = maxH;
-         frame.maxV = maxV;
-         frame.mcusPerLine = mcusPerLine;
-         frame.mcusPerColumn = mcusPerColumn;
++        setTimeout(isFontReady.bind(null, name, callback));
++      }
++
++      var loadTestFontId = 'lt' + Date.now() + this.loadTestFontId++;
++      // Chromium seems to cache fonts based on a hash of the actual font data,
++      // so the font must be modified for each load test else it will appear to
++      // be loaded already.
++      // TODO: This could maybe be made faster by avoiding the btoa of the full
++      // font by splitting it in chunks before hand and padding the font id.
++      var data = this.loadTestFont;
++      var COMMENT_OFFSET = 976; // has to be on 4 byte boundary (for checksum)
++      data = spliceString(data, COMMENT_OFFSET, loadTestFontId.length,
++                          loadTestFontId);
++      // CFF checksum is important for IE, adjusting it
++      var CFF_CHECKSUM_OFFSET = 16;
++      var XXXX_VALUE = 0x58585858; // the "comment" filled with 'X'
++      var checksum = int32(data, CFF_CHECKSUM_OFFSET);
++      for (i = 0, ii = loadTestFontId.length - 3; i < ii; i += 4) {
++        checksum = (checksum - XXXX_VALUE + int32(loadTestFontId, i)) | 0;
++      }
++      if (i < loadTestFontId.length) { // align to 4 bytes boundary
++        checksum = (checksum - XXXX_VALUE +
++                    int32(loadTestFontId + 'XXX', i)) | 0;
++      }
++      data = spliceString(data, CFF_CHECKSUM_OFFSET, 4, string32(checksum));
++
++      var url = 'url(data:font/opentype;base64,' + btoa(data) + ');';
++      var rule = '@font-face { font-family:"' + loadTestFontId + '";src:' +
++                 url + '}';
++      FontLoader.insertRule(rule);
++
++      var names = [];
++      for (i = 0, ii = fonts.length; i < ii; i++) {
++        names.push(fonts[i].loadedName);
 +      }
-       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";
++      names.push(loadTestFontId);
++
++      var div = document.createElement('div');
++      div.setAttribute('style',
++                       'visibility: hidden;' +
++                       'width: 10px; height: 10px;' +
++                       'position: absolute; top: 0px; left: 0px;');
++      for (i = 0, ii = names.length; i < ii; ++i) {
++        var span = document.createElement('span');
++        span.textContent = 'Hi';
++        span.style.fontFamily = names[i];
++        div.appendChild(span);
 +      }
++      document.body.appendChild(div);
 +
-       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;
++      isFontReady(loadTestFontId, function() {
++        document.body.removeChild(div);
++        request.complete();
++      });
++      /** Hack end */
++  }
++};
 +
-           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;
++var FontFace = (function FontFaceClosure() {
++  function FontFace(name, file, properties) {
++    this.compiledGlyphs = {};
++    if (arguments.length === 1) {
++      // importing translated data
++      var data = arguments[0];
++      for (var i in data) {
++        this[i] = data[i];
++      }
++      return;
++    }
++  }
++  FontFace.prototype = {
++    bindDOM: function FontFace_bindDOM() {
++      if (!this.data)
++        return null;
 +
-           case 0xFFC0: // SOF0 (Start of Frame, Baseline DCT)
-           case 0xFFC2: // SOF2 (Start of Frame, Progressive DCT)
-             readUint16(); // skip data length
-             frame = {};
-             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;
++      if (PDFJS.disableFontFace) {
++        this.disableFontFace = true;
++        return null;
++      }
 +
-           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;
++      var data = bytesToString(this.data);
++      var fontName = this.loadedName;
 +
-           case 0xFFDD: // DRI (Define Restart Interval)
-             readUint16(); // skip data length
-             resetInterval = readUint16();
-             break;
++      // 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 + '}';
 +
-           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;
-         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));
-               }
++      FontLoader.insertRule(rule);
 +
-               data[offset++] = R;
-               data[offset++] = G;
-               data[offset++] = B;
-             }
-           }
-           break;
-         case 4:
-           if (!this.adobe)
-             throw 'Unsupported color mode (4 components)';
-           // 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;
++      if (PDFJS.pdfBug && 'FontInspector' in globalScope &&
++          globalScope['FontInspector'].enabled)
++        globalScope['FontInspector'].fontAdded(this, url);
++
++      return rule;
 +    },
-     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) {
-         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';
++    getPathGenerator: function (objs, character) {
++      if (!(character in this.compiledGlyphs)) {
++        var js = objs.get(this.loadedName + '_path_' + character);
++        /*jshint -W054 */
++        this.compiledGlyphs[character] = new Function('c', 'size', js);
 +      }
++      return this.compiledGlyphs[character];
 +    }
 +  };
- 
-   return constructor;
++  return FontFace;
 +})();
 +
 +
 +}).call((typeof window === 'undefined') ? this : window);
 +
++if (!PDFJS.workerSrc && typeof document !== 'undefined') {
++  // workerSrc is not set -- using last script url to define default location
++  PDFJS.workerSrc = (function () {
++    'use strict';
++    var scriptTagContainer = document.body ||
++                             document.getElementsByTagName('head')[0];
++    var pdfjsSrc = scriptTagContainer.lastChild.src;
++    return pdfjsSrc && pdfjsSrc.replace(/\.js$/i, '.worker.js');
++  })();
++}
++
 +
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/pdf.worker.js
index e8cb6fc,0000000..b9fda97
mode 100644,000000..100644
--- a/apps/files_pdfviewer/3rdparty/pdfjs/pdf.worker.js
+++ b/apps/files_pdfviewer/3rdparty/pdfjs/pdf.worker.js
@@@ -1,38754 -1,0 +1,40927 @@@
 +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 +/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
 +/* 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.
 + */
++/*jshint globalstrict: false */
 +
- var PDFJS = {};
- PDFJS.version = '0.7.416';
- PDFJS.build = '79c3546';
++// Initializing PDFJS global object (if still undefined)
++if (typeof PDFJS === 'undefined') {
++  (typeof window !== 'undefined' ? window : this).PDFJS = {};
++}
++
++PDFJS.version = '0.8.1136';
++PDFJS.build = 'ca612e5';
 +
 +(function pdfjsWrapper() {
 +  // Use strict in our context only - users might not want it
 +  'use strict';
 +
 +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 +/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
 +/* 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.
 + */
- /* globals assertWellFormed, calculateMD5, Catalog, error, info, isArray,
-            isArrayBuffer, isDict, isName, isStream, isString, Lexer,
-            Linearization, NullStream, PartialEvaluator, shadow, Stream,
-            StreamsSequenceStream, stringToPDFString, TODO, Util, warn, XRef */
++/* globals Cmd, ColorSpace, Dict, MozBlobBuilder, Name, PDFJS, Ref, URL,
++           Promise */
 +
 +'use strict';
 +
 +var globalScope = (typeof window === 'undefined') ? this : window;
 +
 +var isWorker = (typeof window == 'undefined');
 +
- var ERRORS = 0, WARNINGS = 1, INFOS = 5;
- var verbosity = WARNINGS;
++var FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0];
++
++var TextRenderingMode = {
++  FILL: 0,
++  STROKE: 1,
++  FILL_STROKE: 2,
++  INVISIBLE: 3,
++  FILL_ADD_TO_PATH: 4,
++  STROKE_ADD_TO_PATH: 5,
++  FILL_STROKE_ADD_TO_PATH: 6,
++  ADD_TO_PATH: 7,
++  FILL_STROKE_MASK: 3,
++  ADD_TO_PATH_FLAG: 4
++};
++
++var ImageKind = {
++  GRAYSCALE_1BPP: 1,
++  RGB_24BPP: 2,
++  RGBA_32BPP: 3
++};
 +
 +// The global PDFJS object exposes the API
 +// In production, it will be declared outside a global wrapper
 +// In development, it will be declared here
 +if (!globalScope.PDFJS) {
 +  globalScope.PDFJS = {};
 +}
 +
- // getPdf()
- // Convenience function to perform binary Ajax GET
- // Usage: getPdf('http://...', callback)
- //        getPdf({
- //                 url:String ,
- //                 [,progress:Function, error:Function]
- //               },
- //               callback)
- function getPdf(arg, callback) {
-   var params = arg;
-   if (typeof arg === 'string')
-     params = { url: arg };
-   var xhr = new XMLHttpRequest();
-   xhr.open('GET', params.url);
- 
-   var headers = params.headers;
-   if (headers) {
-     for (var property in headers) {
-       if (typeof headers[property] === 'undefined')
-         continue;
- 
-       xhr.setRequestHeader(property, params.headers[property]);
-     }
-   }
- 
-   xhr.mozResponseType = xhr.responseType = 'arraybuffer';
- 
-   var protocol = params.url.substring(0, params.url.indexOf(':') + 1);
-   xhr.expected = (protocol === 'http:' || protocol === 'https:') ? 200 : 0;
- 
-   if ('progress' in params)
-     xhr.onprogress = params.progress || undefined;
- 
-   var calledErrorBack = false;
- 
-   if ('error' in params) {
-     xhr.onerror = function errorBack() {
-       if (!calledErrorBack) {
-         calledErrorBack = true;
-         params.error();
-       }
-     };
-   }
- 
-   xhr.onreadystatechange = function getPdfOnreadystatechange(e) {
-     if (xhr.readyState === 4) {
-       if (xhr.status === xhr.expected) {
-         var data = (xhr.mozResponseArrayBuffer || xhr.mozResponse ||
-                     xhr.responseArrayBuffer || xhr.response);
-         callback(data);
-       } else if (params.error && !calledErrorBack) {
-         calledErrorBack = true;
-         params.error(e);
-       }
-     }
-   };
-   xhr.send(null);
- }
- globalScope.PDFJS.getPdf = getPdf;
 +globalScope.PDFJS.pdfBug = false;
 +
- var Page = (function PageClosure() {
-   function Page(xref, pageIndex, pageDict, ref) {
-     this.pageIndex = pageIndex;
-     this.pageDict = pageDict;
-     this.xref = xref;
-     this.ref = ref;
- 
-     this.displayReadyPromise = null;
-   }
- 
-   Page.prototype = {
-     getPageProp: function Page_getPageProp(key) {
-       return this.pageDict.get(key);
-     },
-     inheritPageProp: function Page_inheritPageProp(key) {
-       var dict = this.pageDict;
-       var obj = dict.get(key);
-       while (obj === undefined) {
-         dict = dict.get('Parent');
-         if (!dict)
-           break;
-         obj = dict.get(key);
-       }
-       return obj;
-     },
-     get content() {
-       return shadow(this, 'content', this.getPageProp('Contents'));
-     },
-     get resources() {
-       return shadow(this, 'resources', this.inheritPageProp('Resources'));
-     },
-     get mediaBox() {
-       var obj = this.inheritPageProp('MediaBox');
-       // Reset invalid media box to letter size.
-       if (!isArray(obj) || obj.length !== 4)
-         obj = [0, 0, 612, 792];
-       return shadow(this, 'mediaBox', obj);
-     },
-     get view() {
-       var mediaBox = this.mediaBox;
-       var cropBox = this.inheritPageProp('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)
-         return shadow(this, 'view', mediaBox);
- 
-       return shadow(this, 'view', cropBox);
-     },
-     get annotations() {
-       return shadow(this, 'annotations', this.inheritPageProp('Annots'));
-     },
-     get rotate() {
-       var rotate = this.inheritPageProp('Rotate') || 0;
-       // Normalize rotation so it's a multiple of 90 and between 0 and 270
-       if (rotate % 90 !== 0) {
-         rotate = 0;
-       } else if (rotate >= 360) {
-         rotate = rotate % 360;
-       } else if (rotate < 0) {
-         // The spec doesn't cover negatives, assume its counterclockwise
-         // rotation. The following is the other implementation of modulo.
-         rotate = ((rotate % 360) + 360) % 360;
-       }
-       return shadow(this, 'rotate', rotate);
-     },
-     getContentStream: function Page_getContentStream() {
-       var content = this.content;
-       if (isArray(content)) {
-         // fetching items
-         var xref = this.xref;
-         var i, n = content.length;
-         var streams = [];
-         for (i = 0; i < n; ++i)
-           streams.push(xref.fetchIfRef(content[i]));
-         content = new StreamsSequenceStream(streams);
-       } else if (isStream(content)) {
-         content.reset();
-       } else if (!content) {
-         // replacing non-existent page content with empty one
-         content = new NullStream();
-       }
-       return content;
-     },
-     getOperatorList: function Page_getOperatorList(handler, dependency) {
-       var xref = this.xref;
-       var contentStream = this.getContentStream();
-       var resources = this.resources;
-       var pe = this.pe = new PartialEvaluator(
-                                 xref, handler, this.pageIndex,
-                                 'p' + this.pageIndex + '_');
- 
-       var list = pe.getOperatorList(contentStream, resources, dependency);
-       pe.optimizeQueue(list);
-       return list;
-     },
-     extractTextContent: function Page_extractTextContent() {
-       var handler = {
-         on: function nullHandlerOn() {},
-         send: function nullHandlerSend() {}
-       };
- 
-       var xref = this.xref;
-       var contentStream = this.getContentStream();
-       var resources = xref.fetchIfRef(this.resources);
- 
-       var pe = new PartialEvaluator(
-                      xref, handler, this.pageIndex,
-                      'p' + this.pageIndex + '_');
-       return pe.getTextContent(contentStream, resources);
-     },
-     getLinks: function Page_getLinks() {
-       var links = [];
-       var annotations = this.getAnnotations();
-       var i, n = annotations.length;
-       for (i = 0; i < n; ++i) {
-         if (annotations[i].type != 'Link')
-           continue;
-         links.push(annotations[i]);
-       }
-       return links;
-     },
-     getAnnotations: function Page_getAnnotations() {
-       var xref = this.xref;
-       function getInheritableProperty(annotation, name) {
-         var item = annotation;
-         while (item && !item.has(name)) {
-           item = item.get('Parent');
-         }
-         if (!item)
-           return null;
-         return item.get(name);
-       }
-       function isValidUrl(url) {
-         if (!url)
-           return false;
-         var colon = url.indexOf(':');
-         if (colon < 0)
-           return false;
-         var protocol = url.substr(0, colon);
-         switch (protocol) {
-           case 'http':
-           case 'https':
-           case 'ftp':
-           case 'mailto':
-             return true;
-           default:
-             return false;
-         }
-       }
- 
-       var annotations = this.annotations || [];
-       var i, n = annotations.length;
-       var items = [];
-       for (i = 0; i < n; ++i) {
-         var annotationRef = annotations[i];
-         var annotation = xref.fetchIfRef(annotationRef);
-         if (!isDict(annotation))
-           continue;
-         var subtype = annotation.get('Subtype');
-         if (!isName(subtype))
-           continue;
-         var rect = annotation.get('Rect');
- 
-         var item = {};
-         item.type = subtype.name;
-         item.rect = rect;
-         switch (subtype.name) {
-           case 'Link':
-             var a = annotation.get('A');
-             if (a) {
-               switch (a.get('S').name) {
-                 case 'URI':
-                   var url = a.get('URI');
-                   // TODO: pdf spec mentions urls can be relative to a Base
-                   // entry in the dictionary.
-                   if (!isValidUrl(url))
-                     url = '';
-                   item.url = url;
-                   break;
-                 case 'GoTo':
-                   item.dest = a.get('D');
-                   break;
-                 case 'GoToR':
-                   var url = a.get('F');
-                   if (isDict(url)) {
-                     // We assume that the 'url' is a Filspec dictionary
-                     // and fetch the url without checking any further
-                     url = url.get('F') || '';
-                   }
- 
-                   // TODO: pdf reference says that GoToR
-                   // can also have 'NewWindow' attribute
-                   if (!isValidUrl(url))
-                     url = '';
-                   item.url = url;
-                   item.dest = a.get('D');
-                   break;
-                 default:
-                   TODO('unrecognized link type: ' + a.get('S').name);
-               }
-             } else if (annotation.has('Dest')) {
-               // simple destination link
-               var dest = annotation.get('Dest');
-               item.dest = isName(dest) ? dest.name : dest;
-             }
-             break;
-           case 'Widget':
-             var fieldType = getInheritableProperty(annotation, 'FT');
-             if (!isName(fieldType))
-               break;
-             item.fieldType = fieldType.name;
-             // Building the full field name by collecting the field and
-             // its ancestors 'T' properties and joining them using '.'.
-             var fieldName = [];
-             var namedItem = annotation, ref = annotationRef;
-             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;
-             }
-             item.fullName = fieldName.join('.');
-             var alternativeText = stringToPDFString(annotation.get('TU') || '');
-             item.alternativeText = alternativeText;
-             var da = getInheritableProperty(annotation, 'DA') || '';
-             var m = /([\d\.]+)\sTf/.exec(da);
-             if (m)
-               item.fontSize = parseFloat(m[1]);
-             item.textAlignment = getInheritableProperty(annotation, 'Q');
-             item.flags = getInheritableProperty(annotation, 'Ff') || 0;
-             break;
-           case 'Text':
-             var content = annotation.get('Contents');
-             var title = annotation.get('T');
-             item.content = stringToPDFString(content || '');
-             item.title = stringToPDFString(title || '');
-             item.name = !annotation.has('Name') ? 'Note' :
-               annotation.get('Name').name;
-             break;
-           default:
-             TODO('unimplemented annotation type: ' + subtype.name);
-             break;
-         }
-         items.push(item);
-       }
-       return items;
-     }
-   };
- 
-   return Page;
- })();
- 
- /**
-  * The `PDFDocument` holds all the data of the PDF file. Compared to the
-  * `PDFDoc`, this one doesn't have any job management code.
-  * Right now there exists one PDFDocument on the main thread + one object
-  * for each worker. If there is no worker support enabled, there are two
-  * `PDFDocument` objects on the main thread created.
-  */
- var PDFDocument = (function PDFDocumentClosure() {
-   function PDFDocument(arg, password) {
-     if (isStream(arg))
-       init.call(this, arg, password);
-     else if (isArrayBuffer(arg))
-       init.call(this, new Stream(arg), password);
-     else
-       error('PDFDocument: Unknown argument type');
-   }
- 
-   function init(stream, password) {
-     assertWellFormed(stream.length > 0, 'stream must have data');
-     this.stream = stream;
-     this.setup(password);
-     this.acroForm = this.catalog.catDict.get('AcroForm');
-   }
- 
-   function find(stream, needle, limit, backwards) {
-     var pos = stream.pos;
-     var end = stream.end;
-     var str = '';
-     if (pos + limit > end)
-       limit = end - pos;
-     for (var n = 0; n < limit; ++n)
-       str += stream.getChar();
-     stream.pos = pos;
-     var index = backwards ? str.lastIndexOf(needle) : str.indexOf(needle);
-     if (index == -1)
-       return false; /* not found */
-     stream.pos += index;
-     return true; /* found */
-   }
- 
-   var DocumentInfoValidators = {
-     get entries() {
-       // Lazily build this since all the validation functions below are not
-       // defined until after this file loads.
-       return shadow(this, 'entries', {
-         Title: isString,
-         Author: isString,
-         Subject: isString,
-         Keywords: isString,
-         Creator: isString,
-         Producer: isString,
-         CreationDate: isString,
-         ModDate: isString,
-         Trapped: isName
-       });
-     }
-   };
- 
-   PDFDocument.prototype = {
-     get linearization() {
-       var length = this.stream.length;
-       var linearization = false;
-       if (length) {
-         try {
-           linearization = new Linearization(this.stream);
-           if (linearization.length != length)
-             linearization = false;
-         } catch (err) {
-           warn('The linearization data is not available ' +
-                'or unreadable pdf data is found');
-           linearization = false;
-         }
-       }
-       // shadow the prototype getter with a data property
-       return shadow(this, 'linearization', linearization);
-     },
-     get startXRef() {
-       var stream = this.stream;
-       var startXRef = 0;
-       var linearization = this.linearization;
-       if (linearization) {
-         // Find end of first obj.
-         stream.reset();
-         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)
-             pos = 0;
-           stream.pos = pos;
-           found = find(stream, 'startxref', step, true);
-         }
-         if (found) {
-           stream.skip(9);
-           var ch;
-           do {
-             ch = stream.getChar();
-           } while (Lexer.isSpace(ch));
-           var str = '';
-           while ((ch - '0') <= 9) {
-             str += ch;
-             ch = stream.getChar();
-           }
-           startXRef = parseInt(str, 10);
-           if (isNaN(startXRef))
-             startXRef = 0;
-         }
-       }
-       // shadow the prototype getter with a data property
-       return shadow(this, 'startXRef', startXRef);
-     },
-     get mainXRefEntriesOffset() {
-       var mainXRefEntriesOffset = 0;
-       var linearization = this.linearization;
-       if (linearization)
-         mainXRefEntriesOffset = linearization.mainXRefEntriesOffset;
-       // shadow the prototype getter with a data property
-       return shadow(this, 'mainXRefEntriesOffset', mainXRefEntriesOffset);
-     },
-     // Find the header, remove leading garbage and setup the stream
-     // starting from the header.
-     checkHeader: function PDFDocument_checkHeader() {
-       var stream = this.stream;
-       stream.reset();
-       if (find(stream, '%PDF-', 1024)) {
-         // Found the header, trim off any garbage before it.
-         stream.moveStart();
-         // Reading file format version
-         var MAX_VERSION_LENGTH = 12;
-         var version = '', ch;
-         while ((ch = stream.getChar()) > ' ') {
-           if (version.length >= MAX_VERSION_LENGTH) {
-             break;
-           }
-           version += ch;
-         }
-         // removing "%PDF-"-prefix
-         this.pdfFormatVersion = version.substring(5);
-         return;
-       }
-       // May not be a PDF file, continue anyway.
-     },
-     setup: function PDFDocument_setup(password) {
-       this.checkHeader();
-       var xref = new XRef(this.stream,
-                           this.startXRef,
-                           this.mainXRefEntriesOffset,
-                           password);
-       this.xref = xref;
-       this.catalog = new Catalog(xref);
-     },
-     get numPages() {
-       var linearization = this.linearization;
-       var num = linearization ? linearization.numPages : this.catalog.numPages;
-       // shadow the prototype getter
-       return shadow(this, 'numPages', num);
-     },
-     getDocumentInfo: function PDFDocument_getDocumentInfo() {
-       var docInfo = {
-         PDFFormatVersion: this.pdfFormatVersion,
-         IsAcroFormPresent: !!this.acroForm
-       };
-       if (this.xref.trailer.has('Info')) {
-         var infoDict = this.xref.trailer.get('Info');
- 
-         var validEntries = DocumentInfoValidators.entries;
-         // Only fill the document info with valid entries from the spec.
-         for (var key in validEntries) {
-           if (infoDict.has(key)) {
-             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);
-             } else {
-               info('Bad value in document info for "' + key + '"');
-             }
-           }
-         }
-       }
-       return shadow(this, 'getDocumentInfo', docInfo);
-     },
-     getFingerprint: function PDFDocument_getFingerprint() {
-       var xref = this.xref, fileID;
-       if (xref.trailer.has('ID')) {
-         fileID = '';
-         var id = xref.trailer.get('ID')[0];
-         id.split('').forEach(function(el) {
-           fileID += Number(el.charCodeAt(0)).toString(16);
-         });
-       } else {
-         // If we got no fileID, then we generate one,
-         // from the first 100 bytes of PDF
-         var data = this.stream.bytes.subarray(0, 100);
-         var hash = calculateMD5(data, 0, data.length);
-         fileID = '';
-         for (var i = 0, length = hash.length; i < length; i++) {
-           fileID += Number(hash[i]).toString(16);
-         }
-       }
- 
-       return shadow(this, 'getFingerprint', fileID);
-     },
-     getPage: function PDFDocument_getPage(n) {
-       return this.catalog.getPage(n);
-     }
-   };
- 
-   return PDFDocument;
- })();
- 
- 
++PDFJS.VERBOSITY_LEVELS = {
++  errors: 0,
++  warnings: 1,
++  infos: 5
++};
 +
- // 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() {
-     };
-   }
- })();
++// All the possible operations for an operator list.
++var OPS = PDFJS.OPS = {
++  // Intentionally start from 1 so it is easy to spot bad operators that will be
++  // 0's.
++  dependency: 1,
++  setLineWidth: 2,
++  setLineCap: 3,
++  setLineJoin: 4,
++  setMiterLimit: 5,
++  setDash: 6,
++  setRenderingIntent: 7,
++  setFlatness: 8,
++  setGState: 9,
++  save: 10,
++  restore: 11,
++  transform: 12,
++  moveTo: 13,
++  lineTo: 14,
++  curveTo: 15,
++  curveTo2: 16,
++  curveTo3: 17,
++  closePath: 18,
++  rectangle: 19,
++  stroke: 20,
++  closeStroke: 21,
++  fill: 22,
++  eoFill: 23,
++  fillStroke: 24,
++  eoFillStroke: 25,
++  closeFillStroke: 26,
++  closeEOFillStroke: 27,
++  endPath: 28,
++  clip: 29,
++  eoClip: 30,
++  beginText: 31,
++  endText: 32,
++  setCharSpacing: 33,
++  setWordSpacing: 34,
++  setHScale: 35,
++  setLeading: 36,
++  setFont: 37,
++  setTextRenderingMode: 38,
++  setTextRise: 39,
++  moveText: 40,
++  setLeadingMoveText: 41,
++  setTextMatrix: 42,
++  nextLine: 43,
++  showText: 44,
++  showSpacedText: 45,
++  nextLineShowText: 46,
++  nextLineSetSpacingShowText: 47,
++  setCharWidth: 48,
++  setCharWidthAndBounds: 49,
++  setStrokeColorSpace: 50,
++  setFillColorSpace: 51,
++  setStrokeColor: 52,
++  setStrokeColorN: 53,
++  setFillColor: 54,
++  setFillColorN: 55,
++  setStrokeGray: 56,
++  setFillGray: 57,
++  setStrokeRGBColor: 58,
++  setFillRGBColor: 59,
++  setStrokeCMYKColor: 60,
++  setFillCMYKColor: 61,
++  shadingFill: 62,
++  beginInlineImage: 63,
++  beginImageData: 64,
++  endInlineImage: 65,
++  paintXObject: 66,
++  markPoint: 67,
++  markPointProps: 68,
++  beginMarkedContent: 69,
++  beginMarkedContentProps: 70,
++  endMarkedContent: 71,
++  beginCompat: 72,
++  endCompat: 73,
++  paintFormXObjectBegin: 74,
++  paintFormXObjectEnd: 75,
++  beginGroup: 76,
++  endGroup: 77,
++  beginAnnotations: 78,
++  endAnnotations: 79,
++  beginAnnotation: 80,
++  endAnnotation: 81,
++  paintJpegXObject: 82,
++  paintImageMaskXObject: 83,
++  paintImageMaskXObjectGroup: 84,
++  paintImageXObject: 85,
++  paintInlineImageXObject: 86,
++  paintInlineImageXObjectGroup: 87
++};
 +
- // A notice for devs that will not trigger the fallback UI.  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.
++// 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 (verbosity >= INFOS) {
-     log('Info: ' + msg);
-     PDFJS.LogManager.notify('info', msg);
++  if (PDFJS.verbosity >= PDFJS.VERBOSITY_LEVELS.infos) {
++    console.log('Info: ' + msg);
 +  }
 +}
 +
- // Non-fatal warnings that should trigger the fallback UI.
++// Non-fatal warnings.
 +function warn(msg) {
-   if (verbosity >= WARNINGS) {
-     log('Warning: ' + msg);
-     PDFJS.LogManager.notify('warn', msg);
++  if (PDFJS.verbosity >= PDFJS.VERBOSITY_LEVELS.warnings) {
++    console.log('Warning: ' + msg);
 +  }
 +}
 +
 +// Fatal errors that should trigger the fallback UI and halt execution by
 +// throwing an exception.
 +function error(msg) {
 +  // If multiple arguments were passed, pass them all to the log function.
 +  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());
-   PDFJS.LogManager.notify('error', msg);
++  console.log(backtrace());
++  UnsupportedManager.notify(UNSUPPORTED_FEATURES.unknown);
 +  throw new Error(msg);
 +}
 +
- // Missing features that should trigger the fallback UI.
- function TODO(what) {
-   warn('TODO: ' + what);
- }
- 
 +function backtrace() {
 +  try {
 +    throw new Error();
 +  } catch (e) {
 +    return e.stack ? e.stack.split('\n').slice(2).join('\n') : '';
 +  }
 +}
 +
 +function assert(cond, msg) {
-   if (!cond)
++  if (!cond) {
 +    error(msg);
++  }
 +}
 +
++var UNSUPPORTED_FEATURES = PDFJS.UNSUPPORTED_FEATURES = {
++  unknown: 'unknown',
++  forms: 'forms',
++  javaScript: 'javaScript',
++  smask: 'smask',
++  shadingPattern: 'shadingPattern',
++  font: 'font'
++};
++
++var UnsupportedManager = PDFJS.UnsupportedManager =
++  (function UnsupportedManagerClosure() {
++  var listeners = [];
++  return {
++    listen: function (cb) {
++      listeners.push(cb);
++    },
++    notify: function (featureId) {
++      warn('Unsupported feature "' + featureId + '"');
++      for (var i = 0, ii = listeners.length; i < ii; i++) {
++        listeners[i](featureId);
++      }
++    }
++  };
++})();
++
 +// 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) == '/') {
 +    // absolute path
 +    var i = baseUrl.indexOf('://');
-     i = baseUrl.indexOf('/', i + 3);
++    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;
 +    i = baseUrl.lastIndexOf('#');
 +    pathLength = i >= 0 ? i : pathLength;
 +    i = baseUrl.lastIndexOf('?', pathLength);
 +    pathLength = i >= 0 ? i : pathLength;
 +    var prefixLength = baseUrl.lastIndexOf('/', pathLength);
 +    return baseUrl.substring(0, prefixLength + 1) + url;
 +  }
 +}
 +
++// Validates if URL is safe and allowed, e.g. to avoid XSS.
++function isValidUrl(url, allowRelative) {
++  if (!url) {
++    return false;
++  }
++  // 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;
++  }
++  protocol = protocol[0].toLowerCase();
++  switch (protocol) {
++    case 'http':
++    case 'https':
++    case 'ftp':
++    case 'mailto':
++      return true;
++    default:
++      return false;
++  }
++}
++PDFJS.isValidUrl = isValidUrl;
++
 +// In a well-formed PDF, |cond| holds.  If it doesn't, subsequent
 +// behavior is undefined.
 +function assertWellFormed(cond, msg) {
-   if (!cond)
++  if (!cond) {
 +    error(msg);
++  }
 +}
 +
- var LogManager = PDFJS.LogManager = (function LogManagerClosure() {
-   var loggers = [];
-   return {
-     addLogger: function logManager_addLogger(logger) {
-       loggers.push(logger);
-     },
-     notify: function(type, message) {
-       for (var i = 0, ii = loggers.length; i < ii; i++) {
-         var logger = loggers[i];
-         if (logger[type])
-           logger[type](message);
-       }
-     }
-   };
- })();
- 
 +function shadow(obj, prop, value) {
 +  Object.defineProperty(obj, prop, { value: value,
 +                                     enumerable: true,
 +                                     configurable: true,
 +                                     writable: false });
 +  return value;
 +}
 +
++var PasswordResponses = PDFJS.PasswordResponses = {
++  NEED_PASSWORD: 1,
++  INCORRECT_PASSWORD: 2
++};
++
 +var PasswordException = (function PasswordExceptionClosure() {
 +  function PasswordException(msg, code) {
 +    this.name = 'PasswordException';
 +    this.message = msg;
 +    this.code = code;
 +  }
 +
 +  PasswordException.prototype = new Error();
 +  PasswordException.constructor = PasswordException;
 +
 +  return PasswordException;
 +})();
 +
 +var UnknownErrorException = (function UnknownErrorExceptionClosure() {
 +  function UnknownErrorException(msg, details) {
 +    this.name = 'UnknownErrorException';
 +    this.message = msg;
 +    this.details = details;
 +  }
 +
 +  UnknownErrorException.prototype = new Error();
 +  UnknownErrorException.constructor = UnknownErrorException;
 +
 +  return UnknownErrorException;
 +})();
 +
 +var InvalidPDFException = (function InvalidPDFExceptionClosure() {
 +  function InvalidPDFException(msg) {
 +    this.name = 'InvalidPDFException';
 +    this.message = msg;
 +  }
 +
 +  InvalidPDFException.prototype = new Error();
 +  InvalidPDFException.constructor = InvalidPDFException;
 +
 +  return InvalidPDFException;
 +})();
 +
 +var MissingPDFException = (function MissingPDFExceptionClosure() {
 +  function MissingPDFException(msg) {
 +    this.name = 'MissingPDFException';
 +    this.message = msg;
 +  }
 +
 +  MissingPDFException.prototype = new Error();
 +  MissingPDFException.constructor = MissingPDFException;
 +
 +  return MissingPDFException;
 +})();
 +
++var NotImplementedException = (function NotImplementedExceptionClosure() {
++  function NotImplementedException(msg) {
++    this.message = msg;
++  }
++
++  NotImplementedException.prototype = new Error();
++  NotImplementedException.prototype.name = 'NotImplementedException';
++  NotImplementedException.constructor = NotImplementedException;
++
++  return NotImplementedException;
++})();
++
++var MissingDataException = (function MissingDataExceptionClosure() {
++  function MissingDataException(begin, end) {
++    this.begin = begin;
++    this.end = end;
++    this.message = 'Missing data [' + begin + ', ' + end + ')';
++  }
++
++  MissingDataException.prototype = new Error();
++  MissingDataException.prototype.name = 'MissingDataException';
++  MissingDataException.constructor = MissingDataException;
++
++  return MissingDataException;
++})();
++
++var XRefParseException = (function XRefParseExceptionClosure() {
++  function XRefParseException(msg) {
++    this.message = msg;
++  }
++
++  XRefParseException.prototype = new Error();
++  XRefParseException.prototype.name = 'XRefParseException';
++  XRefParseException.constructor = XRefParseException;
++
++  return XRefParseException;
++})();
++
++
 +function bytesToString(bytes) {
-   var str = '';
++  var strBuf = [];
 +  var length = bytes.length;
-   for (var n = 0; n < length; ++n)
-     str += String.fromCharCode(bytes[n]);
-   return str;
++  for (var n = 0; n < length; ++n) {
++    strBuf.push(String.fromCharCode(bytes[n]));
++  }
++  return strBuf.join('');
 +}
 +
 +function stringToBytes(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) & 0xFF;
++  }
 +  return bytes;
 +}
 +
 +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] + ')';
 +  };
 +
 +  Util.makeCssCmyk = function Util_makeCssCmyk(cmyk) {
-     var cs = new DeviceCmykCS();
-     Util.makeCssCmyk = function makeCssCmyk(cmyk) {
-       var rgb = cs.getRgb(cmyk, 0);
-       return Util.makeCssRgb(rgb);
-     };
-     return Util.makeCssCmyk(cmyk);
++    var rgb = ColorSpace.singletons.cmyk.getRgb(cmyk, 0);
++    return Util.makeCssRgb(rgb);
++  };
++
++  // Concatenates two transformation matrices together and returns the result.
++  Util.transform = function Util_transform(m1, m2) {
++    return [
++      m1[0] * m2[0] + m1[2] * m2[1],
++      m1[1] * m2[0] + m1[3] * m2[1],
++      m1[0] * m2[2] + m1[2] * m2[3],
++      m1[1] * m2[2] + m1[3] * m2[3],
++      m1[0] * m2[4] + m1[2] * m2[5] + m1[4],
++      m1[1] * m2[4] + m1[3] * m2[5] + m1[5]
++    ];
 +  };
 +
 +  // For 2d affine transforms
 +  Util.applyTransform = function Util_applyTransform(p, m) {
 +    var xt = p[0] * m[0] + p[1] * m[2] + m[4];
 +    var yt = p[0] * m[1] + p[1] * m[3] + m[5];
 +    return [xt, yt];
 +  };
 +
 +  Util.applyInverseTransform = function Util_applyInverseTransform(p, m) {
 +    var d = m[0] * m[3] - m[1] * m[2];
 +    var xt = (p[0] * m[3] - p[1] * m[2] + m[2] * m[5] - m[4] * m[3]) / d;
 +    var yt = (-p[0] * m[1] + p[1] * m[0] + m[4] * m[1] - m[5] * m[0]) / d;
 +    return [xt, yt];
 +  };
 +
 +  // Applies the transform to the rectangle and finds the minimum axially
 +  // aligned bounding box.
 +  Util.getAxialAlignedBoundingBox =
 +    function Util_getAxialAlignedBoundingBox(r, m) {
 +
 +    var p1 = Util.applyTransform(r, m);
 +    var p2 = Util.applyTransform(r.slice(2, 4), m);
 +    var p3 = Util.applyTransform([r[0], r[3]], m);
 +    var p4 = Util.applyTransform([r[2], r[1]], m);
 +    return [
 +      Math.min(p1[0], p2[0], p3[0], p4[0]),
 +      Math.min(p1[1], p2[1], p3[1], p4[1]),
 +      Math.max(p1[0], p2[0], p3[0], p4[0]),
 +      Math.max(p1[1], p2[1], p3[1], p4[1])
 +    ];
 +  };
 +
 +  Util.inverseTransform = function Util_inverseTransform(m) {
 +    var d = m[0] * m[3] - m[1] * m[2];
 +    return [m[3] / d, -m[1] / d, -m[2] / d, m[0] / d,
 +      (m[2] * m[5] - m[4] * m[3]) / d, (m[4] * m[1] - m[5] * m[0]) / d];
 +  };
 +
 +  // Apply a generic 3d matrix M on a 3-vector v:
 +  //   | a b c |   | X |
 +  //   | d e f | x | Y |
 +  //   | g h i |   | Z |
 +  // M is assumed to be serialized as [a,b,c,d,e,f,g,h,i],
 +  // with v as [X,Y,Z]
 +  Util.apply3dTransform = function Util_apply3dTransform(m, v) {
 +    return [
 +      m[0] * v[0] + m[1] * v[1] + m[2] * v[2],
 +      m[3] * v[0] + m[4] * v[1] + m[5] * v[2],
 +      m[6] * v[0] + m[7] * v[1] + m[8] * v[2]
 +    ];
 +  };
 +
 +  // This calculation uses Singular Value Decomposition.
 +  // The SVD can be represented with formula A = USV. We are interested in the
 +  // matrix S here because it represents the scale values.
 +  Util.singularValueDecompose2dScale =
 +    function Util_singularValueDecompose2dScale(m) {
 +
 +    var transpose = [m[0], m[2], m[1], m[3]];
 +
 +    // Multiply matrix m with its transpose.
 +    var a = m[0] * transpose[0] + m[1] * transpose[2];
 +    var b = m[0] * transpose[1] + m[1] * transpose[3];
 +    var c = m[2] * transpose[0] + m[3] * transpose[2];
 +    var d = m[2] * transpose[1] + m[3] * transpose[3];
 +
 +    // Solve the second degree polynomial to get roots.
 +    var first = (a + d) / 2;
 +    var second = Math.sqrt((a + d) * (a + d) - 4 * (a * d - c * b)) / 2;
 +    var sx = first + second || 1;
 +    var sy = first - second || 1;
 +
 +    // Scale values are the square roots of the eigenvalues.
 +    return [Math.sqrt(sx), Math.sqrt(sy)];
 +  };
 +
 +  // Normalize rectangle rect=[x1, y1, x2, y2] so that (x1,y1) < (x2,y2)
 +  // For coordinate systems whose origin lies in the bottom-left, this
 +  // means normalization to (BL,TR) ordering. For systems with origin in the
 +  // top-left, this means (TL,BR) ordering.
 +  Util.normalizeRect = function Util_normalizeRect(rect) {
 +    var r = rect.slice(0); // clone rect
 +    if (rect[0] > rect[2]) {
 +      r[0] = rect[2];
 +      r[2] = rect[0];
 +    }
 +    if (rect[1] > rect[3]) {
 +      r[1] = rect[3];
 +      r[3] = rect[1];
 +    }
 +    return r;
 +  };
 +
 +  // Returns a rectangle [x1, y1, x2, y2] corresponding to the
 +  // intersection of rect1 and rect2. If no intersection, returns 'false'
 +  // The rectangle coordinates of rect1, rect2 should be [x1, y1, x2, y2]
 +  Util.intersect = function Util_intersect(rect1, rect2) {
 +    function compare(a, b) {
 +      return a - b;
 +    }
 +
 +    // Order points along the axes
 +    var orderedX = [rect1[0], rect1[2], rect2[0], rect2[2]].sort(compare),
 +        orderedY = [rect1[1], rect1[3], rect2[1], rect2[3]].sort(compare),
 +        result = [];
 +
 +    rect1 = Util.normalizeRect(rect1);
 +    rect2 = Util.normalizeRect(rect2);
 +
 +    // X: first and second points belong to different rectangles?
 +    if ((orderedX[0] === rect1[0] && orderedX[1] === rect2[0]) ||
 +        (orderedX[0] === rect2[0] && orderedX[1] === rect1[0])) {
 +      // Intersection must be between second and third points
 +      result[0] = orderedX[1];
 +      result[2] = orderedX[2];
 +    } else {
 +      return false;
 +    }
 +
 +    // Y: first and second points belong to different rectangles?
 +    if ((orderedY[0] === rect1[1] && orderedY[1] === rect2[1]) ||
 +        (orderedY[0] === rect2[1] && orderedY[1] === rect1[1])) {
 +      // Intersection must be between second and third points
 +      result[1] = orderedY[1];
 +      result[3] = orderedY[2];
 +    } else {
 +      return false;
 +    }
 +
 +    return result;
 +  };
 +
 +  Util.sign = function Util_sign(num) {
 +    return num < 0 ? -1 : 1;
 +  };
 +
++  // TODO(mack): Rename appendToArray
++  Util.concatenateToArray = function concatenateToArray(arr1, arr2) {
++    Array.prototype.push.apply(arr1, arr2);
++  };
++
++  Util.prependToArray = function concatenateToArray(arr1, arr2) {
++    Array.prototype.unshift.apply(arr1, arr2);
++  };
++
++  Util.extendObj = function extendObj(obj1, obj2) {
++    for (var key in obj2) {
++      obj1[key] = obj2[key];
++    }
++  };
++
++  Util.getInheritableProperty = function Util_getInheritableProperty(dict,
++                                                                     name) {
++    while (dict && !dict.has(name)) {
++      dict = dict.get('Parent');
++    }
++    if (!dict) {
++      return null;
++    }
++    return dict.get(name);
++  };
++
++  Util.inherit = function Util_inherit(sub, base, prototype) {
++    sub.prototype = Object.create(base.prototype);
++    sub.prototype.constructor = sub;
++    for (var prop in prototype) {
++      sub.prototype[prop] = prototype[prop];
++    }
++  };
++
++  Util.loadScript = function Util_loadScript(src, callback) {
++    var script = document.createElement('script');
++    var loaded = false;
++    script.setAttribute('src', src);
++    if (callback) {
++      script.onload = function() {
++        if (!loaded) {
++          callback();
++        }
++        loaded = true;
++      };
++    }
++    document.getElementsByTagName('head')[0].appendChild(script);
++  };
++
 +  return Util;
 +})();
 +
 +var PageViewport = PDFJS.PageViewport = (function PageViewportClosure() {
-   function PageViewport(viewBox, scale, rotation, offsetX, offsetY) {
++  function PageViewport(viewBox, scale, rotation, offsetX, offsetY, dontFlip) {
 +    this.viewBox = viewBox;
 +    this.scale = scale;
 +    this.rotation = rotation;
 +    this.offsetX = offsetX;
 +    this.offsetY = offsetY;
 +
 +    // creating transform to convert pdf coordinate system to the normal
 +    // canvas like coordinates taking in account scale and rotation
 +    var centerX = (viewBox[2] + viewBox[0]) / 2;
 +    var centerY = (viewBox[3] + viewBox[1]) / 2;
 +    var rotateA, rotateB, rotateC, rotateD;
-     switch (rotation % 360) {
-       case -180:
++    rotation = rotation % 360;
++    rotation = rotation < 0 ? rotation + 360 : rotation;
++    switch (rotation) {
 +      case 180:
 +        rotateA = -1; rotateB = 0; rotateC = 0; rotateD = 1;
 +        break;
-       case -270:
 +      case 90:
 +        rotateA = 0; rotateB = 1; rotateC = 1; rotateD = 0;
 +        break;
-       case -90:
 +      case 270:
 +        rotateA = 0; rotateB = -1; rotateC = -1; rotateD = 0;
 +        break;
-       //case 360:
 +      //case 0:
 +      default:
 +        rotateA = 1; rotateB = 0; rotateC = 0; rotateD = -1;
 +        break;
 +    }
++
++    if (dontFlip) {
++      rotateC = -rotateC; rotateD = -rotateD;
++    }
++
 +    var offsetCanvasX, offsetCanvasY;
 +    var width, height;
 +    if (rotateA === 0) {
 +      offsetCanvasX = Math.abs(centerY - viewBox[1]) * scale + offsetX;
 +      offsetCanvasY = Math.abs(centerX - viewBox[0]) * scale + offsetY;
 +      width = Math.abs(viewBox[3] - viewBox[1]) * scale;
 +      height = Math.abs(viewBox[2] - viewBox[0]) * scale;
 +    } else {
 +      offsetCanvasX = Math.abs(centerX - viewBox[0]) * scale + offsetX;
 +      offsetCanvasY = Math.abs(centerY - viewBox[1]) * scale + offsetY;
 +      width = Math.abs(viewBox[2] - viewBox[0]) * scale;
 +      height = Math.abs(viewBox[3] - viewBox[1]) * scale;
 +    }
 +    // creating transform for the following operations:
 +    // translate(-centerX, -centerY), rotate and flip vertically,
 +    // scale, and translate(offsetCanvasX, offsetCanvasY)
 +    this.transform = [
 +      rotateA * scale,
 +      rotateB * scale,
 +      rotateC * scale,
 +      rotateD * scale,
 +      offsetCanvasX - rotateA * scale * centerX - rotateC * scale * centerY,
 +      offsetCanvasY - rotateB * scale * centerX - rotateD * scale * centerY
 +    ];
 +
 +    this.width = width;
 +    this.height = height;
 +    this.fontScale = scale;
 +  }
 +  PageViewport.prototype = {
 +    clone: function PageViewPort_clone(args) {
 +      args = args || {};
 +      var scale = 'scale' in args ? args.scale : this.scale;
 +      var rotation = 'rotation' in args ? args.rotation : this.rotation;
 +      return new PageViewport(this.viewBox.slice(), scale, rotation,
-                               this.offsetX, this.offsetY);
++                              this.offsetX, this.offsetY, args.dontFlip);
 +    },
 +    convertToViewportPoint: function PageViewport_convertToViewportPoint(x, y) {
 +      return Util.applyTransform([x, y], this.transform);
 +    },
 +    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]];
 +    },
 +    convertToPdfPoint: function PageViewport_convertToPdfPoint(x, y) {
 +      return Util.applyInverseTransform([x, y], this.transform);
 +    }
 +  };
 +  return PageViewport;
 +})();
 +
 +var PDFStringTranslateTable = [
 +  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 +  0x2D8, 0x2C7, 0x2C6, 0x2D9, 0x2DD, 0x2DB, 0x2DA, 0x2DC, 0, 0, 0, 0, 0, 0, 0,
 +  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 +  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 +  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 +  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2022, 0x2020, 0x2021, 0x2026, 0x2014,
 +  0x2013, 0x192, 0x2044, 0x2039, 0x203A, 0x2212, 0x2030, 0x201E, 0x201C,
 +  0x201D, 0x2018, 0x2019, 0x201A, 0x2122, 0xFB01, 0xFB02, 0x141, 0x152, 0x160,
 +  0x178, 0x17D, 0x131, 0x142, 0x153, 0x161, 0x17E, 0, 0x20AC
 +];
 +
 +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) {
 +  return decodeURIComponent(escape(str));
 +}
 +
++function isEmptyObj(obj) {
++  for (var key in obj) {
++    return false;
++  }
++  return true;
++}
++
 +function isBool(v) {
 +  return typeof v == 'boolean';
 +}
 +
 +function isInt(v) {
 +  return typeof v == 'number' && ((v | 0) == v);
 +}
 +
 +function isNum(v) {
 +  return typeof v == 'number';
 +}
 +
 +function isString(v) {
 +  return typeof v == 'string';
 +}
 +
 +function isNull(v) {
 +  return v === null;
 +}
 +
 +function isName(v) {
 +  return v instanceof Name;
 +}
 +
 +function isCmd(v, cmd) {
 +  return v instanceof Cmd && (!cmd || v.cmd == cmd);
 +}
 +
 +function isDict(v, type) {
 +  if (!(v instanceof Dict)) {
 +    return false;
 +  }
 +  if (!type) {
 +    return true;
 +  }
 +  var dictType = v.get('Type');
 +  return isName(dictType) && dictType.name == type;
 +}
 +
 +function isArray(v) {
 +  return v instanceof Array;
 +}
 +
 +function isStream(v) {
 +  return typeof v == 'object' && v !== null && v !== undefined &&
-          ('getChar' in v);
++         ('getBytes' in v);
 +}
 +
 +function isArrayBuffer(v) {
 +  return typeof v == 'object' && v !== null && v !== undefined &&
 +         ('byteLength' in v);
 +}
 +
 +function isRef(v) {
 +  return v instanceof Ref;
 +}
 +
 +function isPDFFunction(v) {
 +  var fnDict;
-   if (typeof v != 'object')
++  if (typeof v != 'object') {
 +    return false;
-   else if (isDict(v))
++  } else if (isDict(v)) {
 +    fnDict = v;
-   else if (isStream(v))
++  } else if (isStream(v)) {
 +    fnDict = v.dict;
-   else
++  } else {
 +    return false;
++  }
 +  return fnDict.has('FunctionType');
 +}
 +
 +/**
-  * 'Promise' object.
-  * Each object that is stored in PDFObjects is based on a Promise object that
-  * contains the status of the object and the data. There migth be situations,
-  * where a function want to use the value of an object, but it isn't ready at
-  * that time. To get a notification, once the object is ready to be used, s.o.
-  * can add a callback using the `then` method on the promise that then calls
-  * the callback once the object gets resolved.
-  * A promise can get resolved only once and only once the data of the promise
-  * can be set. If any of these happens twice or the data is required before
-  * it was set, an exception is throw.
++ * Legacy support for PDFJS Promise implementation.
++ * TODO remove eventually
 + */
- var Promise = PDFJS.Promise = (function PromiseClosure() {
-   var EMPTY_PROMISE = {};
++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;
++  };
++})();
 +
-   /**
-    * If `data` is passed in this constructor, the promise is created resolved.
-    * If there isn't data, it isn't resolved at the beginning.
-    */
-   function Promise(name, data) {
-     this.name = name;
-     this.isRejected = false;
-     this.error = null;
-     this.exception = null;
-     // If you build a promise and pass in some data it's already resolved.
-     if (data !== null && data !== undefined) {
-       this.isResolved = true;
-       this._data = data;
-       this.hasData = true;
-     } else {
-       this.isResolved = false;
-       this._data = EMPTY_PROMISE;
-     }
-     this.callbacks = [];
-     this.errbacks = [];
-     this.progressbacks = [];
-   }
-   /**
-    * Builds a promise that is resolved when all the passed in promises are
-    * resolved.
-    * @param {Promise[]} promises Array of promises to wait for.
-    * @return {Promise} New dependant promise.
-    */
-   Promise.all = function Promise_all(promises) {
-     var deferred = new Promise();
-     var unresolved = promises.length;
-     var results = [];
-     if (unresolved === 0) {
-       deferred.resolve(results);
-       return deferred;
++/**
++ * Polyfill for Promises:
++ * The following promise implementation tries to generally implment 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.
++ *
++ * Based off of the work in:
++ * https://bugzilla.mozilla.org/show_bug.cgi?id=810490
++ */
++(function PromiseClosure() {
++  if (globalScope.Promise) {
++    // Promises existing in the DOM/Worker, checking presence of all/resolve
++    if (typeof globalScope.Promise.all !== 'function') {
++      globalScope.Promise.all = function (iterable) {
++        var count = 0, results = [], resolve, reject;
++        var promise = new globalScope.Promise(function (resolve_, reject_) {
++          resolve = resolve_;
++          reject = reject_;
++        });
++        iterable.forEach(function (p, i) {
++          count++;
++          p.then(function (result) {
++            results[i] = result;
++            count--;
++            if (count === 0) {
++              resolve(results);
++            }
++          }, reject);
++        });
++        if (count === 0) {
++          resolve(results);
++        }
++        return promise;
++      };
 +    }
-     for (var i = 0, ii = promises.length; i < ii; ++i) {
-       var promise = promises[i];
-       promise.then((function(i) {
-         return function(value) {
-           results[i] = value;
-           unresolved--;
-           if (unresolved === 0)
-             deferred.resolve(results);
-         };
-       })(i));
++    if (typeof globalScope.Promise.resolve !== 'function') {
++      globalScope.Promise.resolve = function (x) {
++        return new globalScope.Promise(function (resolve) { resolve(x); });
++      };
 +    }
-     return deferred;
-   };
-   Promise.prototype = {
-     hasData: false,
- 
-     set data(value) {
-       if (value === undefined) {
++    return;
++  }
++  var STATUS_PENDING = 0;
++  var STATUS_RESOLVED = 1;
++  var STATUS_REJECTED = 2;
++
++  // In an attempt to avoid silent exceptions, unhandled rejections are
++  // tracked and if they aren't handled in a certain amount of time an
++  // error is logged.
++  var REJECTION_TIMEOUT = 500;
++
++  var HandlerManager = {
++    handlers: [],
++    running: false,
++    unhandledRejections: [],
++    pendingRejectionCheck: false,
++
++    scheduleHandlers: function scheduleHandlers(promise) {
++      if (promise._status == STATUS_PENDING) {
 +        return;
 +      }
-       if (this._data !== EMPTY_PROMISE) {
-         error('Promise ' + this.name +
-               ': Cannot set the data of a promise twice');
-       }
-       this._data = value;
-       this.hasData = true;
 +
-       if (this.onDataCallback) {
-         this.onDataCallback(value);
-       }
-     },
++      this.handlers = this.handlers.concat(promise._handlers);
++      promise._handlers = [];
 +
-     get data() {
-       if (this._data === EMPTY_PROMISE) {
-         error('Promise ' + this.name + ': Cannot get data that isn\'t set');
++      if (this.running) {
++        return;
 +      }
-       return this._data;
-     },
++      this.running = true;
 +
-     onData: function Promise_onData(callback) {
-       if (this._data !== EMPTY_PROMISE) {
-         callback(this._data);
-       } else {
-         this.onDataCallback = callback;
-       }
++      setTimeout(this.runHandlers.bind(this), 0);
 +    },
 +
-     resolve: function Promise_resolve(data) {
-       if (this.isResolved) {
-         error('A Promise can be resolved only once ' + this.name);
-       }
-       if (this.isRejected) {
-         error('The Promise was already rejected ' + this.name);
-       }
++    runHandlers: function runHandlers() {
++      var RUN_TIMEOUT = 1; // ms
++      var timeoutAt = Date.now() + RUN_TIMEOUT;
++      while (this.handlers.length > 0) {
++        var handler = this.handlers.shift();
 +
-       this.isResolved = true;
-       this.data = (typeof data !== 'undefined') ? data : null;
-       var callbacks = this.callbacks;
++        var nextStatus = handler.thisPromise._status;
++        var nextValue = handler.thisPromise._value;
 +
-       for (var i = 0, ii = callbacks.length; i < ii; i++) {
-         callbacks[i].call(null, data);
-       }
-     },
++        try {
++          if (nextStatus === STATUS_RESOLVED) {
++            if (typeof(handler.onResolve) == 'function') {
++              nextValue = handler.onResolve(nextValue);
++            }
++          } else if (typeof(handler.onReject) === 'function') {
++              nextValue = handler.onReject(nextValue);
++              nextStatus = STATUS_RESOLVED;
 +
-     progress: function Promise_progress(data) {
-       var callbacks = this.progressbacks;
-       for (var i = 0, ii = callbacks.length; i < ii; i++) {
-         callbacks[i].call(null, data);
-       }
-     },
++              if (handler.thisPromise._unhandledRejection) {
++                this.removeUnhandeledRejection(handler.thisPromise);
++              }
++          }
++        } catch (ex) {
++          nextStatus = STATUS_REJECTED;
++          nextValue = ex;
++        }
 +
-     reject: function Promise_reject(reason, exception) {
-       if (this.isRejected) {
-         error('A Promise can be rejected only once ' + this.name);
++        handler.nextPromise._updateStatus(nextStatus, nextValue);
++        if (Date.now() >= timeoutAt) {
++          break;
++        }
 +      }
-       if (this.isResolved) {
-         error('The Promise was already resolved ' + this.name);
++
++      if (this.handlers.length > 0) {
++        setTimeout(this.runHandlers.bind(this), 0);
++        return;
 +      }
 +
-       this.isRejected = true;
-       this.error = reason || null;
-       this.exception = exception || null;
-       var errbacks = this.errbacks;
++      this.running = false;
++    },
 +
-       for (var i = 0, ii = errbacks.length; i < ii; i++) {
-         errbacks[i].call(null, reason, exception);
-       }
++    addUnhandledRejection: function addUnhandledRejection(promise) {
++      this.unhandledRejections.push({
++        promise: promise,
++        time: Date.now()
++      });
++      this.scheduleRejectionCheck();
 +    },
 +
-     then: function Promise_then(callback, errback, progressback) {
-       if (!callback) {
-         error('Requiring callback' + this.name);
++    removeUnhandeledRejection: function removeUnhandeledRejection(promise) {
++      promise._unhandledRejection = false;
++      for (var i = 0; i < this.unhandledRejections.length; i++) {
++        if (this.unhandledRejections[i].promise === promise) {
++          this.unhandledRejections.splice(i);
++          i--;
++        }
 +      }
++    },
 +
-       // If the promise is already resolved, call the callback directly.
-       if (this.isResolved) {
-         var data = this.data;
-         callback.call(null, data);
-       } else if (this.isRejected && errback) {
-         var error = this.error;
-         var exception = this.exception;
-         errback.call(null, error, exception);
-       } else {
-         this.callbacks.push(callback);
-         if (errback)
-           this.errbacks.push(errback);
++    scheduleRejectionCheck: function scheduleRejectionCheck() {
++      if (this.pendingRejectionCheck) {
++        return;
 +      }
- 
-       if (progressback)
-         this.progressbacks.push(progressback);
++      this.pendingRejectionCheck = true;
++      setTimeout(function rejectionCheck() {
++        this.pendingRejectionCheck = false;
++        var now = Date.now();
++        for (var i = 0; i < this.unhandledRejections.length; i++) {
++          if (now - this.unhandledRejections[i].time > REJECTION_TIMEOUT) {
++            var unhandled = this.unhandledRejections[i].promise._value;
++            var msg = 'Unhandled rejection: ' + unhandled;
++            if (unhandled.stack) {
++              msg += '\n' + unhandled.stack;
++            }
++            warn(msg);
++            this.unhandledRejections.splice(i);
++            i--;
++          }
++        }
++        if (this.unhandledRejections.length) {
++          this.scheduleRejectionCheck();
++        }
++      }.bind(this), REJECTION_TIMEOUT);
 +    }
 +  };
 +
-   return Promise;
- })();
- 
- var StatTimer = (function StatTimerClosure() {
++  function Promise(resolver) {
++    this._status = STATUS_PENDING;
++    this._handlers = [];
++    resolver.call(this, this._resolve.bind(this), this._reject.bind(this));
++  }
++  /**
++   * Builds a promise that is resolved when all the passed in promises are
++   * resolved.
++   * @param {array} array of data and/or promises to wait for.
++   * @return {Promise} New dependant promise.
++   */
++  Promise.all = function Promise_all(promises) {
++    var resolveAll, rejectAll;
++    var deferred = new Promise(function (resolve, reject) {
++      resolveAll = resolve;
++      rejectAll = reject;
++    });
++    var unresolved = promises.length;
++    var results = [];
++    if (unresolved === 0) {
++      resolveAll(results);
++      return deferred;
++    }
++    function reject(reason) {
++      if (deferred._status === STATUS_REJECTED) {
++        return;
++      }
++      results = [];
++      rejectAll(reason);
++    }
++    for (var i = 0, ii = promises.length; i < ii; ++i) {
++      var promise = promises[i];
++      var resolve = (function(i) {
++        return function(value) {
++          if (deferred._status === STATUS_REJECTED) {
++            return;
++          }
++          results[i] = value;
++          unresolved--;
++          if (unresolved === 0) {
++            resolveAll(results);
++          }
++        };
++      })(i);
++      if (Promise.isPromise(promise)) {
++        promise.then(resolve, reject);
++      } else {
++        resolve(promise);
++      }
++    }
++    return deferred;
++  };
++
++  /**
++   * Checks if the value is likely a promise (has a 'then' function).
++   * @return {boolean} true if x is thenable
++   */
++  Promise.isPromise = function Promise_isPromise(value) {
++    return value && typeof value.then === 'function';
++  };
++  /**
++   * Creates resolved promise
++   * @param x resolve value
++   * @returns {Promise}
++   */
++  Promise.resolve = function Promise_resolve(x) {
++    return new Promise(function (resolve) { resolve(x); });
++  };
++
++  Promise.prototype = {
++    _status: null,
++    _value: null,
++    _handlers: null,
++    _unhandledRejection: null,
++
++    _updateStatus: function Promise__updateStatus(status, value) {
++      if (this._status === STATUS_RESOLVED ||
++          this._status === STATUS_REJECTED) {
++        return;
++      }
++
++      if (status == STATUS_RESOLVED &&
++          Promise.isPromise(value)) {
++        value.then(this._updateStatus.bind(this, STATUS_RESOLVED),
++                   this._updateStatus.bind(this, STATUS_REJECTED));
++        return;
++      }
++
++      this._status = status;
++      this._value = value;
++
++      if (status === STATUS_REJECTED && this._handlers.length === 0) {
++        this._unhandledRejection = true;
++        HandlerManager.addUnhandledRejection(this);
++      }
++
++      HandlerManager.scheduleHandlers(this);
++    },
++
++    _resolve: function Promise_resolve(value) {
++      this._updateStatus(STATUS_RESOLVED, value);
++    },
++
++    _reject: function Promise_reject(reason) {
++      this._updateStatus(STATUS_REJECTED, reason);
++    },
++
++    then: function Promise_then(onResolve, onReject) {
++      var nextPromise = new Promise(function (resolve, reject) {
++        this.resolve = reject;
++        this.reject = reject;
++      });
++      this._handlers.push({
++        thisPromise: this,
++        onResolve: onResolve,
++        onReject: onReject,
++        nextPromise: nextPromise
++      });
++      HandlerManager.scheduleHandlers(this);
++      return nextPromise;
++    }
++  };
++
++  globalScope.Promise = Promise;
++})();
++
++var StatTimer = (function StatTimerClosure() {
 +  function rpad(str, pad, length) {
-     while (str.length < length)
++    while (str.length < length) {
 +      str += pad;
++    }
 +    return str;
 +  }
 +  function StatTimer() {
 +    this.started = {};
 +    this.times = [];
 +    this.enabled = true;
 +  }
 +  StatTimer.prototype = {
 +    time: function StatTimer_time(name) {
-       if (!this.enabled)
++      if (!this.enabled) {
 +        return;
-       if (name in this.started)
-         throw 'Timer is already running for ' + name;
++      }
++      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))
-         throw 'Timer has not been started for ' + name;
++      }
++      if (!(name in this.started)) {
++        warn('Timer has not been started for ' + name);
++      }
 +      this.times.push({
 +        'name': name,
 +        'start': this.started[name],
 +        'end': Date.now()
 +      });
 +      // Remove timer from started so it can be called again.
 +      delete this.started[name];
 +    },
 +    toString: function StatTimer_toString() {
 +      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) {
 +        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) {
 +        var span = times[i];
 +        var duration = span.end - span.start;
 +        out += rpad(span['name'], ' ', longest) + ' ' + duration + 'ms\n';
 +      }
 +      return out;
 +    }
 +  };
 +  return StatTimer;
 +})();
 +
 +PDFJS.createBlob = function createBlob(data, contentType) {
-   if (typeof Blob === 'function')
++  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);
 +  return bb.getBlob(contentType);
 +};
 +
++PDFJS.createObjectURL = (function createObjectURLClosure() {
++  // 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;
++      var b2 = data[i + 1] & 0xFF;
++      var b3 = data[i + 2] & 0xFF;
++      var d1 = b1 >> 2, d2 = ((b1 & 3) << 4) | (b2 >> 4);
++      var d3 = i + 1 < ii ? ((b2 & 0xF) << 2) | (b3 >> 6) : 64;
++      var d4 = i + 2 < ii ? (b3 & 0x3F) : 64;
++      buffer += digits[d1] + digits[d2] + digits[d3] + digits[d4];
++    }
++    return buffer;
++  };
++})();
 +
- /**
-  * This is the main entry point for loading a PDF and interacting with it.
-  * NOTE: If a URL is used to fetch the PDF data a standard XMLHttpRequest(XHR)
-  * 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.
-  *
-  * @return {Promise} A promise that is resolved with {PDFDocumentProxy} object.
-  */
- PDFJS.getDocument = function getDocument(source) {
-   var workerInitializedPromise, workerReadyPromise, transport;
- 
-   if (typeof source === 'string') {
-     source = { url: source };
-   } else if (isArrayBuffer(source)) {
-     source = { data: source };
-   } else if (typeof source !== 'object') {
-     error('Invalid parameter in getDocument, need either Uint8Array, ' +
-           'string or a parameter object');
-   }
- 
-   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 = {};
-   for (var key in source) {
-     if (key === 'url' && typeof window !== 'undefined') {
-       params[key] = combineUrl(window.location.href, source[key]);
-       continue;
++function MessageHandler(name, comObj) {
++  this.name = name;
++  this.comObj = comObj;
++  this.callbackIndex = 1;
++  this.postMessageTransfers = true;
++  var callbacks = this.callbacks = {};
++  var ah = this.actionHandler = {};
++
++  ah['console_log'] = [function ahConsoleLog(data) {
++    console.log.apply(console, data);
++  }];
++  ah['console_error'] = [function ahConsoleError(data) {
++    console.error.apply(console, data);
++  }];
++  ah['_unsupported_feature'] = [function ah_unsupportedFeature(data) {
++    UnsupportedManager.notify(data);
++  }];
++
++  comObj.onmessage = function messageHandlerComObjOnMessage(event) {
++    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);
++      } 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) {
++          comObj.postMessage({
++            isReply: true,
++            callbackId: data.callbackId,
++            data: resolvedData
++          });
++        });
++        action[0].call(action[1], data.data, deferred);
++      } else {
++        action[0].call(action[1], data.data);
++      }
++    } else {
++      error('Unkown action from worker: ' + data.action);
++    }
++  };
++}
++
++MessageHandler.prototype = {
++  on: function messageHandlerOn(actionName, handler, scope) {
++    var ah = this.actionHandler;
++    if (ah[actionName]) {
++      error('There is already an actionName called "' + actionName + '"');
++    }
++    ah[actionName] = [handler, scope];
++  },
++  /**
++   * 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) {
++    var message = {
++      action: actionName,
++      data: data
++    };
++    if (callback) {
++      var callbackId = this.callbackIndex++;
++      this.callbacks[callbackId] = callback;
++      message.callbackId = callbackId;
++    }
++    if (transfers && this.postMessageTransfers) {
++      this.comObj.postMessage(message, transfers);
++    } else {
++      this.comObj.postMessage(message);
 +    }
-     params[key] = source[key];
 +  }
++};
 +
-   workerInitializedPromise = new PDFJS.Promise();
-   workerReadyPromise = new PDFJS.Promise();
-   transport = new WorkerTransport(workerInitializedPromise, workerReadyPromise);
-   workerInitializedPromise.then(function transportInitialized() {
-     transport.fetchDocument(params);
++function loadJpegStream(id, imageUrl, objs) {
++  var img = new Image();
++  img.onload = (function loadJpegStream_onloadClosure() {
++    objs.resolve(id, img);
 +  });
-   return workerReadyPromise;
- };
++  img.src = imageUrl;
++}
 +
- /**
-  * Proxy to a PDFDocument in the worker thread. Also, contains commonly used
-  * properties that can be read synchronously.
-  */
- var PDFDocumentProxy = (function PDFDocumentProxyClosure() {
-   function PDFDocumentProxy(pdfInfo, transport) {
-     this.pdfInfo = pdfInfo;
-     this.transport = transport;
++
++var ColorSpace = (function ColorSpaceClosure() {
++  // Constructor should define this.numComps, this.defaultColor, this.name
++  function ColorSpace() {
++    error('should not call ColorSpace constructor');
 +  }
-   PDFDocumentProxy.prototype = {
-     /**
-      * @return {number} Total number of pages the PDF contains.
-      */
-     get numPages() {
-       return this.pdfInfo.numPages;
-     },
-     /**
-      * @return {string} A unique ID to identify a PDF. Not guaranteed to be
-      * unique.
-      */
-     get fingerprint() {
-       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}
-      * object.
-      */
-     getPage: function PDFDocumentProxy_getPage(number) {
-       return this.transport.getPage(number);
-     },
-     /**
-      * @return {Promise} A promise that is resolved with a lookup table for
-      * mapping named destinations to reference numbers.
-      */
-     getDestinations: function PDFDocumentProxy_getDestinations() {
-       var promise = new PDFJS.Promise();
-       var destinations = this.pdfInfo.destinations;
-       promise.resolve(destinations);
-       return promise;
-     },
-     /**
-      * @return {Promise} A promise that is resolved with an array of all the
-      * JavaScript strings in the name tree.
-      */
-     getJavaScript: function PDFDocumentProxy_getDestinations() {
-       var promise = new PDFJS.Promise();
-       var js = this.pdfInfo.javaScript;
-       promise.resolve(js);
-       return promise;
-     },
-     /**
-      * @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:
-      * [
-      *  {
-      *   title: string,
-      *   bold: boolean,
-      *   italic: boolean,
-      *   color: rgb array,
-      *   dest: dest obj,
-      *   items: array of more items like this
-      *  },
-      *  ...
-      * ].
-      */
-     getOutline: function PDFDocumentProxy_getOutline() {
-       var promise = new PDFJS.Promise();
-       var outline = this.pdfInfo.outline;
-       promise.resolve(outline);
-       return promise;
-     },
-     /**
-      * @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.Promise();
-       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.Promise();
-       promise.resolve(this.pdfInfo.encrypted);
-       return promise;
-     },
-     /**
-      * @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.Promise();
-       this.transport.getData(promise);
-       return promise;
-     },
-     destroy: function PDFDocumentProxy_destroy() {
-       this.transport.destroy();
-     }
-   };
-   return PDFDocumentProxy;
- })();
 +
- var PDFPageProxy = (function PDFPageProxyClosure() {
-   function PDFPageProxy(pageInfo, transport) {
-     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.renderInProgress = false;
-     this.cleanupAfterRender = false;
-   }
-   PDFPageProxy.prototype = {
-     /**
-      * @return {number} Page number of the page. First page is 1.
-      */
-     get pageNumber() {
-       return this.pageInfo.pageIndex + 1;
-     },
++  ColorSpace.prototype = {
 +    /**
-      * @return {number} The number of degrees the page is rotated clockwise.
++     * 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].
 +     */
-     get rotate() {
-       return this.pageInfo.rotate;
++    getRgb: function ColorSpace_getRgb(src, srcOffset) {
++      var rgb = new Uint8Array(3);
++      this.getRgbItem(src, srcOffset, rgb, 0);
++      return rgb;
 +    },
 +    /**
-      * @return {object} The reference that points to this page. It has 'num' and
-      * 'gen' properties.
++     * Converts the color value to the RGB color, similar to the getRgb method.
++     * The result placed into the dest array starting from the destOffset.
 +     */
-     get ref() {
-       return this.pageInfo.ref;
++    getRgbItem: function ColorSpace_getRgbItem(src, srcOffset,
++                                               dest, destOffset) {
++      error('Should not call ColorSpace.getRgbItem');
 +    },
 +    /**
-      * @return {array} An array of the visible portion of the PDF page in the
-      * user space units - [x1, y1, x2, y2].
++     * 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).
 +     */
-     get view() {
-       return this.pageInfo.view;
++    getRgbBuffer: function ColorSpace_getRgbBuffer(src, srcOffset, count,
++                                                   dest, destOffset, bits,
++                                                   alpha01) {
++      error('Should not call ColorSpace.getRgbBuffer');
 +    },
 +    /**
-      * @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.
++     * 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).
 +     */
-     getViewport: function PDFPageProxy_getViewport(scale, rotate) {
-       if (arguments.length < 2)
-         rotate = this.rotate;
-       return new PDFJS.PageViewport(this.view, scale, rotate, 0, 0);
++    getOutputLength: function ColorSpace_getOutputLength(inputLength,
++                                                         alpha01) {
++      error('Should not call ColorSpace.getOutputLength');
 +    },
 +    /**
-      * @return {Promise} A promise that is resolved with an {array} of the
-      * annotation objects.
++     * Returns true if source data will be equal the result/output data.
 +     */
-     getAnnotations: function PDFPageProxy_getAnnotations() {
-       if (this.annotationsPromise)
-         return this.annotationsPromise;
- 
-       var promise = new PDFJS.Promise();
-       this.annotationsPromise = promise;
-       this.transport.getAnnotations(this.pageInfo.pageIndex);
-       return promise;
++    isPassthrough: function ColorSpace_isPassthrough(bits) {
++      return false;
 +    },
 +    /**
-      * 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 {Promise} A promise that is resolved when the page finishes
-      * rendering.
++     * 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).
 +     */
-     render: function PDFPageProxy_render(params) {
-       this.renderInProgress = true;
- 
-       var promise = new Promise();
-       var stats = this.stats;
-       stats.time('Overall');
-       // If there is no displayReadyPromise yet, then the operatorList was never
-       // requested before. Make the request and create the promise.
-       if (!this.displayReadyPromise) {
-         this.displayReadyPromise = new Promise();
-         this.destroyed = false;
- 
-         this.stats.time('Page Request');
-         this.transport.messageHandler.send('RenderPageRequest', {
-           pageIndex: this.pageNumber - 1
-         });
-       }
- 
-       var self = this;
-       function complete(error) {
-         self.renderInProgress = false;
-         if (self.destroyed || self.cleanupAfterRender) {
-           delete self.displayReadyPromise;
-           delete self.operatorList;
-           self.objs.clear();
++    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;
++
++      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);
++        for (var i = 0; i < numComponentColors; i++) {
++          allColors[i] = i;
 +        }
- 
-         if (error)
-           promise.reject(error);
-         else
-           promise.resolve();
-       }
-       var continueCallback = params.continueCallback;
- 
-       // Once the operatorList and fonts are loaded, do the actual rendering.
-       this.displayReadyPromise.then(
-         function pageDisplayReadyPromise() {
-           if (self.destroyed) {
-             complete();
-             return;
++        var colorMap = new Uint8Array(numComponentColors * 3);
++        this.getRgbBuffer(allColors, 0, numComponentColors, colorMap, 0, bpc,
++                          /* alpha01 = */ 0);
++
++        if (!needsResizing) {
++          // Fill in the RGB values directly into |dest|.
++          var destPos = 0;
++          for (var i = 0; i < count; ++i) {
++            var key = comps[i] * 3;
++            dest[destPos++] = colorMap[key];
++            dest[destPos++] = colorMap[key + 1];
++            dest[destPos++] = colorMap[key + 2];
++            destPos += alpha01;
 +          }
- 
-           var gfx = new CanvasGraphics(params.canvasContext, this.commonObjs,
-             this.objs, params.textLayer, params.imageLayer);
-           try {
-             this.display(gfx, params.viewport, complete, continueCallback);
-           } catch (e) {
-             complete(e);
++        } else {
++          rgbBuf = new Uint8Array(count * 3);
++          var rgbPos = 0;
++          for (var i = 0; i < count; ++i) {
++            var key = comps[i] * 3;
++            rgbBuf[rgbPos++] = colorMap[key];
++            rgbBuf[rgbPos++] = colorMap[key + 1];
++            rgbBuf[rgbPos++] = colorMap[key + 2];
 +          }
-         }.bind(this),
-         function pageDisplayReadPromiseError(reason) {
-           complete(reason);
-         }
-       );
- 
-       return promise;
-     },
-     /**
-      * For internal use only.
-      */
-     startRenderingFromOperatorList:
-       function PDFPageProxy_startRenderingFromOperatorList(operatorList,
-                                                            fonts) {
-       var self = this;
-       this.operatorList = operatorList;
- 
-       var displayContinuation = function pageDisplayContinuation() {
-         // Always defer call to display() to work around bug in
-         // Firefox error reporting from XHR callbacks.
-         setTimeout(function pageSetTimeout() {
-           self.displayReadyPromise.resolve();
-         });
-       };
- 
-       this.ensureFonts(fonts,
-         function pageStartRenderingFromOperatorListEnsureFonts() {
-           displayContinuation();
-         }
-       );
-     },
-     /**
-      * For internal use only.
-      */
-     ensureFonts: function PDFPageProxy_ensureFonts(fonts, callback) {
-       this.stats.time('Font Loading');
-       // Convert the font names to the corresponding font obj.
-       var fontObjs = [];
-       for (var i = 0, ii = fonts.length; i < ii; i++) {
-         var obj = this.commonObjs.getData(fonts[i]);
-         if (obj.error) {
-           warn('Error during font loading: ' + obj.error);
-           continue;
 +        }
-         if (!obj.coded) {
-           this.transport.embeddedFontsUsed = true;
++      } 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);
 +        }
-         fontObjs.push(obj);
 +      }
 +
-       // Load all the fonts
-       FontLoader.bind(
-         fontObjs,
-         function pageEnsureFontsFontObjs(fontObjs) {
-           this.stats.timeEnd('Font Loading');
- 
-           callback.call(this);
-         }.bind(this)
-       );
-     },
-     /**
-      * For internal use only.
-      */
-     display: function PDFPageProxy_display(gfx, viewport, callback,
-                                            continueCallback) {
-       var stats = this.stats;
-       stats.time('Rendering');
- 
-       gfx.beginDrawing(viewport);
- 
-       var startIdx = 0;
-       var length = this.operatorList.fnArray.length;
-       var operatorList = this.operatorList;
-       var stepper = null;
-       if (PDFJS.pdfBug && 'StepperManager' in globalScope &&
-           globalScope['StepperManager'].enabled) {
-         stepper = globalScope['StepperManager'].create(this.pageNumber - 1);
-         stepper.init(operatorList);
-         stepper.nextBreakPoint = stepper.getNextBreakPoint();
-       }
- 
-       var continueWrapper;
-       if (continueCallback)
-         continueWrapper = function() { continueCallback(next); };
-       else
-         continueWrapper = next;
- 
-       var self = this;
-       function next() {
-         startIdx = gfx.executeOperatorList(operatorList, startIdx,
-                                            continueWrapper, stepper);
-         if (startIdx == length) {
-           gfx.endDrawing();
-           stats.timeEnd('Rendering');
-           stats.timeEnd('Overall');
-           if (callback) callback();
++      if (rgbBuf) {
++        if (needsResizing) {
++          rgbBuf = PDFImage.resize(rgbBuf, bpc, 3, originalWidth,
++                                   originalHeight, width, height);
 +        }
-       }
-       continueWrapper();
-     },
-     /**
-      * @return {Promise} That is resolved with the a {string} that is the text
-      * content from the page.
-      */
-     getTextContent: function PDFPageProxy_getTextContent() {
-       var promise = new PDFJS.Promise();
-       this.transport.messageHandler.send('GetTextContent', {
-           pageIndex: this.pageNumber - 1
-         },
-         function textContentCallback(textContent) {
-           promise.resolve(textContent);
++        var rgbPos = 0;
++        var destPos = 0;
++        for (var i = 0, ii = width * actualHeight; i < ii; i++) {
++          dest[destPos++] = rgbBuf[rgbPos++];
++          dest[destPos++] = rgbBuf[rgbPos++];
++          dest[destPos++] = rgbBuf[rgbPos++];
++          destPos += alpha01;
 +        }
-       );
-       return promise;
-     },
-     /**
-      * Stub for future feature.
-      */
-     getOperationList: function PDFPageProxy_getOperationList() {
-       var promise = new PDFJS.Promise();
-       var operationList = { // not implemented
-         dependencyFontsID: null,
-         operatorList: null
-       };
-       promise.resolve(operationList);
-       return promise;
++      }
 +    },
 +    /**
-      * Destroys resources allocated by the page.
++     * 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].
 +     */
-     destroy: function PDFPageProxy_destroy() {
-       this.destroyed = true;
++    usesZeroToOneRange: true
++  };
 +
-       if (!this.renderInProgress) {
-         delete this.operatorList;
-         delete this.displayReadyPromise;
-         this.objs.clear();
-       }
++  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);
 +  };
-   return PDFPageProxy;
- })();
- /**
-  * For internal use only.
-  */
- var WorkerTransport = (function WorkerTransportClosure() {
-   function WorkerTransport(workerInitializedPromise, workerReadyPromise) {
-     this.workerReadyPromise = workerReadyPromise;
-     this.commonObjs = new PDFObjects();
 +
-     this.pageCache = [];
-     this.pagePromises = [];
-     this.embeddedFontsUsed = false;
- 
-     // If worker support isn't disabled explicit and the browser has worker
-     // support, create a new web worker and test if it/the browser fullfills
-     // all requirements to run parts of pdf.js in a web worker.
-     // Right now, the requirement is, that an Uint8Array is still an Uint8Array
-     // as it arrives on the worker. Chrome added this with version 15.
-     if (!globalScope.PDFJS.disableWorker && typeof Worker !== 'undefined') {
-       var workerSrc = PDFJS.workerSrc;
-       if (typeof workerSrc === 'undefined') {
-         error('No PDFJS.workerSrc specified');
-       }
++  ColorSpace.fromIR = function ColorSpace_fromIR(IR) {
++    var name = isArray(IR) ? IR[0] : IR;
 +
-       try {
-         // Some versions of FF can't create a worker on localhost, see:
-         // https://bugzilla.mozilla.org/show_bug.cgi?id=683280
-         var worker = new Worker(workerSrc);
-         var messageHandler = new MessageHandler('main', worker);
-         this.messageHandler = messageHandler;
- 
-         messageHandler.on('test', function transportTest(supportTypedArray) {
-           if (supportTypedArray) {
-             this.worker = worker;
-             this.setupMessageHandler(messageHandler);
-           } else {
-             globalScope.PDFJS.disableWorker = true;
-             this.setupFakeWorker();
-           }
-           workerInitializedPromise.resolve();
-         }.bind(this));
++    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];
 +
-         var testObj = new Uint8Array(1);
-         // Some versions of Opera throw a DATA_CLONE_ERR on
-         // serializing the typed array.
-         messageHandler.send('test', testObj);
-         return;
-       } catch (e) {
-         info('The worker has been disabled.');
-       }
++        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);
 +    }
-     // Either workers are disabled, not supported or have thrown an exception.
-     // Thus, we fallback to a faked worker.
-     globalScope.PDFJS.disableWorker = true;
-     this.setupFakeWorker();
-     workerInitializedPromise.resolve();
-   }
-   WorkerTransport.prototype = {
-     destroy: function WorkerTransport_destroy() {
-       if (this.worker)
-         this.worker.terminate();
- 
-       this.pageCache = [];
-       this.pagePromises = [];
-     },
-     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);
- 
-       // If the main thread is our worker, setup the handling for the messages
-       // the main thread sends to it self.
-       WorkerMessageHandler.setup(messageHandler);
-     },
- 
-     setupMessageHandler:
-       function WorkerTransport_setupMessageHandler(messageHandler) {
-       this.messageHandler = messageHandler;
- 
-       messageHandler.on('GetDoc', function transportDoc(data) {
-         var pdfInfo = data.pdfInfo;
-         var pdfDocument = new PDFDocumentProxy(pdfInfo, this);
-         this.pdfDocument = pdfDocument;
-         this.workerReadyPromise.resolve(pdfDocument);
-       }, this);
- 
-       messageHandler.on('NeedPassword', function transportPassword(data) {
-         this.workerReadyPromise.reject(data.exception.message, data.exception);
-       }, this);
- 
-       messageHandler.on('IncorrectPassword', function transportBadPass(data) {
-         this.workerReadyPromise.reject(data.exception.message, data.exception);
-       }, this);
- 
-       messageHandler.on('InvalidPDF', function transportInvalidPDF(data) {
-         this.workerReadyPromise.reject(data.exception.name, data.exception);
-       }, this);
- 
-       messageHandler.on('MissingPDF', function transportMissingPDF(data) {
-         this.workerReadyPromise.reject(data.exception.message, data.exception);
-       }, this);
- 
-       messageHandler.on('UnknownError', function transportUnknownError(data) {
-         this.workerReadyPromise.reject(data.exception.message, data.exception);
-       }, 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);
-       }, this);
- 
-       messageHandler.on('GetAnnotations', function transportAnnotations(data) {
-         var annotations = data.annotations;
-         var promise = this.pageCache[data.pageIndex].annotationsPromise;
-         promise.resolve(annotations);
-       }, this);
- 
-       messageHandler.on('RenderPage', function transportRender(data) {
-         var page = this.pageCache[data.pageIndex];
-         var depFonts = data.depFonts;
- 
-         page.stats.timeEnd('Page Request');
-         page.startRenderingFromOperatorList(data.operatorList, depFonts);
-       }, this);
- 
-       messageHandler.on('commonobj', function transportObj(data) {
-         var id = data[0];
-         var type = data[1];
-         if (this.commonObjs.hasData(id))
-           return;
++    return null;
++  };
 +
-         switch (type) {
-           case 'Font':
-             var exportedData = data[2];
- 
-             // At this point, only the font object is created but the font is
-             // not yet attached to the DOM. This is done in `FontLoader.bind`.
-             var font;
-             if ('error' in exportedData)
-               font = new ErrorFont(exportedData.error);
-             else
-               font = new Font(exportedData);
-             this.commonObjs.resolve(id, font);
-             break;
-           default:
-             error('Got unknown common object type ' + type);
++  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;
 +        }
-       }, this);
- 
-       messageHandler.on('obj', function transportObj(data) {
-         var id = data[0];
-         var pageIndex = data[1];
-         var type = data[2];
-         var pageProxy = this.pageCache[pageIndex];
-         if (pageProxy.objs.hasData(id))
-           return;
++      }
++    }
 +
-         switch (type) {
-           case 'JpegStream':
-             var imageData = data[3];
-             loadJpegStream(id, imageData, pageProxy.objs);
-             break;
-           case 'Image':
-             var 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 &&
-                 imageData.data.length > MAX_IMAGE_SIZE_TO_STORE) {
-               pageProxy.cleanupAfterRender = true;
-             }
-             break;
-           default:
-             error('Got unknown object type ' + type);
-         }
-       }, this);
++    cs = xref.fetchIfRef(cs);
++    var mode;
 +
-       messageHandler.on('DocProgress', function transportDocProgress(data) {
-         this.workerReadyPromise.progress({
-           loaded: data.loaded,
-           total: data.total
-         });
-       }, this);
++    if (isName(cs)) {
++      mode = cs.name;
++      this.mode = mode;
 +
-       messageHandler.on('DocError', function transportDocError(data) {
-         this.workerReadyPromise.reject(data);
-       }, this);
++      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;
 +
-       messageHandler.on('PageError', function transportError(data) {
-         var page = this.pageCache[data.pageNum - 1];
-         if (page.displayReadyPromise)
-           page.displayReadyPromise.reject(data.error);
-         else
-           error(data.error);
-       }, this);
- 
-       messageHandler.on('JpegDecode', function(data, promise) {
-         var imageData = data[0];
-         var components = data[1];
-         if (components != 3 && components != 1)
-           error('Only 3 component 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;
- 
-           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];
-             }
-           } else if (components == 1) {
-             for (var i = 0, j = 0; i < rgbaLength; i += 4, j++) {
-               buf[j] = data[i];
-             }
++      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';
++          } else if (numComps == 3) {
++            return 'DeviceRgbCS';
++          } else if (numComps == 4) {
++            return 'DeviceCmykCS';
 +          }
-           promise.resolve({ data: buf, width: width, height: height});
-         }).bind(this);
-         var src = 'data:image/jpeg;base64,' + window.btoa(imageData);
-         img.src = src;
-       });
-     },
++          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;
++    }
 +
-     fetchDocument: function WorkerTransport_fetchDocument(source) {
-       this.messageHandler.send('GetDocRequest', {source: source});
-     },
++    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;
++  };
 +
-     getData: function WorkerTransport_getData(promise) {
-       this.messageHandler.send('GetData', null, function(data) {
-         promise.resolve(data);
-       });
++  ColorSpace.singletons = {
++    get gray() {
++      return shadow(this, 'gray', new DeviceGrayCS());
 +    },
- 
-     getPage: function WorkerTransport_getPage(pageNumber, promise) {
-       var pageIndex = pageNumber - 1;
-       if (pageIndex in this.pagePromises)
-         return this.pagePromises[pageIndex];
-       var promise = new PDFJS.Promise('Page ' + pageNumber);
-       this.pagePromises[pageIndex] = promise;
-       this.messageHandler.send('GetPageRequest', { pageIndex: pageIndex });
-       return promise;
++    get rgb() {
++      return shadow(this, 'rgb', new DeviceRgbCS());
 +    },
- 
-     getAnnotations: function WorkerTransport_getAnnotations(pageIndex) {
-       this.messageHandler.send('GetAnnotationsRequest',
-         { pageIndex: pageIndex });
++    get cmyk() {
++      return shadow(this, 'cmyk', new DeviceCmykCS());
 +    }
 +  };
-   return WorkerTransport;
 +
++  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;
++  }
 +
- // <canvas> contexts store most of the state we need natively.
- // However, PDF needs a bit more state, which we store here.
- 
- var TextRenderingMode = {
-   FILL: 0,
-   STROKE: 1,
-   FILL_STROKE: 2,
-   INVISIBLE: 3,
-   FILL_ADD_TO_PATH: 4,
-   STROKE_ADD_TO_PATH: 5,
-   FILL_STROKE_ADD_TO_PATH: 6,
-   ADD_TO_PATH: 7,
-   ADD_TO_PATH_FLAG: 4
- };
- 
- // Minimal font size that would be used during canvas fillText operations.
- var MIN_FONT_SIZE = 1;
- 
- function createScratchCanvas(width, height) {
-   var canvas = document.createElement('canvas');
-   canvas.width = width;
-   canvas.height = height;
-   return canvas;
- }
- 
- function addContextCurrentTransform(ctx) {
-   // If the context doesn't expose a `mozCurrentTransform`, add a JS based on.
-   if (!ctx.mozCurrentTransform) {
-     // Store the original context
-     ctx._scaleX = ctx._scaleX || 1.0;
-     ctx._scaleY = ctx._scaleY || 1.0;
-     ctx._originalSave = ctx.save;
-     ctx._originalRestore = ctx.restore;
-     ctx._originalRotate = ctx.rotate;
-     ctx._originalScale = ctx.scale;
-     ctx._originalTranslate = ctx.translate;
-     ctx._originalTransform = ctx.transform;
- 
-     ctx._transformMatrix = [ctx._scaleX, 0, 0, ctx._scaleY, 0, 0];
-     ctx._transformStack = [];
- 
-     Object.defineProperty(ctx, 'mozCurrentTransform', {
-       get: function getCurrentTransform() {
-         return this._transformMatrix;
-       }
-     });
- 
-     Object.defineProperty(ctx, 'mozCurrentTransformInverse', {
-       get: function getCurrentTransformInverse() {
-         // Calculation done using WolframAlpha:
-         // http://www.wolframalpha.com/input/?
-         //   i=Inverse+{{a%2C+c%2C+e}%2C+{b%2C+d%2C+f}%2C+{0%2C+0%2C+1}}
- 
-         var m = this._transformMatrix;
-         var a = m[0], b = m[1], c = m[2], d = m[3], e = m[4], f = m[5];
- 
-         var ad_bc = a * d - b * c;
-         var bc_ad = b * c - a * d;
++  AlternateCS.prototype = {
++    getRgb: ColorSpace.prototype.getRgb,
++    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,
++                                                    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;
 +
-         return [
-           d / ad_bc,
-           b / bc_ad,
-           c / bc_ad,
-           a / ad_bc,
-           (d * e - c * f) / bc_ad,
-           (b * e - a * f) / ad_bc
-         ];
++      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;
++        }
 +      }
-     });
- 
-     ctx.save = function ctxSave() {
-       var old = this._transformMatrix;
-       this._transformStack.push(old);
-       this._transformMatrix = old.slice(0, 6);
- 
-       this._originalSave();
-     };
- 
-     ctx.restore = function ctxRestore() {
-       var prev = this._transformStack.pop();
-       if (prev) {
-         this._transformMatrix = prev;
-         this._originalRestore();
++      if (!isPassthrough) {
++        base.getRgbBuffer(baseBuf, 0, count, dest, destOffset, 8, alpha01);
 +      }
-     };
- 
-     ctx.translate = function ctxTranslate(x, y) {
-       var m = this._transformMatrix;
-       m[4] = m[0] * x + m[2] * y + m[4];
-       m[5] = m[1] * x + m[3] * y + m[5];
- 
-       this._originalTranslate(x, y);
-     };
- 
-     ctx.scale = function ctxScale(x, y) {
-       var m = this._transformMatrix;
-       m[0] = m[0] * x;
-       m[1] = m[1] * x;
-       m[2] = m[2] * y;
-       m[3] = m[3] * y;
- 
-       this._originalScale(x, y);
-     };
- 
-     ctx.transform = function ctxTransform(a, b, c, d, e, f) {
-       var m = this._transformMatrix;
-       this._transformMatrix = [
-         m[0] * a + m[2] * b,
-         m[1] * a + m[3] * b,
-         m[0] * c + m[2] * d,
-         m[1] * c + m[3] * d,
-         m[0] * e + m[2] * f + m[4],
-         m[1] * e + m[3] * f + m[5]
-       ];
- 
-       ctx._originalTransform(a, b, c, d, e, f);
-     };
++    },
++    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
++  };
 +
-     ctx.rotate = function ctxRotate(angle) {
-       var cosValue = Math.cos(angle);
-       var sinValue = Math.sin(angle);
- 
-       var m = this._transformMatrix;
-       this._transformMatrix = [
-         m[0] * cosValue + m[2] * sinValue,
-         m[1] * cosValue + m[3] * sinValue,
-         m[0] * (-sinValue) + m[2] * cosValue,
-         m[1] * (-sinValue) + m[3] * cosValue,
-         m[4],
-         m[5]
-       ];
++  return AlternateCS;
++})();
 +
-       this._originalRotate(angle);
-     };
++var PatternCS = (function PatternCSClosure() {
++  function PatternCS(baseCS) {
++    this.name = 'Pattern';
++    this.base = baseCS;
 +  }
- }
++  PatternCS.prototype = {};
 +
- var CanvasExtraState = (function CanvasExtraStateClosure() {
-   function CanvasExtraState(old) {
-     // Are soft masks and alpha values shapes or opacities?
-     this.alphaIsShape = false;
-     this.fontSize = 0;
-     this.fontSizeScale = 1;
-     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.textRenderingMode = TextRenderingMode.FILL;
-     this.textRise = 0;
-     // Color spaces
-     this.fillColorSpace = new DeviceGrayCS();
-     this.fillColorSpaceObj = null;
-     this.strokeColorSpace = new DeviceGrayCS();
-     this.strokeColorSpaceObj = null;
-     this.fillColorObj = null;
-     this.strokeColorObj = null;
-     // Default fore and background colors
-     this.fillColor = '#000000';
-     this.strokeColor = '#000000';
-     // Note: fill alpha applies to all non-stroking operations
-     this.fillAlpha = 1;
-     this.strokeAlpha = 1;
-     this.lineWidth = 1;
-     this.paintFormXObjectDepth = 0;
- 
-     this.old = old;
-   }
- 
-   CanvasExtraState.prototype = {
-     clone: function CanvasExtraState_clone() {
-       return Object.create(this);
-     },
-     setCurrentPoint: function CanvasExtraState_setCurrentPoint(x, y) {
-       this.x = x;
-       this.y = y;
-     }
-   };
-   return CanvasExtraState;
++  return PatternCS;
 +})();
 +
- 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;
- 
-   function CanvasGraphics(canvasCtx, commonObjs, objs, textLayer, imageLayer) {
-     this.ctx = canvasCtx;
-     this.current = new CanvasExtraState();
-     this.stateStack = [];
-     this.pendingClip = null;
-     this.res = null;
-     this.xobjs = null;
-     this.commonObjs = commonObjs;
-     this.objs = objs;
-     this.textLayer = textLayer;
-     this.imageLayer = imageLayer;
-     this.groupStack = [];
-     if (canvasCtx) {
-       addContextCurrentTransform(canvasCtx);
-     }
-   }
- 
-   function applyStencilMask(imgArray, width, height, inverseDecode, buffer) {
-     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] = 0;
-         }
-         bufferPos += 4;
-         mask >>= 1;
-       }
-     }
-   }
++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;
 +
-   function putBinaryImageData(ctx, data, w, h) {
-     var tmpImgData = 'createImageData' in ctx ? ctx.createImageData(w, h) :
-       ctx.getImageData(0, 0, w, h);
++    var baseNumComps = base.numComps;
++    var length = baseNumComps * highVal;
++    var lookupArray;
 +
-     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];
++    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);
 +    }
- 
-     ctx.putImageData(tmpImgData, 0, 0);
++    this.lookup = lookupArray;
 +  }
 +
-   function prescaleImage(pixels, width, height, widthScale, heightScale) {
-     pixels = new Uint8Array(pixels); // creating a copy
-     while (widthScale > 2 || heightScale > 2) {
-       if (heightScale > 2) {
-         // scaling image twice vertically
-         var rowSize = width * 4;
-         var k = 0, l = 0;
-         for (var i = 0; i < height - 1; i += 2) {
-           for (var j = 0; j < width; j++) {
-             var alpha1 = pixels[k + 3], alpha2 = pixels[k + 3 + rowSize];
-             if (alpha1 === alpha2) {
-               pixels[l] = (pixels[k] + pixels[k + rowSize]) >> 1;
-               pixels[l + 1] = (pixels[k + 1] + pixels[k + 1 + rowSize]) >> 1;
-               pixels[l + 2] = (pixels[k + 2] + pixels[k + 2 + rowSize]) >> 1;
-               pixels[l + 3] = alpha1;
-             } else if (alpha1 < alpha2) {
-               var d = 256 - alpha2 + alpha1;
-               pixels[l] = (pixels[k] * d + (pixels[k + rowSize] << 8)) >> 9;
-               pixels[l + 1] = (pixels[k + 1] * d +
-                               (pixels[k + 1 + rowSize] << 8)) >> 9;
-               pixels[l + 2] = (pixels[k + 2] * d +
-                               (pixels[k + 2 + rowSize] << 8)) >> 9;
-               pixels[l + 3] = alpha2;
-             } else {
-               var d = 256 - alpha1 + alpha2;
-               pixels[l] = ((pixels[k] << 8) + pixels[k + rowSize] * d) >> 9;
-               pixels[l + 1] = ((pixels[k + 1] << 8) +
-                               pixels[k + 1 + rowSize] * d) >> 9;
-               pixels[l + 2] = ((pixels[k + 2] << 8) +
-                               pixels[k + 2 + rowSize] * d) >> 9;
-               pixels[l + 3] = alpha1;
-             }
-             k += 4; l += 4;
-           }
-           k += rowSize;
-         }
-         if (height & 1) {
-           for (var i = 0; i < rowSize; i++) {
-             pixels[l++] = pixels[k++];
-           }
-         }
-         height = (height + 1) >> 1;
-         heightScale /= 2;
-       }
-       if (widthScale > 2) {
-         // scaling image twice horizontally
-         var k = 0, l = 0;
-         for (var i = 0; i < height; i++) {
-           for (var j = 0; j < width - 1; j += 2) {
-             var alpha1 = pixels[k + 3], alpha2 = pixels[k + 7];
-             if (alpha1 === alpha2) {
-               pixels[l] = (pixels[k] + pixels[k + 4]) >> 1;
-               pixels[l + 1] = (pixels[k + 1] + pixels[k + 5]) >> 1;
-               pixels[l + 2] = (pixels[k + 2] + pixels[k + 6]) >> 1;
-               pixels[l + 3] = alpha1;
-             } else if (alpha1 < alpha2) {
-               var d = 256 - alpha2 + alpha1;
-               pixels[l] = (pixels[k] * d + (pixels[k + 4] << 8)) >> 9;
-               pixels[l + 1] = (pixels[k + 1] * d + (pixels[k + 5] << 8)) >> 9;
-               pixels[l + 2] = (pixels[k + 2] * d + (pixels[k + 6] << 8)) >> 9;
-               pixels[l + 3] = alpha2;
-             } else {
-               var d = 256 - alpha1 + alpha2;
-               pixels[l] = ((pixels[k] << 8) + pixels[k + 4] * d) >> 9;
-               pixels[l + 1] = ((pixels[k + 1] << 8) + pixels[k + 5] * d) >> 9;
-               pixels[l + 2] = ((pixels[k + 2] << 8) + pixels[k + 6] * d) >> 9;
-               pixels[l + 3] = alpha1;
-             }
-             k += 8; l += 4;
-           }
-           if (width & 1) {
-             pixels[l++] = pixels[k++];
-             pixels[l++] = pixels[k++];
-             pixels[l++] = pixels[k++];
-             pixels[l++] = pixels[k++];
-           }
-         }
-         width = (width + 1) >> 1;
-         widthScale /= 2;
-       }
-     }
- 
-     var tmpCanvas = createScratchCanvas(width, height);
-     var tmpCtx = tmpCanvas.getContext('2d');
-     putBinaryImageData(tmpCtx, pixels.subarray(0, width * height * 4),
-                                width, height);
- 
-     return tmpCanvas;
-   }
- 
-   function copyCtxState(sourceCtx, destCtx) {
-     var properties = ['strokeStyle', 'fillStyle', 'fillRule', 'globalAlpha',
-                       'lineWidth', 'lineCap', 'lineJoin', 'miterLimit',
-                       'globalCompositeOperation', 'font'];
-     for (var i = 0, ii = properties.length; i < ii; i++) {
-       var property = properties[i];
-       if (property in sourceCtx) {
-         destCtx[property] = sourceCtx[property];
-       }
-     }
-     if ('setLineDash' in sourceCtx) {
-       destCtx.setLineDash(sourceCtx.getLineDash());
-       destCtx.lineDashOffset =  sourceCtx.lineDashOffset;
-     } else if ('mozDash' in sourceCtx) {
-       destCtx.mozDash = sourceCtx.mozDash;
-       destCtx.mozDashOffset = sourceCtx.mozDashOffset;
-     }
-   }
- 
-   var LINE_CAP_STYLES = ['butt', 'round', 'square'];
-   var LINE_JOIN_STYLES = ['miter', 'round', 'bevel'];
-   var NORMAL_CLIP = {};
-   var EO_CLIP = {};
- 
-   CanvasGraphics.prototype = {
-     slowCommands: {
-       'stroke': true,
-       'closeStroke': true,
-       'fill': true,
-       'eoFill': true,
-       'fillStroke': true,
-       'eoFillStroke': true,
-       'closeFillStroke': true,
-       'closeEOFillStroke': true,
-       'showText': true,
-       'showSpacedText': true,
-       'setStrokeColorSpace': true,
-       'setFillColorSpace': true,
-       'setStrokeColor': true,
-       'setStrokeColorN': true,
-       'setFillColor': true,
-       'setFillColorN': true,
-       'setStrokeGray': true,
-       'setFillGray': true,
-       'setStrokeRGBColor': true,
-       'setFillRGBColor': true,
-       'setStrokeCMYKColor': true,
-       'setFillCMYKColor': true,
-       'paintJpegXObject': true,
-       'paintImageXObject': true,
-       'paintInlineImageXObject': true,
-       'paintInlineImageXObjectGroup': true,
-       'paintImageMaskXObject': true,
-       'paintImageMaskXObjectGroup': true,
-       'shadingFill': true
-     },
- 
-     beginDrawing: function CanvasGraphics_beginDrawing(viewport) {
-       var transform = viewport.transform;
-       this.ctx.save();
-       this.ctx.transform.apply(this.ctx, transform);
- 
-       if (this.textLayer) {
-         this.textLayer.beginLayout();
-       }
-       if (this.imageLayer) {
-         this.imageLayer.beginLayout();
-       }
-     },
- 
-     executeOperatorList: function CanvasGraphics_executeOperatorList(
-                                     operatorList,
-                                     executionStartIdx, continueCallback,
-                                     stepper) {
-       var argsArray = operatorList.argsArray;
-       var fnArray = operatorList.fnArray;
-       var i = executionStartIdx || 0;
-       var argsArrayLen = argsArray.length;
- 
-       // Sometimes the OperatorList to execute is empty.
-       if (argsArrayLen == i) {
-         return i;
-       }
- 
-       var executionEndIdx;
-       var endTime = Date.now() + EXECUTION_TIME;
- 
-       var commonObjs = this.commonObjs;
-       var objs = this.objs;
-       var fnName;
-       var slowCommands = this.slowCommands;
- 
-       while (true) {
-         if (stepper && i === stepper.nextBreakPoint) {
-           stepper.breakIt(i, continueCallback);
-           return i;
-         }
- 
-         fnName = fnArray[i];
- 
-         if (fnName !== 'dependency') {
-           this[fnName].apply(this, argsArray[i]);
-         } else {
-           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_';
- 
-             // 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);
-               return i;
-             }
-           }
-         }
- 
-         i++;
- 
-         // If the entire operatorList was executed, stop as were done.
-         if (i == argsArrayLen) {
-           return i;
-         }
- 
-         // If the execution took longer then a certain amount of time, shedule
-         // to continue exeution after a short delay.
-         // However, this is only possible if a 'continueCallback' is passed in.
-         if (continueCallback && slowCommands[fnName] && Date.now() > endTime) {
-           setTimeout(continueCallback, 0);
-           return i;
-         }
- 
-         // If the operatorList isn't executed completely yet OR the execution
-         // time was short enough, do another execution round.
-       }
++  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;
 +
-     endDrawing: function CanvasGraphics_endDrawing() {
-       this.ctx.restore();
- 
-       if (this.textLayer) {
-         this.textLayer.endLayout();
-       }
-       if (this.imageLayer) {
-         this.imageLayer.endLayout();
++      for (var i = 0; i < count; ++i) {
++        var lookupPos = src[srcOffset++] * numComps;
++        base.getRgbBuffer(lookup, lookupPos, 1, dest, destOffset, 8, alpha01);
++        destOffset += outputDelta;
 +      }
 +    },
- 
-     // Graphics state
-     setLineWidth: function CanvasGraphics_setLineWidth(width) {
-       this.current.lineWidth = width;
-       this.ctx.lineWidth = width;
-     },
-     setLineCap: function CanvasGraphics_setLineCap(style) {
-       this.ctx.lineCap = LINE_CAP_STYLES[style];
++    getOutputLength: function IndexedCS_getOutputLength(inputLength, alpha01) {
++      return this.base.getOutputLength(inputLength * this.base.numComps,
++                                       alpha01);
 +    },
-     setLineJoin: function CanvasGraphics_setLineJoin(style) {
-       this.ctx.lineJoin = LINE_JOIN_STYLES[style];
++    isPassthrough: ColorSpace.prototype.isPassthrough,
++    fillRgb: ColorSpace.prototype.fillRgb,
++    isDefaultDecode: function IndexedCS_isDefaultDecode(decodeMap) {
++      // indexed color maps shouldn't be changed
++      return true;
 +    },
-     setMiterLimit: function CanvasGraphics_setMiterLimit(limit) {
-       this.ctx.miterLimit = limit;
++    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;
 +    },
-     setDash: function CanvasGraphics_setDash(dashArray, dashPhase) {
-       var ctx = this.ctx;
-       if ('setLineDash' in ctx) {
-         ctx.setLineDash(dashArray);
-         ctx.lineDashOffset = dashPhase;
-       } else {
-         ctx.mozDash = dashArray;
-         ctx.mozDashOffset = dashPhase;
++    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;
 +      }
 +    },
-     setRenderingIntent: function CanvasGraphics_setRenderingIntent(intent) {
-       // Maybe if we one day fully support color spaces this will be important
-       // for now we can ignore.
-       // TODO set rendering intent?
++    getOutputLength: function DeviceGrayCS_getOutputLength(inputLength,
++                                                           alpha01) {
++      return inputLength * (3 + alpha01);
 +    },
-     setFlatness: function CanvasGraphics_setFlatness(flatness) {
-       // There's no way to control this with canvas, but we can safely ignore.
-       // TODO set flatness?
++    isPassthrough: ColorSpace.prototype.isPassthrough,
++    fillRgb: ColorSpace.prototype.fillRgb,
++    isDefaultDecode: function DeviceGrayCS_isDefaultDecode(decodeMap) {
++      return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
 +    },
-     setGState: function CanvasGraphics_setGState(states) {
-       for (var i = 0, ii = states.length; i < ii; i++) {
-         var state = states[i];
-         var key = state[0];
-         var value = state[1];
++    usesZeroToOneRange: true
++  };
++  return DeviceGrayCS;
++})();
 +
-         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':
-             this.setRenderingIntent(value);
-             break;
-           case 'FL':
-             this.setFlatness(value);
-             break;
-           case 'Font':
-             this.setFont(state[1], state[2]);
-             break;
-           case 'CA':
-             this.current.strokeAlpha = state[1];
-             break;
-           case 'ca':
-             this.current.fillAlpha = state[1];
-             this.ctx.globalAlpha = state[1];
-             break;
-           case 'BM':
-             if (value && value.name && (value.name !== 'Normal')) {
-               var mode = value.name.replace(/([A-Z])/g,
-                 function(c) {
-                   return '-' + c.toLowerCase();
-                 }
-               ).substring(1);
-               this.ctx.globalCompositeOperation = mode;
-               if (this.ctx.globalCompositeOperation !== mode) {
-                 warn('globalCompositeOperation "' + mode +
-                      '" is not supported');
-               }
-             } else {
-               this.ctx.globalCompositeOperation = 'source-over';
-             }
-             break;
-         }
-       }
-     },
-     save: function CanvasGraphics_save() {
-       this.ctx.save();
-       var old = this.current;
-       this.stateStack.push(old);
-       this.current = old.clone();
++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;
 +    },
-     restore: function CanvasGraphics_restore() {
-       if ('textClipLayers' in this) {
-         this.completeTextClipping();
++    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 prev = this.stateStack.pop();
-       if (prev) {
-         this.current = prev;
-         this.ctx.restore();
++      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;
 +      }
 +    },
-     transform: function CanvasGraphics_transform(a, b, c, d, e, f) {
-       this.ctx.transform(a, b, c, d, e, f);
++    getOutputLength: function DeviceRgbCS_getOutputLength(inputLength,
++                                                          alpha01) {
++      return (inputLength * (3 + alpha01) / 3) | 0;
 +    },
- 
-     // 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) {
-       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);
-     },
-     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)
-         ctx.lineWidth = this.getSinglePixelWidth();
-       // For stroke we want to temporarily change the global alpha to the
-       // stroking alpha.
-       ctx.globalAlpha = this.current.strokeAlpha;
-       if (strokeColor && strokeColor.hasOwnProperty('type') &&
-           strokeColor.type === 'Pattern') {
-         // for patterns, we transform to pattern space, calculate
-         // the pattern, call stroke, and restore to user space
-         ctx.save();
-         ctx.strokeStyle = strokeColor.getPattern(ctx);
-         ctx.stroke();
-         ctx.restore();
-       } else {
-         ctx.stroke();
-       }
-       if (consumePath)
-         this.consumePath();
-       // Restore the global alpha to the fill alpha
-       ctx.globalAlpha = this.current.fillAlpha;
-     },
-     closeStroke: function CanvasGraphics_closeStroke() {
-       this.closePath();
-       this.stroke();
-     },
-     fill: function CanvasGraphics_fill(consumePath) {
-       consumePath = typeof consumePath !== 'undefined' ? consumePath : true;
-       var ctx = this.ctx;
-       var fillColor = this.current.fillColor;
- 
-       if (fillColor && fillColor.hasOwnProperty('type') &&
-           fillColor.type === 'Pattern') {
-         ctx.save();
-         ctx.fillStyle = fillColor.getPattern(ctx);
-         ctx.fill();
-         ctx.restore();
-       } else {
-         ctx.fill();
-       }
-       if (consumePath)
-         this.consumePath();
++    isPassthrough: function DeviceRgbCS_isPassthrough(bits) {
++      return bits == 8;
 +    },
-     eoFill: function CanvasGraphics_eoFill() {
-       var savedFillRule = this.setEOFillRule();
-       this.fill();
-       this.restoreFillRule(savedFillRule);
++    fillRgb: ColorSpace.prototype.fillRgb,
++    isDefaultDecode: function DeviceRgbCS_isDefaultDecode(decodeMap) {
++      return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
 +    },
-     fillStroke: function CanvasGraphics_fillStroke() {
-       this.fill(false);
-       this.stroke(false);
++    usesZeroToOneRange: true
++  };
++  return DeviceRgbCS;
++})();
 +
-       this.consumePath();
-     },
-     eoFillStroke: function CanvasGraphics_eoFillStroke() {
-       var savedFillRule = this.setEOFillRule();
-       this.fillStroke();
-       this.restoreFillRule(savedFillRule);
-     },
-     closeFillStroke: function CanvasGraphics_closeFillStroke() {
-       this.closePath();
-       this.fillStroke();
-     },
-     closeEOFillStroke: function CanvasGraphics_closeEOFillStroke() {
-       var savedFillRule = this.setEOFillRule();
-       this.closePath();
-       this.fillStroke();
-       this.restoreFillRule(savedFillRule);
-     },
-     endPath: function CanvasGraphics_endPath() {
-       this.consumePath();
-     },
++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;
++  }
 +
-     // Clipping
-     clip: function CanvasGraphics_clip() {
-       this.pendingClip = NORMAL_CLIP;
-     },
-     eoClip: function CanvasGraphics_eoClip() {
-       this.pendingClip = EO_CLIP;
++  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);
 +    },
- 
-     // Text
-     beginText: function CanvasGraphics_beginText() {
-       this.current.textMatrix = IDENTITY_MATRIX;
-       this.current.x = this.current.lineX = 0;
-       this.current.y = this.current.lineY = 0;
-     },
-     endText: function CanvasGraphics_endText() {
-       if ('textClipLayers' in this) {
-         this.swapImageForTextClipping();
-       }
-     },
-     getCurrentTextClipping: function CanvasGraphics_getCurrentTextClipping() {
-       var ctx = this.ctx;
-       var transform = ctx.mozCurrentTransform;
-       if ('textClipLayers' in this) {
-         // we need to reset only font and transform
-         var maskCtx = this.textClipLayers.maskCtx;
-         maskCtx.setTransform.apply(maskCtx, transform);
-         maskCtx.font = ctx.font;
-         return maskCtx;
-       }
- 
-       var canvasWidth = ctx.canvas.width;
-       var canvasHeight = ctx.canvas.height;
-       // keeping track of the text clipping of the separate canvas
-       var maskCanvas = createScratchCanvas(canvasWidth, canvasHeight);
-       var maskCtx = maskCanvas.getContext('2d');
-       maskCtx.setTransform.apply(maskCtx, transform);
-       maskCtx.font = ctx.font;
-       var textClipLayers = {
-         maskCanvas: maskCanvas,
-         maskCtx: maskCtx
-       };
-       this.textClipLayers = textClipLayers;
-       return maskCtx;
-     },
-     swapImageForTextClipping:
-       function CanvasGraphics_swapImageForTextClipping() {
-       var ctx = this.ctx;
-       var canvasWidth = ctx.canvas.width;
-       var canvasHeight = ctx.canvas.height;
-       // saving current image content and clearing whole canvas
-       ctx.save();
-       ctx.setTransform(1, 0, 0, 1, 0, 0);
-       var data = ctx.getImageData(0, 0, canvasWidth, canvasHeight);
-       this.textClipLayers.imageData = data;
-       ctx.clearRect(0, 0, canvasWidth, canvasHeight);
-       ctx.restore();
-     },
-     completeTextClipping: function CanvasGraphics_completeTextClipping() {
-       var ctx = this.ctx;
-       // applying mask to the image (result is saved in maskCanvas)
-       var maskCtx = this.textClipLayers.maskCtx;
-       maskCtx.setTransform(1, 0, 0, 1, 0, 0);
-       maskCtx.globalCompositeOperation = 'source-in';
-       maskCtx.drawImage(ctx.canvas, 0, 0);
- 
-       // restoring image data and applying the result of masked drawing
-       ctx.save();
-       ctx.setTransform(1, 0, 0, 1, 0, 0);
-       ctx.putImageData(this.textClipLayers.imageData, 0, 0);
-       ctx.drawImage(this.textClipLayers.maskCanvas, 0, 0);
-       ctx.restore();
- 
-       delete this.textClipLayers;
-     },
-     setCharSpacing: function CanvasGraphics_setCharSpacing(spacing) {
-       this.current.charSpacing = spacing;
-     },
-     setWordSpacing: function CanvasGraphics_setWordSpacing(spacing) {
-       this.current.wordSpacing = spacing;
-     },
-     setHScale: function CanvasGraphics_setHScale(scale) {
-       this.current.textHScale = scale / 100;
-     },
-     setLeading: function CanvasGraphics_setLeading(leading) {
-       this.current.leading = -leading;
-     },
-     setFont: function CanvasGraphics_setFont(fontRefName, size) {
-       var fontObj = this.commonObjs.get(fontRefName);
-       var current = this.current;
- 
-       if (!fontObj)
-         error('Can\'t find font for ' + fontRefName);
- 
-       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.
-       if (current.fontMatrix[0] === 0 ||
-           current.fontMatrix[3] === 0) {
-         warn('Invalid font matrix for font ' + fontRefName);
-       }
- 
-       // The spec for Tf (setFont) says that 'size' specifies the font 'scale',
-       // and in some docs this can be negative (inverted x-y axes).
-       if (size < 0) {
-         size = -size;
-         current.fontDirection = -1;
-       } else {
-         current.fontDirection = 1;
++    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;
 +      }
- 
-       this.current.font = fontObj;
-       this.current.fontSize = size;
- 
-       if (fontObj.coded)
-         return; // we don't need ctx.font for Type3 fonts
- 
-       var name = fontObj.loadedName || 'sans-serif';
-       var bold = fontObj.black ? (fontObj.bold ? 'bolder' : 'bold') :
-                                  (fontObj.bold ? 'bold' : 'normal');
- 
-       var italic = fontObj.italic ? 'italic' : 'normal';
-       var typeface = '"' + name + '", ' + fontObj.fallbackName;
- 
-       // Some font backends cannot handle fonts below certain size.
-       // Keeping the font at minimal size and using the fontSizeScale to change
-       // 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 :
-                                    size / MIN_FONT_SIZE;
- 
-       var rule = italic + ' ' + bold + ' ' + browserFontSize + 'px ' + typeface;
-       this.ctx.font = rule;
-     },
-     setTextRenderingMode: function CanvasGraphics_setTextRenderingMode(mode) {
-       this.current.textRenderingMode = mode;
-     },
-     setTextRise: function CanvasGraphics_setTextRise(rise) {
-       this.current.textRise = rise;
-     },
-     moveText: function CanvasGraphics_moveText(x, y) {
-       this.current.x = this.current.lineX += x;
-       this.current.y = this.current.lineY += y;
-     },
-     setLeadingMoveText: function CanvasGraphics_setLeadingMoveText(x, y) {
-       this.setLeading(-y);
-       this.moveText(x, y);
 +    },
-     setTextMatrix: function CanvasGraphics_setTextMatrix(a, b, c, d, e, f) {
-       this.current.textMatrix = [a, b, c, d, e, f];
- 
-       this.current.x = this.current.lineX = 0;
-       this.current.y = this.current.lineY = 0;
++    getOutputLength: function DeviceCmykCS_getOutputLength(inputLength,
++                                                           alpha01) {
++      return (inputLength / 4 * (3 + alpha01)) | 0;
 +    },
-     nextLine: function CanvasGraphics_nextLine() {
-       this.moveText(0, this.current.leading);
++    isPassthrough: ColorSpace.prototype.isPassthrough,
++    fillRgb: ColorSpace.prototype.fillRgb,
++    isDefaultDecode: function DeviceCmykCS_isDefaultDecode(decodeMap) {
++      return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
 +    },
-     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;
-       if (ctxMatrix) {
-         var bl = Util.applyTransform([0, 0], ctxMatrix);
-         var tr = Util.applyTransform([1, 1], ctxMatrix);
-         geometry.x = bl[0];
-         geometry.y = bl[1];
-         geometry.hScale = tr[0] - bl[0];
-         geometry.vScale = tr[1] - bl[1];
-       }
-       geometry.spaceWidth = font.spaceWidth;
-       geometry.fontName = font.loadedName;
-       geometry.fontFamily = font.fallbackName;
-       geometry.fontSize = this.current.fontSize;
-       return geometry;
-     },
- 
-     showText: function CanvasGraphics_showText(str, skipTextSelection) {
-       var ctx = this.ctx;
-       var current = this.current;
-       var font = current.font;
-       var glyphs = font.charsToGlyphs(str);
-       var fontSize = current.fontSize;
-       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 glyphsLength = glyphs.length;
-       var textLayer = this.textLayer;
-       var geom;
-       var textSelection = textLayer && !skipTextSelection ? true : false;
-       var textRenderingMode = current.textRenderingMode;
-       var canvasWidth = 0.0;
-       var vertical = font.vertical;
-       var defaultVMetrics = font.defaultVMetrics;
- 
-       // 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);
- 
-         ctx.scale(textHScale, 1);
- 
-         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.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();
-       } else {
-         ctx.save();
-         this.applyTextTransforms();
- 
-         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;
- 
-         if (textSelection)
-           geom = this.createTextGeometry();
++    usesZeroToOneRange: true
++  };
 +
-         if (fontSizeScale != 1.0) {
-           ctx.scale(fontSizeScale, fontSizeScale);
-           lineWidth /= fontSizeScale;
-         }
++  return DeviceCmykCS;
++})();
 +
-         ctx.lineWidth = lineWidth;
++//
++// 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]);
 +
-         var x = 0;
-         for (var i = 0; i < glyphsLength; ++i) {
-           var glyph = glyphs[i];
-           if (glyph === null) {
-             // word break
-             x += current.fontDirection * wordSpacing;
-             continue;
-           }
++    if (!whitePoint) {
++      error('WhitePoint missing - required for color space CalGray');
++    }
++    blackPoint = blackPoint || [0, 0, 0];
++    gamma = gamma || 1;
 +
-           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;
++    // Translate arguments to spec variables.
++    this.XW = whitePoint[0];
++    this.YW = whitePoint[1];
++    this.ZW = whitePoint[2];
 +
-           var scaledX, scaledY, scaledAccentX, scaledAccentY;
-           if (!glyph.disabled) {
-             if (vertical) {
-               scaledX = vx / fontSizeScale;
-               scaledY = (x + vy) / fontSizeScale;
-             } else {
-               scaledX = x / fontSizeScale;
-               scaledY = 0;
-             }
-             if (accent) {
-               scaledAccentX = scaledX + accent.offset.x / fontSizeScale;
-               scaledAccentY = scaledY - accent.offset.y / fontSizeScale;
-             }
-             switch (textRenderingMode) {
-               default: // other unsupported rendering modes
-               case TextRenderingMode.FILL:
-               case TextRenderingMode.FILL_ADD_TO_PATH:
-                 ctx.fillText(character, scaledX, scaledY);
-                 if (accent) {
-                   ctx.fillText(accent.fontChar, scaledAccentX, scaledAccentY);
-                 }
-                 break;
-               case TextRenderingMode.STROKE:
-               case TextRenderingMode.STROKE_ADD_TO_PATH:
-                 ctx.strokeText(character, scaledX, scaledY);
-                 if (accent) {
-                   ctx.strokeText(accent.fontChar, scaledAccentX, scaledAccentY);
-                 }
-                 break;
-               case TextRenderingMode.FILL_STROKE:
-               case TextRenderingMode.FILL_STROKE_ADD_TO_PATH:
-                 ctx.fillText(character, scaledX, scaledY);
-                 ctx.strokeText(character, scaledX, scaledY);
-                 if (accent) {
-                   ctx.fillText(accent.fontChar, scaledAccentX, scaledAccentY);
-                   ctx.strokeText(accent.fontChar, scaledAccentX, scaledAccentY);
-                 }
-                 break;
-               case TextRenderingMode.INVISIBLE:
-               case TextRenderingMode.ADD_TO_PATH:
-                 break;
-             }
-             if (textRenderingMode & TextRenderingMode.ADD_TO_PATH_FLAG) {
-               var clipCtx = this.getCurrentTextClipping();
-               clipCtx.fillText(character, scaledX, scaledY);
-               if (accent) {
-                 clipCtx.fillText(accent.fontChar, scaledAccentX, scaledAccentY);
-               }
-             }
-           }
++    this.XB = blackPoint[0];
++    this.YB = blackPoint[1];
++    this.ZB = blackPoint[2];
 +
-           x += charWidth;
++    this.G = gamma;
 +
-           canvasWidth += charWidth;
-         }
-         if (vertical) {
-           current.y -= x * textHScale;
-         } else {
-           current.x += x * textHScale;
-         }
-         ctx.restore();
-       }
- 
-       if (textSelection) {
-         geom.canvasWidth = canvasWidth;
-         if (vertical) {
-           var vmetric = font.defaultVMetrics;
-           geom.x += vmetric[1] * fontSize * current.fontMatrix[0] /
-                     fontSizeScale * geom.hScale;
-           geom.y += vmetric[2] * fontSize * current.fontMatrix[0] /
-                     fontSizeScale * geom.vScale;
-         }
-         this.textLayer.appendText(geom);
-       }
- 
-       return canvasWidth;
-     },
-     showSpacedText: function CanvasGraphics_showSpacedText(arr) {
-       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;
- 
-       if (textSelection) {
-         ctx.save();
-         this.applyTextTransforms();
-         geom = this.createTextGeometry();
-         ctx.restore();
-       }
- 
-       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;
-           }
++    // 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 (textSelection)
-             spacingAccumulator += spacingLength;
-         } else if (isString(e)) {
-           var shownCanvasWidth = this.showText(e, true);
++    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 (textSelection) {
-             canvasWidth += spacingAccumulator + shownCanvasWidth;
-             spacingAccumulator = 0;
-           }
-         } else {
-           error('TJ array element ' + e + ' is not string or num');
-         }
-       }
++    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 (textSelection) {
-         geom.canvasWidth = canvasWidth;
-         if (vertical) {
-           var fontSizeScale = current.fontSizeScale;
-           var vmetric = font.defaultVMetrics;
-           geom.x += vmetric[1] * fontSize * current.fontMatrix[0] /
-                     fontSizeScale * geom.hScale;
-           geom.y += vmetric[2] * fontSize * current.fontMatrix[0] /
-                     fontSizeScale * geom.vScale;
-         }
-         this.textLayer.appendText(geom);
-       }
-     },
-     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);
-     },
++    if (this.G < 1) {
++      info('Invalid Gamma: ' + this.G + ' for ' + this.name +
++           ', falling back to default');
++      this.G = 1;
++    }
++  }
 +
-     // Type3 fonts
-     setCharWidth: function CanvasGraphics_setCharWidth(xWidth, yWidth) {
-       // We can safely ignore this since the width should be the same
-       // as the width in the Widths array.
-     },
-     setCharWidthAndBounds: function CanvasGraphics_setCharWidthAndBounds(xWidth,
-                                                                         yWidth,
-                                                                         llx,
-                                                                         lly,
-                                                                         urx,
-                                                                         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.clip();
-       this.endPath();
-     },
++  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;
++  }
 +
-     // 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);
-       } else if (IR[0] == 'RadialAxial' || IR[0] == 'Dummy') {
-         var pattern = Pattern.shadingFromIR(IR);
-       } else {
-         error('Unkown IR type ' + IR[0]);
-       }
-       return pattern;
++  CalGrayCS.prototype = {
++    getRgb: ColorSpace.prototype.getRgb,
++    getRgbItem: function CalGrayCS_getRgbItem(src, srcOffset,
++                                              dest, destOffset) {
++      convertToRgb(this, src, srcOffset, dest, destOffset, 1);
 +    },
-     setStrokeColorN: function CanvasGraphics_setStrokeColorN(/*...*/) {
-       var cs = this.current.strokeColorSpace;
++    getRgbBuffer: function CalGrayCS_getRgbBuffer(src, srcOffset, count,
++                                                  dest, destOffset, bits,
++                                                  alpha01) {
++      var scale = 1 / ((1 << bits) - 1);
 +
-       if (cs.name == 'Pattern') {
-         this.current.strokeColor = this.getColorN_Pattern(arguments, cs);
-       } else {
-         this.setStrokeColor.apply(this, arguments);
++      for (var i = 0; i < count; ++i) {
++        convertToRgb(this, src, srcOffset, dest, destOffset, scale);
++        srcOffset += 1;
++        destOffset += 3 + alpha01;
 +      }
 +    },
-     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;
++    getOutputLength: function CalGrayCS_getOutputLength(inputLength, alpha01) {
++      return inputLength * (3 + alpha01);
 +    },
-     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);
-       }
++    isPassthrough: ColorSpace.prototype.isPassthrough,
++    fillRgb: ColorSpace.prototype.fillRgb,
++    isDefaultDecode: function CalGrayCS_isDefaultDecode(decodeMap) {
++      return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
 +    },
-     setStrokeGray: function CanvasGraphics_setStrokeGray(gray) {
-       if (!(this.current.strokeColorSpace instanceof DeviceGrayCS))
-         this.current.strokeColorSpace = new DeviceGrayCS();
++    usesZeroToOneRange: true
++  };
++  return CalGrayCS;
++})();
 +
-       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) {
-       if (!(this.current.fillColorSpace instanceof DeviceGrayCS))
-         this.current.fillColorSpace = new DeviceGrayCS();
++//
++// 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]);
 +
-       var rgbColor = this.current.fillColorSpace.getRgb(arguments, 0);
-       var color = Util.makeCssRgb(rgbColor);
-       this.ctx.fillStyle = color;
-       this.current.fillColor = color;
-     },
-     setStrokeRGBColor: function CanvasGraphics_setStrokeRGBColor(r, g, b) {
-       if (!(this.current.strokeColorSpace instanceof DeviceRgbCS))
-         this.current.strokeColorSpace = new DeviceRgbCS();
++    if (!whitePoint) {
++      error('WhitePoint missing - required for color space Lab');
++    }
++    blackPoint = blackPoint || [0, 0, 0];
++    range = range || [-100, 100, -100, 100];
 +
-       var rgbColor = this.current.strokeColorSpace.getRgb(arguments, 0);
-       var color = Util.makeCssRgb(rgbColor);
-       this.ctx.strokeStyle = color;
-       this.current.strokeColor = color;
-     },
-     setFillRGBColor: function CanvasGraphics_setFillRGBColor(r, g, b) {
-       if (!(this.current.fillColorSpace instanceof DeviceRgbCS))
-         this.current.fillColorSpace = new DeviceRgbCS();
++    // 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];
 +
-       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) {
-       if (!(this.current.strokeColorSpace instanceof DeviceCmykCS))
-         this.current.strokeColorSpace = new DeviceCmykCS();
++    // 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];
 +
-       var color = Util.makeCssCmyk(arguments);
-       this.ctx.strokeStyle = color;
-       this.current.strokeColor = color;
-     },
-     setFillCMYKColor: function CanvasGraphics_setFillCMYKColor(c, m, y, k) {
-       if (!(this.current.fillColorSpace instanceof DeviceCmykCS))
-         this.current.fillColorSpace = new DeviceCmykCS();
++    // Validate vars as per spec
++    if (this.XW < 0 || this.ZW < 0 || this.YW !== 1) {
++      error('Invalid WhitePoint components, no fallback available');
++    }
 +
-       var color = Util.makeCssCmyk(arguments);
-       this.ctx.fillStyle = color;
-       this.current.fillColor = color;
-     },
++    if (this.XB < 0 || this.YB < 0 || this.ZB < 0) {
++      info('Invalid BlackPoint, falling back to default');
++      this.XB = this.YB = this.ZB = 0;
++    }
 +
-     shadingFill: function CanvasGraphics_shadingFill(patternIR) {
-       var ctx = this.ctx;
++    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;
++    }
++  }
 +
-       this.save();
-       var pattern = Pattern.shadingFromIR(patternIR);
-       ctx.fillStyle = pattern.getPattern(ctx);
++  // Function g(x) from spec
++  function fn_g(x) {
++    if (x >= 6 / 29) {
++      return x * x * x;
++    } else {
++      return (108 / 841) * (x - 4 / 29);
++    }
++  }
 +
-       var inv = ctx.mozCurrentTransformInverse;
-       if (inv) {
-         var canvas = ctx.canvas;
-         var width = canvas.width;
-         var height = canvas.height;
++  function decode(value, high1, low2, high2) {
++    return low2 + (value) * (high2 - low2) / (high1);
++  }
 +
-         var bl = Util.applyTransform([0, 0], inv);
-         var br = Util.applyTransform([0, height], inv);
-         var ul = Util.applyTransform([width, 0], inv);
-         var ur = Util.applyTransform([width, height], inv);
++  // 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);
++    }
 +
-         var x0 = Math.min(bl[0], br[0], ul[0], ur[0]);
-         var y0 = Math.min(bl[1], br[1], ul[1], ur[1]);
-         var x1 = Math.max(bl[0], br[0], ul[0], ur[0]);
-         var y1 = Math.max(bl[1], br[1], ul[1], ur[1]);
++    // 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;
 +
-         this.ctx.fillRect(x0, y0, x1 - x0, y1 - y0);
-       } else {
-         // HACK to draw the gradient onto an infinite rectangle.
-         // PDF gradients are drawn across the entire image while
-         // Canvas only allows gradients to be drawn in a rectangle
-         // The following bug should allow us to remove this.
-         // https://bugzilla.mozilla.org/show_bug.cgi?id=664884
++    // Computes intermediate variables X,Y,Z as per spec
++    var M = (Ls + 16) / 116;
++    var L = M + (as / 500);
++    var N = M - (bs / 200);
 +
-         this.ctx.fillRect(-1e10, -1e10, 2e10, 2e10);
-       }
++    var X = cs.XW * fn_g(L);
++    var Y = cs.YW * fn_g(M);
++    var Z = cs.ZW * fn_g(N);
 +
-       this.restore();
-     },
++    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;
++  }
 +
-     // Images
-     beginInlineImage: function CanvasGraphics_beginInlineImage() {
-       error('Should not call beginInlineImage');
-     },
-     beginImageData: function CanvasGraphics_beginImageData() {
-       error('Should not call beginImageData');
++  LabCS.prototype = {
++    getRgb: ColorSpace.prototype.getRgb,
++    getRgbItem: function LabCS_getRgbItem(src, srcOffset, dest, destOffset) {
++      convertToRgb(this, src, srcOffset, false, dest, destOffset);
 +    },
- 
-     paintFormXObjectBegin: function CanvasGraphics_paintFormXObjectBegin(matrix,
-                                                                         bbox) {
-       this.save();
-       this.current.paintFormXObjectDepth++;
- 
-       if (matrix && isArray(matrix) && 6 == matrix.length)
-         this.transform.apply(this, matrix);
- 
-       if (bbox && 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.clip();
-         this.endPath();
++    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;
 +      }
 +    },
- 
-     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);
-     },
- 
-     beginGroup: function CanvasGraphics_beginGroup(group) {
-       this.save();
-       var currentCtx = this.ctx;
-       // TODO non-isolated groups - according to Rik at adobe non-isolated
-       // group results aren't usually that different and they even have tools
-       // that ignore this setting. Notes from Rik on implmenting:
-       // - When you encounter an transparency group, create a new canvas with
-       // the dimensions of the bbox
-       // - copy the content from the previous canvas to the new canvas
-       // - draw as usual
-       // - remove the backdrop alpha:
-       // alphaNew = 1 - (1 - alpha)/(1 - alphaBackdrop) with 'alpha' the alpha
-       // value of your transparency group and 'alphaBackdrop' the alpha of the
-       // backdrop
-       // - remove background color:
-       // colorNew = color - alphaNew *colorBackdrop /(1 - alphaNew)
-       if (!group.isolated) {
-         TODO('Support non-isolated groups.');
-       }
- 
-       // TODO knockout - supposedly possible with the clever use of compositing
-       // modes.
-       if (group.knockout) {
-         TODO('Support knockout groups.');
-       }
- 
-       var currentTransform = currentCtx.mozCurrentTransform;
-       if (group.matrix) {
-         currentCtx.transform.apply(currentCtx, group.matrix);
-       }
-       assert(group.bbox, 'Bounding box is required.');
- 
-       // Based on the current transform figure out how big the bounding box
-       // will actually be.
-       var bounds = Util.getAxialAlignedBoundingBox(
-                     group.bbox,
-                     currentCtx.mozCurrentTransform);
-       // Use ceil in case we're between sizes so we don't create canvas that is
-       // too small.
-       var drawnWidth = Math.ceil(bounds[2] - bounds[0]);
-       var drawnHeight = Math.ceil(bounds[3] - bounds[1]);
-       var scratchCanvas = createScratchCanvas(drawnWidth, drawnHeight);
-       var groupCtx = scratchCanvas.getContext('2d');
-       addContextCurrentTransform(groupCtx);
-       // 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.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);
- 
-       // 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]
-       ]);
-       this.groupStack.push(currentCtx);
++    getOutputLength: function LabCS_getOutputLength(inputLength, alpha01) {
++      return (inputLength * (3 + alpha01) / 3) | 0;
 +    },
- 
-     endGroup: function CanvasGraphics_endGroup(group) {
-       var groupCtx = this.ctx;
-       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) {
-         this.ctx.imageSmoothingEnabled = false;
-       } else {
-         this.ctx.mozImageSmoothingEnabled = false;
-       }
-       this.ctx.drawImage(groupCtx.canvas, 0, 0);
-       this.restore();
++    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;
++})();
 +
-     paintJpegXObject: function CanvasGraphics_paintJpegXObject(objId, w, h) {
-       var domImage = this.objs.get(objId);
-       if (!domImage) {
-         error('Dependent image isn\'t ready yet');
-       }
 +
-       this.save();
 +
-       var ctx = this.ctx;
-       // scale the image to the unit square
-       ctx.scale(1 / w, -1 / h);
++var PDFFunction = (function PDFFunctionClosure() {
++  var CONSTRUCT_SAMPLED = 0;
++  var CONSTRUCT_INTERPOLATED = 2;
++  var CONSTRUCT_STICHED = 3;
++  var CONSTRUCT_POSTSCRIPT = 4;
 +
-       ctx.drawImage(domImage, 0, 0, domImage.width, domImage.height,
-                     0, -h, w, h);
-       if (this.imageLayer) {
-         var currentTransform = ctx.mozCurrentTransformInverse;
-         var position = this.getCanvasPosition(0, 0);
-         this.imageLayer.appendImage({
-           objId: objId,
-           left: position[0],
-           top: position[1],
-           width: w / currentTransform[0],
-           height: h / currentTransform[3]
-         });
++  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];
 +      }
-       this.restore();
-     },
- 
-     paintImageMaskXObject: function CanvasGraphics_paintImageMaskXObject(
-                              imgArray, inverseDecode, width, height) {
-       var ctx = this.ctx;
-       var tmpCanvas = createScratchCanvas(width, height);
-       var tmpCtx = tmpCanvas.getContext('2d');
++      length *= outputSize;
 +
-       var fillColor = this.current.fillColor;
-       tmpCtx.fillStyle = (fillColor && fillColor.hasOwnProperty('type') &&
-                           fillColor.type === 'Pattern') ?
-                           fillColor.getPattern(tmpCtx) : fillColor;
-       tmpCtx.fillRect(0, 0, width, height);
++      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 imgData = tmpCtx.getImageData(0, 0, width, height);
-       var pixels = imgData.data;
++      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;
++    },
 +
-       applyStencilMask(imgArray, width, height, inverseDecode, pixels);
++    getIR: function PDFFunction_getIR(xref, fn) {
++      var dict = fn.dict;
++      if (!dict) {
++        dict = fn;
++      }
 +
-       this.paintInlineImageXObject(imgData);
-     },
++      var types = [this.constructSampled,
++                   null,
++                   this.constructInterpolated,
++                   this.constructStiched,
++                   this.constructPostScript];
 +
-     paintImageMaskXObjectGroup:
-       function CanvasGraphics_paintImageMaskXObjectGroup(images) {
-       var ctx = this.ctx;
-       var tmpCanvasWidth = 0, tmpCanvasHeight = 0, tmpCanvas, tmpCtx;
-       for (var i = 0, ii = images.length; i < ii; i++) {
-         var image = images[i];
-         var w = image.width, h = image.height;
-         if (w > tmpCanvasWidth || h > tmpCanvasHeight) {
-           tmpCanvasWidth = Math.max(w, tmpCanvasWidth);
-           tmpCanvasHeight = Math.max(h, tmpCanvasHeight);
-           tmpCanvas = createScratchCanvas(tmpCanvasWidth, tmpCanvasHeight);
-           tmpCtx = tmpCanvas.getContext('2d');
++      var typeNum = dict.get('FunctionType');
++      var typeFn = types[typeNum];
++      if (!typeFn) {
++        error('Unknown type of function');
++      }
 +
-           var fillColor = this.current.fillColor;
-           tmpCtx.fillStyle = (fillColor && fillColor.hasOwnProperty('type') &&
-                               fillColor.type === 'Pattern') ?
-                               fillColor.getPattern(tmpCtx) : fillColor;
-         }
-         tmpCtx.fillRect(0, 0, w, h);
++      return typeFn.call(this, fn, dict, xref);
++    },
 +
-         var imgData = tmpCtx.getImageData(0, 0, w, h);
-         var pixels = imgData.data;
++    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);
++      }
++    },
 +
-         applyStencilMask(image.data, w, h, image.inverseDecode, pixels);
++    parse: function PDFFunction_parse(xref, fn) {
++      var IR = this.getIR(xref, fn);
++      return this.fromIR(IR);
++    },
 +
-         tmpCtx.putImageData(imgData, 0, 0);
++    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');
 +
-         ctx.save();
-         ctx.transform.apply(ctx, image.transform);
-         ctx.scale(1, -1);
-         ctx.drawImage(tmpCanvas, 0, 0, w, h,
-                       0, -1, 1, 1);
-         ctx.restore();
++      if (!domain || !range) {
++        error('No domain or range');
 +      }
-     },
 +
-     paintImageXObject: function CanvasGraphics_paintImageXObject(objId) {
-       var imgData = this.objs.get(objId);
-       if (!imgData)
-         error('Dependent image isn\'t ready yet');
++      var inputSize = domain.length / 2;
++      var outputSize = range.length / 2;
 +
-       this.paintInlineImageXObject(imgData);
-     },
++      domain = toMultiArray(domain);
++      range = toMultiArray(range);
 +
-     paintInlineImageXObject:
-       function CanvasGraphics_paintInlineImageXObject(imgData) {
-       var width = imgData.width;
-       var height = imgData.height;
-       var ctx = this.ctx;
-       this.save();
-       // scale the image to the unit square
-       ctx.scale(1 / width, -1 / height);
++      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 currentTransform = ctx.mozCurrentTransformInverse;
-       var widthScale = Math.max(Math.abs(currentTransform[0]), 1);
-       var heightScale = Math.max(Math.abs(currentTransform[3]), 1);
-       var tmpCanvas = createScratchCanvas(width, height);
-       var tmpCtx = tmpCanvas.getContext('2d');
++      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);
 +
-       if (widthScale > 2 || heightScale > 2) {
-         // canvas does not resize well large images to small -- using simple
-         // algorithm to perform pre-scaling
-         tmpCanvas = prescaleImage(imgData.data,
-                                  width, height,
-                                  widthScale, heightScale);
-         ctx.drawImage(tmpCanvas, 0, 0, tmpCanvas.width, tmpCanvas.height,
-                                  0, -height, width, height);
++      var decode = dict.get('Decode');
++      if (!decode) {
++        decode = range;
 +      } else {
-         if (typeof ImageData !== 'undefined' && imgData instanceof ImageData) {
-           tmpCtx.putImageData(imgData, 0, 0);
-         } else {
-           putBinaryImageData(tmpCtx, imgData.data, width, height);
-         }
-         ctx.drawImage(tmpCanvas, 0, -height);
++        decode = toMultiArray(decode);
 +      }
 +
-       if (this.imageLayer) {
-         var position = this.getCanvasPosition(0, -height);
-         this.imageLayer.appendImage({
-           imgData: imgData,
-           left: position[0],
-           top: position[1],
-           width: width / currentTransform[0],
-           height: height / currentTransform[3]
-         });
++      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)));
 +      }
-       this.restore();
-     },
- 
-     paintInlineImageXObjectGroup:
-       function CanvasGraphics_paintInlineImageXObjectGroup(imgData, map) {
-       var ctx = this.ctx;
-       var w = imgData.width;
-       var h = imgData.height;
- 
-       var tmpCanvas = createScratchCanvas(w, h);
-       var tmpCtx = tmpCanvas.getContext('2d');
-       putBinaryImageData(tmpCtx, imgData.data, w, h);
- 
-       for (var i = 0, ii = map.length; i < ii; i++) {
-         var entry = map[i];
-         ctx.save();
-         ctx.transform.apply(ctx, entry.transform);
-         ctx.scale(1, -1);
-         ctx.drawImage(tmpCanvas, entry.x, entry.y, entry.w, entry.h,
-                       0, -1, 1, 1);
-         if (this.imageLayer) {
-           var position = this.getCanvasPosition(entry.x, entry.y);
-           this.imageLayer.appendImage({
-             imgData: imgData,
-             left: position[0],
-             top: position[1],
-             width: w,
-             height: h
-           });
++
++      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);
 +        }
-         ctx.restore();
-       }
-     },
 +
-     // Marked content
++        var x = args;
 +
-     markPoint: function CanvasGraphics_markPoint(tag) {
-       // TODO Marked content.
-     },
-     markPointProps: function CanvasGraphics_markPointProps(tag, properties) {
-       // TODO Marked content.
-     },
-     beginMarkedContent: function CanvasGraphics_beginMarkedContent(tag) {
-       // TODO Marked content.
-     },
-     beginMarkedContentProps: function CanvasGraphics_beginMarkedContentProps(
-                                         tag, properties) {
-       // TODO Marked content.
-     },
-     endMarkedContent: function CanvasGraphics_endMarkedContent() {
-       // TODO Marked content.
-     },
++        // 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;
++        }
 +
-     // Compatibility
++        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);
 +
-     beginCompat: function CanvasGraphics_beginCompat() {
-       // TODO ignore undefined operators (should we do that anyway?)
-     },
-     endCompat: function CanvasGraphics_endCompat() {
-       // TODO stop ignoring undefined operators
-     },
++          // 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]);
 +
-     // Helper functions
++          // 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);
 +
-     consumePath: function CanvasGraphics_consumePath() {
-       if (this.pendingClip) {
-         var savedFillRule = null;
-         if (this.pendingClip == EO_CLIP)
-           savedFillRule = this.setEOFillRule();
++          // 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;
++            }
++          }
 +
-         this.ctx.clip();
++          k *= size_i;
++          pos <<= 1;
++        }
 +
-         this.pendingClip = null;
-         if (savedFillRule !== null)
-           this.restoreFillRule(savedFillRule);
-       }
-       this.ctx.beginPath();
-     },
-     // We generally keep the canvas context set for
-     // nonzero-winding, and just set evenodd for the operations
-     // that need them.
-     setEOFillRule: function CanvasGraphics_setEOFillRule() {
-       var savedFillRule = this.ctx.mozFillRule;
-       this.ctx.mozFillRule = 'evenodd';
-       return savedFillRule;
-     },
-     restoreFillRule: function CanvasGraphics_restoreFillRule(rule) {
-       this.ctx.mozFillRule = rule;
-     },
-     getSinglePixelWidth: function CanvasGraphics_getSinglePixelWidth(scale) {
-       var inverse = this.ctx.mozCurrentTransformInverse;
-       // max of the current horizontal and vertical scale
-       return Math.sqrt(Math.max(
-         (inverse[0] * inverse[0] + inverse[1] * inverse[1]),
-         (inverse[2] * inverse[2] + inverse[3] * inverse[3])));
-     },
-     getCanvasPosition: function CanvasGraphics_getCanvasPosition(x, y) {
-         var transform = this.ctx.mozCurrentTransform;
-         return [
-           transform[0] * x + transform[2] * y + transform[4],
-           transform[1] * x + transform[3] * y + transform[5]
-         ];
-     }
-   };
++        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];
++          }
 +
-   return CanvasGraphics;
- })();
++          // 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;
++      };
++    },
 +
- var Name = (function NameClosure() {
-   function Name(name) {
-     this.name = name;
-   }
++    constructInterpolated: function PDFFunction_constructInterpolated(str,
++                                                                      dict) {
++      var c0 = dict.get('C0') || [0];
++      var c1 = dict.get('C1') || [1];
++      var n = dict.get('N');
 +
-   Name.prototype = {};
++      if (!isArray(c0) || !isArray(c1)) {
++        error('Illegal dictionary for interpolated function');
++      }
 +
-   return Name;
- })();
++      var length = c0.length;
++      var diff = [];
++      for (var i = 0; i < length; ++i) {
++        diff.push(c1[i] - c0[i]);
++      }
 +
- var Cmd = (function CmdClosure() {
-   function Cmd(cmd) {
-     this.cmd = cmd;
-   }
++      return [CONSTRUCT_INTERPOLATED, c0, diff, n];
++    },
 +
-   Cmd.prototype = {};
++    constructInterpolatedFromIR:
++      function PDFFunction_constructInterpolatedFromIR(IR) {
++      var c0 = IR[1];
++      var diff = IR[2];
++      var n = IR[3];
 +
-   var cmdCache = {};
++      var length = diff.length;
 +
-   Cmd.get = function Cmd_get(cmd) {
-     var cmdValue = cmdCache[cmd];
-     if (cmdValue)
-       return cmdValue;
++      return function constructInterpolatedFromIRResult(args) {
++        var x = n == 1 ? args[0] : Math.pow(args[0], n);
 +
-     return cmdCache[cmd] = new Cmd(cmd);
-   };
++        var out = [];
++        for (var j = 0; j < length; ++j) {
++          out.push(c0[j] + (x * diff[j]));
++        }
 +
-   return Cmd;
- })();
++        return out;
 +
- var Dict = (function DictClosure() {
-   // xref is optional
-   function Dict(xref) {
-     // Map should only be used internally, use functions below to access.
-     var map = Object.create(null);
++      };
++    },
 +
-     this.assignXref = function Dict_assignXref(newXref) {
-       xref = newXref;
-     };
++    constructStiched: function PDFFunction_constructStiched(fn, dict, xref) {
++      var domain = dict.get('Domain');
 +
-     // automatically dereferences Ref objects
-     this.get = function Dict_get(key1, key2, key3) {
-       var value;
-       if (typeof (value = map[key1]) != 'undefined' || key1 in map ||
-           typeof key2 == 'undefined') {
-         return xref ? xref.fetchIfRef(value) : value;
-       }
-       if (typeof (value = map[key2]) != 'undefined' || key2 in map ||
-           typeof key3 == 'undefined') {
-         return xref ? xref.fetchIfRef(value) : value;
++      if (!domain) {
++        error('No domain');
 +      }
-       value = map[key3] || null;
-       return xref ? xref.fetchIfRef(value) : value;
-     };
 +
-     // no dereferencing
-     this.getRaw = function Dict_getRaw(key) {
-       return map[key];
-     };
++      var inputSize = domain.length / 2;
++      if (inputSize != 1) {
++        error('Bad domain for stiched function');
++      }
 +
-     // creates new map and dereferences all Refs
-     this.getAll = function Dict_getAll() {
-       var all = {};
-       for (var key in map) {
-         var obj = this.get(key);
-         all[key] = obj instanceof Dict ? obj.getAll() : obj;
++      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])));
 +      }
-       return all;
-     };
 +
-     this.set = function Dict_set(key, value) {
-       map[key] = value;
-     };
++      var bounds = dict.get('Bounds');
++      var encode = dict.get('Encode');
 +
-     this.has = function Dict_has(key) {
-       return key in map;
-     };
++      return [CONSTRUCT_STICHED, domain, bounds, encode, fns];
++    },
 +
-     this.forEach = function Dict_forEach(callback) {
-       for (var key in map) {
-         callback(key, this.get(key));
++    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 Dict;
- })();
++      return function constructStichedFromIRResult(args) {
++        var clip = function constructStichedFromIRClip(v, min, max) {
++          if (v > max) {
++            v = max;
++          } else if (v < min) {
++            v = min;
++          }
++          return v;
++        };
 +
- var Ref = (function RefClosure() {
-   function Ref(num, gen) {
-     this.num = num;
-     this.gen = gen;
-   }
++        // 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;
++          }
++        }
 +
-   Ref.prototype = {};
++        // 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];
++        }
 +
-   return Ref;
- })();
++        var rmin = encode[2 * i];
++        var rmax = encode[2 * i + 1];
 +
- // 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 = {};
-   }
++        var v2 = rmin + (v - dmin) * (rmax - rmin) / (dmax - dmin);
 +
-   RefSet.prototype = {
-     has: function RefSet_has(ref) {
-       return !!this.dict['R' + ref.num + '.' + ref.gen];
++        // call the appropriate function
++        return fns[i]([v2]);
++      };
 +    },
 +
-     put: function RefSet_put(ref) {
-       this.dict['R' + ref.num + '.' + ref.gen] = ref;
-     }
-   };
++    constructPostScript: function PDFFunction_constructPostScript(fn, dict,
++                                                                  xref) {
++      var domain = dict.get('Domain');
++      var range = dict.get('Range');
 +
-   return RefSet;
- })();
++      if (!domain) {
++        error('No domain.');
++      }
 +
- var Catalog = (function CatalogClosure() {
-   function Catalog(xref) {
-     this.xref = xref;
-     var obj = xref.getCatalogObj();
-     assertWellFormed(isDict(obj), 'catalog object is not a dictionary');
-     this.catDict = obj;
-   }
++      if (!range) {
++        error('No range.');
++      }
 +
-   Catalog.prototype = {
-     get metadata() {
-       var streamRef = this.catDict.getRaw('Metadata');
-       if (!isRef(streamRef))
-         return shadow(this, 'metadata', null);
++      var lexer = new PostScriptLexer(fn);
++      var parser = new PostScriptParser(lexer);
++      var code = parser.parse();
 +
-       var encryptMetadata = !this.xref.encrypt ? false :
-         this.xref.encrypt.encryptMetadata;
++      return [CONSTRUCT_POSTSCRIPT, domain, range, code];
++    },
 +
-       var stream = this.xref.fetch(streamRef, !encryptMetadata);
-       var metadata;
-       if (stream && isDict(stream.dict)) {
-         var type = stream.dict.get('Type');
-         var subtype = stream.dict.get('Subtype');
++    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]);
++        }
 +
-         if (isName(type) && isName(subtype) &&
-             type.name === 'Metadata' && subtype.name === 'XML') {
-           // XXX: This should examine the charset the XML document defines,
-           // however since there are currently no real means to decode
-           // arbitrary charsets, let's just hope that the author of the PDF
-           // was reasonable enough to stick with the XML default charset,
-           // which is UTF-8.
-           try {
-             metadata = stringToUTF8String(bytesToString(stream.getBytes()));
-           } catch (e) {
-             info('Skipping invalid metadata.');
-           }
++        var key = initialStack.join('_');
++        if (cache.has(key)) {
++          return cache.get(key);
 +        }
-       }
 +
-       return shadow(this, 'metadata', metadata);
-     },
-     get toplevelPagesDict() {
-       var pagesObj = this.catDict.get('Pages');
-       assertWellFormed(isDict(pagesObj), 'invalid top-level pages dictionary');
-       // shadow the prototype getter
-       return shadow(this, 'toplevelPagesDict', pagesObj);
-     },
-     get documentOutline() {
-       var xref = this.xref;
-       var obj = this.catDict.get('Outlines');
-       var root = { items: [] };
-       if (isDict(obj)) {
-         obj = obj.getRaw('First');
-         var processed = new RefSet();
-         if (isRef(obj)) {
-           var queue = [{obj: obj, parent: root}];
-           // to avoid recursion keeping track of the items
-           // in the processed dictionary
-           processed.put(obj);
-           while (queue.length > 0) {
-             var i = queue.shift();
-             var outlineDict = xref.fetchIfRef(i.obj);
-             if (outlineDict === null)
-               continue;
-             if (!outlineDict.has('Title'))
-               error('Invalid outline item');
-             var dest = outlineDict.get('A');
-             if (dest)
-               dest = dest.get('D');
-             else if (outlineDict.has('Dest')) {
-               dest = outlineDict.getRaw('Dest');
-               if (isName(dest))
-                 dest = dest.name;
-             }
-             var title = outlineDict.get('Title');
-             var outlineItem = {
-               dest: dest,
-               title: stringToPDFString(title),
-               color: outlineDict.get('C') || [0, 0, 0],
-               count: outlineDict.get('Count'),
-               bold: !!(outlineDict.get('F') & 2),
-               italic: !!(outlineDict.get('F') & 1),
-               items: []
-             };
-             i.parent.items.push(outlineItem);
-             obj = outlineDict.getRaw('First');
-             if (isRef(obj) && !processed.has(obj)) {
-               queue.push({obj: obj, parent: outlineItem});
-               processed.put(obj);
-             }
-             obj = outlineDict.getRaw('Next');
-             if (isRef(obj) && !processed.has(obj)) {
-               queue.push({obj: obj, parent: i.parent});
-               processed.put(obj);
-             }
++        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;
 +        }
-       }
-       obj = root.items.length > 0 ? root.items : null;
-       return shadow(this, 'documentOutline', obj);
-     },
-     get numPages() {
-       var obj = this.toplevelPagesDict.get('Count');
-       assertWellFormed(
-         isInt(obj),
-         'page count in top level pages object is not an integer'
-       );
-       // shadow the prototype getter
-       return shadow(this, 'num', obj);
++        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;
 +    },
-     traverseKids: function Catalog_traverseKids(pagesDict) {
-       var pageCache = this.pageCache;
-       var kids = pagesDict.get('Kids');
-       assertWellFormed(isArray(kids),
-                        'page dictionary kids object is not an array');
-       for (var i = 0, ii = kids.length; i < ii; ++i) {
-         var kid = kids[i];
-         assertWellFormed(isRef(kid),
-                         'page dictionary kid is not a reference');
-         var obj = this.xref.fetch(kid);
-         if (isDict(obj, 'Page') || (isDict(obj) && !obj.has('Kids'))) {
-           pageCache.push(new Page(this.xref, pageCache.length, obj, kid));
-         } else { // must be a child page dictionary
-           assertWellFormed(
-             isDict(obj),
-             'page dictionary kid reference points to wrong type of object'
-           );
-           this.traverseKids(obj);
-         }
-       }
++    get: function FunctionCache_get(key) {
++      return this.cache[key];
 +    },
-     get destinations() {
-       function fetchDestination(dest) {
-         return isDict(dest) ? dest.get('D') : dest;
++    set: function FunctionCache_set(key, value) {
++      if (this.total < MAX_CACHE_SIZE) {
++        this.cache[key] = value;
++        this.total++;
 +      }
++    }
++  };
++  return FunctionCache;
++})();
 +
-       var xref = this.xref;
-       var dests = {}, nameTreeRef, nameDictionaryRef;
-       var obj = this.catDict.get('Names');
-       if (obj)
-         nameTreeRef = obj.getRaw('Dests');
-       else if (this.catDict.has('Dests'))
-         nameDictionaryRef = this.catDict.get('Dests');
++var PostScriptStack = (function PostScriptStackClosure() {
++  var MAX_STACK_SIZE = 100;
++  function PostScriptStack(initialStack) {
++    this.stack = initialStack || [];
++  }
 +
-       if (nameDictionaryRef) {
-         // reading simple destination dictionary
-         obj = nameDictionaryRef;
-         obj.forEach(function catalogForEach(key, value) {
-           if (!value) return;
-           dests[key] = fetchDestination(value);
-         });
++  PostScriptStack.prototype = {
++    push: function PostScriptStack_push(value) {
++      if (this.stack.length >= MAX_STACK_SIZE) {
++        error('PostScript function stack overflow.');
 +      }
-       if (nameTreeRef) {
-         var nameTree = new NameTree(nameTreeRef, xref);
-         var names = nameTree.getAll();
-         for (var name in names) {
-           if (!names.hasOwnProperty(name)) {
-             continue;
-           }
-           dests[name] = fetchDestination(names[name]);
-         }
++      this.stack.push(value);
++    },
++    pop: function PostScriptStack_pop() {
++      if (this.stack.length <= 0) {
++        error('PostScript function stack underflow.');
 +      }
-       return shadow(this, 'destinations', dests);
++      return this.stack.pop();
 +    },
-     get javaScript() {
-       var xref = this.xref;
-       var obj = this.catDict.get('Names');
- 
-       var javaScript = [];
-       if (obj && obj.has('JavaScript')) {
-         var nameTree = new NameTree(obj.getRaw('JavaScript'), xref);
-         var names = nameTree.getAll();
-         for (var name in names) {
-           if (!names.hasOwnProperty(name)) {
-             continue;
-           }
-           // We don't really use the JavaScript right now so this code is
-           // defensive so we don't cause errors on document load.
-           var jsDict = names[name];
-           if (!isDict(jsDict)) {
-             continue;
-           }
-           var type = jsDict.get('S');
-           if (!isName(type) || type.name !== 'JavaScript') {
-             continue;
-           }
-           var js = jsDict.get('JS');
-           if (!isString(js) && !isStream(js)) {
-             continue;
-           }
-           if (isStream(js)) {
-             js = bytesToString(js.getBytes());
-           }
-           javaScript.push(stringToPDFString(js));
-         }
++    copy: function PostScriptStack_copy(n) {
++      if (this.stack.length + n >= MAX_STACK_SIZE) {
++        error('PostScript function stack overflow.');
 +      }
-       return shadow(this, 'javaScript', javaScript);
++      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]);
 +    },
-     getPage: function Catalog_getPage(n) {
-       var pageCache = this.pageCache;
-       if (!pageCache) {
-         pageCache = this.pageCache = [];
-         this.traverseKids(this.toplevelPagesDict);
++    // 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 this.pageCache[n - 1];
 +    }
 +  };
++  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;
 +
-   return Catalog;
++          // 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 XRef = (function XRefClosure() {
-   function XRef(stream, startXRef, mainXRefEntriesOffset, password) {
-     this.stream = stream;
-     this.entries = [];
-     this.xrefstms = {};
-     var trailerDict = this.readXRef(startXRef);
-     trailerDict.assignXref(this);
-     this.trailer = trailerDict;
-     // prepare the XRef cache
-     this.cache = [];
 +
-     var encrypt = trailerDict.get('Encrypt');
-     if (encrypt) {
-       var ids = trailerDict.get('ID');
-       var fileId = (ids && ids.length) ? ids[0] : '';
-       this.encrypt = new CipherTransformFactory(encrypt, fileId, password);
++var HIGHLIGHT_OFFSET = 4; // 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]];
 +    }
 +
-     // get the root dictionary (catalog) object
-     if (!(this.root = trailerDict.get('Root')))
-       error('Invalid root reference');
++    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
++    ];
 +  }
 +
-   XRef.prototype = {
-     readXRefTable: function XRef_readXRefTable(parser) {
-       // Example of cross-reference table:
-       // xref
-       // 0 1                    <-- subsection header (first obj #, obj count)
-       // 0000000000 65535 f     <-- actual object (offset, generation #, f/n)
-       // 23 2                   <-- subsection header ... and so on ...
-       // 0000025518 00002 n
-       // 0000025635 00000 n
-       // trailer
-       // ...
++  function getDefaultAppearance(dict) {
++    var appearanceState = dict.get('AP');
++    if (!isDict(appearanceState)) {
++      return;
++    }
 +
-       // Outer loop is over subsection headers
-       var obj;
-       while (!isCmd(obj = parser.getObj(), 'trailer')) {
-         var first = obj,
-             count = parser.getObj();
++    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;
++  }
 +
-         if (!isInt(first) || !isInt(count))
-           error('Invalid XRef table: wrong types in subsection header');
++  function Annotation(params) {
++    if (params.data) {
++      this.data = params.data;
++      return;
++    }
 +
-         // Inner loop is over objects themselves
-         for (var i = 0; i < count; i++) {
-           var entry = {};
-           entry.offset = parser.getObj();
-           entry.gen = parser.getObj();
-           var type = parser.getObj();
++    var dict = params.dict;
++    var data = this.data = {};
 +
-           if (isCmd(type, 'f'))
-             entry.free = true;
-           else if (isCmd(type, 'n'))
-             entry.uncompressed = true;
++    data.subtype = dict.get('Subtype').name;
++    var rect = dict.get('Rect');
++    data.rect = Util.normalizeRect(rect);
++    data.annotationFlags = dict.get('F');
 +
-           // Validate entry obj
-           if (!isInt(entry.offset) || !isInt(entry.gen) ||
-               !(entry.free || entry.uncompressed)) {
-             error('Invalid entry in XRef subsection: ' + first + ', ' + count);
-           }
++    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];
++    }
 +
-           if (!this.entries[i + first])
-             this.entries[i + first] = entry;
++    // 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 && isArray(dashArray)) {
++        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++) {
++            if (!(+dashArray[i] >= 0)) {
++              isInvalid = true;
++              break;
++            } else if (dashArray[i] > 0) {
++              numPositive++;
++            }
++          }
++          if (isInvalid || numPositive === 0) {
++            data.borderWidth = 0;
++          }
 +        }
 +      }
++    }
 +
-       // Sanity check: as per spec, first object must be free
-       if (this.entries[0] && !this.entries[0].free)
-         error('Invalid XRef table: unexpected first object');
++    this.appearance = getDefaultAppearance(dict);
++    data.hasAppearance = !!this.appearance;
++  }
 +
-       // Sanity check
-       if (!isCmd(obj, 'trailer'))
-         error('Invalid XRef table: could not find trailer dictionary');
++  Annotation.prototype = {
 +
-       // Read trailer dictionary, e.g.
-       // trailer
-       //    << /Size 22
-       //      /Root 20R
-       //      /Info 10R
-       //      /ID [ <81b14aafa313db63dbd6f981e49f94f4> ]
-       //    >>
-       // 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');
++    getData: function Annotation_getData() {
++      return this.data;
++    },
 +
-       return dict;
++    hasHtml: function Annotation_hasHtml() {
++      return false;
 +    },
-     readXRefStream: function XRef_readXRefStream(stream) {
-       var streamParameters = stream.parameters;
-       var byteWidths = streamParameters.get('W');
-       var range = streamParameters.get('Index');
-       if (!range)
-         range = [0, streamParameters.get('Size')];
-       var i, j;
-       while (range.length > 0) {
-         var first = range[0], n = range[1];
-         if (!isInt(first) || !isInt(n))
-           error('Invalid XRef range fields: ' + first + ', ' + n);
-         var typeFieldWidth = byteWidths[0];
-         var offsetFieldWidth = byteWidths[1];
-         var generationFieldWidth = byteWidths[2];
-         if (!isInt(typeFieldWidth) || !isInt(offsetFieldWidth) ||
-             !isInt(generationFieldWidth)) {
-           error('Invalid XRef entry fields length: ' + first + ', ' + n);
-         }
-         for (i = 0; i < n; ++i) {
-           var type = 0, offset = 0, generation = 0;
-           for (j = 0; j < typeFieldWidth; ++j)
-             type = (type << 8) | stream.getByte();
-           // if type field is absent, its default value = 1
-           if (typeFieldWidth === 0)
-             type = 1;
-           for (j = 0; j < offsetFieldWidth; ++j)
-             offset = (offset << 8) | stream.getByte();
-           for (j = 0; j < generationFieldWidth; ++j)
-             generation = (generation << 8) | stream.getByte();
-           var entry = {};
-           entry.offset = offset;
-           entry.gen = generation;
-           switch (type) {
-             case 0:
-               entry.free = true;
-               break;
-             case 1:
-               entry.uncompressed = true;
-               break;
-             case 2:
-               break;
-             default:
-               error('Invalid XRef entry type: ' + type);
-           }
-           if (!this.entries[first + i])
-             this.entries[first + i] = entry;
-         }
-         range.splice(0, 2);
-       }
-       return streamParameters;
++
++    getHtmlElement: function Annotation_getHtmlElement(commonObjs) {
++      throw new NotImplementedException(
++        'getHtmlElement() should be implemented in subclass');
 +    },
-     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)
-             break;
-           token += String.fromCharCode(ch);
-           ch = data[offset];
-         }
-         return token;
-       }
-       function skipUntil(data, offset, what) {
-         var length = what.length, dataLength = data.length;
-         var skipped = 0;
-         // finding byte sequence
-         while (offset < dataLength) {
-           var i = 0;
-           while (i < length && data[offset + i] == what[i])
-             ++i;
-           if (i >= length)
-             break; // sequence found
 +
-           offset++;
-           skipped++;
-         }
-         return skipped;
++    // TODO(mack): Remove this, it's not really that helpful.
++    getEmptyContainer: function Annotation_getEmptyContainer(tagName, rect,
++                                                             borderWidth) {
++      assert(!isWorker,
++        'getEmptyContainer() should be called from main thread');
++
++      var bWidth = borderWidth || 0;
++
++      rect = rect || this.data.rect;
++      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;
++    },
++
++    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
 +      }
-       var trailerBytes = new Uint8Array([116, 114, 97, 105, 108, 101, 114]);
-       var startxrefBytes = new Uint8Array([115, 116, 97, 114, 116, 120, 114,
-                                           101, 102]);
-       var endobjBytes = new Uint8Array([101, 110, 100, 111, 98, 106]);
-       var xrefBytes = new Uint8Array([47, 88, 82, 101, 102]);
++    },
 +
-       var stream = this.stream;
-       stream.pos = 0;
-       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) {
-           ++position;
-           continue;
-         }
-         if (ch === 37) { // %-comment
-           do {
-             ++position;
-             ch = buffer[position];
-           } while (ch !== 13 && ch !== 10);
-           continue;
++    isViewable: function Annotation_isViewable() {
++      var data = this.data;
++      return !!(!this.isInvisible() &&
++                data &&
++                (!data.annotationFlags ||
++                 !(data.annotationFlags & 0x22)) &&  // Hidden or NoView
++                data.rect);                          // rectangle is nessessary
++    },
++
++    isPrintable: function Annotation_isPrintable() {
++      var data = this.data;
++      return !!(!this.isInvisible() &&
++                data &&
++                data.annotationFlags &&              // Default: not printable
++                data.annotationFlags & 0x4 &&        // Print
++                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 token = readToken(buffer, position);
-         var m;
-         if (token === 'xref') {
-           position += skipUntil(buffer, position, trailerBytes);
-           trailers.push(position);
-           position += skipUntil(buffer, position, startxrefBytes);
-         } else if ((m = /^(\d+)\s+(\d+)\s+obj\b/.exec(token))) {
-           this.entries[m[1]] = {
-             offset: position,
-             gen: m[2] | 0,
-             uncompressed: true
-           };
++        var objectLoader = new ObjectLoader(resources.map,
++                                            keys,
++                                            resources.xref);
++        objectLoader.load().then(function() {
++          promise.resolve(resources);
++        });
++      }.bind(this));
 +
-           var contentLength = skipUntil(buffer, position, endobjBytes) + 7;
-           var content = buffer.subarray(position, position + contentLength);
++      return promise;
++    },
 +
-           // checking XRef stream suspect
-           // (it shall have '/XRef' and next char is not a letter)
-           var xrefTagOffset = skipUntil(content, 0, xrefBytes);
-           if (xrefTagOffset < contentLength &&
-               content[xrefTagOffset + 5] < 64) {
-             xrefStms.push(position);
-             this.xrefstms[position] = 1; // don't read it recursively
-           }
++    getOperatorList: function Annotation_getOperatorList(evaluator) {
 +
-           position += contentLength;
-         } else
-           position += token.length + 1;
-       }
-       // reading XRef streams
-       for (var i = 0, ii = xrefStms.length; i < ii; ++i) {
-           this.readXRef(xrefStms[i], true);
++      var promise = new LegacyPromise();
++
++      if (!this.appearance) {
++        promise.resolve(new OperatorList());
++        return promise;
 +      }
-       // finding main trailer
-       var dict;
-       for (var i = 0, ii = trailers.length; i < ii; ++i) {
-         stream.pos = trailers[i];
-         var parser = new Parser(new Lexer(stream), true, null);
-         var obj = parser.getObj();
-         if (!isCmd(obj, 'trailer'))
-           continue;
-         // read the trailer dictionary
-         if (!isDict(dict = parser.getObj()))
-           continue;
-         // taking the first one with 'ID'
-         if (dict.has('ID'))
-           return dict;
-       }
-       // no tailer with 'ID', taking last one (if exists)
-       if (dict)
-         return dict;
-       // nothing helps
-       // calling error() would reject worker with an UnknownErrorException.
-       throw new InvalidPDFException('Invalid PDF structure');
-     },
-     readXRef: function XRef_readXRef(startXRef, recoveryMode) {
-       var stream = this.stream;
-       stream.pos = startXRef;
 +
-       try {
-         var parser = new Parser(new Lexer(stream), true, null);
-         var obj = parser.getObj();
-         var dict;
- 
-         // Get dictionary
-         if (isCmd(obj, 'xref')) {
-           // Parse end-of-file XRef
-           dict = this.readXRefTable(parser);
++      var data = this.data;
 +
-           // Recursively get other XRefs 'XRefStm', if any
-           obj = dict.get('XRefStm');
-           if (isInt(obj)) {
-             var pos = obj;
-             // ignore previously loaded xref streams
-             // (possible infinite recursion)
-             if (!(pos in this.xrefstms)) {
-               this.xrefstms[pos] = 1;
-               this.readXRef(pos);
-             }
-           }
-         } else if (isInt(obj)) {
-           // Parse in-stream XRef
-           if (!isInt(parser.getObj()) ||
-               !isCmd(parser.getObj(), 'obj') ||
-               !isStream(obj = parser.getObj())) {
-             error('Invalid XRef stream');
-           }
-           dict = this.readXRefStream(obj);
-           if (!dict)
-             error('Failed to read XRef stream');
-         }
++      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);
 +
-         // Recursively get previous dictionary, if any
-         obj = dict.get('Prev');
-         if (isInt(obj))
-           this.readXRef(obj, recoveryMode);
-         else if (isRef(obj)) {
-           // The spec says Prev must not be a reference, i.e. "/Prev NNN"
-           // This is a fallback for non-compliant PDFs, i.e. "/Prev NNN 0 R"
-           this.readXRef(obj.num, recoveryMode);
-         }
++      var border = data.border;
 +
-         return dict;
-       } catch (e) {
-         log('(while reading XRef): ' + e);
-       }
++      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);
 +
-       if (recoveryMode)
-         return;
++        this.appearance.reset();
++      }.bind(this));
 +
-       warn('Indexing all PDF objects');
-       return this.indexObjects();
-     },
-     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
-     },
-     fetchIfRef: function XRef_fetchIfRef(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');
-       var num = ref.num;
-       if (num in this.cache)
-         return this.cache[num];
++      return promise;
++    }
++  };
 +
-       var e = this.getEntry(num);
++  Annotation.getConstructor =
++      function Annotation_getConstructor(subtype, fieldType) {
 +
-       // the referenced entry can be free
-       if (e === null)
-         return (this.cache[num] = e);
++    if (!subtype) {
++      return;
++    }
 +
-       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();
-         }
-         // Don't cache streams since they are mutable (except images).
-         if (!isStream(e) || e instanceof JpegStream)
-           this.cache[num] = e;
-         return e;
++    // TODO(mack): Implement FreeText annotations
++    if (subtype === 'Link') {
++      return LinkAnnotation;
++    } else if (subtype === 'Text') {
++      return TextAnnotation;
++    } else if (subtype === 'Widget') {
++      if (!fieldType) {
++        return;
 +      }
 +
-       // compressed entry
-       var tableOffset = e.offset;
-       stream = this.fetch(new Ref(tableOffset, 0));
-       if (!isStream(stream))
-         error('bad ObjStm stream');
-       var first = stream.parameters.get('First');
-       var n = stream.parameters.get('N');
-       if (!isInt(first) || !isInt(n)) {
-         error('invalid first and n parameters for ObjStm stream');
-       }
-       parser = new Parser(new Lexer(stream), false, this);
-       parser.allowStreams = true;
-       var i, entries = [], nums = [];
-       // read the object numbers to populate cache
-       for (i = 0; i < n; ++i) {
-         num = parser.getObj();
-         if (!isInt(num)) {
-           error('invalid object number in the ObjStm stream: ' + num);
-         }
-         nums.push(num);
-         var offset = parser.getObj();
-         if (!isInt(offset)) {
-           error('invalid object offset in the ObjStm stream: ' + offset);
-         }
-       }
-       // read stream objects for cache
-       for (i = 0; i < n; ++i) {
-         entries.push(parser.getObj());
-         num = nums[i];
-         var entry = this.entries[num];
-         if (entry && entry.offset === tableOffset && entry.gen === i) {
-           this.cache[num] = entries[i];
-         }
-       }
-       e = entries[e.gen];
-       if (!e) {
-         error('bad XRef entry for compressed object');
++      if (fieldType === 'Tx') {
++        return TextWidgetAnnotation;
++      } else {
++        return WidgetAnnotation;
 +      }
-       return e;
-     },
-     getCatalogObj: function XRef_getCatalogObj() {
-       return this.root;
++    } else {
++      return Annotation;
 +    }
 +  };
 +
-   return XRef;
- })();
++  // 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 });
++    }
++  };
 +
- /**
-  * A NameTree is like a Dict but has some adventagous 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() {
-   function NameTree(root, xref) {
-     this.root = root;
-     this.xref = xref;
-   }
++  Annotation.fromRef = function Annotation_fromRef(xref, ref) {
 +
-   NameTree.prototype = {
-     getAll: function NameTree_getAll() {
-       var dict = {};
-       if (!this.root) {
-         return dict;
-       }
-       var xref = this.xref;
-       // reading name tree
-       var processed = new RefSet();
-       processed.put(this.root);
-       var queue = [this.root];
-       while (queue.length > 0) {
-         var i, n;
-         var obj = xref.fetchIfRef(queue.shift());
-         if (!isDict(obj)) {
-           continue;
-         }
-         if (obj.has('Kids')) {
-           var kids = obj.get('Kids');
-           for (i = 0, n = kids.length; i < n; i++) {
-             var kid = kids[i];
-             if (processed.has(kid))
-               error('invalid destinations');
-             queue.push(kid);
-             processed.put(kid);
-           }
-           continue;
-         }
-         var names = obj.get('Names');
-         if (names) {
-           for (i = 0, n = names.length; i < n; i += 2) {
-             dict[names[i]] = xref.fetchIfRef(names[i + 1]);
-           }
-         }
-       }
-       return dict;
++    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 {
++      warn('unimplemented annotation type: ' + subtype);
 +    }
 +  };
-   return NameTree;
- })();
 +
- /**
-  * A PDF document and page is built of many objects. E.g. there are objects
-  * 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.
-  */
- var PDFObjects = (function PDFObjectsClosure() {
-   function PDFObjects() {
-     this.objs = {};
-   }
++  Annotation.appendToOperatorList = function Annotation_appendToOperatorList(
++      annotations, opList, pdfManager, partialEvaluator, intent) {
 +
-   PDFObjects.prototype = {
-     /**
-      * Internal function.
-      * Ensures there is an object defined for `objId`. Stores `data` on the
-      * object *if* it is created.
-      */
-     ensureObj: function PDFObjects_ensureObj(objId, data) {
-       if (this.objs[objId])
-         return this.objs[objId];
-       return this.objs[objId] = new Promise(objId, data);
-     },
++    function reject(e) {
++      annotationsReadyPromise.reject(e);
++    }
 +
-     /**
-      * If called *without* callback, this returns the data of `objId` but the
-      * object needs to be resolved. If it isn't, this function throws.
-      *
-      * If called *with* a callback, the callback is called with the data of the
-      * object once the object is resolved. That means, if you call this
-      * function and the object is already resolved, the callback gets called
-      * right away.
-      */
-     get: function PDFObjects_get(objId, callback) {
-       // 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).then(callback);
-         return null;
++    var annotationsReadyPromise = new LegacyPromise();
++
++    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, []);
++      annotationsReadyPromise.resolve();
++    }, reject);
 +
-       // If there isn't a callback, the user expects to get the resolved data
-       // directly.
-       var obj = this.objs[objId];
++    return annotationsReadyPromise;
++  };
 +
-       // If there isn't an object yet or the object isn't resolved, then the
-       // data isn't ready yet!
-       if (!obj || !obj.isResolved)
-         error('Requesting object that isn\'t resolved yet ' + objId);
++  return Annotation;
++})();
++PDFJS.Annotation = Annotation;
 +
-       return obj.data;
-     },
 +
-     /**
-      * Resolves the object `objId` with optional `data`.
-      */
-     resolve: function PDFObjects_resolve(objId, data) {
-       var objs = this.objs;
++var WidgetAnnotation = (function WidgetAnnotationClosure() {
 +
-       // In case there is a promise already on this object, just resolve it.
-       if (objs[objId]) {
-         objs[objId].resolve(data);
-       } else {
-         this.ensureObj(objId, data);
-       }
-     },
++  function WidgetAnnotation(params) {
++    Annotation.call(this, params);
 +
-     onData: function PDFObjects_onData(objId, callback) {
-       this.ensureObj(objId).onData(callback);
-     },
++    if (params.data) {
++      return;
++    }
 +
-     isResolved: function PDFObjects_isResolved(objId) {
-       var objs = this.objs;
-       if (!objs[objId]) {
-         return false;
++    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 {
-         return objs[objId].isResolved;
++        // 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('.');
++  }
 +
-     hasData: function PDFObjects_hasData(objId) {
-       var objs = this.objs;
-       if (!objs[objId]) {
++  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;
-       } else {
-         return objs[objId].hasData;
 +      }
-     },
 +
-     /**
-      * Returns the data of `objId` if object exists, null otherwise.
-      */
-     getData: function PDFObjects_getData(objId) {
-       var objs = this.objs;
-       if (!objs[objId] || !objs[objId].hasData) {
-         return null;
-       } else {
-         return objs[objId].data;
-       }
-     },
++      return parent.isViewable.call(this);
++    }
++  });
 +
-     /**
-      * Sets the data of an object but *doesn't* resolve it.
-      */
-     setData: function PDFObjects_setData(objId, data) {
-       // Watchout! If you call `this.ensureObj(objId, data)` you're going to
-       // create a *resolved* promise which shouldn't be the case!
-       this.ensureObj(objId).data = data;
-     },
++  return WidgetAnnotation;
++})();
++
++var TextWidgetAnnotation = (function TextWidgetAnnotationClosure() {
++  function TextWidgetAnnotation(params) {
++    WidgetAnnotation.call(this, params);
 +
-     clear: function PDFObjects_clear() {
-       this.objs = {};
++    if (params.data) {
++      return;
 +    }
-   };
-   return PDFObjects;
- })();
 +
++    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 PDFFunction = (function PDFFunctionClosure() {
-   var CONSTRUCT_SAMPLED = 0;
-   var CONSTRUCT_INTERPOLATED = 2;
-   var CONSTRUCT_STICHED = 3;
-   var CONSTRUCT_POSTSCRIPT = 4;
++    var style = element.style;
++    style.fontSize = item.fontSize + 'px';
++    style.direction = item.fontDirection < 0 ? 'rtl': 'ltr';
 +
-   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;
++    if (!fontObj) {
++      return;
++    }
 +
-       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);
++    style.fontWeight = fontObj.black ?
++                            (fontObj.bold ? 'bolder' : 'bold') :
++                            (fontObj.bold ? 'bold' : 'normal');
++    style.fontStyle = fontObj.italic ? 'italic' : 'normal';
 +
-       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;
++    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;
 +    },
 +
-     getIR: function PDFFunction_getIR(xref, fn) {
-       var dict = fn.dict;
-       if (!dict)
-         dict = fn;
++    getHtmlElement: function TextWidgetAnnotation_getHtmlElement(commonObjs) {
++      assert(!isWorker, 'getHtmlElement() shall be called from main thread');
 +
-       var types = [this.constructSampled,
-                    null,
-                    this.constructInterpolated,
-                    this.constructStiched,
-                    this.constructPostScript];
++      var item = this.data;
 +
-       var typeNum = dict.get('FunctionType');
-       var typeFn = types[typeNum];
-       if (!typeFn)
-         error('Unknown type of function');
++      var element = this.getEmptyContainer('div');
++      element.style.display = 'table';
 +
-       return typeFn.call(this, fn, dict, xref);
-     },
++      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';
 +
-     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);
-       }
-     },
++      var fontObj = item.fontRefName ?
++                    commonObjs.getData(item.fontRefName) : null;
++      var cssRules = setTextStyles(content, item, fontObj);
 +
-     parse: function PDFFunction_parse(xref, fn) {
-       var IR = this.getIR(xref, fn);
-       return this.fromIR(IR);
++      element.appendChild(content);
++
++      return element;
 +    },
 +
-     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;
++    getOperatorList: function TextWidgetAnnotation_getOperatorList(evaluator) {
++      if (this.appearance) {
++        return Annotation.prototype.getOperatorList.call(this, evaluator);
 +      }
-       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;
++      var promise = new LegacyPromise();
++      var opList = new OperatorList();
++      var data = this.data;
 +
-       domain = toMultiArray(domain);
-       range = toMultiArray(range);
++      // Even if there is an appearance stream, ignore it. This is the
++      // behaviour used by Adobe Reader.
 +
-       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
-         TODO('No support for cubic spline interpolation: ' + order);
++      var defaultAppearance = data.defaultAppearance;
++      if (!defaultAppearance) {
++        promise.resolve(opList);
++        return promise;
 +      }
 +
-       var encode = dict.get('Encode');
-       if (!encode) {
-         encode = [];
-         for (var i = 0; i < inputSize; ++i) {
-           encode.push(0);
-           encode.push(size[i] - 1);
++      // 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];
 +        }
 +      }
-       encode = toMultiArray(encode);
++      promise.resolve(opList);
++      return promise;
++    }
++  });
 +
-       var decode = dict.get('Decode');
-       if (!decode)
-         decode = range;
-       else
-         decode = toMultiArray(decode);
++  return TextWidgetAnnotation;
++})();
 +
-       var samples = this.getSampleArray(size, outputSize, bps, str);
++var InteractiveAnnotation = (function InteractiveAnnotationClosure() {
++  function InteractiveAnnotation(params) {
++    Annotation.call(this, params);
++  }
 +
-       return [
-         CONSTRUCT_SAMPLED, inputSize, domain, encode, decode, samples, size,
-         outputSize, Math.pow(2, bps) - 1, range
-       ];
++  Util.inherit(InteractiveAnnotation, Annotation, {
++    hasHtml: function InteractiveAnnotation_hasHtml() {
++      return true;
 +    },
 +
-     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)));
++    highlight: function InteractiveAnnotation_highlight() {
++      if (this.highlightElement &&
++         this.highlightElement.hasAttribute('hidden')) {
++        this.highlightElement.removeAttribute('hidden');
 +      }
++    },
 +
-       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];
++    unhighlight: function InteractiveAnnotation_unhighlight() {
++      if (this.highlightElement &&
++         !this.highlightElement.hasAttribute('hidden')) {
++        this.highlightElement.setAttribute('hidden', true);
++      }
++    },
 +
-         if (m != args.length)
-           error('Incorrect number of arguments: ' + m + ' != ' +
-                 args.length);
++    initContainer: function InteractiveAnnotation_initContainer() {
 +
-         var x = args;
++      var item = this.data;
++      var rect = item.rect;
 +
-         // 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 container = this.getEmptyContainer('section', rect, item.borderWidth);
++      container.style.backgroundColor = item.color;
 +
-         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);
++      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);
 +
-           // 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]);
++      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);
 +
-           // 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);
++      this.highlightElement = highlight;
++      container.appendChild(this.highlightElement);
 +
-           // 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;
-             }
-           }
++      return container;
++    }
++  });
 +
-           k *= size_i;
-           pos <<= 1;
-         }
++  return InteractiveAnnotation;
++})();
 +
-         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];
++var TextAnnotation = (function TextAnnotationClosure() {
++  function TextAnnotation(params) {
++    InteractiveAnnotation.call(this, params);
 +
-           // 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]);
++    if (params.data) {
++      return;
++    }
 +
-           // y_j = min(max(r_j, range_2j), range_2j+1)
-           y[j] = Math.min(Math.max(rj, range[j][0]), range[j][1]);
-         }
++    var dict = params.dict;
++    var data = this.data;
 +
-         return y;
-       };
-     },
++    var content = dict.get('Contents');
++    var title = dict.get('T');
++    data.content = stringToPDFString(content || '');
++    data.title = stringToPDFString(title || '');
 +
-     constructInterpolated: function PDFFunction_constructInterpolated(str,
-                                                                       dict) {
-       var c0 = dict.get('C0') || [0];
-       var c1 = dict.get('C1') || [1];
-       var n = dict.get('N');
++    if (data.hasAppearance) {
++      data.name = 'NoIcon';
++    } else {
++      data.name = dict.has('Name') ? dict.get('Name').name : 'Note';
++    }
 +
-       if (!isArray(c0) || !isArray(c1))
-         error('Illegal dictionary for interpolated function');
++    if (dict.has('C')) {
++      data.hasBgColor = true;
++    }
++  }
 +
-       var length = c0.length;
-       var diff = [];
-       for (var i = 0; i < length; ++i)
-         diff.push(c1[i] - c0[i]);
++  var ANNOT_MIN_SIZE = 10;
 +
-       return [CONSTRUCT_INTERPOLATED, c0, diff, n];
-     },
++  Util.inherit(TextAnnotation, InteractiveAnnotation, {
 +
-     constructInterpolatedFromIR:
-       function PDFFunction_constructInterpolatedFromIR(IR) {
-       var c0 = IR[1];
-       var diff = IR[2];
-       var n = IR[3];
++    getHtmlElement: function TextAnnotation_getHtmlElement(commonObjs) {
++      assert(!isWorker, 'getHtmlElement() shall be called from main thread');
 +
-       var length = diff.length;
++      var item = this.data;
++      var rect = item.rect;
 +
-       return function constructInterpolatedFromIRResult(args) {
-         var x = n == 1 ? args[0] : Math.pow(args[0], n);
++      // 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 out = [];
-         for (var j = 0; j < length; ++j)
-           out.push(c0[j] + (x * diff[j]));
++      var container = this.initContainer();
++      container.className = 'annotText';
 +
-         return out;
++      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';
 +
-     constructStiched: function PDFFunction_constructStiched(fn, dict, xref) {
-       var domain = dict.get('Domain');
++      var content = document.createElement('div');
++      content.className = 'annotTextContent';
++      content.setAttribute('hidden', true);
++      if (item.hasBgColor) {
++        var color = item.color;
++        var rgb = [];
++        for (var 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);
++      }
 +
-       if (!domain)
-         error('No domain');
++      var title = document.createElement('h1');
++      var text = document.createElement('p');
++      title.textContent = item.title;
 +
-       var inputSize = domain.length / 2;
-       if (inputSize != 1)
-         error('Bad domain for stiched function');
++      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 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 pinned = false;
 +
-       var bounds = dict.get('Bounds');
-       var encode = dict.get('Encode');
++        var showAnnotation = function showAnnotation(pin) {
++          if (pin) {
++            pinned = true;
++          }
++          if (content.hasAttribute('hidden')) {
++            container.style.zIndex += 1;
++            content.removeAttribute('hidden');
++          }
++        };
 +
-       return [CONSTRUCT_STICHED, domain, bounds, encode, fns];
-     },
++        var hideAnnotation = function hideAnnotation(unpin) {
++          if (unpin) {
++            pinned = false;
++          }
++          if (!content.hasAttribute('hidden') && !pinned) {
++            container.style.zIndex -= 1;
++            content.setAttribute('hidden', true);
++          }
++        };
 +
-     constructStichedFromIR: function PDFFunction_constructStichedFromIR(IR) {
-       var domain = IR[1];
-       var bounds = IR[2];
-       var encode = IR[3];
-       var fnsIR = IR[4];
-       var fns = [];
++        var toggleAnnotation = function toggleAnnotation() {
++          if (pinned) {
++            hideAnnotation(true);
++          } else {
++            showAnnotation(true);
++          }
++        };
 +
-       for (var i = 0, ii = fnsIR.length; i < ii; i++) {
-         fns.push(PDFFunction.fromIR(fnsIR[i]));
++        var self = this;
++        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);
 +      }
 +
-       return function constructStichedFromIRResult(args) {
-         var clip = function constructStichedFromIRClip(v, min, max) {
-           if (v > max)
-             v = max;
-           else if (v < min)
-             v = min;
-           return v;
-         };
++      content.appendChild(title);
++      content.appendChild(text);
++      contentWrapper.appendChild(content);
++      container.appendChild(image);
++      container.appendChild(contentWrapper);
 +
-         // 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;
-         }
++      return container;
++    }
++  });
 +
-         // 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];
++  return TextAnnotation;
++})();
 +
-         var rmin = encode[2 * i];
-         var rmax = encode[2 * i + 1];
++var LinkAnnotation = (function LinkAnnotationClosure() {
++  function LinkAnnotation(params) {
++    InteractiveAnnotation.call(this, params);
 +
-         var v2 = rmin + (v - dmin) * (rmax - rmin) / (dmax - dmin);
++    if (params.data) {
++      return;
++    }
 +
-         // call the appropropriate function
-         return fns[i]([v2]);
-       };
++    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 = 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;
 +    },
 +
-     constructPostScript: function PDFFunction_constructPostScript(fn, dict,
-                                                                   xref) {
-       var domain = dict.get('Domain');
-       var range = dict.get('Range');
++    getHtmlElement: function LinkAnnotation_getHtmlElement(commonObjs) {
 +
-       if (!domain)
-         error('No domain.');
++      var container = this.initContainer();
++      container.className = 'annotLink';
 +
-       if (!range)
-         error('No range.');
++      var item = this.data;
++      var rect = item.rect;
 +
-       var lexer = new PostScriptLexer(fn);
-       var parser = new PostScriptParser(lexer);
-       var code = parser.parse();
++      container.style.borderColor = item.colorCssRgb;
++      container.style.borderStyle = 'solid';
 +
-       return [CONSTRUCT_POSTSCRIPT, domain, range, code];
-     },
++      var link = document.createElement('a');
++      link.href = link.title = this.data.url || '';
 +
-     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);
++      container.appendChild(link);
 +
-         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;
-       };
++      return container;
 +    }
-   };
++  });
++
++  return LinkAnnotation;
 +})();
 +
- 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;
++
++
++
++var NetworkManager = (function NetworkManagerClosure() {
++
++  var OK_RESPONSE = 200;
++  var PARTIAL_CONTENT_RESPONSE = 206;
++
++  function NetworkManager(url, args) {
++    this.url = url;
++    args = args || {};
++    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();
++      };
++
++    this.currXhrId = 0;
++    this.pendingRequests = {};
++    this.loadedRequests = {};
 +  }
-   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 || [];
++  function getArrayBuffer(xhr) {
++    var data = (xhr.mozResponseArrayBuffer || xhr.mozResponse ||
++                xhr.responseArrayBuffer || xhr.response);
++    if (typeof data !== 'string') {
++      return data;
++    }
++    var length = data.length;
++    var buffer = new Uint8Array(length);
++    for (var i = 0; i < length; i++) {
++      buffer[i] = data.charCodeAt(i) & 0xFF;
++    }
++    return buffer;
 +  }
 +
-   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();
++  NetworkManager.prototype = {
++    requestRange: function NetworkManager_requestRange(begin, end, listeners) {
++      var args = {
++        begin: begin,
++        end: end
++      };
++      for (var prop in listeners) {
++        args[prop] = listeners[prop];
++      }
++      return this.request(args);
 +    },
-     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]);
++
++    requestFull: function NetworkManager_requestRange(listeners) {
++      return this.request(listeners);
 +    },
-     index: function PostScriptStack_index(n) {
-       this.push(this.stack[this.stack.length - n - 1]);
++
++    request: function NetworkManager_requestRange(args) {
++      var xhr = this.getXhr();
++      var xhrId = this.currXhrId++;
++      var pendingRequest = this.pendingRequests[xhrId] = {
++        xhr: xhr
++      };
++
++      xhr.open('GET', this.url);
++      xhr.withCredentials = this.withCredentials;
++      for (var property in this.httpHeaders) {
++        var value = this.httpHeaders[property];
++        if (typeof value === 'undefined') {
++          continue;
++        }
++        xhr.setRequestHeader(property, value);
++      }
++      if (this.isHttp && 'begin' in args && 'end' in args) {
++        var rangeStr = args.begin + '-' + (args.end - 1);
++        xhr.setRequestHeader('Range', 'bytes=' + rangeStr);
++        pendingRequest.expectedStatus = 206;
++      } else {
++        pendingRequest.expectedStatus = 200;
++      }
++
++      xhr.mozResponseType = xhr.responseType = 'arraybuffer';
++
++      if (args.onProgress) {
++        xhr.onprogress = args.onProgress;
++      }
++      if (args.onError) {
++        xhr.onerror = function(evt) {
++          args.onError(xhr.status);
++        };
++      }
++      xhr.onreadystatechange = this.onStateChange.bind(this, xhrId);
++
++      pendingRequest.onHeadersReceived = args.onHeadersReceived;
++      pendingRequest.onDone = args.onDone;
++      pendingRequest.onError = args.onError;
++
++      xhr.send(null);
++
++      return xhrId;
 +    },
-     // 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;
++
++    onStateChange: function NetworkManager_onStateChange(xhrId, evt) {
++      var pendingRequest = this.pendingRequests[xhrId];
++      if (!pendingRequest) {
++        // Maybe abortRequest was called...
++        return;
 +      }
-       for (i = l, j = c - 1; i < j; i++, j--) {
-         t = stack[i]; stack[i] = stack[j]; stack[j] = t;
++
++      var xhr = pendingRequest.xhr;
++      if (xhr.readyState >= 2 && pendingRequest.onHeadersReceived) {
++        pendingRequest.onHeadersReceived();
++        delete pendingRequest.onHeadersReceived;
 +      }
-       for (i = c, j = r; i < j; i++, j--) {
-         t = stack[i]; stack[i] = stack[j]; stack[j] = t;
++
++      if (xhr.readyState !== 4) {
++        return;
 +      }
-     }
-   };
-   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;
++
++      if (!(xhrId in this.pendingRequests)) {
++        // The XHR request might have been aborted in onHeadersReceived()
++        // callback, in which case we should abort request
++        return;
++      }
++
++      delete this.pendingRequests[xhrId];
++
++      // success status == 0 can be on ftp, file and other protocols
++      if (xhr.status === 0 && this.isHttp) {
++        if (pendingRequest.onError) {
++          pendingRequest.onError(xhr.status);
 +        }
-         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;
++        return;
++      }
++      var xhrStatus = xhr.status || OK_RESPONSE;
 +
-           // 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;
++      // From http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35.2:
++      // "A server MAY ignore the Range header". This means it's possible to
++      // get a 200 rather than a 206 response from a range request.
++      var ok_response_on_range_request =
++          xhrStatus === OK_RESPONSE &&
++          pendingRequest.expectedStatus === PARTIAL_CONTENT_RESPONSE;
++
++      if (!ok_response_on_range_request &&
++          xhrStatus !== pendingRequest.expectedStatus) {
++        if (pendingRequest.onError) {
++          pendingRequest.onError(xhr.status);
 +        }
++        return;
 +      }
-       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();
++      this.loadedRequests[xhrId] = true;
++
++      var chunk = getArrayBuffer(xhr);
++      if (xhrStatus === PARTIAL_CONTENT_RESPONSE) {
++        var rangeHeader = xhr.getResponseHeader('Content-Range');
++        var matches = /bytes (\d+)-(\d+)\/(\d+)/.exec(rangeHeader);
++        var begin = parseInt(matches[1], 10);
++        pendingRequest.onDone({
++          begin: begin,
++          chunk: chunk
++        });
++      } else {
++        pendingRequest.onDone({
++          begin: 0,
++          chunk: chunk
++        });
++      }
 +    },
-     accept: function PostScriptParser_accept(type) {
-       if (this.token.type == type) {
-         this.nextToken();
++
++    hasPendingRequests: function NetworkManager_hasPendingRequests() {
++      for (var xhrId in this.pendingRequests) {
 +        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;
++
++    getRequestXhr: function NetworkManager_getXhr(xhrId) {
++      return this.pendingRequests[xhrId].xhr;
 +    },
-     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;
-         }
-       }
++
++    isPendingRequest: function NetworkManager_isPendingRequest(xhrId) {
++      return xhrId in this.pendingRequests;
 +    },
-     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';
++    isLoadedRequest: function NetworkManager_isLoadedRequest(xhrId) {
++      return xhrId in this.loadedRequests;
++    },
 +
-         this.operators[conditionLocation] = endOfTrue;
-         this.operators[conditionLocation + 1] = 'jz';
-       } else {
-         error('PS Function: error parsing conditional.');
++    abortAllRequests: function NetworkManager_abortAllRequests() {
++      for (var xhrId in this.pendingRequests) {
++        this.abortRequest(xhrId | 0);
 +      }
++    },
++
++    abortRequest: function NetworkManager_abortRequest(xhrId) {
++      var xhr = this.pendingRequests[xhrId].xhr;
++      delete this.pendingRequests[xhrId];
++      xhr.abort();
 +    }
 +  };
-   return PostScriptParser;
++
++  return NetworkManager;
 +})();
 +
- 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 ChunkedStream = (function ChunkedStreamClosure() {
++  function ChunkedStream(length, chunkSize, manager) {
++    this.bytes = new Uint8Array(length);
++    this.start = 0;
++    this.pos = 0;
++    this.end = length;
++    this.chunkSize = chunkSize;
++    this.loadedChunks = [];
++    this.numChunksLoaded = 0;
++    this.numChunks = Math.ceil(length / chunkSize);
++    this.manager = manager;
++    this.initialDataLength = 0;
 +  }
 +
-   var opCache = {};
++  // required methods for a stream. if a particular stream does not
++  // implement these, an error should be thrown
++  ChunkedStream.prototype = {
 +
-   PostScriptToken.getOperator = function PostScriptToken_getOperator(op) {
-     var opValue = opCache[op];
-     if (opValue)
-       return opValue;
++    getMissingChunks: function ChunkedStream_getMissingChunks() {
++      var chunks = [];
++      for (var chunk = 0, n = this.numChunks; chunk < n; ++chunk) {
++        if (!(chunk in this.loadedChunks)) {
++          chunks.push(chunk);
++        }
++      }
++      return chunks;
++    },
 +
-     return opCache[op] = new PostScriptToken(PostScriptTokenTypes.OPERATOR, op);
-   };
++    getBaseStreams: function ChunkedStream_getBaseStreams() {
++      return [this];
++    },
 +
-   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;
- })();
++    allChunksLoaded: function ChunkedStream_allChunksLoaded() {
++      return this.numChunksLoaded === this.numChunks;
++    },
 +
- var PostScriptLexer = (function PostScriptLexerClosure() {
-   function PostScriptLexer(stream) {
-     this.stream = stream;
-   }
-   PostScriptLexer.prototype = {
-     getToken: function PostScriptLexer_getToken() {
-       var s = '';
-       var ch;
-       var comment = false;
-       var stream = this.stream;
++    onReceiveData: function(begin, chunk) {
++      var end = begin + chunk.byteLength;
 +
-       // skip comments
-       while (true) {
-         if (!(ch = stream.getChar()))
-           return EOF;
++      assert(begin % this.chunkSize === 0, 'Bad begin offset: ' + begin);
++      // Using this.length is inaccurate here since this.start can be moved
++      // See ChunkedStream.moveStart()
++      var length = this.bytes.length;
++      assert(end % this.chunkSize === 0 || end === length,
++        'Bad end offset: ' + end);
 +
-         if (comment) {
-           if (ch == '\x0a' || ch == '\x0d')
-             comment = false;
-         } else if (ch == '%') {
-           comment = true;
-         } else if (!Lexer.isSpace(ch)) {
-           break;
++      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;
++
++      for (var chunk = beginChunk; chunk < endChunk; ++chunk) {
++        if (!(chunk in this.loadedChunks)) {
++          this.loadedChunks[chunk] = true;
++          ++this.numChunksLoaded;
 +        }
 +      }
-       switch (ch) {
-         case '0': case '1': case '2': case '3': case '4':
-         case '5': case '6': case '7': case '8': case '9':
-         case '+': case '-': case '.':
-           return new PostScriptToken(PostScriptTokenTypes.NUMBER,
-                                       this.getNumber(ch));
-         case '{':
-           return PostScriptToken.LBRACE;
-         case '}':
-           return PostScriptToken.RBRACE;
-       }
-       // operator
-       var str = ch.toLowerCase();
-       while (true) {
-         ch = stream.lookChar();
-         if (ch === null)
-           break;
-         ch = ch.toLowerCase();
-         if (ch >= 'a' && ch <= 'z')
-           str += ch;
-         else
-           break;
-         stream.skip();
-       }
-       switch (str) {
-         case 'if':
-           return PostScriptToken.IF;
-         case 'ifelse':
-           return PostScriptToken.IFELSE;
-         default:
-           return PostScriptToken.getOperator(str);
++    },
++
++    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;
 +      }
 +    },
-     getNumber: function PostScriptLexer_getNumber(ch) {
-       var str = ch;
-       var stream = this.stream;
-       while (true) {
-         ch = stream.lookChar();
-         if ((ch >= '0' && ch <= '9') || ch == '-' || ch == '.')
-           str += ch;
-         else
-           break;
-         stream.skip();
++
++    ensureRange: function ChunkedStream_ensureRange(begin, end) {
++      if (begin >= end) {
++        return;
 +      }
-       var value = parseFloat(str);
-       if (isNaN(value))
-         error('Invalid floating point number: ' + value);
-       return value;
-     }
-   };
-   return PostScriptLexer;
- })();
 +
++      if (end <= this.initialDataLength) {
++        return;
++      }
 +
++      var chunkSize = this.chunkSize;
++      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)) {
++          throw new MissingDataException(begin, end);
++        }
++      }
++    },
 +
- var ISOAdobeCharset = [
-   '.notdef', 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar',
-   'percent', 'ampersand', 'quoteright', 'parenleft', 'parenright',
-   'asterisk', 'plus', 'comma', 'hyphen', 'period', 'slash', 'zero',
-   'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight',
-   'nine', 'colon', 'semicolon', 'less', 'equal', 'greater', 'question',
-   'at', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
-   'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
-   'bracketleft', 'backslash', 'bracketright', 'asciicircum', 'underscore',
-   'quoteleft', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
-   'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
-   'braceleft', 'bar', 'braceright', 'asciitilde', 'exclamdown', 'cent',
-   'sterling', 'fraction', 'yen', 'florin', 'section', 'currency',
-   'quotesingle', 'quotedblleft', 'guillemotleft', 'guilsinglleft',
-   'guilsinglright', 'fi', 'fl', 'endash', 'dagger', 'daggerdbl',
-   'periodcentered', 'paragraph', 'bullet', 'quotesinglbase',
-   'quotedblbase', 'quotedblright', 'guillemotright', 'ellipsis',
-   'perthousand', 'questiondown', 'grave', 'acute', 'circumflex', 'tilde',
-   'macron', 'breve', 'dotaccent', 'dieresis', 'ring', 'cedilla',
-   'hungarumlaut', 'ogonek', 'caron', 'emdash', 'AE', 'ordfeminine',
-   'Lslash', 'Oslash', 'OE', 'ordmasculine', 'ae', 'dotlessi', 'lslash',
-   'oslash', 'oe', 'germandbls', 'onesuperior', 'logicalnot', 'mu',
-   'trademark', 'Eth', 'onehalf', 'plusminus', 'Thorn', 'onequarter',
-   'divide', 'brokenbar', 'degree', 'thorn', 'threequarters', 'twosuperior',
-   'registered', 'minus', 'eth', 'multiply', 'threesuperior', 'copyright',
-   'Aacute', 'Acircumflex', 'Adieresis', 'Agrave', 'Aring', 'Atilde',
-   'Ccedilla', 'Eacute', 'Ecircumflex', 'Edieresis', 'Egrave', 'Iacute',
-   'Icircumflex', 'Idieresis', 'Igrave', 'Ntilde', 'Oacute', 'Ocircumflex',
-   'Odieresis', 'Ograve', 'Otilde', 'Scaron', 'Uacute', 'Ucircumflex',
-   'Udieresis', 'Ugrave', 'Yacute', 'Ydieresis', 'Zcaron', 'aacute',
-   'acircumflex', 'adieresis', 'agrave', 'aring', 'atilde', 'ccedilla',
-   'eacute', 'ecircumflex', 'edieresis', 'egrave', 'iacute', 'icircumflex',
-   'idieresis', 'igrave', 'ntilde', 'oacute', 'ocircumflex', 'odieresis',
-   'ograve', 'otilde', 'scaron', 'uacute', 'ucircumflex', 'udieresis',
-   'ugrave', 'yacute', 'ydieresis', 'zcaron'
- ];
++    nextEmptyChunk: function ChunkedStream_nextEmptyChunk(beginChunk) {
++      for (var chunk = beginChunk, n = this.numChunks; chunk < n; ++chunk) {
++        if (!(chunk in this.loadedChunks)) {
++          return chunk;
++        }
++      }
++      // Wrap around to beginning
++      for (var chunk = 0; chunk < beginChunk; ++chunk) {
++        if (!(chunk in this.loadedChunks)) {
++          return chunk;
++        }
++      }
++      return null;
++    },
 +
- var ExpertCharset = [
-   '.notdef', 'space', 'exclamsmall', 'Hungarumlautsmall', 'dollaroldstyle',
-   'dollarsuperior', 'ampersandsmall', 'Acutesmall', 'parenleftsuperior',
-   'parenrightsuperior', 'twodotenleader', 'onedotenleader', 'comma',
-   'hyphen', 'period', 'fraction', 'zerooldstyle', 'oneoldstyle',
-   'twooldstyle', 'threeoldstyle', 'fouroldstyle', 'fiveoldstyle',
-   'sixoldstyle', 'sevenoldstyle', 'eightoldstyle', 'nineoldstyle',
-   'colon', 'semicolon', 'commasuperior', 'threequartersemdash',
-   'periodsuperior', 'questionsmall', 'asuperior', 'bsuperior',
-   'centsuperior', 'dsuperior', 'esuperior', 'isuperior', 'lsuperior',
-   'msuperior', 'nsuperior', 'osuperior', 'rsuperior', 'ssuperior',
-   'tsuperior', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'parenleftinferior',
-   'parenrightinferior', 'Circumflexsmall', 'hyphensuperior', 'Gravesmall',
-   'Asmall', 'Bsmall', 'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall',
-   'Hsmall', 'Ismall', 'Jsmall', 'Ksmall', 'Lsmall', 'Msmall', 'Nsmall',
-   'Osmall', 'Psmall', 'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall',
-   'Vsmall', 'Wsmall', 'Xsmall', 'Ysmall', 'Zsmall', 'colonmonetary',
-   'onefitted', 'rupiah', 'Tildesmall', 'exclamdownsmall', 'centoldstyle',
-   'Lslashsmall', 'Scaronsmall', 'Zcaronsmall', 'Dieresissmall',
-   'Brevesmall', 'Caronsmall', 'Dotaccentsmall', 'Macronsmall',
-   'figuredash', 'hypheninferior', 'Ogoneksmall', 'Ringsmall',
-   'Cedillasmall', 'onequarter', 'onehalf', 'threequarters',
-   'questiondownsmall', 'oneeighth', 'threeeighths', 'fiveeighths',
-   'seveneighths', 'onethird', 'twothirds', 'zerosuperior', 'onesuperior',
-   'twosuperior', 'threesuperior', 'foursuperior', 'fivesuperior',
-   'sixsuperior', 'sevensuperior', 'eightsuperior', 'ninesuperior',
-   'zeroinferior', 'oneinferior', 'twoinferior', 'threeinferior',
-   'fourinferior', 'fiveinferior', 'sixinferior', 'seveninferior',
-   'eightinferior', 'nineinferior', 'centinferior', 'dollarinferior',
-   'periodinferior', 'commainferior', 'Agravesmall', 'Aacutesmall',
-   'Acircumflexsmall', 'Atildesmall', 'Adieresissmall', 'Aringsmall',
-   'AEsmall', 'Ccedillasmall', 'Egravesmall', 'Eacutesmall',
-   'Ecircumflexsmall', 'Edieresissmall', 'Igravesmall', 'Iacutesmall',
-   'Icircumflexsmall', 'Idieresissmall', 'Ethsmall', 'Ntildesmall',
-   'Ogravesmall', 'Oacutesmall', 'Ocircumflexsmall', 'Otildesmall',
-   'Odieresissmall', 'OEsmall', 'Oslashsmall', 'Ugravesmall', 'Uacutesmall',
-   'Ucircumflexsmall', 'Udieresissmall', 'Yacutesmall', 'Thornsmall',
-   'Ydieresissmall'
- ];
++    hasChunk: function ChunkedStream_hasChunk(chunk) {
++      return chunk in this.loadedChunks;
++    },
 +
- var ExpertSubsetCharset = [
-   '.notdef', 'space', 'dollaroldstyle', 'dollarsuperior',
-   'parenleftsuperior', 'parenrightsuperior', 'twodotenleader',
-   'onedotenleader', 'comma', 'hyphen', 'period', 'fraction',
-   'zerooldstyle', 'oneoldstyle', 'twooldstyle', 'threeoldstyle',
-   'fouroldstyle', 'fiveoldstyle', 'sixoldstyle', 'sevenoldstyle',
-   'eightoldstyle', 'nineoldstyle', 'colon', 'semicolon', 'commasuperior',
-   'threequartersemdash', 'periodsuperior', 'asuperior', 'bsuperior',
-   'centsuperior', 'dsuperior', 'esuperior', 'isuperior', 'lsuperior',
-   'msuperior', 'nsuperior', 'osuperior', 'rsuperior', 'ssuperior',
-   'tsuperior', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'parenleftinferior',
-   'parenrightinferior', 'hyphensuperior', 'colonmonetary', 'onefitted',
-   'rupiah', 'centoldstyle', 'figuredash', 'hypheninferior', 'onequarter',
-   'onehalf', 'threequarters', 'oneeighth', 'threeeighths', 'fiveeighths',
-   'seveneighths', 'onethird', 'twothirds', 'zerosuperior', 'onesuperior',
-   'twosuperior', 'threesuperior', 'foursuperior', 'fivesuperior',
-   'sixsuperior', 'sevensuperior', 'eightsuperior', 'ninesuperior',
-   'zeroinferior', 'oneinferior', 'twoinferior', 'threeinferior',
-   'fourinferior', 'fiveinferior', 'sixinferior', 'seveninferior',
-   'eightinferior', 'nineinferior', 'centinferior', 'dollarinferior',
-   'periodinferior', 'commainferior'
- ];
++    get length() {
++      return this.end - this.start;
++    },
 +
++    getByte: function ChunkedStream_getByte() {
++      var pos = this.pos;
++      if (pos >= this.end) {
++        return -1;
++      }
++      this.ensureRange(pos, pos + 1);
++      return this.bytes[this.pos++];
++    },
 +
++    // returns subarray of original buffer
++    // should only be read
++    getBytes: function ChunkedStream_getBytes(length) {
++      var bytes = this.bytes;
++      var pos = this.pos;
++      var strEnd = this.end;
 +
- 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}]
- };
++      if (!length) {
++        this.ensureRange(pos, strEnd);
++        return bytes.subarray(pos, strEnd);
++      }
++
++      var end = pos + length;
++      if (end > strEnd)
++        end = strEnd;
++      this.ensureRange(pos, end);
++
++      this.pos = end;
++      return bytes.subarray(pos, end);
++    },
++
++    peekBytes: function ChunkedStream_peekBytes(length) {
++      var bytes = this.getBytes(length);
++      this.pos -= bytes.length;
++      return bytes;
++    },
++
++    getByteRange: function ChunkedStream_getBytes(begin, end) {
++      this.ensureRange(begin, end);
++      return this.bytes.subarray(begin, end);
++    },
++
++    skip: function ChunkedStream_skip(n) {
++      if (!n)
++        n = 1;
++      this.pos += n;
++    },
++
++    reset: function ChunkedStream_reset() {
++      this.pos = this.start;
++    },
++
++    moveStart: function ChunkedStream_moveStart() {
++      this.start = this.pos;
++    },
++
++    makeSubStream: function ChunkedStream_makeSubStream(start, length, dict) {
++      function ChunkedStreamSubstream() {}
++      ChunkedStreamSubstream.prototype = Object.create(this);
++      ChunkedStreamSubstream.prototype.getMissingChunks = function() {
++        var chunkSize = this.chunkSize;
++        var beginChunk = Math.floor(this.start / chunkSize);
++        var endChunk = Math.floor((this.end - 1) / chunkSize) + 1;
++        var missingChunks = [];
++        for (var chunk = beginChunk; chunk < endChunk; ++chunk) {
++          if (!(chunk in this.loadedChunks)) {
++            missingChunks.push(chunk);
++          }
++        }
++        return missingChunks;
++      };
++      var subStream = new ChunkedStreamSubstream();
++      subStream.pos = subStream.start = start;
++      subStream.end = start + length || this.end;
++      subStream.dict = dict;
++      return subStream;
++    },
++
++    isStream: true
++  };
++
++  return ChunkedStream;
++})();
++
++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;
++    this.url = url;
++    this.disableAutoFetch = args.disableAutoFetch;
++    var msgHandler = this.msgHandler = args.msgHandler;
++
++    if (args.chunkedViewerLoading) {
++      msgHandler.on('OnDataRange', this.onReceiveData.bind(this));
++      msgHandler.on('OnDataProgress', this.onProgress.bind(this));
++      this.sendRequest = function ChunkedStreamManager_sendRequest(begin, end) {
++        msgHandler.send('RequestDataRange', { begin: begin, end: end });
++      };
++    } else {
++
++      var getXhr = function getXhr() {
++        return new XMLHttpRequest();
++      };
++      this.networkManager = new NetworkManager(this.url, {
++        getXhr: getXhr,
++        httpHeaders: args.httpHeaders,
++        withCredentials: args.withCredentials
++      });
++      this.sendRequest = function ChunkedStreamManager_sendRequest(begin, end) {
++        this.networkManager.requestRange(begin, end, {
++          onDone: this.onReceiveData.bind(this),
++          onProgress: this.onProgress.bind(this)
++        });
++      };
++    }
++
++    this.currRequestId = 0;
++
++    this.chunksNeededByRequest = {};
++    this.requestsByChunk = {};
++    this.callbacksByRequest = {};
++
++    this.loadedStream = new LegacyPromise();
++    if (args.initialData) {
++      this.setInitialData(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;
++    },
++
++    // Get all the chunks that are not yet loaded and groups them into
++    // contiguous ranges to load in as few requests as possible
++    requestAllChunks: function ChunkedStreamManager_requestAllChunks() {
++      var missingChunks = this.stream.getMissingChunks();
++      this.requestChunks(missingChunks);
++      return this.loadedStream;
++    },
++
++    requestChunks: function ChunkedStreamManager_requestChunks(chunks,
++                                                               callback) {
++      var requestId = this.currRequestId++;
++
++      var chunksNeeded;
++      this.chunksNeededByRequest[requestId] = chunksNeeded = {};
++      for (var i = 0, ii = chunks.length; i < ii; i++) {
++        if (!this.stream.hasChunk(chunks[i])) {
++          chunksNeeded[chunks[i]] = true;
++        }
++      }
++
++      if (isEmptyObj(chunksNeeded)) {
++        if (callback) {
++          callback();
++        }
++        return;
++      }
++
++      this.callbacksByRequest[requestId] = callback;
++
++      var chunksToRequest = [];
++      for (var chunk in chunksNeeded) {
++        chunk = chunk | 0;
++        if (!(chunk in this.requestsByChunk)) {
++          this.requestsByChunk[chunk] = [];
++          chunksToRequest.push(chunk);
++        }
++        this.requestsByChunk[chunk].push(requestId);
++      }
++
++      if (!chunksToRequest.length) {
++        return;
++      }
++
++      var groupedChunksToRequest = this.groupChunks(chunksToRequest);
++
++      for (var 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);
++        this.sendRequest(begin, end);
++      }
++    },
++
++    getStream: function ChunkedStreamManager_getStream() {
++      return this.stream;
++    },
++
++    // Loads any chunks in the requested range that are not yet loaded
++    requestRange: function ChunkedStreamManager_requestRange(
++                      begin, end, callback) {
++
++      end = Math.min(end, this.length);
++
++      var beginChunk = this.getBeginChunk(begin);
++      var endChunk = this.getEndChunk(end);
++
++      var chunks = [];
++      for (var chunk = beginChunk; chunk < endChunk; ++chunk) {
++        chunks.push(chunk);
++      }
++
++      this.requestChunks(chunks, callback);
++    },
++
++    requestRanges: function ChunkedStreamManager_requestRanges(ranges,
++                                                               callback) {
++      ranges = ranges || [];
++      var chunksToRequest = [];
++
++      for (var i = 0; i < ranges.length; i++) {
++        var beginChunk = this.getBeginChunk(ranges[i].begin);
++        var endChunk = this.getEndChunk(ranges[i].end);
++        for (var chunk = beginChunk; chunk < endChunk; ++chunk) {
++          if (chunksToRequest.indexOf(chunk) < 0) {
++            chunksToRequest.push(chunk);
++          }
++        }
++      }
++
++      chunksToRequest.sort(function(a, b) { return a - b; });
++      this.requestChunks(chunksToRequest, callback);
++    },
++
++    // Groups a sorted array of chunks into as few continguous larger
++    // chunks as possible
++    groupChunks: function ChunkedStreamManager_groupChunks(chunks) {
++      var groupedChunks = [];
++      var beginChunk = -1;
++      var prevChunk = -1;
++      for (var i = 0; i < chunks.length; ++i) {
++        var chunk = chunks[i];
++
++        if (beginChunk < 0) {
++          beginChunk = chunk;
++        }
++
++        if (prevChunk >= 0 && prevChunk + 1 !== chunk) {
++          groupedChunks.push({
++            beginChunk: beginChunk, endChunk: prevChunk + 1});
++          beginChunk = chunk;
++        }
++        if (i + 1 === chunks.length) {
++          groupedChunks.push({
++            beginChunk: beginChunk, endChunk: chunk + 1});
++        }
++
++        prevChunk = chunk;
++      }
++      return groupedChunks;
++    },
++
++    onProgress: function ChunkedStreamManager_onProgress(args) {
++      var bytesLoaded = this.stream.numChunksLoaded * this.chunkSize +
++                        args.loaded;
++      this.msgHandler.send('DocProgress', {
++        loaded: bytesLoaded,
++        total: this.length
++      });
++    },
++
++    onReceiveData: function ChunkedStreamManager_onReceiveData(args) {
++      var chunk = args.chunk;
++      var begin = args.begin;
++      var end = begin + chunk.byteLength;
++
++      var beginChunk = this.getBeginChunk(begin);
++      var endChunk = this.getEndChunk(end);
++
++      this.stream.onReceiveData(begin, chunk);
++      if (this.stream.allChunksLoaded()) {
++        this.loadedStream.resolve(this.stream);
++      }
++
++      var loadedRequests = [];
++      for (var 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];
++          var chunksNeeded = this.chunksNeededByRequest[requestId];
++          if (chunk in chunksNeeded) {
++            delete chunksNeeded[chunk];
++          }
++
++          if (!isEmptyObj(chunksNeeded)) {
++            continue;
++          }
++
++          loadedRequests.push(requestId);
++        }
++      }
++
++      // If there are no pending requests, automatically fetch the next
++      // unfetched chunk of the PDF
++      if (!this.disableAutoFetch && isEmptyObj(this.requestsByChunk)) {
++        var nextEmptyChunk;
++        if (this.stream.numChunksLoaded === 1) {
++          // This is a special optimization so that after fetching the first
++          // chunk, rather than fetching the second chunk, we fetch the last
++          // chunk.
++          var lastChunk = this.stream.numChunks - 1;
++          if (!this.stream.hasChunk(lastChunk)) {
++            nextEmptyChunk = lastChunk;
++          }
++        } else {
++          nextEmptyChunk = this.stream.nextEmptyChunk(endChunk);
++        }
++        if (isInt(nextEmptyChunk)) {
++          this.requestChunks([nextEmptyChunk]);
++        }
++      }
++
++      for (var i = 0; i < loadedRequests.length; ++i) {
++        var requestId = loadedRequests[i];
++        var callback = this.callbacksByRequest[requestId];
++        delete this.callbacksByRequest[requestId];
++        if (callback) {
++          callback();
++        }
++      }
++
++      this.msgHandler.send('DocProgress', {
++        loaded: this.stream.numChunksLoaded * this.chunkSize,
++        total: this.length
++      });
++    },
++
++    getBeginChunk: function ChunkedStreamManager_getBeginChunk(begin) {
++      var chunk = Math.floor(begin / this.chunkSize);
++      return chunk;
++    },
++
++    getEndChunk: function ChunkedStreamManager_getEndChunk(end) {
++      if (end % this.chunkSize === 0) {
++        return end / this.chunkSize;
++      }
++
++      // 0 -> 0
++      // 1 -> 1
++      // 99 -> 1
++      // 100 -> 1
++      // 101 -> 2
++      var chunk = Math.floor((end - 1) / this.chunkSize) + 1;
++      return chunk;
++    }
++  };
++
++  return ChunkedStreamManager;
++})();
++
++
++
++// 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() {
++    throw new Error('Cannot initialize BaseManagerManager');
++  }
++
++  BasePdfManager.prototype = {
++    onLoadedStream: function BasePdfManager_onLoadedStream() {
++      throw new NotImplementedException();
++    },
++
++    ensureModel: function BasePdfManager_ensureModel(prop, args) {
++      return this.ensure(this.pdfModel, prop, args);
++    },
++
++    ensureXRef: function BasePdfManager_ensureXRef(prop, args) {
++      return this.ensure(this.pdfModel.xref, prop, args);
++    },
++
++    ensureCatalog: function BasePdfManager_ensureCatalog(prop, args) {
++      return this.ensure(this.pdfModel.catalog, prop, args);
++    },
++
++    getPage: function BasePdfManager_pagePage(pageIndex) {
++      return this.pdfModel.getPage(pageIndex);
++    },
++
++    cleanup: function BasePdfManager_cleanup() {
++      return this.pdfModel.cleanup();
++    },
++
++    ensure: function BasePdfManager_ensure(obj, prop, args) {
++      return new NotImplementedException();
++    },
++
++    requestRange: function BasePdfManager_ensure(begin, end) {
++      return new NotImplementedException();
++    },
++
++    requestLoadedStream: function BasePdfManager_requestLoadedStream() {
++      return new NotImplementedException();
++    },
++
++    updatePassword: function BasePdfManager_updatePassword(password) {
++      this.pdfModel.xref.password = this.password = password;
++      if (this.passwordChangedPromise) {
++        this.passwordChangedPromise.resolve();
++      }
++    },
++
++    terminate: function BasePdfManager_terminate() {
++      return new NotImplementedException();
++    }
++  };
++
++  return BasePdfManager;
++})();
++
++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);
++  }
++
++  LocalPdfManager.prototype = Object.create(BasePdfManager.prototype);
++  LocalPdfManager.prototype.constructor = LocalPdfManager;
++
++  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;
++      }
++      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;
++  };
++
++  LocalPdfManager.prototype.requestLoadedStream =
++      function LocalPdfManager_requestLoadedStream() {
++  };
++
++  LocalPdfManager.prototype.onLoadedStream =
++      function LocalPdfManager_getLoadedStream() {
++    return this.loadedStream;
++  };
++
++  LocalPdfManager.prototype.terminate =
++      function LocalPdfManager_terminate() {
++    return;
++  };
++
++  return LocalPdfManager;
++})();
++
++var NetworkPdfManager = (function NetworkPdfManagerClosure() {
++  function NetworkPdfManager(args, msgHandler) {
++
++    this.msgHandler = msgHandler;
++
++    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, RANGE_CHUNK_SIZE,
++                                                  args.url, params);
++
++    this.pdfModel = new PDFDocument(this, this.streamManager.getStream(),
++                                    args.password);
++  }
++
++  NetworkPdfManager.prototype = Object.create(BasePdfManager.prototype);
++  NetworkPdfManager.prototype.constructor = NetworkPdfManager;
++
++  NetworkPdfManager.prototype.ensure =
++      function NetworkPdfManager_ensure(obj, prop, args) {
++    var promise = new LegacyPromise();
++    this.ensureHelper(promise, obj, prop, args);
++    return promise;
++  };
++
++  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;
++      }
++
++      this.streamManager.requestRange(e.begin, e.end, function() {
++        this.ensureHelper(promise, obj, prop, args);
++      }.bind(this));
++    }
++  };
++
++  NetworkPdfManager.prototype.requestRange =
++      function NetworkPdfManager_requestRange(begin, end) {
++    var promise = new LegacyPromise();
++    this.streamManager.requestRange(begin, end, function() {
++      promise.resolve();
++    });
++    return promise;
++  };
++
++  NetworkPdfManager.prototype.requestLoadedStream =
++      function NetworkPdfManager_requestLoadedStream() {
++    this.streamManager.requestAllChunks();
++  };
++
++  NetworkPdfManager.prototype.onLoadedStream =
++      function NetworkPdfManager_getLoadedStream() {
++    return this.streamManager.onLoadedStream();
++  };
++
++  NetworkPdfManager.prototype.terminate =
++      function NetworkPdfManager_terminate() {
++    this.streamManager.networkManager.abortAllRequests();
++  };
++
++  return NetworkPdfManager;
++})();
++
++
++
++var Page = (function PageClosure() {
++
++  function Page(pdfManager, xref, pageIndex, pageDict, ref, fontCache) {
++    this.pdfManager = pdfManager;
++    this.pageIndex = pageIndex;
++    this.pageDict = pageDict;
++    this.xref = xref;
++    this.ref = ref;
++    this.fontCache = fontCache;
++    this.idCounters = {
++      obj: 0
++    };
++    this.resourcesPromise = null;
++  }
++
++  Page.prototype = {
++    getPageProp: function Page_getPageProp(key) {
++      return this.pageDict.get(key);
++    },
++    inheritPageProp: function Page_inheritPageProp(key) {
++      var dict = this.pageDict;
++      var obj = dict.get(key);
++      while (obj === undefined) {
++        dict = dict.get('Parent');
++        if (!dict)
++          break;
++        obj = dict.get(key);
++      }
++      return obj;
++    },
++    get content() {
++      return this.getPageProp('Contents');
++    },
++    get resources() {
++      return shadow(this, 'resources', this.inheritPageProp('Resources'));
++    },
++    get mediaBox() {
++      var obj = this.inheritPageProp('MediaBox');
++      // Reset invalid media box to letter size.
++      if (!isArray(obj) || obj.length !== 4)
++        obj = [0, 0, 612, 792];
++      return shadow(this, 'mediaBox', obj);
++    },
++    get view() {
++      var mediaBox = this.mediaBox;
++      var cropBox = this.inheritPageProp('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)
++        return shadow(this, 'view', mediaBox);
++
++      return shadow(this, 'view', cropBox);
++    },
++    get annotationRefs() {
++      return shadow(this, 'annotationRefs', this.inheritPageProp('Annots'));
++    },
++    get rotate() {
++      var rotate = this.inheritPageProp('Rotate') || 0;
++      // Normalize rotation so it's a multiple of 90 and between 0 and 270
++      if (rotate % 90 !== 0) {
++        rotate = 0;
++      } else if (rotate >= 360) {
++        rotate = rotate % 360;
++      } else if (rotate < 0) {
++        // The spec doesn't cover negatives, assume its counterclockwise
++        // rotation. The following is the other implementation of modulo.
++        rotate = ((rotate % 360) + 360) % 360;
++      }
++      return shadow(this, 'rotate', rotate);
++    },
++    getContentStream: function Page_getContentStream() {
++      var content = this.content;
++      var stream;
++      if (isArray(content)) {
++        // fetching items
++        var xref = this.xref;
++        var i, n = content.length;
++        var streams = [];
++        for (i = 0; i < n; ++i)
++          streams.push(xref.fetchIfRef(content[i]));
++        stream = new StreamsSequenceStream(streams);
++      } else if (isStream(content)) {
++        stream = content;
++      } else {
++        // replacing non-existent page content with empty one
++        stream = new NullStream();
++      }
++      return stream;
++    },
++    loadResources: function(keys) {
++      if (!this.resourcesPromise) {
++        // TODO: add async inheritPageProp and remove this.
++        this.resourcesPromise = this.pdfManager.ensure(this, 'resources');
++      }
++      var promise = new LegacyPromise();
++      this.resourcesPromise.then(function resourceSuccess() {
++        var objectLoader = new ObjectLoader(this.resources.map,
++                                            keys,
++                                            this.xref);
++        objectLoader.load().then(function objectLoaderSuccess() {
++          promise.resolve();
++        });
++      }.bind(this));
++      return promise;
++    },
++    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',
++                                                   []);
++      var resourcesPromise = this.loadResources([
++        'ExtGState',
++        'ColorSpace',
++        'Pattern',
++        'Shading',
++        'XObject',
++        'Font',
++        // ProcSet
++        // Properties
++      ]);
++
++      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 contentStream = data[0];
++
++
++        var opList = new OperatorList(intent, handler, self.pageIndex);
++
++        handler.send('StartRenderPage', {
++          transparency: partialEvaluator.hasBlendModes(self.resources),
++          pageIndex: self.pageIndex,
++          intent: intent
++        });
++        partialEvaluator.getOperatorList(contentStream, self.resources, opList);
++        pageListPromise.resolve(opList);
++      });
++
++      var annotationsPromise = pdfManager.ensure(this, 'annotations');
++      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;
++        }
++
++        var annotationsReadyPromise = Annotation.appendToOperatorList(
++          annotations, pageOpList, pdfManager, partialEvaluator, intent);
++        annotationsReadyPromise.then(function () {
++          pageOpList.flush(true);
++          promise.resolve(pageOpList);
++        }, reject);
++      }, reject);
++
++      return promise;
++    },
++    extractTextContent: function Page_extractTextContent() {
++      var handler = {
++        on: function nullHandlerOn() {},
++        send: function nullHandlerSend() {}
++      };
++
++      var self = this;
++
++      var textContentPromise = new LegacyPromise();
++
++      var pdfManager = this.pdfManager;
++      var contentStreamPromise = pdfManager.ensure(this, 'getContentStream',
++                                                   []);
++
++      var resourcesPromise = this.loadResources([
++        'ExtGState',
++        'XObject',
++        'Font'
++      ]);
++
++      var dataPromises = Promise.all([contentStreamPromise,
++                                      resourcesPromise]);
++      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 bidiTexts = partialEvaluator.getTextContent(contentStream,
++                                                        self.resources);
++        textContentPromise.resolve(bidiTexts);
++      });
++
++      return textContentPromise;
++    },
++
++    getAnnotationsData: function Page_getAnnotationsData() {
++      var annotations = this.annotations;
++      var annotationsData = [];
++      for (var i = 0, n = annotations.length; i < n; ++i) {
++        annotationsData.push(annotations[i].getData());
++      }
++      return annotationsData;
++    },
++
++    get annotations() {
++      var annotations = [];
++      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);
++        if (annotation) {
++          annotations.push(annotation);
++        }
++      }
++      return shadow(this, 'annotations', annotations);
++    }
++  };
++
++  return Page;
++})();
++
++/**
++ * The `PDFDocument` holds all the data of the PDF file. Compared to the
++ * `PDFDoc`, this one doesn't have any job management code.
++ * Right now there exists one PDFDocument on the main thread + one object
++ * for each worker. If there is no worker support enabled, there are two
++ * `PDFDocument` objects on the main thread created.
++ */
++var PDFDocument = (function PDFDocumentClosure() {
++  function PDFDocument(pdfManager, arg, password) {
++    if (isStream(arg))
++      init.call(this, pdfManager, arg, password);
++    else if (isArrayBuffer(arg))
++      init.call(this, pdfManager, new Stream(arg), password);
++    else
++      error('PDFDocument: Unknown argument type');
++  }
++
++  function init(pdfManager, stream, password) {
++    assertWellFormed(stream.length > 0, 'stream must have data');
++    this.pdfManager = pdfManager;
++    this.stream = stream;
++    var xref = new XRef(this.stream, password, pdfManager);
++    this.xref = xref;
++  }
++
++  function find(stream, needle, limit, backwards) {
++    var pos = stream.pos;
++    var end = stream.end;
++    var strBuf = [];
++    if (pos + limit > end)
++      limit = end - pos;
++    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)
++      return false; /* not found */
++    stream.pos += index;
++    return true; /* found */
++  }
++
++  var DocumentInfoValidators = {
++    get entries() {
++      // Lazily build this since all the validation functions below are not
++      // defined until after this file loads.
++      return shadow(this, 'entries', {
++        Title: isString,
++        Author: isString,
++        Subject: isString,
++        Keywords: isString,
++        Creator: isString,
++        Producer: isString,
++        CreationDate: isString,
++        ModDate: isString,
++        Trapped: isName
++      });
++    }
++  };
++
++  PDFDocument.prototype = {
++    parse: function PDFDocument_parse(recoveryMode) {
++      this.setup(recoveryMode);
++      try {
++        // checking if AcroForm is present
++        this.acroForm = this.catalog.catDict.get('AcroForm');
++        if (this.acroForm) {
++          this.xfa = this.acroForm.get('XFA');
++          var fields = this.acroForm.get('Fields');
++          if ((!fields || !isArray(fields) || fields.length === 0) &&
++              !this.xfa) {
++            // no fields and no XFA -- not a form (?)
++            this.acroForm = null;
++          }
++        }
++      } catch (ex) {
++        info('Something wrong with AcroForm entry');
++        this.acroForm = null;
++      }
++    },
++
++    get linearization() {
++      var length = this.stream.length;
++      var linearization = false;
++      if (length) {
++        try {
++          linearization = new Linearization(this.stream);
++          if (linearization.length != length) {
++            linearization = false;
++          }
++        } catch (err) {
++          if (err instanceof MissingDataException) {
++            throw err;
++          }
++
++          info('The linearization data is not available ' +
++               'or unreadable PDF data is found');
++          linearization = false;
++        }
++      }
++      // shadow the prototype getter with a data property
++      return shadow(this, 'linearization', linearization);
++    },
++    get startXRef() {
++      var stream = this.stream;
++      var startXRef = 0;
++      var linearization = this.linearization;
++      if (linearization) {
++        // Find end of first obj.
++        stream.reset();
++        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)
++            pos = 0;
++          stream.pos = pos;
++          found = find(stream, 'startxref', step, true);
++        }
++        if (found) {
++          stream.skip(9);
++          var ch;
++          do {
++            ch = stream.getByte();
++          } while (Lexer.isSpace(ch));
++          var str = '';
++          while (ch >= 0x20 && ch <= 0x39) { // < '9'
++            str += String.fromCharCode(ch);
++            ch = stream.getByte();
++          }
++          startXRef = parseInt(str, 10);
++          if (isNaN(startXRef))
++            startXRef = 0;
++        }
++      }
++      // shadow the prototype getter with a data property
++      return shadow(this, 'startXRef', startXRef);
++    },
++    get mainXRefEntriesOffset() {
++      var mainXRefEntriesOffset = 0;
++      var linearization = this.linearization;
++      if (linearization)
++        mainXRefEntriesOffset = linearization.mainXRefEntriesOffset;
++      // shadow the prototype getter with a data property
++      return shadow(this, 'mainXRefEntriesOffset', mainXRefEntriesOffset);
++    },
++    // Find the header, remove leading garbage and setup the stream
++    // starting from the header.
++    checkHeader: function PDFDocument_checkHeader() {
++      var stream = this.stream;
++      stream.reset();
++      if (find(stream, '%PDF-', 1024)) {
++        // Found the header, trim off any garbage before it.
++        stream.moveStart();
++        // Reading file format version
++        var MAX_VERSION_LENGTH = 12;
++        var version = '', ch;
++        while ((ch = stream.getByte()) > 0x20) { // SPACE
++          if (version.length >= MAX_VERSION_LENGTH) {
++            break;
++          }
++          version += String.fromCharCode(ch);
++        }
++        // removing "%PDF-"-prefix
++        this.pdfFormatVersion = version.substring(5);
++        return;
++      }
++      // May not be a PDF file, continue anyway.
++    },
++    parseStartXRef: function PDFDocument_parseStartXRef() {
++      var startXRef = this.startXRef;
++      this.xref.setStartXRef(startXRef);
++    },
++    setup: function PDFDocument_setup(recoveryMode) {
++      this.xref.parse(recoveryMode);
++      this.catalog = new Catalog(this.pdfManager, this.xref);
++    },
++    get numPages() {
++      var linearization = this.linearization;
++      var num = linearization ? linearization.numPages : this.catalog.numPages;
++      // shadow the prototype getter
++      return shadow(this, 'numPages', num);
++    },
++    get documentInfo() {
++      var docInfo = {
++        PDFFormatVersion: this.pdfFormatVersion,
++        IsAcroFormPresent: !!this.acroForm,
++        IsXFAPresent: !!this.xfa
++      };
++      var infoDict;
++      try {
++        infoDict = this.xref.trailer.get('Info');
++      } catch (err) {
++        info('The document information dictionary is invalid.');
++      }
++      if (infoDict) {
++        var validEntries = DocumentInfoValidators.entries;
++        // Only fill the document info with valid entries from the spec.
++        for (var key in validEntries) {
++          if (infoDict.has(key)) {
++            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);
++            } else {
++              info('Bad value in document info for "' + key + '"');
++            }
++          }
++        }
++      }
++      return shadow(this, 'documentInfo', docInfo);
++    },
++    get fingerprint() {
++      var xref = this.xref, hash, fileID = '';
++
++      if (xref.trailer.has('ID')) {
++        hash = stringToBytes(xref.trailer.get('ID')[0]);
++      } else {
++        hash = calculateMD5(this.stream.bytes.subarray(0, 100), 0, 100);
++      }
++
++      for (var i = 0, n = hash.length; i < n; i++) {
++        fileID += hash[i].toString(16);
++      }
++
++      return shadow(this, 'fingerprint', fileID);
++    },
++
++    getPage: function PDFDocument_getPage(pageIndex) {
++      return this.catalog.getPage(pageIndex);
++    },
++
++    cleanup: function PDFDocument_cleanup() {
++      return this.catalog.cleanup();
++    }
++  };
++
++  return PDFDocument;
++})();
++
++
++
++var Name = (function NameClosure() {
++  function Name(name) {
++    this.name = name;
++  }
++
++  Name.prototype = {};
++
++  var nameCache = {};
++
++  Name.get = function Name_get(name) {
++    var nameValue = nameCache[name];
++    return nameValue ? nameValue : (nameCache[name] = new Name(name));
++  };
++
++  return Name;
++})();
++
++var Cmd = (function CmdClosure() {
++  function Cmd(cmd) {
++    this.cmd = cmd;
++  }
++
++  Cmd.prototype = {};
++
++  var cmdCache = {};
++
++  Cmd.get = function Cmd_get(cmd) {
++    var cmdValue = cmdCache[cmd];
++    return cmdValue ? cmdValue : (cmdCache[cmd] = new Cmd(cmd));
++  };
++
++  return Cmd;
++})();
++
++var Dict = (function DictClosure() {
++  var nonSerializable = function nonSerializableClosure() {
++    return nonSerializable; // creating closure on some variable
++  };
++
++  // 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.__nonSerializable__ = nonSerializable; // disable cloning of the Dict
++  }
++
++  Dict.prototype = {
++    assignXref: function Dict_assignXref(newXref) {
++      this.xref = newXref;
++    },
++
++    // automatically dereferences Ref objects
++    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') {
++        return xref ? xref.fetchIfRef(value) : value;
++      }
++      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;
++      return xref ? xref.fetchIfRef(value) : value;
++    },
++
++    // 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 (xref) {
++          return xref.fetchIfRefAsync(value);
++        }
++        promise = new LegacyPromise();
++        promise.resolve(value);
++        return promise;
++      }
++      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;
++      }
++      value = this.map[key3] || null;
++      if (xref) {
++        return xref.fetchIfRefAsync(value);
++      }
++      promise = new LegacyPromise();
++      promise.resolve(value);
++      return promise;
++    },
++
++    // no dereferencing
++    getRaw: function Dict_getRaw(key) {
++      return this.map[key];
++    },
++
++    // 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;
++      }
++      return all;
++    },
++
++    set: function Dict_set(key, value) {
++      this.map[key] = value;
++    },
++
++    has: function Dict_has(key) {
++      return key in this.map;
++    },
++
++    forEach: function Dict_forEach(callback) {
++      for (var key in this.map) {
++        callback(key, this.get(key));
++      }
++    }
++  };
++
++  return Dict;
++})();
++
++var Ref = (function RefClosure() {
++  function Ref(num, gen) {
++    this.num = num;
++    this.gen = gen;
++  }
++
++  Ref.prototype = {};
++
++  return Ref;
++})();
++
++// 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 = {};
++  }
++
++  RefSet.prototype = {
++    has: function RefSet_has(ref) {
++      return ('R' + ref.num + '.' + ref.gen) in this.dict;
++    },
++
++    put: function RefSet_put(ref) {
++      this.dict['R' + ref.num + '.' + ref.gen] = true;
++    },
++
++    remove: function RefSet_remove(ref) {
++      delete this.dict['R' + ref.num + '.' + ref.gen];
++    }
++  };
++
++  return RefSet;
++})();
++
++var RefSetCache = (function RefSetCacheClosure() {
++  function RefSetCache() {
++    this.dict = Object.create(null);
++  }
++
++  RefSetCache.prototype = {
++    get: function RefSetCache_get(ref) {
++      return this.dict['R' + ref.num + '.' + ref.gen];
++    },
++
++    has: function RefSetCache_has(ref) {
++      return ('R' + ref.num + '.' + ref.gen) in this.dict;
++    },
++
++    put: function RefSetCache_put(ref, obj) {
++      this.dict['R' + ref.num + '.' + ref.gen] = obj;
++    },
++
++    forEach: function RefSetCache_forEach(fn, thisArg) {
++      for (var i in this.dict) {
++        fn.call(thisArg, this.dict[i]);
++      }
++    },
++
++    clear: function RefSetCache_clear() {
++      this.dict = Object.create(null);
++    }
++  };
++
++  return RefSetCache;
++})();
++
++var Catalog = (function CatalogClosure() {
++  function Catalog(pdfManager, xref) {
++    this.pdfManager = pdfManager;
++    this.xref = xref;
++    this.catDict = xref.getCatalogObj();
++    this.fontCache = new RefSetCache();
++    assertWellFormed(isDict(this.catDict),
++      'catalog object is not a dictionary');
++
++    this.pagePromises = [];
++  }
++
++  Catalog.prototype = {
++    get metadata() {
++      var streamRef = this.catDict.getRaw('Metadata');
++      if (!isRef(streamRef)) {
++        return shadow(this, 'metadata', null);
++      }
++
++      var encryptMetadata = !this.xref.encrypt ? false :
++        this.xref.encrypt.encryptMetadata;
++
++      var stream = this.xref.fetch(streamRef, !encryptMetadata);
++      var metadata;
++      if (stream && isDict(stream.dict)) {
++        var type = stream.dict.get('Type');
++        var subtype = stream.dict.get('Subtype');
++
++        if (isName(type) && isName(subtype) &&
++            type.name === 'Metadata' && subtype.name === 'XML') {
++          // XXX: This should examine the charset the XML document defines,
++          // however since there are currently no real means to decode
++          // arbitrary charsets, let's just hope that the author of the PDF
++          // was reasonable enough to stick with the XML default charset,
++          // which is UTF-8.
++          try {
++            metadata = stringToUTF8String(bytesToString(stream.getBytes()));
++          } catch (e) {
++            info('Skipping invalid metadata.');
++          }
++        }
++      }
++
++      return shadow(this, 'metadata', metadata);
++    },
++    get toplevelPagesDict() {
++      var pagesObj = this.catDict.get('Pages');
++      assertWellFormed(isDict(pagesObj), 'invalid top-level pages dictionary');
++      // shadow the prototype getter
++      return shadow(this, 'toplevelPagesDict', pagesObj);
++    },
++    get documentOutline() {
++      var obj = null;
++      try {
++        obj = this.readDocumentOutline();
++      } catch (ex) {
++        if (ex instanceof MissingDataException) {
++          throw ex;
++        }
++        warn('Unable to read document outline');
++      }
++      return shadow(this, 'documentOutline', obj);
++    },
++    readDocumentOutline: function Catalog_readDocumentOutline() {
++      var xref = this.xref;
++      var obj = this.catDict.get('Outlines');
++      var root = { items: [] };
++      if (isDict(obj)) {
++        obj = obj.getRaw('First');
++        var processed = new RefSet();
++        if (isRef(obj)) {
++          var queue = [{obj: obj, parent: root}];
++          // to avoid recursion keeping track of the items
++          // in the processed dictionary
++          processed.put(obj);
++          while (queue.length > 0) {
++            var i = queue.shift();
++            var outlineDict = xref.fetchIfRef(i.obj);
++            if (outlineDict === null) {
++              continue;
++            }
++            if (!outlineDict.has('Title')) {
++              error('Invalid outline item');
++            }
++            var dest = outlineDict.get('A');
++            if (dest) {
++              dest = dest.get('D');
++            } else if (outlineDict.has('Dest')) {
++              dest = outlineDict.getRaw('Dest');
++              if (isName(dest)) {
++                dest = dest.name;
++              }
++            }
++            var title = outlineDict.get('Title');
++            var outlineItem = {
++              dest: dest,
++              title: stringToPDFString(title),
++              color: outlineDict.get('C') || [0, 0, 0],
++              count: outlineDict.get('Count'),
++              bold: !!(outlineDict.get('F') & 2),
++              italic: !!(outlineDict.get('F') & 1),
++              items: []
++            };
++            i.parent.items.push(outlineItem);
++            obj = outlineDict.getRaw('First');
++            if (isRef(obj) && !processed.has(obj)) {
++              queue.push({obj: obj, parent: outlineItem});
++              processed.put(obj);
++            }
++            obj = outlineDict.getRaw('Next');
++            if (isRef(obj) && !processed.has(obj)) {
++              queue.push({obj: obj, parent: i.parent});
++              processed.put(obj);
++            }
++          }
++        }
++      }
++      return root.items.length > 0 ? root.items : null;
++    },
++    get numPages() {
++      var obj = this.toplevelPagesDict.get('Count');
++      assertWellFormed(
++        isInt(obj),
++        'page count in top level pages object is not an integer'
++      );
++      // shadow the prototype getter
++      return shadow(this, 'num', obj);
++    },
++    get destinations() {
++      function fetchDestination(dest) {
++        return isDict(dest) ? dest.get('D') : dest;
++      }
++
++      var xref = this.xref;
++      var dests = {}, nameTreeRef, nameDictionaryRef;
++      var obj = this.catDict.get('Names');
++      if (obj) {
++        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;
++          }
++          dests[key] = fetchDestination(value);
++        });
++      }
++      if (nameTreeRef) {
++        var nameTree = new NameTree(nameTreeRef, xref);
++        var names = nameTree.getAll();
++        for (var name in names) {
++          if (!names.hasOwnProperty(name)) {
++            continue;
++          }
++          dests[name] = fetchDestination(names[name]);
++        }
++      }
++      return shadow(this, 'destinations', dests);
++    },
++    get javaScript() {
++      var xref = this.xref;
++      var obj = this.catDict.get('Names');
++
++      var javaScript = [];
++      if (obj && obj.has('JavaScript')) {
++        var nameTree = new NameTree(obj.getRaw('JavaScript'), xref);
++        var names = nameTree.getAll();
++        for (var name in names) {
++          if (!names.hasOwnProperty(name)) {
++            continue;
++          }
++          // We don't really use the JavaScript right now so this code is
++          // defensive so we don't cause errors on document load.
++          var jsDict = names[name];
++          if (!isDict(jsDict)) {
++            continue;
++          }
++          var type = jsDict.get('S');
++          if (!isName(type) || type.name !== 'JavaScript') {
++            continue;
++          }
++          var js = jsDict.get('JS');
++          if (!isString(js) && !isStream(js)) {
++            continue;
++          }
++          if (isStream(js)) {
++            js = bytesToString(js.getBytes());
++          }
++          javaScript.push(stringToPDFString(js));
++        }
++      }
++      return shadow(this, 'javaScript', javaScript);
++    },
++
++    cleanup: function Catalog_cleanup() {
++      this.fontCache.forEach(function (font) {
++        delete font.sent;
++        delete font.translated;
++      });
++      this.fontCache.clear();
++    },
++
++    getPage: function Catalog_getPage(pageIndex) {
++      if (!(pageIndex in this.pagePromises)) {
++        this.pagePromises[pageIndex] = this.getPageDict(pageIndex).then(
++          function (a) {
++            var dict = a[0];
++            var ref = a[1];
++            return new Page(this.pdfManager, this.xref, pageIndex, dict, ref,
++                            this.fontCache);
++          }.bind(this)
++        );
++      }
++      return this.pagePromises[pageIndex];
++    },
++
++    getPageDict: function Catalog_getPageDict(pageIndex) {
++      var promise = new LegacyPromise();
++      var nodesToVisit = [this.catDict.getRaw('Pages')];
++      var currentPageIndex = 0;
++      var xref = this.xref;
++
++      function next() {
++        while (nodesToVisit.length) {
++          var currentNode = nodesToVisit.pop();
++
++          if (isRef(currentNode)) {
++            xref.fetchAsync(currentNode).then(function (obj) {
++              if ((isDict(obj, 'Page') || (isDict(obj) && !obj.has('Kids')))) {
++                if (pageIndex === currentPageIndex) {
++                  promise.resolve([obj, currentNode]);
++                } else {
++                  currentPageIndex++;
++                  next();
++                }
++                return;
++              }
++              nodesToVisit.push(obj);
++              next();
++            }.bind(this), promise.reject.bind(promise));
++            return;
++          }
++
++          // must be a child page dictionary
++          assert(
++            isDict(currentNode),
++            'page dictionary kid reference points to wrong type of object'
++          );
++          var count = currentNode.get('Count');
++          // Skip nodes where the page can't be.
++          if (currentPageIndex + count <= pageIndex) {
++            currentPageIndex += count;
++            continue;
++          }
++
++          var kids = currentNode.get('Kids');
++          assert(isArray(kids), 'page dictionary kids object is not an array');
++          if (count === kids.length) {
++            // Nodes that don't have the page have been skipped and this is the
++            // bottom of the tree which means the page requested must be a
++            // descendant of this pages node. Ideally we would just resolve the
++            // promise with the page ref here, but there is the case where more
++            // pages nodes could link to single a page (see issue 3666 pdf). To
++            // handle this push it back on the queue so if it is a pages node it
++            // will be descended into.
++            nodesToVisit = [kids[pageIndex - currentPageIndex]];
++            currentPageIndex = pageIndex;
++            continue;
++          } else {
++            for (var last = kids.length - 1; last >= 0; last--) {
++              nodesToVisit.push(kids[last]);
++            }
++          }
++        }
++        promise.reject('Page index ' + pageIndex + ' not found.');
++      }
++      next();
++      return promise;
++    },
++
++    getPageIndex: function Catalog_getPageIndex(ref) {
++      // The page tree nodes have the count of all the leaves below them. To get
++      // how many pages are before we just have to walk up the tree and keep
++      // adding the count of siblings to the left of the node.
++      var xref = this.xref;
++      function pagesBeforeRef(kidRef) {
++        var total = 0;
++        var parentRef;
++        return xref.fetchAsync(kidRef).then(function (node) {
++          if (!node) {
++            return null;
++          }
++          parentRef = node.getRaw('Parent');
++          return node.getAsync('Parent');
++        }).then(function (parent) {
++          if (!parent) {
++            return null;
++          }
++          return parent.getAsync('Kids');
++        }).then(function (kids) {
++          if (!kids) {
++            return null;
++          }
++          var kidPromises = [];
++          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) {
++              found = true;
++              break;
++            }
++            kidPromises.push(xref.fetchAsync(kid).then(function (kid) {
++              if (kid.has('Count')) {
++                var count = kid.get('Count');
++                total += count;
++              } else { // page leaf node
++                total++;
++              }
++            }));
++          }
++          if (!found) {
++            error('kid ref not found in parents kids');
++          }
++          return Promise.all(kidPromises).then(function () {
++            return [total, parentRef];
++          });
++        });
++      }
++
++      var total = 0;
++      function next(ref) {
++        return pagesBeforeRef(ref).then(function (args) {
++          if (!args) {
++            return total;
++          }
++          var count = args[0];
++          var parentRef = args[1];
++          total += count;
++          return next(parentRef);
++        });
++      }
++
++      return next(ref);
++    }
++  };
++
++  return Catalog;
++})();
++
++var XRef = (function XRefClosure() {
++  function XRef(stream, password) {
++
++    this.stream = stream;
++    this.entries = [];
++    this.xrefstms = {};
++    // prepare the XRef cache
++    this.cache = [];
++    this.password = password;
++  }
++
++  XRef.prototype = {
++    setStartXRef: function XRef_setStartXRef(startXRef) {
++      // Store the starting positions of xref tables as we process them
++      // so we can recover from missing data errors
++      this.startXRefQueue = [startXRef];
++    },
++
++    parse: function XRef_parse(recoveryMode) {
++      var trailerDict;
++      if (!recoveryMode) {
++        trailerDict = this.readXRef();
++      } else {
++        warn('Indexing all PDF objects');
++        trailerDict = this.indexObjects();
++      }
++      trailerDict.assignXref(this);
++      this.trailer = trailerDict;
++      var encrypt = trailerDict.get('Encrypt');
++      if (encrypt) {
++        var ids = trailerDict.get('ID');
++        var fileId = (ids && ids.length) ? ids[0] : '';
++        this.encrypt = new CipherTransformFactory(
++            encrypt, fileId, this.password);
++      }
++
++      // get the root dictionary (catalog) object
++      if (!(this.root = trailerDict.get('Root'))) {
++        error('Invalid root reference');
++      }
++    },
++
++    processXRefTable: function XRef_processXRefTable(parser) {
++      if (!('tableState' in this)) {
++        // Stores state of the table as we process it so we can resume
++        // from middle of table in case of missing data error
++        this.tableState = {
++          entryNum: 0,
++          streamPos: parser.lexer.stream.pos,
++          parserBuf1: parser.buf1,
++          parserBuf2: parser.buf2
++        };
++      }
++
++      var obj = this.readXRefTable(parser);
++
++      // Sanity check
++      if (!isCmd(obj, 'trailer')) {
++        error('Invalid XRef table: could not find trailer dictionary');
++      }
++      // Read trailer dictionary, e.g.
++      // trailer
++      //    << /Size 22
++      //      /Root 20R
++      //      /Info 10R
++      //      /ID [ <81b14aafa313db63dbd6f981e49f94f4> ]
++      //    >>
++      // 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');
++      }
++      delete this.tableState;
++
++      return dict;
++    },
++
++    readXRefTable: function XRef_readXRefTable(parser) {
++      // Example of cross-reference table:
++      // xref
++      // 0 1                    <-- subsection header (first obj #, obj count)
++      // 0000000000 65535 f     <-- actual object (offset, generation #, f/n)
++      // 23 2                   <-- subsection header ... and so on ...
++      // 0000025518 00002 n
++      // 0000025635 00000 n
++      // trailer
++      // ...
++
++      var stream = parser.lexer.stream;
++      var tableState = this.tableState;
++      stream.pos = tableState.streamPos;
++      parser.buf1 = tableState.parserBuf1;
++      parser.buf2 = tableState.parserBuf2;
++
++      // Outer loop is over subsection headers
++      var obj;
++
++      while (true) {
++        if (!('firstEntryNum' in tableState) || !('entryCount' in tableState)) {
++          if (isCmd(obj = parser.getObj(), 'trailer')) {
++            break;
++          }
++          tableState.firstEntryNum = obj;
++          tableState.entryCount = parser.getObj();
++        }
 +
++        var first = tableState.firstEntryNum;
++        var count = tableState.entryCount;
++        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;
++          tableState.entryNum = i;
++          tableState.parserBuf1 = parser.buf1;
++          tableState.parserBuf2 = parser.buf2;
 +
++          var entry = {};
++          entry.offset = parser.getObj();
++          entry.gen = parser.getObj();
++          var type = parser.getObj();
 +
- var ColorSpace = (function ColorSpaceClosure() {
-   // Constructor should define this.numComps, this.defaultColor, this.name
-   function ColorSpace() {
-     error('should not call ColorSpace constructor');
-   }
++          if (isCmd(type, 'f'))
++            entry.free = true;
++          else if (isCmd(type, 'n'))
++            entry.uncompressed = true;
 +
-   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);
++          // 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);
++          }
 +
-         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];
++          if (!this.entries[i + first]) {
++            this.entries[i + first] = entry;
++          }
 +        }
-         return dest;
++
++        tableState.entryNum = 0;
++        tableState.streamPos = stream.pos;
++        tableState.parserBuf1 = parser.buf1;
++        tableState.parserBuf2 = parser.buf2;
++        delete tableState.firstEntryNum;
++        delete tableState.entryCount;
 +      }
-       this.getRgbBuffer(src, srcOffset, count, dest, 0, bits);
-       return dest;
-     }
-   };
 +
-   ColorSpace.parse = function ColorSpace_parse(cs, xref, res) {
-     var IR = ColorSpace.parseToIR(cs, xref, res);
-     if (IR instanceof AlternateCS)
-       return IR;
++      // Per issue 3248: hp scanners generate bad XRef
++      if (first === 1 && this.entries[1] && this.entries[1].free) {
++        // shifting the entries
++        this.entries.shift();
++      }
 +
-     return ColorSpace.fromIR(IR);
-   };
++      // Sanity check: as per spec, first object must be free
++      if (this.entries[0] && !this.entries[0].free) {
++        error('Invalid XRef table: unexpected first object');
++      }
++      return obj;
++    },
 +
-   ColorSpace.fromIR = function ColorSpace_fromIR(IR) {
-     var name = isArray(IR) ? IR[0] : IR;
++    processXRefStream: function XRef_processXRefStream(stream) {
++      if (!('streamState' in this)) {
++        // Stores state of the stream as we process it so we can resume
++        // from middle of stream in case of missing data error
++        var streamParameters = stream.dict;
++        var byteWidths = streamParameters.get('W');
++        var range = streamParameters.get('Index');
++        if (!range) {
++          range = [0, streamParameters.get('Size')];
++        }
 +
-     switch (name) {
-       case 'DeviceGrayCS':
-         return new DeviceGrayCS();
-       case 'DeviceRgbCS':
-         return new DeviceRgbCS();
-       case 'DeviceCmykCS':
-         return new DeviceCmykCS();
-       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];
++        this.streamState = {
++          entryRanges: range,
++          byteWidths: byteWidths,
++          entryNum: 0,
++          streamPos: stream.pos
++        };
++      }
++      this.readXRefStream(stream);
++      delete this.streamState;
 +
-         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;
-   };
++      return stream.dict;
++    },
 +
-   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;
-       }
-     }
++    readXRefStream: function XRef_readXRefStream(stream) {
++      var i, j;
++      var streamState = this.streamState;
++      stream.pos = streamState.streamPos;
 +
-     cs = xref.fetchIfRef(cs);
-     var mode;
++      var byteWidths = streamState.byteWidths;
++      var typeFieldWidth = byteWidths[0];
++      var offsetFieldWidth = byteWidths[1];
++      var generationFieldWidth = byteWidths[2];
 +
-     if (isName(cs)) {
-       mode = cs.name;
-       this.mode = mode;
++      var entryRanges = streamState.entryRanges;
++      while (entryRanges.length > 0) {
 +
-       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 first = entryRanges[0];
++        var n = entryRanges[1];
 +
-       switch (mode) {
-         case 'DeviceGray':
-         case 'G':
-           return 'DeviceGrayCS';
-         case 'DeviceRGB':
-         case 'RGB':
-           return 'DeviceRgbCS';
-         case 'DeviceCMYK':
-         case 'CMYK':
-           return 'DeviceCmykCS';
-         case 'CalGray':
-           return 'DeviceGrayCS';
-         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();
++        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);
++        }
++        for (i = streamState.entryNum; i < n; ++i) {
++          streamState.entryNum = i;
++          streamState.streamPos = stream.pos;
++
++          var type = 0, offset = 0, generation = 0;
++          for (j = 0; j < typeFieldWidth; ++j)
++            type = (type << 8) | stream.getByte();
++          // if type field is absent, its default value = 1
++          if (typeFieldWidth === 0) {
++            type = 1;
 +          }
-           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 + '"');
++          for (j = 0; j < offsetFieldWidth; ++j) {
++            offset = (offset << 8) | stream.getByte();
++          }
++          for (j = 0; j < generationFieldWidth; ++j) {
++            generation = (generation << 8) | stream.getByte();
++          }
++          var entry = {};
++          entry.offset = offset;
++          entry.gen = generation;
++          switch (type) {
++            case 0:
++              entry.free = true;
++              break;
++            case 1:
++              entry.uncompressed = true;
++              break;
++            case 2:
++              break;
++            default:
++              error('Invalid XRef entry type: ' + type);
++          }
++          if (!this.entries[first + i]) {
++            this.entries[first + i] = entry;
++          }
++        }
++
++        streamState.entryNum = 0;
++        streamState.streamPos = stream.pos;
++        entryRanges.splice(0, 2);
 +      }
-     } 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;
-   };
++    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)
++            break;
++          token += String.fromCharCode(ch);
++          ch = data[offset];
++        }
++        return token;
++      }
++      function skipUntil(data, offset, what) {
++        var length = what.length, dataLength = data.length;
++        var skipped = 0;
++        // finding byte sequence
++        while (offset < dataLength) {
++          var i = 0;
++          while (i < length && data[offset + i] == what[i]) {
++            ++i;
++          }
++          if (i >= length)
++            break; // sequence found
 +
-   return ColorSpace;
- })();
++          offset++;
++          skipped++;
++        }
++        return skipped;
++      }
++      var trailerBytes = new Uint8Array([116, 114, 97, 105, 108, 101, 114]);
++      var startxrefBytes = new Uint8Array([115, 116, 97, 114, 116, 120, 114,
++                                          101, 102]);
++      var endobjBytes = new Uint8Array([101, 110, 100, 111, 98, 106]);
++      var xrefBytes = new Uint8Array([47, 88, 82, 101, 102]);
 +
- /**
-  * 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;
-   }
++      var stream = this.stream;
++      stream.pos = 0;
++      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) {
++          ++position;
++          continue;
++        }
++        if (ch === 37) { // %-comment
++          do {
++            ++position;
++            if (position >= length) {
++              break;
++            }
++            ch = buffer[position];
++          } while (ch !== 13 && ch !== 10);
++          continue;
++        }
++        var token = readToken(buffer, position);
++        var m;
++        if (token === 'xref') {
++          position += skipUntil(buffer, position, trailerBytes);
++          trailers.push(position);
++          position += skipUntil(buffer, position, startxrefBytes);
++        } else if ((m = /^(\d+)\s+(\d+)\s+obj\b/.exec(token))) {
++          this.entries[m[1]] = {
++            offset: position,
++            gen: m[2] | 0,
++            uncompressed: true
++          };
 +
-   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 isGetRgbBufferSupported = 'getRgbBuffer' in base;
-       var isPassthrough = base.isPassthrough(8) || !isGetRgbBufferSupported;
-       var pos = isPassthrough ? destOffset : 0;
-       var baseBuf = isPassthrough ? dest : new Uint8Array(baseNumComps * count);
-       var numComps = this.numComps;
++          var contentLength = skipUntil(buffer, position, endobjBytes) + 7;
++          var content = buffer.subarray(position, position + contentLength);
 +
-       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 (isGetRgbBufferSupported) {
-           for (var j = 0; j < baseNumComps; j++) {
-             baseBuf[pos++] = tinted[j] * 255;
++          // checking XRef stream suspect
++          // (it shall have '/XRef' and next char is not a letter)
++          var xrefTagOffset = skipUntil(content, 0, xrefBytes);
++          if (xrefTagOffset < contentLength &&
++              content[xrefTagOffset + 5] < 64) {
++            xrefStms.push(position);
++            this.xrefstms[position] = 1; // don't read it recursively
 +          }
++
++          position += contentLength;
 +        } else {
-           base.getRgbItem(tinted, 0, baseBuf, pos);
-           pos += baseNumComps;
++          position += token.length + 1;
 +        }
 +      }
-       if (!isPassthrough) {
-         base.getRgbBuffer(baseBuf, 0, count, dest, destOffset, 8);
++      // reading XRef streams
++      for (var 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) {
++        stream.pos = trailers[i];
++        var parser = new Parser(new Lexer(stream), true, null);
++        var obj = parser.getObj();
++        if (!isCmd(obj, 'trailer')) {
++          continue;
++        }
++        // read the trailer dictionary
++        if (!isDict(dict = parser.getObj())) {
++          continue;
++        }
++        // taking the first one with 'ID'
++        if (dict.has('ID')) {
++          return dict;
++        }
++      }
++      // no tailer with 'ID', taking last one (if exists)
++      if (dict) {
++        return dict;
++      }
++      // nothing helps
++      // calling error() would reject worker with an UnknownErrorException.
++      throw new InvalidPDFException('Invalid PDF structure');
 +    },
-     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);
-     }
-   };
 +
-   return AlternateCS;
- })();
++    readXRef: function XRef_readXRef(recoveryMode) {
++      var stream = this.stream;
 +
- var PatternCS = (function PatternCSClosure() {
-   function PatternCS(baseCS) {
-     this.name = 'Pattern';
-     this.base = baseCS;
-   }
-   PatternCS.prototype = {};
++      try {
++        while (this.startXRefQueue.length) {
++          var startXRef = this.startXRefQueue[0];
 +
-   return PatternCS;
- })();
++          stream.pos = startXRef + stream.start;
 +
- 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 parser = new Parser(new Lexer(stream), true, null);
++          var obj = parser.getObj();
++          var dict;
 +
-     var baseNumComps = base.numComps;
-     var length = baseNumComps * highVal;
-     var lookupArray;
++          // Get dictionary
++          if (isCmd(obj, 'xref')) {
 +
-     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) {
-       lookupArray = lookup;
-     } else {
-       error('Unrecognized lookup table: ' + lookup);
-     }
-     this.lookup = lookupArray;
-   }
++            // Parse end-of-file XRef
++            dict = this.processXRefTable(parser);
++            if (!this.topDict) {
++              this.topDict = dict;
++            }
 +
-   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);
++            // Recursively get other XRefs 'XRefStm', if any
++            obj = dict.get('XRefStm');
++            if (isInt(obj)) {
++              var pos = obj;
++              // ignore previously loaded xref streams
++              // (possible infinite recursion)
++              if (!(pos in this.xrefstms)) {
++                this.xrefstms[pos] = 1;
++                this.startXRefQueue.push(pos);
++              }
++            }
++          } else if (isInt(obj)) {
++
++            // Parse in-stream XRef
++            if (!isInt(parser.getObj()) ||
++                !isCmd(parser.getObj(), 'obj') ||
++                !isStream(obj = parser.getObj())) {
++              error('Invalid XRef stream');
++            }
++            dict = this.processXRefStream(obj);
++            if (!this.topDict) {
++              this.topDict = dict;
++            }
++
++            if (!dict) {
++              error('Failed to read XRef stream');
++            }
++          } else {
++            error('Invalid XRef stream header');
++          }
++
++          // Recursively get previous dictionary, if any
++          obj = dict.get('Prev');
++          if (isInt(obj)) {
++            this.startXRefQueue.push(obj);
++          } else if (isRef(obj)) {
++            // The spec says Prev must not be a reference, i.e. "/Prev NNN"
++            // This is a fallback for non-compliant PDFs, i.e. "/Prev NNN 0 R"
++            this.startXRefQueue.push(obj.num);
++          }
++
++          this.startXRefQueue.shift();
++        }
++
++        return this.topDict;
++      } catch (e) {
++        if (e instanceof MissingDataException) {
++          throw e;
++        }
++        info('(while reading XRef): ' + e);
++      }
++
++      if (recoveryMode) {
++        return;
++      }
++      throw new XRefParseException();
 +    },
-     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);
++
++    getEntry: function XRef_getEntry(i) {
++      var xrefEntry = this.entries[i];
++      if (xrefEntry !== null && !xrefEntry.free && xrefEntry.offset) {
++        return xrefEntry;
++      }
++      return null;
 +    },
-     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;
++    fetchIfRef: function XRef_fetchIfRef(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');
++      var num = ref.num;
++      if (num in this.cache) {
++        var cacheEntry = this.cache[num];
++        return cacheEntry;
++      }
++
++      var xrefEntry = this.getEntry(num);
++
++      // the referenced entry can be free
++      if (xrefEntry === null) {
++        return (this.cache[num] = null);
++      }
++
++      if (xrefEntry.uncompressed) {
++        return this.fetchUncompressed(ref, xrefEntry, suppressEncryption);
++      } else {
++        return this.fetchCompressed(xrefEntry, suppressEncryption);
 +      }
 +    },
-     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;
-     }
-   };
-   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;
++    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) {
++        try {
++          xrefEntry = 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 {
++        xrefEntry = parser.getObj();
++      }
++      if (!isStream(xrefEntry)) {
++        this.cache[num] = xrefEntry;
++      }
++      return xrefEntry;
 +    },
-     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;
++
++    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');
++      }
++      var parser = new Parser(new Lexer(stream), false, this);
++      parser.allowStreams = true;
++      var i, entries = [], num, nums = [];
++      // read the object numbers to populate cache
++      for (i = 0; i < n; ++i) {
++        num = parser.getObj();
++        if (!isInt(num)) {
++          error('invalid object number in the ObjStm stream: ' + num);
++        }
++        nums.push(num);
++        var offset = parser.getObj();
++        if (!isInt(offset)) {
++          error('invalid object offset in the ObjStm stream: ' + offset);
++        }
++      }
++      // read stream objects for cache
++      for (i = 0; i < n; ++i) {
++        entries.push(parser.getObj());
++        num = nums[i];
++        var entry = this.entries[num];
++        if (entry && entry.offset === tableOffset && entry.gen === i) {
++          this.cache[num] = entries[i];
++        }
++      }
++      xrefEntry = entries[xrefEntry.gen];
++      if (xrefEntry === undefined) {
++        error('bad XRef entry for compressed object');
++      }
++      return xrefEntry;
 +    },
-     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;
++
++    fetchIfRefAsync: function XRef_fetchIfRefAsync(obj) {
++      if (!isRef(obj)) {
++        var promise = new LegacyPromise();
++        promise.resolve(obj);
++        return promise;
 +      }
++      return this.fetchAsync(obj);
 +    },
-     getOutputLength: function DeviceGrayCS_getOutputLength(inputLength) {
-       return inputLength * 3;
++
++    fetchAsync: function XRef_fetchAsync(ref, suppressEncryption) {
++      var promise = new LegacyPromise();
++      var tryFetch = function (promise) {
++        try {
++          promise.resolve(this.fetch(ref, suppressEncryption));
++        } catch (e) {
++          if (e instanceof MissingDataException) {
++            this.stream.manager.requestRange(e.begin, e.end, tryFetch);
++            return;
++          }
++          promise.reject(e);
++        }
++      }.bind(this, promise);
++      tryFetch();
++      return promise;
 +    },
-     isPassthrough: ColorSpace.prototype.isPassthrough,
-     createRgbBuffer: ColorSpace.prototype.createRgbBuffer,
-     isDefaultDecode: function DeviceGrayCS_isDefaultDecode(decodeMap) {
-       return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
++
++    getCatalogObj: function XRef_getCatalogObj() {
++      return this.root;
 +    }
 +  };
-   return DeviceGrayCS;
++
++  return XRef;
 +})();
 +
- var DeviceRgbCS = (function DeviceRgbCSClosure() {
-   function DeviceRgbCS() {
-     this.name = 'DeviceRGB';
-     this.numComps = 3;
-     this.defaultColor = new Float32Array([0, 0, 0]);
++/**
++ * A NameTree is like a Dict but has some adventagous 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() {
++  function NameTree(root, xref) {
++    this.root = root;
++    this.xref = xref;
 +  }
-   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;
++
++  NameTree.prototype = {
++    getAll: function NameTree_getAll() {
++      var dict = {};
++      if (!this.root) {
++        return dict;
 +      }
-       var scale = 255 / ((1 << bits) - 1);
-       var j = srcOffset, q = destOffset;
-       for (var i = 0; i < length; ++i) {
-         dest[q++] = (scale * src[j++]) | 0;
++      var xref = this.xref;
++      // reading name tree
++      var processed = new RefSet();
++      processed.put(this.root);
++      var queue = [this.root];
++      while (queue.length > 0) {
++        var i, n;
++        var obj = xref.fetchIfRef(queue.shift());
++        if (!isDict(obj)) {
++          continue;
++        }
++        if (obj.has('Kids')) {
++          var kids = obj.get('Kids');
++          for (i = 0, n = kids.length; i < n; i++) {
++            var kid = kids[i];
++            if (processed.has(kid)) {
++              error('invalid destinations');
++            }
++            queue.push(kid);
++            processed.put(kid);
++          }
++          continue;
++        }
++        var names = obj.get('Names');
++        if (names) {
++          for (i = 0, n = names.length; i < n; i += 2) {
++            dict[names[i]] = xref.fetchIfRef(names[i + 1]);
++          }
++        }
 +      }
-     },
-     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);
++      return dict;
 +    }
 +  };
-   return DeviceRgbCS;
++  return NameTree;
 +})();
 +
- var DeviceCmykCS = (function DeviceCmykCSClosure() {
-   // Sampled RGB colors from CMYK US Web Coated (SWOP) colorspace
-   var lut = new Uint8Array([
-     255, 255, 254, 221, 222, 223, 191, 193, 195, 161, 163, 166, 133, 136, 138,
-     105, 107, 109, 75, 75, 77, 35, 31, 32, 255, 252, 224, 226, 220, 198, 195,
-     191, 173, 164, 162, 147, 136, 134, 122, 107, 106, 96, 75, 74, 66, 33, 29,
-     24, 255, 249, 197, 229, 218, 174, 198, 190, 153, 166, 160, 129, 138, 133,
-     107, 108, 104, 83, 76, 73, 56, 33, 28, 15, 255, 247, 168, 232, 216, 149,
-     200, 188, 130, 168, 158, 110, 139, 131, 90, 110, 103, 70, 77, 72, 45, 32,
-     27, 4, 255, 245, 140, 234, 214, 124, 202, 186, 108, 170, 157, 91, 140, 130,
-     74, 110, 102, 56, 77, 71, 33, 31, 27, 0, 255, 243, 107, 235, 212, 95, 203,
-     184, 83, 171, 155, 69, 141, 129, 55, 111, 101, 40, 77, 70, 19, 29, 26, 0,
-     255, 241, 64, 237, 211, 59, 204, 183, 52, 171, 154, 42, 142, 128, 31, 111,
-     100, 16, 77, 69, 0, 27, 26, 0, 255, 240, 0, 238, 209, 0, 205, 182, 3, 172,
-     153, 0, 142, 127, 0, 112, 100, 0, 77, 69, 0, 26, 25, 0, 251, 225, 236, 218,
-     196, 207, 189, 171, 181, 160, 144, 154, 133, 120, 128, 105, 94, 101, 74, 64,
-     70, 35, 21, 25, 255, 222, 208, 222, 195, 184, 192, 169, 161, 162, 143, 136,
-     135, 118, 113, 106, 92, 88, 75, 63, 60, 34, 20, 17, 255, 220, 184, 225, 193,
-     162, 195, 168, 142, 164, 142, 120, 136, 117, 99, 107, 91, 77, 75, 62, 50,
-     33, 20, 8, 255, 218, 157, 227, 191, 139, 197, 166, 121, 165, 140, 102, 137,
-     116, 84, 108, 90, 64, 76, 61, 40, 32, 19, 0, 255, 216, 132, 229, 189, 116,
-     198, 165, 101, 167, 139, 85, 138, 115, 69, 109, 89, 51, 76, 61, 28, 31, 18,
-     0, 255, 214, 102, 230, 188, 90, 199, 163, 78, 167, 138, 65, 139, 114, 51,
-     109, 89, 35, 76, 60, 14, 29, 18, 0, 255, 213, 65, 232, 186, 58, 200, 162,
-     50, 168, 136, 39, 139, 113, 28, 110, 88, 12, 76, 60, 0, 27, 18, 0, 255, 212,
-     8, 232, 185, 13, 201, 161, 11, 169, 136, 3, 139, 112, 0, 110, 87, 0, 76, 59,
-     0, 26, 18, 0, 248, 197, 219, 216, 172, 192, 187, 150, 168, 158, 126, 143,
-     132, 104, 119, 104, 81, 93, 74, 54, 64, 35, 10, 19, 251, 195, 193, 219, 171,
-     171, 190, 149, 150, 161, 125, 127, 133, 103, 105, 106, 80, 81, 75, 53, 54,
-     34, 10, 10, 254, 193, 171, 221, 169, 151, 192, 148, 132, 162, 124, 112, 134,
-     102, 92, 106, 79, 70, 75, 52, 45, 34, 9, 1, 255, 191, 147, 223, 168, 130,
-     193, 146, 113, 163, 123, 95, 135, 101, 77, 107, 78, 58, 75, 52, 35, 32, 9,
-     0, 255, 190, 124, 225, 166, 109, 195, 145, 95, 164, 122, 79, 136, 100, 63,
-     107, 77, 46, 76, 51, 24, 31, 9, 0, 255, 188, 97, 226, 165, 85, 196, 143, 74,
-     165, 121, 60, 137, 99, 47, 108, 77, 31, 75, 51, 10, 29, 9, 0, 255, 187, 64,
-     227, 164, 56, 196, 142, 48, 165, 120, 37, 137, 98, 25, 108, 76, 9, 75, 50,
-     0, 28, 9, 0, 255, 186, 23, 228, 163, 21, 197, 142, 15, 166, 119, 5, 137, 98,
-     0, 108, 76, 0, 75, 50, 0, 27, 8, 0, 245, 168, 201, 214, 147, 177, 186, 128,
-     155, 157, 107, 131, 131, 88, 109, 104, 67, 85, 74, 42, 57, 35, 0, 12, 248,
-     166, 178, 216, 146, 157, 188, 127, 138, 159, 107, 116, 132, 87, 96, 105, 66,
-     74, 74, 41, 48, 35, 0, 3, 250, 165, 158, 218, 145, 139, 189, 126, 122, 160,
-     106, 103, 133, 86, 84, 105, 66, 64, 75, 41, 39, 33, 0, 0, 252, 164, 136,
-     220, 144, 120, 190, 125, 104, 161, 105, 87, 134, 86, 71, 106, 65, 52, 75,
-     41, 29, 32, 0, 0, 253, 162, 115, 221, 142, 101, 191, 124, 88, 161, 104, 72,
-     134, 85, 58, 106, 64, 41, 75, 40, 19, 31, 0, 0, 254, 161, 91, 222, 141, 80,
-     192, 123, 68, 162, 103, 55, 134, 84, 42, 106, 64, 26, 75, 40, 6, 29, 0, 0,
-     255, 160, 62, 223, 140, 54, 193, 122, 45, 162, 102, 34, 135, 83, 22, 106,
-     63, 5, 74, 40, 0, 28, 0, 0, 255, 159, 29, 223, 140, 25, 193, 121, 18, 163,
-     101, 7, 135, 83, 0, 107, 63, 0, 74, 40, 0, 28, 0, 0, 243, 142, 185, 212,
-     123, 163, 184, 107, 142, 156, 89, 120, 130, 72, 100, 104, 53, 77, 74, 29,
-     51, 35, 0, 4, 245, 140, 164, 214, 123, 145, 186, 106, 127, 157, 89, 107,
-     131, 72, 88, 104, 53, 67, 74, 29, 42, 34, 0, 0, 247, 139, 146, 215, 122,
-     129, 187, 106, 112, 158, 88, 94, 132, 71, 77, 104, 53, 57, 74, 29, 33, 33,
-     0, 0, 248, 138, 126, 217, 121, 111, 188, 105, 96, 159, 87, 80, 132, 70, 64,
-     105, 52, 47, 74, 29, 24, 31, 0, 0, 249, 137, 107, 218, 120, 94, 189, 104,
-     81, 159, 86, 66, 132, 70, 52, 105, 52, 36, 74, 29, 15, 30, 0, 0, 250, 136,
-     85, 218, 119, 74, 189, 103, 63, 160, 86, 51, 133, 69, 38, 105, 51, 22, 74,
-     29, 2, 29, 0, 0, 251, 135, 59, 219, 118, 51, 190, 102, 42, 160, 85, 31, 133,
-     69, 19, 105, 51, 3, 74, 29, 0, 29, 0, 0, 252, 134, 31, 219, 118, 26, 190,
-     102, 19, 160, 85, 7, 133, 69, 0, 105, 51, 0, 73, 29, 0, 28, 0, 0, 240, 113,
-     169, 210, 98, 149, 183, 84, 130, 155, 69, 110, 129, 54, 90, 103, 37, 70, 74,
-     11, 44, 32, 0, 1, 242, 111, 150, 212, 97, 132, 184, 84, 116, 156, 69, 97,
-     130, 54, 79, 103, 37, 60, 74, 12, 36, 31, 0, 0, 244, 111, 134, 213, 97, 118,
-     185, 83, 102, 157, 68, 86, 130, 54, 69, 104, 37, 51, 74, 13, 28, 30, 0, 0,
-     245, 110, 116, 214, 96, 102, 186, 83, 88, 157, 68, 73, 131, 53, 58, 104, 37,
-     41, 74, 14, 19, 29, 0, 0, 246, 110, 98, 215, 96, 86, 186, 82, 74, 157, 67,
-     60, 131, 53, 46, 104, 37, 30, 73, 14, 10, 28, 0, 0, 247, 109, 79, 215, 95,
-     69, 187, 82, 58, 158, 67, 46, 131, 53, 33, 104, 37, 18, 73, 15, 1, 28, 0, 0,
-     247, 108, 56, 216, 95, 48, 187, 82, 40, 158, 67, 29, 131, 53, 16, 104, 37,
-     0, 73, 15, 0, 27, 0, 0, 248, 108, 32, 216, 94, 27, 187, 81, 20, 158, 67, 8,
-     131, 53, 0, 104, 37, 0, 72, 16, 0, 27, 0, 0, 238, 78, 154, 208, 66, 135,
-     181, 55, 118, 154, 43, 99, 129, 30, 81, 103, 12, 62, 74, 0, 38, 27, 0, 0,
-     240, 77, 136, 210, 66, 120, 183, 56, 105, 155, 43, 88, 129, 30, 71, 103, 13,
-     53, 73, 0, 29, 26, 0, 0, 241, 77, 122, 211, 66, 107, 183, 56, 93, 155, 44,
-     77, 129, 31, 62, 103, 14, 44, 73, 0, 23, 26, 0, 0, 242, 77, 106, 211, 66,
-     92, 184, 56, 80, 155, 44, 65, 129, 31, 51, 103, 15, 35, 73, 0, 14, 25, 0, 0,
-     243, 77, 90, 212, 66, 79, 184, 56, 67, 156, 44, 54, 129, 32, 41, 103, 16,
-     25, 73, 0, 6, 25, 0, 0, 243, 77, 73, 213, 66, 63, 184, 56, 53, 156, 44, 41,
-     130, 32, 28, 103, 17, 13, 72, 0, 0, 25, 0, 0, 244, 77, 53, 213, 67, 45, 185,
-     56, 37, 156, 45, 26, 130, 33, 13, 103, 18, 0, 72, 0, 0, 25, 0, 0, 244, 77,
-     33, 213, 67, 28, 185, 57, 21, 156, 45, 9, 130, 33, 0, 103, 19, 0, 72, 0, 0,
-     24, 0, 0, 237, 13, 138, 207, 4, 122, 180, 0, 106, 153, 0, 89, 128, 0, 72,
-     102, 0, 54, 73, 0, 31, 21, 0, 0, 238, 16, 123, 208, 6, 108, 181, 0, 94, 154,
-     0, 78, 128, 0, 63, 102, 0, 46, 72, 0, 24, 21, 0, 0, 239, 20, 110, 209, 11,
-     96, 181, 1, 83, 154, 0, 69, 128, 0, 54, 102, 0, 38, 72, 0, 17, 22, 0, 0,
-     239, 23, 96, 209, 15, 84, 182, 5, 72, 154, 0, 58, 128, 0, 45, 102, 0, 29,
-     72, 0, 9, 22, 0, 0, 240, 26, 82, 210, 19, 71, 182, 10, 60, 154, 0, 48, 128,
-     0, 35, 102, 0, 20, 72, 0, 3, 22, 0, 0, 241, 27, 67, 210, 21, 58, 182, 14,
-     48, 154, 3, 37, 128, 0, 24, 102, 0, 8, 71, 0, 0, 22, 0, 0, 241, 29, 50, 210,
-     23, 42, 183, 17, 34, 154, 6, 23, 129, 0, 10, 102, 0, 0, 71, 0, 0, 22, 0, 0,
-     241, 30, 34, 211, 25, 28, 183, 19, 21, 155, 9, 10, 129, 0, 0, 102, 0, 0, 71,
-     0, 0, 22, 0, 0, 211, 239, 252, 184, 210, 221, 160, 183, 194, 135, 155, 164,
-     111, 128, 137, 87, 101, 109, 59, 70, 76, 22, 28, 32, 218, 237, 223, 190,
-     208, 196, 165, 181, 172, 139, 153, 146, 114, 127, 121, 89, 100, 95, 61, 69,
-     66, 21, 27, 25, 223, 235, 196, 195, 206, 174, 169, 179, 152, 142, 151, 129,
-     117, 126, 107, 91, 99, 83, 62, 68, 56, 20, 26, 17, 227, 232, 168, 198, 204,
-     149, 171, 177, 130, 144, 150, 110, 119, 124, 91, 93, 98, 70, 63, 68, 46, 20,
-     25, 6, 231, 230, 142, 201, 202, 125, 174, 176, 109, 146, 148, 92, 120, 123,
-     75, 94, 97, 57, 63, 67, 35, 19, 25, 0, 234, 229, 112, 203, 200, 98, 176,
-     174, 86, 147, 147, 71, 121, 122, 57, 94, 96, 42, 64, 66, 21, 17, 24, 0, 236,
-     227, 75, 205, 199, 66, 177, 173, 57, 148, 146, 47, 122, 121, 35, 95, 95, 21,
-     64, 65, 2, 14, 24, 0, 238, 226, 32, 207, 198, 30, 178, 172, 25, 149, 145,
-     17, 123, 120, 6, 95, 94, 0, 64, 65, 0, 11, 24, 0, 211, 211, 233, 184, 186,
-     206, 160, 162, 180, 135, 137, 153, 112, 113, 127, 88, 89, 100, 61, 60, 70,
-     23, 18, 26, 217, 209, 207, 190, 184, 183, 165, 161, 160, 139, 136, 136, 115,
-     112, 113, 90, 88, 88, 62, 59, 60, 23, 17, 19, 221, 208, 183, 193, 183, 162,
-     167, 159, 142, 141, 134, 120, 116, 111, 99, 91, 87, 77, 62, 59, 51, 22, 17,
-     10, 224, 206, 158, 196, 181, 139, 170, 157, 122, 143, 133, 103, 118, 110,
-     84, 92, 86, 64, 63, 58, 40, 22, 16, 0, 227, 204, 133, 198, 179, 118, 172,
-     156, 102, 144, 132, 86, 119, 109, 70, 93, 85, 52, 64, 57, 30, 20, 16, 0,
-     230, 203, 106, 200, 178, 93, 173, 155, 81, 145, 130, 67, 120, 108, 53, 94,
-     84, 37, 64, 57, 17, 17, 16, 0, 232, 201, 73, 202, 177, 64, 175, 154, 55,
-     146, 129, 44, 121, 107, 33, 94, 83, 18, 64, 56, 0, 15, 16, 0, 233, 201, 38,
-     203, 176, 32, 175, 153, 27, 147, 129, 18, 121, 106, 6, 94, 83, 0, 64, 56, 0,
-     13, 16, 0, 210, 186, 216, 184, 163, 191, 160, 143, 167, 136, 120, 142, 112,
-     99, 118, 88, 77, 93, 61, 50, 64, 24, 6, 21, 215, 184, 192, 189, 162, 170,
-     164, 141, 149, 138, 119, 126, 115, 98, 104, 90, 76, 81, 62, 50, 54, 24, 6,
-     12, 219, 183, 171, 192, 161, 151, 166, 140, 132, 140, 118, 112, 116, 97, 92,
-     91, 75, 71, 63, 49, 46, 23, 6, 3, 222, 181, 148, 194, 159, 130, 168, 139,
-     114, 142, 117, 95, 117, 96, 78, 92, 74, 59, 63, 49, 36, 22, 6, 0, 224, 180,
-     125, 196, 158, 110, 170, 138, 96, 143, 116, 80, 118, 95, 64, 92, 74, 47, 64,
-     48, 25, 20, 6, 0, 226, 178, 100, 197, 157, 88, 171, 136, 76, 144, 115, 62,
-     119, 94, 49, 93, 73, 33, 64, 48, 13, 18, 6, 0, 228, 177, 71, 199, 156, 62,
-     172, 135, 52, 144, 114, 41, 119, 94, 30, 93, 72, 14, 64, 47, 0, 16, 6, 0,
-     229, 177, 40, 200, 155, 34, 173, 135, 27, 145, 113, 18, 120, 93, 5, 93, 72,
-     0, 63, 47, 0, 15, 6, 0, 210, 159, 199, 184, 140, 176, 160, 122, 154, 136,
-     102, 131, 113, 84, 108, 89, 64, 85, 62, 39, 57, 25, 0, 14, 214, 158, 177,
-     188, 139, 157, 163, 121, 137, 138, 102, 116, 114, 83, 96, 90, 63, 74, 63,
-     38, 48, 25, 0, 5, 217, 157, 158, 190, 138, 139, 165, 120, 122, 139, 101,
-     103, 115, 82, 84, 91, 62, 64, 63, 38, 40, 23, 0, 0, 219, 156, 137, 192, 137,
-     120, 167, 119, 105, 140, 100, 88, 116, 82, 71, 91, 62, 53, 63, 38, 30, 22,
-     0, 0, 221, 155, 116, 193, 136, 102, 168, 118, 89, 141, 99, 73, 117, 81, 59,
-     92, 61, 42, 63, 38, 21, 20, 0, 0, 223, 153, 94, 195, 135, 82, 169, 117, 70,
-     142, 98, 57, 117, 80, 44, 92, 61, 29, 63, 37, 8, 18, 0, 0, 224, 153, 68,
-     196, 134, 58, 170, 116, 49, 143, 97, 38, 118, 80, 26, 92, 60, 11, 63, 37, 0,
-     17, 0, 0, 225, 152, 41, 197, 133, 34, 170, 116, 27, 143, 97, 17, 118, 79, 4,
-     92, 60, 0, 63, 37, 0, 16, 0, 0, 209, 134, 183, 183, 118, 162, 160, 102, 142,
-     136, 85, 120, 113, 69, 100, 89, 50, 77, 62, 26, 51, 23, 0, 6, 213, 133, 163,
-     187, 117, 144, 163, 102, 126, 137, 85, 107, 114, 68, 88, 90, 50, 67, 63, 26,
-     43, 22, 0, 1, 215, 133, 146, 188, 116, 129, 164, 101, 112, 139, 84, 94, 115,
-     68, 77, 91, 50, 58, 63, 27, 34, 20, 0, 0, 217, 132, 127, 190, 116, 111, 165,
-     100, 97, 139, 84, 81, 116, 67, 65, 91, 49, 48, 63, 27, 25, 19, 0, 0, 219,
-     131, 108, 191, 115, 95, 166, 100, 82, 140, 83, 68, 116, 67, 53, 91, 49, 37,
-     63, 27, 17, 17, 0, 0, 220, 130, 88, 192, 114, 76, 167, 99, 65, 141, 82, 53,
-     116, 66, 40, 91, 49, 24, 63, 27, 5, 16, 0, 0, 221, 129, 64, 193, 113, 55,
-     168, 98, 46, 141, 82, 35, 117, 66, 23, 91, 49, 7, 63, 27, 0, 14, 0, 0, 222,
-     129, 41, 194, 113, 34, 168, 98, 26, 141, 81, 16, 117, 66, 3, 92, 48, 0, 62,
-     27, 0, 13, 0, 0, 209, 108, 168, 183, 94, 148, 160, 81, 130, 135, 66, 110,
-     113, 51, 91, 89, 35, 70, 63, 8, 45, 18, 0, 1, 212, 107, 150, 186, 94, 132,
-     162, 81, 116, 137, 66, 97, 114, 52, 80, 90, 35, 60, 63, 9, 37, 16, 0, 0,
-     214, 107, 134, 187, 93, 118, 163, 80, 103, 138, 66, 86, 114, 51, 70, 90, 35,
-     52, 63, 10, 29, 15, 0, 0, 215, 106, 117, 188, 93, 103, 164, 80, 89, 138, 66,
-     74, 115, 51, 59, 90, 35, 42, 63, 11, 21, 13, 0, 0, 216, 106, 100, 189, 92,
-     88, 164, 79, 75, 139, 65, 62, 115, 51, 48, 91, 35, 32, 63, 12, 12, 12, 0, 0,
-     217, 105, 82, 190, 92, 71, 165, 79, 60, 139, 65, 48, 115, 51, 35, 91, 35,
-     20, 62, 13, 3, 11, 0, 0, 218, 105, 61, 191, 92, 52, 166, 79, 43, 140, 65,
-     32, 116, 51, 20, 91, 35, 3, 62, 14, 0, 10, 0, 0, 219, 104, 41, 192, 91, 34,
-     166, 78, 26, 140, 65, 15, 116, 51, 2, 91, 35, 0, 62, 14, 0, 10, 0, 0, 208,
-     76, 153, 183, 65, 135, 159, 54, 118, 135, 42, 99, 113, 29, 82, 89, 10, 62,
-     62, 0, 38, 10, 0, 0, 211, 76, 137, 185, 65, 121, 161, 55, 105, 136, 43, 88,
-     114, 30, 72, 90, 12, 54, 63, 0, 31, 9, 0, 0, 212, 76, 122, 186, 66, 108,
-     162, 55, 94, 137, 43, 78, 114, 30, 63, 90, 13, 45, 62, 0, 24, 9, 0, 0, 213,
-     76, 107, 187, 66, 94, 162, 55, 81, 137, 43, 67, 114, 31, 52, 90, 15, 36, 62,
-     0, 16, 8, 0, 0, 214, 76, 92, 188, 66, 80, 163, 55, 69, 138, 44, 56, 114, 31,
-     42, 90, 16, 27, 62, 0, 8, 8, 0, 0, 215, 76, 76, 188, 66, 65, 164, 55, 55,
-     138, 44, 43, 114, 32, 31, 90, 16, 16, 62, 0, 1, 7, 0, 0, 216, 76, 57, 189,
-     66, 49, 164, 56, 40, 138, 44, 29, 115, 32, 16, 90, 17, 1, 61, 0, 0, 7, 0, 0,
-     217, 76, 40, 190, 66, 33, 164, 56, 25, 138, 44, 14, 114, 33, 1, 90, 18, 0,
-     61, 0, 0, 7, 0, 0, 207, 26, 139, 182, 16, 122, 159, 3, 106, 135, 0, 89, 113,
-     0, 73, 89, 0, 55, 62, 0, 32, 4, 0, 0, 210, 27, 124, 184, 18, 109, 160, 7,
-     95, 136, 0, 79, 113, 0, 64, 90, 0, 47, 62, 0, 25, 4, 0, 0, 211, 30, 111,
-     185, 21, 98, 161, 11, 84, 136, 0, 70, 113, 0, 55, 90, 0, 39, 62, 0, 18, 4,
-     0, 0, 212, 32, 98, 185, 24, 85, 161, 15, 73, 136, 2, 60, 113, 0, 46, 90, 0,
-     30, 61, 0, 11, 4, 0, 0, 213, 34, 85, 186, 26, 73, 162, 17, 62, 137, 5, 50,
-     113, 0, 37, 89, 0, 22, 61, 0, 5, 4, 0, 0, 213, 35, 70, 187, 27, 60, 162, 19,
-     50, 137, 8, 39, 114, 0, 26, 89, 0, 11, 61, 0, 0, 4, 0, 0, 214, 35, 54, 187,
-     29, 45, 163, 21, 37, 137, 11, 26, 114, 0, 13, 89, 0, 0, 60, 0, 0, 4, 0, 0,
-     214, 35, 40, 188, 29, 32, 163, 22, 24, 137, 12, 13, 114, 0, 0, 89, 0, 0, 60,
-     0, 0, 4, 0, 0, 169, 226, 249, 148, 199, 219, 129, 173, 192, 108, 147, 163,
-     88, 122, 136, 68, 96, 108, 43, 66, 76, 4, 25, 33, 178, 224, 221, 156, 197,
-     195, 136, 172, 171, 114, 145, 145, 93, 121, 120, 71, 95, 95, 46, 65, 66, 4,
-     24, 25, 185, 222, 196, 162, 195, 173, 140, 170, 151, 117, 144, 128, 96, 119,
-     106, 74, 94, 83, 47, 65, 57, 4, 24, 18, 190, 220, 169, 166, 193, 149, 144,
-     168, 130, 120, 142, 110, 99, 118, 91, 76, 93, 70, 49, 64, 46, 3, 23, 8, 195,
-     218, 143, 170, 191, 126, 147, 167, 110, 123, 141, 93, 100, 117, 76, 77, 92,
-     58, 50, 63, 36, 3, 23, 0, 199, 216, 115, 173, 190, 101, 149, 165, 88, 125,
-     140, 74, 102, 116, 59, 78, 91, 43, 51, 63, 23, 0, 23, 0, 202, 215, 83, 176,
-     189, 72, 152, 164, 62, 126, 138, 51, 103, 115, 39, 79, 90, 25, 51, 62, 6, 0,
-     22, 0, 204, 214, 50, 178, 188, 43, 153, 163, 37, 127, 138, 28, 104, 114, 18,
-     80, 89, 3, 51, 62, 0, 0, 22, 0, 172, 200, 231, 152, 176, 204, 132, 154, 178,
-     111, 130, 152, 91, 108, 126, 70, 84, 100, 46, 57, 70, 9, 15, 27, 180, 198,
-     205, 158, 175, 182, 138, 153, 159, 116, 129, 135, 95, 107, 112, 73, 83, 88,
-     48, 56, 60, 8, 15, 20, 186, 197, 182, 163, 173, 161, 141, 151, 141, 119,
-     128, 119, 97, 106, 99, 75, 82, 77, 49, 55, 51, 8, 14, 11, 190, 195, 158,
-     166, 172, 139, 144, 150, 122, 121, 127, 103, 99, 105, 84, 77, 81, 65, 50,
-     55, 41, 8, 14, 2, 194, 193, 135, 169, 170, 119, 147, 148, 103, 123, 125, 87,
-     101, 104, 70, 78, 81, 53, 51, 54, 31, 5, 14, 0, 197, 192, 109, 172, 169, 96,
-     149, 147, 83, 124, 124, 69, 102, 103, 55, 79, 80, 39, 51, 54, 19, 2, 14, 0,
-     200, 191, 80, 174, 168, 69, 150, 146, 59, 126, 123, 48, 103, 102, 36, 79,
-     79, 22, 52, 53, 2, 0, 14, 0, 202, 190, 51, 176, 167, 43, 152, 145, 36, 127,
-     123, 27, 103, 101, 16, 80, 79, 1, 52, 53, 0, 0, 14, 0, 175, 176, 215, 154,
-     156, 190, 134, 136, 166, 113, 115, 141, 93, 94, 118, 72, 73, 93, 48, 47, 64,
-     12, 2, 22, 182, 175, 191, 160, 154, 169, 139, 135, 148, 117, 114, 126, 96,
-     94, 104, 75, 72, 81, 50, 47, 55, 12, 3, 14, 186, 174, 170, 163, 153, 151,
-     142, 134, 132, 119, 113, 111, 98, 93, 92, 76, 71, 71, 51, 46, 46, 11, 3, 5,
-     190, 172, 148, 166, 152, 130, 144, 132, 114, 121, 112, 96, 100, 92, 78, 77,
-     71, 59, 51, 46, 36, 9, 4, 0, 192, 171, 127, 169, 151, 111, 146, 131, 97,
-     123, 111, 81, 101, 91, 65, 78, 70, 48, 52, 45, 26, 6, 4, 0, 195, 170, 103,
-     171, 150, 90, 148, 130, 78, 124, 110, 64, 102, 90, 51, 79, 70, 35, 52, 45,
-     15, 3, 5, 0, 198, 169, 76, 173, 149, 66, 149, 129, 56, 125, 109, 45, 103,
-     89, 33, 79, 69, 18, 52, 45, 0, 1, 5, 0, 199, 168, 51, 174, 148, 43, 150,
-     129, 35, 126, 108, 26, 103, 89, 14, 80, 69, 0, 52, 45, 0, 0, 5, 0, 177, 151,
-     198, 156, 134, 175, 136, 117, 153, 115, 98, 130, 95, 80, 108, 74, 60, 85,
-     50, 36, 58, 11, 0, 15, 183, 150, 176, 161, 133, 156, 140, 116, 137, 118, 97,
-     116, 97, 79, 96, 76, 60, 74, 51, 36, 49, 11, 0, 6, 186, 150, 158, 163, 132,
-     139, 142, 115, 122, 120, 97, 103, 99, 79, 84, 77, 59, 64, 52, 36, 41, 9, 0,
-     1, 189, 148, 137, 166, 131, 121, 144, 114, 105, 121, 96, 88, 100, 78, 72,
-     78, 59, 54, 52, 36, 31, 7, 0, 0, 191, 147, 118, 168, 130, 103, 145, 113, 90,
-     122, 95, 75, 101, 77, 60, 78, 59, 43, 52, 35, 22, 5, 0, 0, 193, 147, 97,
-     169, 129, 84, 147, 112, 72, 123, 94, 59, 101, 77, 46, 79, 58, 31, 52, 35,
-     11, 4, 0, 0, 195, 146, 73, 171, 128, 62, 148, 111, 53, 124, 93, 41, 102, 76,
-     30, 79, 58, 15, 52, 35, 0, 3, 0, 0, 197, 145, 50, 172, 128, 42, 149, 111,
-     34, 125, 93, 24, 102, 76, 12, 79, 57, 0, 52, 35, 0, 2, 0, 0, 179, 128, 183,
-     157, 113, 162, 137, 98, 142, 116, 82, 120, 96, 66, 100, 75, 48, 78, 51, 24,
-     52, 5, 0, 8, 183, 128, 163, 161, 113, 144, 140, 98, 126, 119, 81, 107, 98,
-     65, 88, 76, 48, 68, 52, 24, 43, 6, 0, 1, 186, 127, 146, 163, 112, 129, 142,
-     97, 112, 120, 81, 95, 99, 65, 77, 77, 47, 58, 52, 24, 35, 4, 0, 0, 188, 126,
-     128, 165, 111, 112, 144, 96, 97, 121, 80, 81, 100, 65, 66, 78, 47, 48, 53,
-     24, 26, 3, 0, 0, 190, 126, 110, 167, 110, 96, 145, 96, 83, 122, 80, 69, 101,
-     64, 54, 78, 47, 38, 52, 25, 18, 2, 0, 0, 192, 125, 90, 168, 110, 79, 146,
-     95, 67, 123, 79, 54, 101, 64, 42, 79, 47, 26, 52, 25, 7, 2, 0, 0, 194, 124,
-     69, 170, 109, 59, 147, 95, 49, 123, 79, 38, 101, 63, 26, 79, 47, 11, 52, 25,
-     0, 1, 0, 0, 195, 124, 49, 171, 109, 40, 148, 94, 32, 124, 78, 22, 102, 63,
-     9, 79, 46, 0, 52, 25, 0, 1, 0, 0, 180, 104, 168, 158, 91, 148, 138, 78, 130,
-     117, 64, 110, 97, 49, 91, 76, 33, 70, 52, 7, 46, 2, 0, 1, 184, 103, 150,
-     162, 91, 133, 141, 78, 116, 119, 64, 98, 99, 50, 80, 77, 33, 61, 52, 8, 37,
-     2, 0, 0, 186, 103, 135, 163, 90, 119, 142, 78, 103, 120, 64, 87, 99, 50, 70,
-     78, 33, 52, 52, 10, 30, 1, 0, 0, 188, 103, 118, 165, 90, 103, 143, 77, 90,
-     121, 63, 75, 100, 49, 60, 78, 33, 43, 52, 11, 22, 1, 0, 0, 189, 102, 102,
-     166, 89, 89, 144, 77, 76, 121, 63, 63, 100, 49, 49, 78, 34, 33, 52, 12, 14,
-     0, 0, 0, 191, 102, 84, 167, 89, 73, 145, 77, 62, 122, 63, 50, 101, 49, 37,
-     78, 34, 22, 52, 13, 4, 0, 0, 0, 192, 101, 65, 168, 89, 55, 146, 76, 46, 123,
-     63, 35, 101, 49, 23, 78, 34, 7, 51, 13, 0, 0, 0, 0, 193, 101, 48, 169, 88,
-     39, 146, 76, 31, 123, 63, 20, 101, 49, 8, 78, 34, 0, 51, 14, 0, 0, 0, 0,
-     181, 75, 154, 159, 64, 136, 139, 54, 118, 118, 41, 100, 98, 28, 82, 77, 8,
-     63, 51, 0, 39, 0, 0, 0, 184, 75, 137, 162, 65, 121, 141, 54, 106, 119, 42,
-     89, 99, 29, 72, 77, 11, 54, 52, 0, 32, 0, 0, 0, 186, 75, 123, 163, 65, 109,
-     142, 54, 94, 120, 43, 79, 99, 30, 63, 78, 12, 46, 52, 0, 25, 0, 0, 0, 187,
-     76, 108, 164, 65, 95, 143, 55, 82, 121, 43, 68, 100, 31, 54, 78, 14, 37, 52,
-     0, 17, 0, 0, 0, 188, 76, 94, 165, 65, 82, 144, 55, 70, 121, 43, 57, 100, 31,
-     44, 78, 15, 28, 51, 0, 9, 0, 0, 0, 189, 75, 78, 166, 65, 68, 144, 55, 57,
-     121, 43, 45, 100, 31, 33, 78, 16, 18, 51, 0, 2, 0, 0, 0, 190, 75, 61, 167,
-     65, 52, 145, 55, 42, 122, 44, 31, 100, 32, 19, 78, 16, 4, 51, 0, 0, 0, 0, 0,
-     191, 75, 46, 168, 65, 37, 145, 55, 29, 122, 44, 18, 100, 32, 5, 78, 17, 0,
-     50, 0, 0, 0, 0, 0, 181, 35, 140, 160, 24, 123, 140, 12, 107, 118, 0, 90, 98,
-     0, 74, 77, 0, 56, 51, 0, 33, 0, 0, 0, 184, 34, 125, 162, 26, 110, 141, 15,
-     96, 120, 1, 80, 99, 0, 65, 78, 0, 48, 51, 0, 26, 0, 0, 0, 186, 36, 113, 163,
-     27, 99, 142, 18, 86, 120, 5, 71, 99, 0, 57, 78, 0, 40, 51, 0, 20, 0, 0, 0,
-     187, 38, 99, 164, 30, 87, 142, 21, 74, 120, 8, 61, 99, 0, 48, 78, 0, 32, 51,
-     0, 12, 0, 0, 0, 187, 39, 87, 164, 31, 75, 143, 22, 64, 120, 11, 51, 100, 0,
-     39, 78, 0, 24, 51, 0, 6, 0, 0, 0, 188, 40, 73, 165, 32, 62, 143, 24, 52,
-     121, 13, 40, 100, 0, 28, 78, 0, 14, 51, 0, 0, 0, 0, 0, 189, 40, 58, 166, 33,
-     48, 144, 25, 39, 121, 15, 28, 100, 1, 16, 78, 0, 2, 50, 0, 0, 0, 0, 0, 190,
-     40, 45, 166, 34, 36, 144, 26, 27, 121, 16, 17, 100, 3, 3, 77, 0, 0, 49, 0,
-     0, 0, 0, 0, 120, 213, 247, 106, 188, 217, 92, 164, 190, 76, 139, 162, 60,
-     115, 135, 43, 91, 107, 21, 62, 76, 0, 22, 34, 134, 211, 219, 118, 186, 193,
-     102, 162, 169, 84, 138, 144, 67, 114, 120, 49, 90, 95, 26, 62, 66, 0, 22,
-     26, 143, 209, 195, 125, 184, 172, 108, 161, 151, 90, 136, 128, 72, 113, 106,
-     53, 89, 83, 29, 61, 57, 0, 22, 19, 150, 207, 169, 131, 182, 149, 113, 159,
-     130, 94, 135, 110, 76, 112, 91, 56, 88, 71, 31, 60, 47, 0, 21, 9, 156, 205,
-     145, 136, 181, 127, 117, 158, 111, 97, 133, 94, 78, 111, 77, 58, 87, 59, 33,
-     60, 37, 0, 21, 0, 161, 204, 118, 141, 179, 104, 121, 156, 90, 100, 132, 75,
-     81, 110, 61, 60, 86, 45, 35, 59, 25, 0, 21, 0, 165, 203, 89, 144, 178, 77,
-     124, 155, 67, 102, 131, 55, 82, 109, 43, 62, 85, 29, 36, 59, 10, 0, 21, 0,
-     169, 202, 62, 147, 178, 53, 126, 155, 45, 104, 131, 36, 84, 108, 25, 62, 85,
-     11, 36, 58, 0, 0, 21, 0, 129, 189, 229, 114, 167, 202, 99, 146, 177, 83,
-     124, 151, 67, 102, 126, 49, 79, 99, 28, 53, 70, 0, 12, 28, 140, 188, 204,
-     124, 166, 180, 107, 145, 158, 89, 123, 134, 72, 101, 111, 54, 79, 88, 31,
-     53, 60, 0, 12, 21, 148, 186, 182, 130, 164, 161, 112, 144, 141, 93, 121,
-     119, 76, 100, 99, 56, 78, 77, 33, 52, 51, 0, 12, 13, 153, 184, 158, 134,
-     163, 140, 116, 142, 122, 97, 120, 103, 78, 99, 85, 59, 77, 65, 35, 52, 42,
-     0, 12, 3, 158, 183, 136, 138, 161, 120, 119, 141, 104, 99, 119, 87, 80, 98,
-     71, 60, 77, 54, 36, 51, 32, 0, 12, 0, 162, 182, 112, 142, 160, 98, 122, 140,
-     85, 102, 118, 70, 82, 97, 56, 62, 76, 41, 37, 51, 21, 0, 11, 0, 166, 181,
-     85, 145, 159, 74, 125, 139, 63, 103, 117, 51, 84, 97, 39, 63, 75, 25, 37,
-     51, 6, 0, 11, 0, 168, 180, 60, 147, 158, 51, 126, 138, 43, 105, 116, 34, 85,
-     96, 23, 64, 75, 8, 38, 50, 0, 0, 11, 0, 136, 167, 213, 120, 148, 188, 105,
-     129, 165, 88, 109, 140, 71, 90, 117, 54, 69, 92, 32, 44, 64, 0, 2, 23, 145,
-     166, 190, 128, 147, 168, 111, 128, 147, 93, 108, 125, 75, 89, 104, 57, 68,
-     81, 34, 44, 55, 0, 2, 15, 151, 165, 170, 133, 146, 150, 115, 127, 131, 96,
-     107, 111, 78, 88, 92, 59, 68, 71, 36, 43, 46, 0, 2, 6, 155, 163, 148, 136,
-     144, 131, 118, 126, 114, 99, 106, 96, 80, 87, 79, 61, 67, 60, 37, 43, 37, 0,
-     2, 0, 159, 162, 128, 140, 143, 112, 121, 125, 97, 101, 105, 82, 82, 87, 66,
-     62, 67, 49, 38, 43, 27, 0, 2, 0, 163, 161, 105, 142, 142, 92, 123, 124, 80,
-     103, 104, 66, 83, 86, 52, 63, 66, 37, 39, 43, 17, 0, 2, 0, 166, 160, 81,
-     145, 141, 70, 125, 123, 59, 104, 104, 48, 84, 85, 36, 64, 66, 21, 39, 42, 2,
-     0, 1, 0, 168, 160, 59, 147, 141, 50, 126, 122, 41, 105, 103, 32, 85, 85, 20,
-     64, 65, 6, 39, 42, 0, 0, 1, 0, 142, 144, 197, 125, 128, 174, 109, 111, 153,
-     92, 93, 130, 75, 76, 108, 57, 57, 85, 36, 33, 58, 0, 0, 16, 149, 143, 176,
-     131, 127, 156, 114, 110, 136, 96, 93, 116, 78, 75, 96, 60, 57, 74, 37, 33,
-     49, 0, 0, 7, 153, 142, 157, 135, 126, 139, 117, 110, 122, 98, 92, 103, 80,
-     75, 84, 61, 56, 65, 38, 33, 41, 0, 0, 1, 157, 142, 138, 138, 125, 121, 120,
-     109, 106, 100, 91, 89, 82, 74, 72, 62, 56, 54, 39, 33, 32, 0, 0, 0, 160,
-     141, 119, 140, 124, 105, 122, 108, 91, 102, 91, 76, 83, 74, 61, 63, 56, 44,
-     40, 33, 23, 0, 0, 0, 163, 140, 99, 143, 123, 86, 124, 107, 74, 103, 90, 61,
-     84, 73, 48, 64, 55, 32, 40, 33, 13, 0, 0, 0, 165, 139, 77, 145, 122, 66,
-     125, 107, 56, 104, 89, 44, 85, 73, 33, 65, 55, 18, 40, 33, 1, 0, 0, 0, 167,
-     139, 57, 146, 122, 48, 126, 106, 39, 105, 89, 29, 86, 72, 18, 65, 55, 3, 40,
-     33, 0, 0, 0, 0, 146, 123, 182, 129, 108, 161, 113, 94, 141, 95, 78, 120, 78,
-     62, 99, 60, 45, 78, 38, 21, 52, 0, 0, 9, 152, 122, 163, 134, 108, 144, 117,
-     94, 126, 98, 78, 107, 80, 62, 88, 61, 45, 68, 39, 22, 44, 0, 0, 1, 156, 122,
-     146, 137, 107, 129, 119, 93, 113, 100, 77, 95, 82, 62, 78, 63, 45, 59, 40,
-     22, 36, 0, 0, 0, 158, 121, 128, 139, 107, 113, 121, 92, 98, 101, 77, 82, 83,
-     62, 66, 64, 45, 49, 40, 23, 27, 0, 0, 0, 161, 120, 111, 141, 106, 97, 122,
-     92, 84, 103, 77, 70, 84, 62, 56, 64, 45, 40, 40, 23, 19, 0, 0, 0, 163, 120,
-     93, 143, 105, 81, 124, 91, 69, 104, 76, 56, 85, 61, 43, 65, 45, 28, 40, 24,
-     9, 0, 0, 0, 165, 119, 73, 145, 105, 62, 125, 91, 52, 105, 76, 41, 85, 61,
-     29, 65, 44, 15, 40, 24, 0, 0, 0, 0, 166, 119, 55, 146, 104, 46, 126, 90, 37,
-     105, 75, 27, 86, 61, 15, 65, 44, 0, 40, 24, 0, 0, 0, 0, 150, 100, 168, 132,
-     88, 148, 115, 75, 130, 97, 61, 110, 80, 47, 91, 62, 30, 71, 39, 7, 46, 0, 0,
-     2, 154, 100, 150, 136, 88, 133, 119, 75, 116, 100, 61, 98, 82, 47, 81, 63,
-     31, 62, 40, 9, 38, 0, 0, 0, 157, 100, 135, 138, 87, 119, 120, 75, 104, 101,
-     61, 87, 83, 48, 71, 64, 31, 53, 40, 10, 31, 0, 0, 0, 159, 99, 119, 140, 87,
-     104, 122, 75, 91, 102, 61, 75, 84, 48, 61, 64, 32, 44, 40, 11, 23, 0, 0, 0,
-     161, 99, 104, 141, 87, 90, 123, 74, 78, 103, 61, 64, 84, 48, 50, 65, 32, 35,
-     40, 12, 15, 0, 0, 0, 163, 99, 87, 143, 86, 75, 124, 74, 64, 104, 61, 52, 85,
-     47, 39, 65, 32, 24, 40, 13, 6, 0, 0, 0, 164, 98, 69, 144, 86, 58, 125, 74,
-     49, 104, 61, 38, 85, 47, 26, 65, 32, 11, 40, 13, 0, 0, 0, 0, 166, 98, 53,
-     145, 86, 44, 126, 74, 35, 105, 60, 25, 86, 47, 13, 65, 32, 0, 40, 14, 0, 0,
-     0, 0, 152, 75, 154, 134, 64, 136, 117, 53, 119, 99, 41, 101, 82, 27, 83, 63,
-     7, 64, 39, 0, 40, 0, 0, 0, 156, 74, 138, 138, 64, 122, 120, 53, 106, 101,
-     41, 90, 83, 28, 73, 64, 10, 55, 40, 0, 33, 0, 0, 0, 158, 74, 124, 139, 64,
-     110, 121, 54, 95, 102, 42, 80, 84, 29, 64, 65, 12, 47, 41, 0, 26, 0, 0, 0,
-     160, 75, 110, 140, 64, 96, 122, 54, 83, 103, 42, 69, 84, 30, 55, 65, 13, 39,
-     41, 0, 18, 0, 0, 0, 161, 75, 96, 142, 64, 83, 123, 54, 71, 103, 43, 58, 85,
-     30, 45, 65, 14, 30, 41, 0, 11, 0, 0, 0, 163, 75, 81, 143, 64, 70, 124, 54,
-     59, 104, 43, 47, 85, 31, 35, 65, 15, 20, 41, 0, 3, 0, 0, 0, 164, 74, 65,
-     144, 64, 55, 125, 54, 45, 104, 43, 34, 85, 31, 22, 66, 16, 7, 41, 0, 0, 0,
-     0, 0, 165, 74, 51, 145, 64, 42, 125, 54, 33, 105, 43, 22, 86, 32, 10, 65,
-     17, 0, 40, 0, 0, 0, 0, 0, 154, 41, 142, 136, 30, 124, 119, 19, 108, 101, 3,
-     91, 83, 0, 75, 64, 0, 57, 39, 0, 34, 0, 0, 0, 158, 40, 127, 139, 31, 112,
-     121, 21, 97, 102, 7, 81, 84, 0, 66, 65, 0, 49, 40, 0, 27, 0, 0, 0, 159, 41,
-     114, 140, 32, 100, 122, 23, 87, 103, 10, 72, 85, 0, 58, 65, 0, 42, 40, 0,
-     21, 0, 0, 0, 160, 43, 101, 141, 34, 88, 123, 25, 76, 103, 13, 62, 85, 0, 49,
-     65, 0, 33, 41, 0, 14, 0, 0, 0, 161, 44, 89, 142, 35, 77, 123, 26, 65, 103,
-     15, 53, 85, 1, 40, 65, 0, 25, 41, 0, 7, 0, 0, 0, 162, 44, 75, 143, 36, 64,
-     124, 28, 54, 104, 17, 42, 85, 3, 30, 65, 0, 16, 40, 0, 1, 0, 0, 0, 164, 45,
-     61, 144, 37, 51, 124, 29, 42, 104, 18, 31, 85, 4, 19, 65, 0, 4, 40, 0, 0, 0,
-     0, 0, 164, 45, 49, 144, 37, 40, 125, 29, 31, 105, 19, 20, 86, 6, 7, 65, 0,
-     0, 39, 0, 0, 0, 0, 0, 49, 202, 244, 45, 178, 215, 38, 156, 188, 28, 132,
-     160, 14, 110, 134, 0, 86, 107, 0, 59, 76, 0, 20, 34, 80, 200, 217, 70, 176,
-     192, 60, 154, 168, 47, 131, 143, 34, 109, 119, 16, 85, 94, 0, 58, 66, 0, 20,
-     27, 95, 198, 194, 84, 175, 171, 71, 153, 150, 57, 130, 127, 42, 108, 106,
-     25, 84, 83, 0, 58, 57, 0, 20, 19, 107, 196, 169, 93, 173, 149, 79, 151, 130,
-     64, 128, 110, 49, 106, 91, 32, 84, 71, 3, 57, 47, 0, 19, 10, 115, 195, 145,
-     100, 171, 128, 86, 150, 112, 69, 127, 94, 53, 105, 78, 36, 83, 59, 8, 57,
-     37, 0, 19, 1, 122, 193, 120, 107, 170, 106, 91, 149, 92, 74, 126, 77, 57,
-     104, 62, 39, 82, 46, 13, 56, 26, 0, 18, 0, 128, 192, 93, 112, 169, 81, 95,
-     148, 70, 77, 125, 58, 60, 104, 46, 42, 81, 31, 15, 56, 13, 0, 17, 0, 132,
-     191, 69, 115, 168, 60, 98, 147, 51, 79, 124, 41, 62, 103, 30, 43, 81, 17,
-     16, 56, 0, 0, 17, 0, 77, 180, 227, 69, 159, 200, 60, 139, 176, 48, 118, 150,
-     35, 97, 125, 20, 75, 99, 0, 50, 70, 0, 9, 29, 96, 178, 203, 85, 158, 179,
-     73, 138, 157, 59, 117, 133, 45, 96, 111, 29, 75, 87, 3, 50, 60, 0, 9, 21,
-     107, 177, 181, 94, 156, 160, 80, 137, 140, 65, 116, 119, 51, 96, 98, 34, 74,
-     77, 9, 49, 52, 0, 8, 14, 115, 175, 158, 101, 155, 140, 86, 135, 122, 71,
-     114, 103, 55, 95, 85, 38, 73, 65, 14, 49, 42, 0, 7, 4, 121, 174, 137, 106,
-     153, 120, 91, 134, 105, 74, 113, 88, 58, 94, 72, 41, 73, 54, 17, 49, 33, 0,
-     6, 0, 127, 173, 114, 111, 152, 100, 95, 133, 86, 78, 112, 72, 61, 93, 58,
-     43, 72, 42, 19, 48, 22, 0, 6, 0, 132, 172, 88, 115, 151, 77, 98, 132, 66,
-     80, 112, 54, 63, 92, 42, 45, 72, 28, 20, 48, 9, 0, 5, 0, 135, 171, 67, 118,
-     151, 57, 100, 131, 49, 82, 111, 39, 65, 92, 28, 46, 71, 13, 21, 48, 0, 0, 5,
-     0, 93, 159, 211, 83, 141, 187, 72, 123, 164, 59, 104, 140, 46, 85, 116, 31,
-     65, 92, 8, 41, 64, 0, 1, 23, 106, 158, 189, 94, 140, 167, 81, 122, 147, 67,
-     103, 124, 52, 85, 103, 36, 65, 81, 14, 41, 55, 0, 0, 15, 114, 157, 169, 100,
-     139, 150, 87, 121, 131, 71, 102, 111, 56, 84, 92, 40, 64, 71, 17, 41, 47, 0,
-     0, 7, 121, 156, 148, 106, 138, 131, 91, 120, 114, 75, 101, 96, 60, 83, 79,
-     43, 64, 60, 20, 40, 37, 0, 0, 1, 126, 155, 129, 110, 136, 113, 95, 119, 98,
-     78, 101, 82, 62, 83, 67, 45, 63, 50, 22, 40, 28, 0, 0, 0, 130, 154, 107,
-     114, 135, 94, 98, 118, 81, 81, 100, 67, 64, 82, 54, 46, 63, 38, 23, 40, 18,
-     0, 0, 0, 134, 153, 84, 117, 135, 73, 101, 117, 62, 83, 99, 51, 66, 81, 39,
-     48, 62, 24, 24, 40, 5, 0, 0, 0, 137, 152, 65, 119, 134, 55, 102, 117, 46,
-     84, 99, 36, 67, 81, 25, 48, 62, 11, 24, 40, 0, 0, 0, 0, 105, 138, 196, 93,
-     122, 173, 81, 106, 152, 67, 89, 129, 53, 72, 107, 38, 54, 84, 17, 30, 58, 0,
-     0, 17, 115, 137, 175, 101, 121, 155, 88, 106, 136, 73, 89, 115, 58, 72, 95,
-     42, 54, 74, 21, 31, 49, 0, 0, 8, 120, 136, 157, 106, 120, 139, 92, 105, 121,
-     76, 88, 103, 61, 71, 84, 44, 53, 65, 23, 31, 41, 0, 0, 1, 125, 135, 138,
-     110, 119, 122, 95, 104, 106, 79, 87, 89, 63, 71, 73, 46, 53, 55, 25, 31, 33,
-     0, 0, 0, 129, 134, 120, 113, 119, 105, 98, 103, 91, 81, 87, 76, 65, 71, 61,
-     48, 53, 45, 26, 31, 24, 0, 0, 0, 133, 134, 101, 116, 118, 88, 100, 103, 76,
-     83, 86, 62, 67, 70, 49, 49, 53, 34, 27, 31, 14, 0, 0, 0, 136, 133, 80, 119,
-     117, 69, 102, 102, 58, 85, 86, 47, 68, 70, 35, 50, 52, 20, 27, 31, 3, 0, 0,
-     0, 138, 133, 62, 121, 117, 52, 104, 102, 43, 86, 85, 33, 69, 69, 22, 50, 52,
-     7, 27, 31, 0, 0, 0, 0, 114, 118, 182, 100, 104, 161, 87, 90, 141, 73, 75,
-     120, 59, 59, 99, 43, 42, 78, 22, 20, 52, 0, 0, 10, 121, 117, 163, 106, 104,
-     144, 92, 90, 126, 77, 75, 107, 62, 59, 88, 46, 42, 68, 24, 21, 44, 0, 0, 2,
-     125, 117, 146, 110, 103, 129, 95, 89, 113, 79, 74, 95, 64, 59, 78, 47, 42,
-     59, 26, 21, 36, 0, 0, 0, 129, 116, 129, 113, 102, 113, 98, 89, 99, 82, 74,
-     83, 66, 59, 67, 49, 42, 50, 27, 22, 28, 0, 0, 0, 132, 116, 112, 116, 102,
-     98, 100, 88, 85, 83, 73, 71, 67, 59, 57, 50, 43, 41, 28, 22, 20, 0, 0, 0,
-     134, 115, 95, 118, 101, 82, 102, 88, 71, 85, 73, 58, 68, 59, 45, 51, 43, 30,
-     29, 22, 11, 0, 0, 0, 137, 115, 76, 120, 101, 65, 104, 87, 55, 86, 73, 44,
-     69, 58, 32, 51, 42, 18, 29, 22, 1, 0, 0, 0, 139, 114, 60, 122, 100, 50, 105,
-     87, 41, 87, 72, 31, 70, 58, 19, 51, 42, 4, 29, 22, 0, 0, 0, 0, 120, 97, 168,
-     106, 85, 149, 92, 73, 130, 77, 59, 110, 63, 45, 91, 47, 28, 71, 25, 6, 47,
-     0, 0, 3, 126, 97, 151, 111, 85, 133, 96, 73, 117, 80, 59, 98, 65, 46, 81,
-     48, 29, 62, 27, 7, 39, 0, 0, 0, 129, 97, 136, 113, 85, 120, 98, 73, 104, 82,
-     59, 88, 67, 46, 72, 50, 30, 54, 29, 8, 32, 0, 0, 0, 132, 96, 120, 116, 84,
-     105, 100, 72, 91, 84, 59, 76, 68, 46, 61, 51, 30, 45, 29, 9, 24, 0, 0, 0,
-     134, 96, 105, 117, 84, 92, 102, 72, 79, 85, 59, 65, 69, 46, 52, 51, 30, 36,
-     30, 10, 16, 0, 0, 0, 136, 96, 89, 119, 84, 77, 103, 72, 66, 86, 59, 53, 69,
-     46, 41, 52, 31, 26, 30, 11, 7, 0, 0, 0, 138, 95, 71, 121, 83, 61, 105, 72,
-     51, 87, 59, 40, 70, 46, 28, 52, 31, 14, 30, 11, 0, 0, 0, 0, 139, 95, 57,
-     122, 83, 47, 106, 71, 38, 88, 59, 28, 71, 46, 17, 52, 31, 2, 29, 12, 0, 0,
-     0, 0, 125, 74, 155, 110, 63, 137, 96, 52, 120, 81, 40, 101, 66, 27, 83, 49,
-     7, 64, 27, 0, 41, 0, 0, 0, 129, 73, 139, 114, 63, 123, 99, 53, 107, 83, 41,
-     90, 68, 28, 74, 51, 10, 56, 29, 0, 33, 0, 0, 0, 132, 74, 125, 116, 63, 110,
-     101, 53, 96, 84, 41, 80, 69, 29, 65, 51, 12, 48, 30, 0, 27, 0, 0, 0, 134,
-     74, 111, 118, 64, 97, 102, 53, 84, 85, 42, 70, 69, 29, 56, 52, 13, 40, 30,
-     0, 19, 0, 0, 0, 136, 74, 97, 119, 64, 85, 103, 53, 73, 86, 42, 60, 70, 30,
-     47, 52, 14, 31, 30, 0, 12, 0, 0, 0, 137, 74, 83, 121, 64, 71, 104, 54, 61,
-     87, 42, 49, 71, 30, 36, 53, 15, 22, 30, 0, 5, 0, 0, 0, 139, 74, 67, 122, 64,
-     57, 105, 54, 47, 88, 42, 36, 71, 31, 25, 53, 16, 9, 30, 0, 0, 0, 0, 0, 140,
-     73, 54, 123, 64, 45, 106, 54, 36, 88, 43, 26, 71, 31, 14, 53, 17, 1, 29, 0,
-     0, 0, 0, 0, 129, 44, 143, 114, 34, 126, 99, 24, 110, 84, 9, 92, 68, 0, 76,
-     51, 0, 58, 28, 0, 35, 0, 0, 0, 132, 44, 128, 117, 35, 113, 102, 25, 98, 85,
-     12, 82, 69, 0, 67, 52, 0, 50, 29, 0, 28, 0, 0, 0, 134, 45, 116, 118, 36,
-     102, 103, 27, 88, 86, 14, 73, 70, 0, 59, 52, 0, 43, 29, 0, 22, 0, 0, 0, 136,
-     46, 103, 119, 37, 90, 103, 28, 77, 87, 17, 64, 71, 1, 50, 53, 0, 35, 30, 0,
-     15, 0, 0, 0, 137, 47, 90, 120, 38, 78, 104, 29, 67, 87, 18, 54, 71, 3, 42,
-     53, 0, 27, 29, 0, 8, 0, 0, 0, 138, 47, 77, 121, 39, 66, 105, 30, 56, 88, 19,
-     44, 71, 5, 32, 53, 0, 18, 29, 0, 2, 0, 0, 0, 139, 48, 63, 122, 39, 53, 106,
-     31, 44, 88, 20, 33, 71, 7, 21, 53, 0, 6, 28, 0, 0, 0, 0, 0, 140, 48, 52,
-     123, 40, 42, 107, 31, 33, 89, 21, 23, 72, 8, 10, 53, 0, 0, 27, 0, 0, 0, 0,
-     0, 0, 192, 242, 0, 169, 213, 0, 148, 187, 0, 125, 159, 0, 104, 133, 0, 82,
-     106, 0, 56, 76, 0, 18, 34, 0, 189, 216, 0, 167, 190, 0, 147, 167, 0, 124,
-     142, 0, 103, 119, 0, 81, 94, 0, 55, 66, 0, 16, 27, 0, 188, 193, 0, 166, 170,
-     0, 145, 149, 0, 123, 127, 0, 102, 105, 0, 80, 83, 0, 55, 57, 0, 15, 20, 32,
-     186, 168, 27, 164, 149, 17, 144, 130, 0, 122, 110, 0, 101, 91, 0, 79, 71, 0,
-     55, 47, 0, 14, 11, 56, 184, 146, 47, 163, 129, 37, 142, 113, 23, 121, 95, 5,
-     100, 78, 0, 79, 60, 0, 54, 38, 0, 14, 2, 70, 183, 122, 60, 161, 107, 49,
-     141, 94, 35, 120, 79, 20, 100, 64, 0, 78, 48, 0, 54, 27, 0, 13, 0, 80, 182,
-     96, 69, 160, 84, 57, 140, 73, 43, 119, 61, 28, 99, 48, 6, 78, 34, 0, 53, 15,
-     0, 13, 0, 87, 181, 74, 75, 160, 65, 62, 140, 56, 47, 119, 46, 32, 98, 35,
-     12, 77, 21, 0, 53, 2, 0, 13, 0, 0, 171, 225, 0, 151, 199, 0, 132, 174, 0,
-     112, 149, 0, 92, 124, 0, 71, 98, 0, 47, 69, 0, 4, 29, 0, 169, 201, 0, 150,
-     178, 0, 131, 156, 0, 111, 133, 0, 92, 111, 0, 71, 87, 0, 47, 60, 0, 3, 22,
-     41, 168, 180, 36, 148, 159, 28, 130, 140, 15, 110, 118, 0, 91, 98, 0, 70,
-     77, 0, 46, 52, 0, 2, 14, 61, 166, 158, 53, 147, 139, 43, 129, 122, 31, 109,
-     103, 17, 90, 85, 0, 70, 66, 0, 46, 43, 0, 2, 5, 73, 165, 137, 64, 146, 121,
-     53, 128, 106, 40, 108, 89, 26, 89, 73, 6, 69, 55, 0, 46, 33, 0, 1, 0, 83,
-     164, 115, 72, 145, 101, 60, 127, 88, 46, 107, 73, 32, 89, 59, 14, 69, 43, 0,
-     46, 23, 0, 1, 0, 90, 163, 91, 78, 144, 80, 65, 126, 69, 51, 106, 57, 37, 88,
-     44, 19, 68, 30, 0, 45, 11, 0, 1, 0, 95, 163, 72, 82, 143, 62, 69, 125, 53,
-     54, 106, 43, 39, 88, 32, 22, 68, 18, 0, 45, 0, 0, 1, 0, 0, 152, 210, 0, 134,
-     186, 0, 117, 163, 0, 99, 139, 0, 81, 116, 0, 62, 92, 0, 38, 64, 0, 1, 24,
-     47, 151, 188, 42, 133, 167, 35, 117, 146, 24, 98, 124, 10, 81, 103, 0, 61,
-     81, 0, 38, 55, 0, 0, 16, 65, 150, 169, 57, 132, 149, 47, 116, 131, 36, 98,
-     111, 23, 80, 92, 4, 61, 71, 0, 38, 47, 0, 0, 7, 76, 148, 148, 67, 131, 131,
-     56, 115, 114, 44, 97, 96, 31, 79, 79, 14, 61, 61, 0, 38, 38, 0, 0, 1, 84,
-     147, 129, 74, 130, 114, 62, 114, 99, 49, 96, 83, 35, 79, 68, 19, 60, 50, 0,
-     37, 29, 0, 0, 0, 91, 146, 109, 80, 129, 95, 67, 113, 83, 53, 95, 69, 39, 78,
-     55, 23, 60, 39, 1, 37, 20, 0, 0, 0, 97, 146, 87, 84, 128, 76, 71, 112, 65,
-     57, 95, 53, 42, 78, 41, 26, 60, 26, 4, 37, 7, 0, 0, 0, 101, 145, 69, 88,
-     128, 59, 74, 112, 50, 59, 94, 40, 44, 77, 29, 27, 59, 15, 4, 37, 0, 0, 0, 0,
-     52, 132, 195, 47, 117, 172, 40, 102, 151, 30, 85, 129, 19, 69, 107, 2, 51,
-     84, 0, 28, 58, 0, 0, 18, 70, 131, 175, 61, 116, 155, 52, 101, 135, 41, 85,
-     115, 29, 68, 95, 13, 51, 74, 0, 28, 49, 0, 0, 9, 80, 130, 157, 70, 115, 139,
-     59, 100, 121, 47, 84, 103, 35, 68, 85, 19, 51, 65, 0, 28, 42, 0, 0, 1, 87,
-     130, 138, 76, 114, 122, 65, 100, 106, 52, 84, 89, 39, 68, 73, 24, 50, 55, 4,
-     28, 33, 0, 0, 0, 93, 129, 121, 81, 114, 106, 69, 99, 92, 56, 83, 77, 42, 67,
-     62, 27, 50, 46, 7, 29, 25, 0, 0, 0, 98, 128, 102, 86, 113, 89, 73, 98, 77,
-     59, 82, 64, 45, 67, 50, 29, 50, 35, 9, 29, 16, 0, 0, 0, 102, 127, 82, 89,
-     112, 71, 76, 98, 61, 61, 82, 49, 47, 66, 37, 31, 50, 23, 11, 29, 4, 0, 0, 0,
-     105, 127, 66, 92, 112, 56, 78, 97, 47, 63, 82, 37, 48, 66, 25, 32, 50, 11,
-     10, 29, 0, 0, 0, 0, 72, 114, 181, 63, 100, 160, 54, 87, 140, 44, 72, 119,
-     32, 57, 99, 18, 39, 78, 0, 18, 52, 0, 0, 11, 83, 113, 163, 73, 100, 144, 62,
-     86, 126, 50, 71, 107, 38, 57, 88, 24, 40, 68, 3, 19, 44, 0, 0, 3, 89, 113,
-     147, 78, 99, 129, 67, 86, 113, 55, 71, 95, 42, 57, 78, 27, 40, 60, 8, 19,
-     37, 0, 0, 0, 95, 112, 129, 83, 98, 114, 71, 85, 99, 58, 71, 83, 45, 56, 67,
-     30, 40, 50, 11, 20, 29, 0, 0, 0, 99, 111, 113, 86, 98, 99, 74, 85, 86, 60,
-     70, 72, 47, 56, 57, 31, 40, 41, 12, 20, 21, 0, 0, 0, 103, 111, 96, 90, 97,
-     84, 77, 84, 72, 63, 70, 59, 49, 56, 46, 33, 40, 31, 13, 21, 12, 0, 0, 0,
-     106, 110, 78, 93, 97, 67, 79, 84, 57, 64, 70, 46, 50, 56, 34, 34, 40, 19,
-     13, 21, 2, 0, 0, 0, 108, 110, 63, 95, 97, 53, 81, 84, 44, 66, 69, 34, 51,
-     56, 22, 35, 40, 7, 13, 21, 0, 0, 0, 0, 85, 94, 168, 74, 82, 149, 64, 70,
-     130, 53, 57, 110, 41, 43, 91, 27, 26, 71, 5, 5, 47, 0, 0, 4, 92, 94, 151,
-     81, 82, 134, 70, 70, 117, 57, 57, 99, 45, 44, 81, 30, 27, 62, 10, 7, 39, 0,
-     0, 0, 97, 94, 136, 85, 82, 120, 73, 70, 105, 60, 57, 88, 47, 44, 72, 32, 28,
-     54, 13, 8, 32, 0, 0, 0, 101, 94, 121, 88, 82, 106, 76, 70, 92, 62, 57, 77,
-     49, 44, 62, 34, 28, 45, 14, 9, 25, 0, 0, 0, 104, 93, 106, 91, 81, 93, 78,
-     70, 80, 64, 57, 66, 50, 44, 52, 35, 29, 37, 14, 10, 17, 0, 0, 0, 106, 93,
-     90, 93, 81, 78, 80, 69, 67, 66, 57, 55, 52, 44, 42, 36, 29, 27, 15, 11, 8,
-     0, 0, 0, 109, 92, 74, 96, 81, 63, 82, 69, 53, 67, 57, 42, 53, 44, 30, 36,
-     29, 16, 15, 11, 1, 0, 0, 0, 111, 92, 60, 97, 80, 50, 83, 69, 41, 68, 57, 31,
-     53, 44, 20, 37, 30, 5, 15, 11, 0, 0, 0, 0, 94, 73, 155, 82, 63, 137, 72, 52,
-     120, 59, 40, 102, 47, 26, 84, 32, 8, 65, 9, 0, 42, 0, 0, 0, 99, 73, 140, 87,
-     63, 124, 76, 52, 108, 62, 40, 91, 49, 27, 75, 34, 11, 57, 12, 0, 34, 0, 0,
-     0, 103, 73, 126, 90, 63, 111, 78, 53, 97, 64, 41, 81, 51, 28, 66, 35, 13,
-     49, 13, 0, 27, 0, 0, 0, 105, 73, 112, 92, 63, 98, 80, 53, 85, 66, 41, 71,
-     52, 29, 57, 36, 14, 41, 15, 0, 20, 0, 0, 0, 107, 73, 99, 94, 63, 86, 81, 53,
-     74, 67, 41, 61, 53, 29, 48, 37, 15, 32, 16, 0, 13, 0, 0, 0, 110, 73, 85, 96,
-     63, 73, 83, 53, 62, 68, 42, 50, 54, 30, 38, 38, 16, 23, 16, 1, 5, 0, 0, 0,
-     112, 73, 69, 98, 63, 59, 84, 53, 49, 69, 42, 38, 55, 30, 27, 38, 16, 12, 17,
-     1, 0, 0, 0, 0, 113, 73, 57, 99, 63, 47, 85, 53, 38, 70, 42, 28, 55, 30, 17,
-     38, 17, 3, 16, 2, 0, 0, 0, 0, 101, 47, 144, 88, 38, 127, 77, 27, 111, 64,
-     14, 94, 51, 0, 77, 35, 0, 59, 9, 0, 36, 0, 0, 0, 105, 47, 129, 92, 38, 114,
-     80, 28, 99, 66, 16, 83, 53, 0, 68, 37, 0, 51, 13, 0, 29, 0, 0, 0, 107, 48,
-     117, 94, 39, 103, 81, 29, 89, 67, 18, 74, 54, 2, 60, 38, 0, 44, 15, 0, 23,
-     0, 0, 0, 109, 49, 104, 95, 40, 91, 82, 31, 79, 68, 19, 65, 54, 5, 51, 39, 0,
-     36, 17, 0, 16, 0, 0, 0, 110, 50, 92, 97, 40, 80, 84, 31, 68, 69, 20, 56, 55,
-     7, 43, 39, 0, 28, 17, 0, 9, 0, 0, 0, 112, 50, 79, 98, 41, 68, 85, 32, 57,
-     70, 21, 46, 56, 8, 34, 40, 0, 20, 18, 0, 3, 0, 0, 0, 113, 50, 65, 100, 41,
-     55, 86, 33, 46, 71, 22, 35, 56, 10, 23, 40, 0, 8, 17, 0, 0, 0, 0, 0, 115,
-     50, 54, 101, 41, 44, 87, 33, 36, 71, 23, 25, 56, 11, 14, 40, 0, 1, 16, 0, 0,
-     0, 0, 0, 0, 182, 240, 0, 161, 212, 0, 141, 185, 0, 120, 158, 0, 99, 132, 0,
-     78, 106, 0, 53, 75, 0, 12, 35, 0, 180, 214, 0, 159, 189, 0, 140, 166, 0,
-     119, 141, 0, 99, 118, 0, 77, 94, 0, 53, 66, 0, 11, 28, 0, 179, 192, 0, 158,
-     169, 0, 138, 149, 0, 118, 126, 0, 98, 105, 0, 77, 83, 0, 52, 57, 0, 10, 21,
-     0, 177, 168, 0, 156, 149, 0, 137, 130, 0, 116, 110, 0, 97, 91, 0, 76, 71, 0,
-     52, 48, 0, 9, 12, 0, 175, 146, 0, 155, 129, 0, 136, 113, 0, 115, 96, 0, 96,
-     79, 0, 75, 60, 0, 51, 39, 0, 9, 3, 0, 174, 123, 0, 154, 109, 0, 135, 95, 0,
-     115, 80, 0, 95, 65, 0, 75, 49, 0, 51, 28, 0, 8, 0, 0, 173, 98, 0, 153, 87,
-     0, 134, 76, 0, 114, 63, 0, 95, 50, 0, 74, 35, 0, 51, 17, 0, 8, 0, 0, 172,
-     78, 0, 152, 70, 0, 134, 60, 0, 114, 49, 0, 94, 38, 0, 74, 24, 0, 51, 5, 0,
-     8, 0, 0, 163, 224, 0, 144, 198, 0, 126, 173, 0, 107, 148, 0, 88, 123, 0, 68,
-     98, 0, 44, 69, 0, 1, 29, 0, 162, 200, 0, 143, 177, 0, 125, 155, 0, 106, 132,
-     0, 88, 110, 0, 68, 87, 0, 44, 60, 0, 1, 22, 0, 160, 180, 0, 142, 159, 0,
-     124, 139, 0, 105, 118, 0, 87, 98, 0, 67, 77, 0, 44, 52, 0, 0, 15, 0, 159,
-     158, 0, 140, 139, 0, 123, 122, 0, 104, 103, 0, 86, 85, 0, 67, 66, 0, 43, 43,
-     0, 0, 5, 0, 157, 138, 0, 139, 121, 0, 122, 106, 0, 103, 89, 0, 85, 73, 0,
-     66, 56, 0, 43, 34, 0, 0, 0, 0, 156, 116, 0, 138, 102, 0, 121, 89, 0, 103,
-     75, 0, 85, 60, 0, 66, 44, 0, 43, 24, 0, 0, 0, 6, 155, 94, 2, 137, 82, 0,
-     120, 71, 0, 102, 59, 0, 84, 46, 0, 65, 32, 0, 43, 13, 0, 0, 0, 30, 155, 75,
-     23, 137, 66, 11, 120, 57, 0, 102, 46, 0, 84, 35, 0, 65, 20, 0, 43, 2, 0, 0,
-     0, 0, 145, 209, 0, 129, 185, 0, 112, 162, 0, 95, 138, 0, 77, 115, 0, 59, 91,
-     0, 35, 64, 0, 1, 24, 0, 144, 188, 0, 128, 166, 0, 112, 145, 0, 94, 124, 0,
-     77, 103, 0, 58, 81, 0, 35, 55, 0, 0, 16, 0, 143, 168, 0, 127, 149, 0, 111,
-     130, 0, 93, 111, 0, 77, 92, 0, 58, 71, 0, 35, 47, 0, 0, 8, 0, 142, 148, 0,
-     126, 131, 0, 110, 114, 0, 93, 97, 0, 76, 79, 0, 58, 61, 0, 35, 38, 0, 0, 1,
-     0, 141, 130, 0, 125, 114, 0, 109, 100, 0, 92, 84, 0, 75, 68, 0, 58, 51, 0,
-     35, 30, 0, 0, 0, 27, 140, 110, 22, 124, 97, 12, 108, 84, 0, 91, 70, 0, 75,
-     56, 0, 57, 40, 0, 35, 21, 0, 0, 0, 43, 139, 89, 36, 123, 78, 26, 108, 67,
-     12, 91, 55, 0, 74, 43, 0, 57, 28, 0, 35, 9, 0, 0, 0, 51, 139, 72, 43, 123,
-     63, 33, 107, 53, 20, 90, 43, 3, 74, 31, 0, 57, 18, 0, 35, 1, 0, 0, 0, 0,
-     127, 194, 0, 112, 172, 0, 98, 151, 0, 81, 128, 0, 66, 107, 0, 48, 84, 0, 26,
-     58, 0, 0, 18, 0, 126, 174, 0, 111, 154, 0, 97, 135, 0, 81, 115, 0, 65, 95,
-     0, 48, 74, 0, 26, 50, 0, 0, 9, 0, 125, 157, 0, 111, 139, 0, 96, 121, 0, 81,
-     103, 0, 65, 85, 0, 48, 65, 0, 27, 42, 0, 0, 2, 20, 125, 139, 17, 110, 122,
-     9, 96, 107, 0, 80, 90, 0, 65, 73, 0, 48, 56, 0, 27, 34, 0, 0, 0, 39, 124,
-     122, 33, 109, 107, 25, 95, 93, 13, 80, 78, 0, 65, 63, 0, 48, 46, 0, 27, 26,
-     0, 0, 0, 51, 123, 103, 43, 108, 90, 34, 94, 78, 23, 79, 65, 8, 64, 51, 0,
-     48, 36, 0, 27, 17, 0, 0, 0, 59, 122, 84, 51, 108, 73, 41, 94, 63, 29, 79,
-     51, 15, 64, 39, 0, 47, 24, 0, 27, 6, 0, 0, 0, 64, 122, 69, 55, 107, 59, 45,
-     94, 50, 32, 78, 39, 19, 64, 28, 0, 47, 14, 0, 27, 0, 0, 0, 0, 0, 110, 181,
-     0, 97, 160, 0, 83, 140, 0, 69, 119, 0, 54, 99, 0, 37, 78, 0, 16, 53, 0, 0,
-     12, 7, 109, 163, 8, 96, 144, 3, 83, 126, 0, 69, 107, 0, 54, 88, 0, 38, 68,
-     0, 17, 45, 0, 0, 3, 34, 109, 147, 30, 96, 129, 23, 83, 113, 13, 69, 95, 0,
-     54, 78, 0, 38, 60, 0, 18, 37, 0, 0, 0, 48, 108, 130, 41, 95, 114, 33, 82,
-     99, 23, 68, 84, 10, 54, 68, 0, 38, 51, 0, 18, 29, 0, 0, 0, 56, 108, 114, 49,
-     94, 100, 40, 82, 87, 29, 68, 72, 16, 54, 58, 0, 38, 42, 0, 18, 22, 0, 0, 0,
-     63, 107, 97, 55, 94, 85, 45, 81, 73, 34, 68, 60, 21, 54, 47, 5, 38, 32, 0,
-     18, 13, 0, 0, 0, 68, 106, 80, 59, 93, 69, 49, 81, 59, 37, 67, 47, 25, 54,
-     35, 9, 38, 21, 0, 18, 4, 0, 0, 0, 72, 106, 66, 63, 93, 56, 52, 81, 47, 40,
-     67, 36, 27, 53, 25, 11, 38, 11, 0, 18, 0, 0, 0, 0, 28, 92, 168, 24, 80, 149,
-     19, 68, 130, 11, 55, 111, 0, 41, 92, 0, 25, 71, 0, 6, 47, 0, 0, 5, 46, 92,
-     151, 40, 80, 134, 33, 68, 117, 24, 55, 99, 12, 42, 81, 0, 26, 63, 0, 7, 40,
-     0, 0, 0, 55, 91, 137, 48, 80, 121, 40, 68, 105, 30, 55, 89, 18, 42, 72, 2,
-     27, 55, 0, 8, 32, 0, 0, 0, 62, 91, 121, 54, 79, 107, 45, 68, 93, 34, 55, 77,
-     23, 42, 62, 7, 27, 46, 0, 8, 25, 0, 0, 0, 67, 91, 107, 58, 79, 93, 49, 68,
-     81, 38, 55, 67, 26, 42, 53, 12, 27, 37, 0, 8, 18, 0, 0, 0, 72, 90, 91, 62,
-     79, 79, 52, 67, 68, 41, 55, 56, 29, 42, 43, 15, 28, 28, 1, 9, 9, 0, 0, 0,
-     76, 90, 75, 66, 78, 65, 56, 67, 55, 43, 55, 44, 31, 42, 32, 17, 28, 18, 2,
-     9, 2, 0, 0, 0, 78, 90, 62, 68, 78, 52, 58, 67, 43, 45, 55, 33, 32, 42, 22,
-     19, 28, 7, 2, 9, 0, 0, 0, 0, 53, 72, 156, 46, 62, 138, 39, 51, 121, 30, 39,
-     102, 20, 25, 84, 2, 9, 65, 0, 0, 42, 0, 0, 0, 62, 72, 140, 55, 62, 124, 46,
-     52, 108, 36, 40, 91, 25, 27, 75, 9, 11, 57, 0, 0, 34, 0, 0, 0, 68, 72, 127,
-     59, 62, 112, 50, 52, 97, 39, 40, 82, 28, 27, 66, 13, 12, 49, 0, 0, 28, 0, 0,
-     0, 72, 73, 113, 63, 62, 99, 53, 52, 86, 42, 40, 71, 30, 28, 57, 17, 13, 41,
-     0, 0, 21, 0, 0, 0, 76, 72, 100, 66, 62, 87, 56, 52, 75, 44, 41, 62, 32, 29,
-     48, 19, 14, 33, 3, 0, 13, 0, 0, 0, 79, 72, 86, 69, 62, 74, 58, 52, 63, 46,
-     41, 51, 34, 29, 39, 21, 15, 24, 4, 1, 6, 0, 0, 0, 81, 72, 71, 71, 62, 61,
-     60, 52, 51, 48, 41, 40, 35, 29, 28, 22, 15, 13, 5, 1, 0, 0, 0, 0, 83, 72,
-     59, 73, 62, 49, 62, 52, 41, 49, 41, 31, 36, 30, 20, 22, 16, 5, 4, 2, 0, 0,
-     0, 0, 67, 49, 144, 59, 40, 128, 50, 30, 112, 40, 18, 95, 29, 2, 78, 13, 0,
-     60, 0, 0, 37, 0, 0, 0, 73, 50, 130, 64, 40, 115, 55, 31, 100, 44, 19, 84,
-     32, 4, 69, 18, 0, 52, 0, 0, 30, 0, 0, 0, 76, 50, 118, 67, 41, 104, 57, 32,
-     90, 46, 20, 75, 34, 7, 61, 20, 0, 45, 0, 0, 24, 0, 0, 0, 79, 51, 105, 69,
-     42, 92, 59, 33, 80, 47, 21, 66, 35, 9, 52, 22, 0, 37, 1, 0, 16, 0, 0, 0, 81,
-     52, 93, 71, 42, 81, 61, 33, 70, 49, 22, 57, 36, 11, 44, 23, 0, 29, 2, 0, 9,
-     0, 0, 0, 83, 52, 80, 73, 43, 69, 62, 34, 59, 50, 23, 47, 37, 12, 35, 23, 0,
-     21, 3, 0, 3, 0, 0, 0, 85, 52, 67, 75, 43, 57, 64, 34, 47, 51, 24, 36, 38,
-     13, 25, 24, 0, 10, 3, 0, 0, 0, 0, 0, 87, 52, 56, 76, 43, 46, 65, 34, 37, 52,
-     24, 27, 39, 14, 16, 24, 0, 2, 2, 0, 0, 0, 0, 0, 0, 174, 238, 0, 154, 210, 0,
-     135, 184, 0, 115, 157, 0, 95, 132, 0, 75, 105, 0, 50, 75, 0, 6, 35, 0, 172,
-     213, 0, 153, 188, 0, 134, 165, 0, 114, 141, 0, 94, 118, 0, 74, 93, 0, 50,
-     66, 0, 5, 28, 0, 171, 191, 0, 151, 169, 0, 133, 148, 0, 113, 126, 0, 94,
-     105, 0, 73, 83, 0, 50, 57, 0, 5, 21, 0, 169, 168, 0, 150, 148, 0, 131, 130,
-     0, 112, 110, 0, 93, 92, 0, 73, 71, 0, 49, 48, 0, 5, 13, 0, 167, 146, 0, 148,
-     130, 0, 130, 113, 0, 111, 96, 0, 92, 79, 0, 72, 61, 0, 49, 39, 0, 4, 3, 0,
-     166, 124, 0, 147, 110, 0, 129, 96, 0, 110, 81, 0, 92, 66, 0, 72, 49, 0, 49,
-     29, 0, 4, 0, 0, 165, 100, 0, 146, 89, 0, 129, 78, 0, 110, 65, 0, 91, 52, 0,
-     72, 37, 0, 49, 18, 0, 4, 0, 0, 164, 82, 0, 146, 73, 0, 128, 64, 0, 109, 52,
-     0, 91, 41, 0, 72, 26, 0, 49, 8, 0, 4, 0, 0, 157, 223, 0, 138, 197, 0, 121,
-     172, 0, 102, 147, 0, 84, 123, 0, 65, 98, 0, 41, 69, 0, 1, 30, 0, 155, 199,
-     0, 137, 176, 0, 120, 155, 0, 102, 132, 0, 84, 110, 0, 65, 87, 0, 41, 60, 0,
-     1, 22, 0, 154, 179, 0, 136, 158, 0, 119, 139, 0, 101, 118, 0, 83, 98, 0, 64,
-     77, 0, 41, 52, 0, 0, 15, 0, 152, 158, 0, 135, 139, 0, 118, 122, 0, 100, 103,
-     0, 83, 85, 0, 64, 66, 0, 41, 43, 0, 0, 6, 0, 151, 138, 0, 133, 122, 0, 117,
-     106, 0, 99, 90, 0, 82, 74, 0, 64, 56, 0, 41, 35, 0, 0, 0, 0, 150, 117, 0,
-     133, 103, 0, 116, 90, 0, 99, 76, 0, 82, 61, 0, 63, 45, 0, 41, 25, 0, 0, 0,
-     0, 149, 95, 0, 132, 84, 0, 116, 73, 0, 98, 61, 0, 81, 48, 0, 63, 33, 0, 41,
-     15, 0, 0, 0, 0, 148, 78, 0, 131, 69, 0, 115, 59, 0, 98, 49, 0, 81, 37, 0,
-     63, 23, 0, 40, 4, 0, 0, 0, 0, 140, 208, 0, 124, 184, 0, 108, 161, 0, 91,
-     137, 0, 74, 115, 0, 56, 91, 0, 33, 64, 0, 1, 24, 0, 139, 187, 0, 123, 165,
-     0, 107, 145, 0, 90, 123, 0, 74, 102, 0, 56, 80, 0, 33, 55, 0, 0, 17, 0, 138,
-     168, 0, 122, 149, 0, 106, 130, 0, 90, 110, 0, 73, 91, 0, 56, 71, 0, 33, 47,
-     0, 0, 8, 0, 136, 148, 0, 121, 131, 0, 105, 115, 0, 89, 97, 0, 73, 80, 0, 55,
-     61, 0, 33, 39, 0, 0, 1, 0, 135, 130, 0, 120, 115, 0, 105, 100, 0, 88, 84, 0,
-     72, 69, 0, 55, 52, 0, 33, 30, 0, 0, 0, 0, 135, 111, 0, 119, 98, 0, 104, 85,
-     0, 88, 71, 0, 72, 57, 0, 55, 41, 0, 33, 22, 0, 0, 0, 0, 134, 91, 0, 118, 80,
-     0, 103, 69, 0, 87, 57, 0, 72, 44, 0, 54, 30, 0, 33, 11, 0, 0, 0, 0, 133, 75,
-     0, 118, 65, 0, 103, 56, 0, 87, 45, 0, 71, 34, 0, 54, 20, 0, 33, 2, 0, 0, 0,
-     0, 123, 194, 0, 108, 171, 0, 94, 150, 0, 78, 128, 0, 63, 106, 0, 46, 84, 0,
-     24, 58, 0, 0, 19, 0, 122, 174, 0, 107, 154, 0, 93, 135, 0, 78, 114, 0, 63,
-     95, 0, 46, 74, 0, 25, 50, 0, 0, 10, 0, 121, 157, 0, 107, 139, 0, 93, 121, 0,
-     78, 103, 0, 63, 85, 0, 46, 65, 0, 25, 42, 0, 0, 2, 0, 120, 139, 0, 106, 122,
-     0, 92, 107, 0, 77, 90, 0, 62, 74, 0, 46, 56, 0, 25, 34, 0, 0, 0, 0, 119,
-     122, 0, 105, 107, 0, 91, 93, 0, 77, 78, 0, 62, 63, 0, 45, 47, 0, 25, 26, 0,
-     0, 0, 0, 119, 104, 0, 104, 91, 0, 91, 79, 0, 76, 66, 0, 62, 52, 0, 45, 37,
-     0, 25, 18, 0, 0, 0, 0, 118, 86, 0, 104, 75, 0, 90, 64, 0, 76, 52, 0, 61, 40,
-     0, 45, 26, 0, 25, 7, 0, 0, 0, 0, 118, 71, 0, 104, 61, 0, 90, 52, 0, 75, 42,
-     0, 61, 30, 0, 45, 17, 0, 24, 1, 0, 0, 0, 0, 107, 181, 0, 94, 160, 0, 81,
-     140, 0, 66, 119, 0, 52, 99, 0, 35, 78, 0, 15, 53, 0, 0, 13, 0, 106, 163, 0,
-     93, 144, 0, 80, 126, 0, 66, 107, 0, 52, 88, 0, 36, 68, 0, 15, 45, 0, 0, 4,
-     0, 106, 147, 0, 93, 130, 0, 80, 113, 0, 66, 96, 0, 52, 79, 0, 36, 60, 0, 16,
-     37, 0, 0, 0, 0, 105, 130, 0, 92, 115, 0, 79, 100, 0, 66, 84, 0, 52, 68, 0,
-     36, 51, 0, 16, 30, 0, 0, 0, 0, 104, 115, 0, 91, 101, 0, 79, 87, 0, 65, 73,
-     0, 52, 59, 0, 36, 43, 0, 16, 22, 0, 0, 0, 0, 104, 98, 0, 91, 86, 0, 79, 74,
-     0, 65, 61, 0, 52, 48, 0, 36, 33, 0, 16, 14, 0, 0, 0, 0, 103, 81, 0, 90, 70,
-     0, 78, 60, 0, 65, 49, 0, 52, 37, 0, 36, 22, 0, 16, 5, 0, 0, 0, 0, 103, 68,
-     0, 90, 58, 0, 78, 49, 0, 65, 38, 0, 51, 27, 0, 36, 13, 0, 16, 0, 0, 0, 0, 0,
-     90, 168, 0, 78, 149, 0, 67, 130, 0, 54, 111, 0, 40, 92, 0, 24, 72, 0, 6, 47,
-     0, 0, 6, 0, 90, 152, 0, 78, 134, 0, 67, 117, 0, 54, 99, 0, 40, 82, 0, 25,
-     63, 0, 6, 40, 0, 0, 0, 0, 89, 137, 0, 78, 121, 0, 66, 106, 0, 54, 89, 0, 41,
-     73, 0, 26, 55, 0, 7, 33, 0, 0, 0, 0, 89, 122, 0, 77, 107, 0, 66, 93, 0, 54,
-     78, 0, 41, 63, 0, 26, 46, 0, 7, 25, 0, 0, 0, 0, 89, 108, 0, 77, 94, 0, 66,
-     81, 0, 53, 68, 0, 41, 54, 0, 26, 38, 0, 8, 18, 0, 0, 0, 7, 88, 92, 4, 77,
-     80, 0, 66, 69, 0, 53, 57, 0, 41, 44, 0, 27, 29, 0, 8, 10, 0, 0, 0, 23, 88,
-     77, 19, 76, 66, 11, 65, 56, 0, 53, 45, 0, 41, 33, 0, 27, 19, 0, 8, 3, 0, 0,
-     0, 30, 88, 64, 26, 76, 54, 18, 65, 45, 4, 53, 35, 0, 41, 24, 0, 27, 9, 0, 8,
-     0, 0, 0, 0, 0, 72, 156, 0, 62, 138, 0, 51, 121, 0, 39, 103, 0, 26, 85, 0, 9,
-     66, 0, 0, 42, 0, 0, 0, 0, 72, 141, 0, 62, 125, 0, 51, 109, 0, 39, 92, 0, 27,
-     75, 0, 11, 57, 0, 0, 35, 0, 0, 0, 0, 72, 128, 0, 62, 113, 0, 51, 98, 0, 40,
-     82, 0, 27, 67, 0, 12, 50, 0, 1, 28, 0, 0, 0, 17, 72, 114, 13, 62, 100, 6,
-     51, 87, 0, 40, 72, 0, 28, 58, 0, 13, 42, 0, 1, 21, 0, 0, 0, 28, 72, 101, 23,
-     61, 88, 16, 51, 76, 4, 40, 62, 0, 28, 49, 0, 14, 34, 0, 1, 14, 0, 0, 0, 36,
-     72, 87, 30, 61, 75, 23, 51, 64, 12, 40, 52, 1, 28, 40, 0, 14, 25, 0, 1, 7,
-     0, 0, 0, 41, 71, 72, 35, 61, 62, 28, 51, 52, 17, 40, 41, 5, 28, 29, 0, 14,
-     15, 0, 0, 0, 0, 0, 0, 45, 71, 60, 39, 61, 51, 31, 51, 42, 20, 40, 32, 8, 29,
-     21, 0, 15, 6, 0, 0, 0, 0, 0, 0, 0, 51, 145, 0, 42, 129, 0, 33, 113, 0, 20,
-     96, 0, 5, 79, 0, 0, 60, 0, 0, 37, 0, 0, 0, 24, 52, 131, 21, 42, 116, 15, 33,
-     101, 5, 21, 85, 0, 7, 69, 0, 0, 52, 0, 1, 30, 0, 0, 0, 34, 52, 119, 29, 43,
-     105, 22, 33, 91, 12, 22, 76, 0, 8, 61, 0, 0, 45, 0, 1, 24, 0, 0, 0, 40, 53,
-     106, 34, 43, 93, 27, 34, 80, 17, 23, 67, 5, 9, 53, 0, 0, 37, 0, 0, 16, 0, 0,
-     0, 45, 53, 94, 38, 44, 82, 31, 34, 70, 20, 24, 58, 10, 11, 45, 0, 0, 29, 0,
-     0, 9, 0, 0, 0, 48, 53, 81, 42, 44, 70, 34, 35, 60, 24, 24, 48, 13, 12, 36,
-     0, 0, 21, 0, 0, 3, 0, 0, 0, 51, 53, 68, 45, 44, 58, 37, 35, 48, 26, 25, 37,
-     15, 13, 26, 2, 1, 11, 0, 0, 0, 0, 0, 0, 54, 54, 57, 47, 44, 47, 39, 35, 39,
-     28, 25, 29, 17, 13, 17, 4, 1, 3, 0, 0, 0, 0, 0, 0]);
++/**
++ * 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
++ * has traversed as many objects that are available it attempts to bundle the
++ * missing data requests and then resume from the nodes that weren't ready.
++ *
++ * NOTE: It provides protection from circular references by keeping track of
++ * of loaded references. However, you must be careful not to load any graphs
++ * that have references to the catalog or other pages since that will cause the
++ * entire PDF document object graph to be traversed.
++ */
++var ObjectLoader = (function() {
 +
-   function convertToRgb(src, srcOffset, srcScale, dest, destOffset) {
-     // using lut as in spline interpolation (see function.js)
-     var cubeVertices = 16; // 1 << number of colors
-     var cubeN = new Float32Array(cubeVertices);
-     var cubeVertex = new Uint32Array(cubeVertices);
-     for (var j = 0; j < cubeVertices; j++)
-       cubeN[j] = 1;
- 
-     var k = 3, pos = 1;
-     var lutDomain = 7, lutStep = 8;
-     for (var i = 3; i >= 0; i--) {
-       var e = src[srcOffset + i] * srcScale * lutDomain;
- 
-       var e0 = e < lutDomain ? 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;
++  function mayHaveChildren(value) {
++    return isRef(value) || isDict(value) || isArray(value) || isStream(value);
++  }
++
++  function addChildren(node, nodesToVisit) {
++    if (isDict(node) || isStream(node)) {
++      var map;
++      if (isDict(node)) {
++        map = node.map;
++      } else {
++        map = node.dict.map;
++      }
++      for (var key in map) {
++        var 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];
++        if (mayHaveChildren(value)) {
++          nodesToVisit.push(value);
 +        }
 +      }
- 
-       k *= lutStep;
-       pos <<= 1;
 +    }
-     var y0 = 0, y1 = 0, y2 = 0;
-     for (var i = 0; i < cubeVertices; i++)
-       y0 += lut[cubeVertex[i]] * cubeN[i];
-     for (var i = 0; i < cubeVertices; i++)
-       y1 += lut[cubeVertex[i] + 1] * cubeN[i];
-     for (var i = 0; i < cubeVertices; i++)
-       y2 += lut[cubeVertex[i] + 2] * cubeN[i];
-     dest[destOffset] = y0 > 255 ? 255 : y0;
-     dest[destOffset + 1] = y1 > 255 ? 255 : y1;
-     dest[destOffset + 2] = y2 > 255 ? 255 : y2;
 +  }
 +
-   function DeviceCmykCS() {
-     this.name = 'DeviceCMYK';
-     this.numComps = 4;
-     this.defaultColor = new Float32Array([0, 0, 0, 1]);
++  function ObjectLoader(obj, keys, xref) {
++    this.obj = obj;
++    this.keys = keys;
++    this.xref = xref;
++    this.refSet = null;
 +  }
-   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);
-     }
-   };
 +
-   return DeviceCmykCS;
- })();
++  ObjectLoader.prototype = {
 +
- //
- // 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]);
++    load: function ObjectLoader_load() {
++      var keys = this.keys;
++      this.promise = new LegacyPromise();
++      // 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;
++      }
 +
-     if (!whitePoint)
-       error('WhitePoint missing - required for color space Lab');
-     blackPoint = blackPoint || [0, 0, 0];
-     range = range || [-100, 100, -100, 100];
++      this.refSet = new RefSet();
++      // Setup the initial nodes to visit.
++      var nodesToVisit = [];
++      for (var i = 0; i < keys.length; i++) {
++        nodesToVisit.push(this.obj[keys[i]]);
++      }
 +
-     // 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];
++      this.walk(nodesToVisit);
++      return this.promise;
++    },
 +
-     // 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];
++    walk: function ObjectLoader_walk(nodesToVisit) {
++      var nodesToRevisit = [];
++      var pendingRequests = [];
++      // DFS walk of the object graph.
++      while (nodesToVisit.length) {
++        var currentNode = nodesToVisit.pop();
 +
-     // Validate vars as per spec
-     if (this.XW < 0 || this.ZW < 0 || this.YW !== 1)
-       error('Invalid WhitePoint components, no fallback available');
++        // Only references or chunked streams can cause missing data exceptions.
++        if (isRef(currentNode)) {
++          // Skip nodes that have already been visited.
++          if (this.refSet.has(currentNode)) {
++            continue;
++          }
++          try {
++            var ref = currentNode;
++            this.refSet.put(ref);
++            currentNode = this.xref.fetch(currentNode);
++          } catch (e) {
++            if (!(e instanceof MissingDataException)) {
++              throw e;
++            }
++            nodesToRevisit.push(currentNode);
++            pendingRequests.push({ begin: e.begin, end: e.end });
++          }
++        }
++        if (currentNode && currentNode.getBaseStreams) {
++          var baseStreams = currentNode.getBaseStreams();
++          var foundMissingData = false;
++          for (var i = 0; i < baseStreams.length; i++) {
++            var stream = baseStreams[i];
++            if (stream.getMissingChunks && stream.getMissingChunks().length) {
++              foundMissingData = true;
++              pendingRequests.push({
++                begin: stream.start,
++                end: stream.end
++              });
++            }
++          }
++          if (foundMissingData) {
++            nodesToRevisit.push(currentNode);
++          }
++        }
 +
-     if (this.XB < 0 || this.YB < 0 || this.ZB < 0) {
-       info('Invalid BlackPoint, falling back to default');
-       this.XB = this.YB = this.ZB = 0;
-     }
++        addChildren(currentNode, nodesToVisit);
++      }
 +
-     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;
++      if (pendingRequests.length) {
++        this.xref.stream.manager.requestRanges(pendingRequests,
++            function pendingRequestCallback() {
++          nodesToVisit = nodesToRevisit;
++          for (var i = 0; i < nodesToRevisit.length; i++) {
++            var node = nodesToRevisit[i];
++            // Remove any reference nodes from the currrent refset so they
++            // aren't skipped when we revist them.
++            if (isRef(node)) {
++              this.refSet.remove(node);
++            }
++          }
++          this.walk(nodesToVisit);
++        }.bind(this));
++        return;
++      }
++      // Everything is loaded.
++      this.refSet = null;
++      this.promise.resolve();
 +    }
-   }
 +
-   // 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 convertToRgb(cs, src, srcOffset, dest, destOffset) {
-     // Ls,as,bs <---> L*,a*,b* in the spec
-     var Ls = src[srcOffset];
-     var as = src[srcOffset + 1];
-     var bs = src[srcOffset + 2];
++  return ObjectLoader;
++})();
 +
-     // 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 ISOAdobeCharset = [
++  '.notdef', 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar',
++  'percent', 'ampersand', 'quoteright', 'parenleft', 'parenright',
++  'asterisk', 'plus', 'comma', 'hyphen', 'period', 'slash', 'zero',
++  'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight',
++  'nine', 'colon', 'semicolon', 'less', 'equal', 'greater', 'question',
++  'at', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
++  'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
++  'bracketleft', 'backslash', 'bracketright', 'asciicircum', 'underscore',
++  'quoteleft', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
++  'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
++  'braceleft', 'bar', 'braceright', 'asciitilde', 'exclamdown', 'cent',
++  'sterling', 'fraction', 'yen', 'florin', 'section', 'currency',
++  'quotesingle', 'quotedblleft', 'guillemotleft', 'guilsinglleft',
++  'guilsinglright', 'fi', 'fl', 'endash', 'dagger', 'daggerdbl',
++  'periodcentered', 'paragraph', 'bullet', 'quotesinglbase',
++  'quotedblbase', 'quotedblright', 'guillemotright', 'ellipsis',
++  'perthousand', 'questiondown', 'grave', 'acute', 'circumflex', 'tilde',
++  'macron', 'breve', 'dotaccent', 'dieresis', 'ring', 'cedilla',
++  'hungarumlaut', 'ogonek', 'caron', 'emdash', 'AE', 'ordfeminine',
++  'Lslash', 'Oslash', 'OE', 'ordmasculine', 'ae', 'dotlessi', 'lslash',
++  'oslash', 'oe', 'germandbls', 'onesuperior', 'logicalnot', 'mu',
++  'trademark', 'Eth', 'onehalf', 'plusminus', 'Thorn', 'onequarter',
++  'divide', 'brokenbar', 'degree', 'thorn', 'threequarters', 'twosuperior',
++  'registered', 'minus', 'eth', 'multiply', 'threesuperior', 'copyright',
++  'Aacute', 'Acircumflex', 'Adieresis', 'Agrave', 'Aring', 'Atilde',
++  'Ccedilla', 'Eacute', 'Ecircumflex', 'Edieresis', 'Egrave', 'Iacute',
++  'Icircumflex', 'Idieresis', 'Igrave', 'Ntilde', 'Oacute', 'Ocircumflex',
++  'Odieresis', 'Ograve', 'Otilde', 'Scaron', 'Uacute', 'Ucircumflex',
++  'Udieresis', 'Ugrave', 'Yacute', 'Ydieresis', 'Zcaron', 'aacute',
++  'acircumflex', 'adieresis', 'agrave', 'aring', 'atilde', 'ccedilla',
++  'eacute', 'ecircumflex', 'edieresis', 'egrave', 'iacute', 'icircumflex',
++  'idieresis', 'igrave', 'ntilde', 'oacute', 'ocircumflex', 'odieresis',
++  'ograve', 'otilde', 'scaron', 'uacute', 'ucircumflex', 'udieresis',
++  'ugrave', 'yacute', 'ydieresis', 'zcaron'
++];
 +
-     var X = cs.XW * fn_g(L);
-     var Y = cs.YW * fn_g(M);
-     var Z = cs.ZW * fn_g(N);
++var ExpertCharset = [
++  '.notdef', 'space', 'exclamsmall', 'Hungarumlautsmall', 'dollaroldstyle',
++  'dollarsuperior', 'ampersandsmall', 'Acutesmall', 'parenleftsuperior',
++  'parenrightsuperior', 'twodotenleader', 'onedotenleader', 'comma',
++  'hyphen', 'period', 'fraction', 'zerooldstyle', 'oneoldstyle',
++  'twooldstyle', 'threeoldstyle', 'fouroldstyle', 'fiveoldstyle',
++  'sixoldstyle', 'sevenoldstyle', 'eightoldstyle', 'nineoldstyle',
++  'colon', 'semicolon', 'commasuperior', 'threequartersemdash',
++  'periodsuperior', 'questionsmall', 'asuperior', 'bsuperior',
++  'centsuperior', 'dsuperior', 'esuperior', 'isuperior', 'lsuperior',
++  'msuperior', 'nsuperior', 'osuperior', 'rsuperior', 'ssuperior',
++  'tsuperior', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'parenleftinferior',
++  'parenrightinferior', 'Circumflexsmall', 'hyphensuperior', 'Gravesmall',
++  'Asmall', 'Bsmall', 'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall',
++  'Hsmall', 'Ismall', 'Jsmall', 'Ksmall', 'Lsmall', 'Msmall', 'Nsmall',
++  'Osmall', 'Psmall', 'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall',
++  'Vsmall', 'Wsmall', 'Xsmall', 'Ysmall', 'Zsmall', 'colonmonetary',
++  'onefitted', 'rupiah', 'Tildesmall', 'exclamdownsmall', 'centoldstyle',
++  'Lslashsmall', 'Scaronsmall', 'Zcaronsmall', 'Dieresissmall',
++  'Brevesmall', 'Caronsmall', 'Dotaccentsmall', 'Macronsmall',
++  'figuredash', 'hypheninferior', 'Ogoneksmall', 'Ringsmall',
++  'Cedillasmall', 'onequarter', 'onehalf', 'threequarters',
++  'questiondownsmall', 'oneeighth', 'threeeighths', 'fiveeighths',
++  'seveneighths', 'onethird', 'twothirds', 'zerosuperior', 'onesuperior',
++  'twosuperior', 'threesuperior', 'foursuperior', 'fivesuperior',
++  'sixsuperior', 'sevensuperior', 'eightsuperior', 'ninesuperior',
++  'zeroinferior', 'oneinferior', 'twoinferior', 'threeinferior',
++  'fourinferior', 'fiveinferior', 'sixinferior', 'seveninferior',
++  'eightinferior', 'nineinferior', 'centinferior', 'dollarinferior',
++  'periodinferior', 'commainferior', 'Agravesmall', 'Aacutesmall',
++  'Acircumflexsmall', 'Atildesmall', 'Adieresissmall', 'Aringsmall',
++  'AEsmall', 'Ccedillasmall', 'Egravesmall', 'Eacutesmall',
++  'Ecircumflexsmall', 'Edieresissmall', 'Igravesmall', 'Iacutesmall',
++  'Icircumflexsmall', 'Idieresissmall', 'Ethsmall', 'Ntildesmall',
++  'Ogravesmall', 'Oacutesmall', 'Ocircumflexsmall', 'Otildesmall',
++  'Odieresissmall', 'OEsmall', 'Oslashsmall', 'Ugravesmall', 'Uacutesmall',
++  'Ucircumflexsmall', 'Udieresissmall', 'Yacutesmall', 'Thornsmall',
++  'Ydieresissmall'
++];
 +
-     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;
-     }
++var ExpertSubsetCharset = [
++  '.notdef', 'space', 'dollaroldstyle', 'dollarsuperior',
++  'parenleftsuperior', 'parenrightsuperior', 'twodotenleader',
++  'onedotenleader', 'comma', 'hyphen', 'period', 'fraction',
++  'zerooldstyle', 'oneoldstyle', 'twooldstyle', 'threeoldstyle',
++  'fouroldstyle', 'fiveoldstyle', 'sixoldstyle', 'sevenoldstyle',
++  'eightoldstyle', 'nineoldstyle', 'colon', 'semicolon', 'commasuperior',
++  'threequartersemdash', 'periodsuperior', 'asuperior', 'bsuperior',
++  'centsuperior', 'dsuperior', 'esuperior', 'isuperior', 'lsuperior',
++  'msuperior', 'nsuperior', 'osuperior', 'rsuperior', 'ssuperior',
++  'tsuperior', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'parenleftinferior',
++  'parenrightinferior', 'hyphensuperior', 'colonmonetary', 'onefitted',
++  'rupiah', 'centoldstyle', 'figuredash', 'hypheninferior', 'onequarter',
++  'onehalf', 'threequarters', 'oneeighth', 'threeeighths', 'fiveeighths',
++  'seveneighths', 'onethird', 'twothirds', 'zerosuperior', 'onesuperior',
++  'twosuperior', 'threesuperior', 'foursuperior', 'fivesuperior',
++  'sixsuperior', 'sevensuperior', 'eightsuperior', 'ninesuperior',
++  'zeroinferior', 'oneinferior', 'twoinferior', 'threeinferior',
++  'fourinferior', 'fiveinferior', 'sixinferior', 'seveninferior',
++  'eightinferior', 'nineinferior', 'centinferior', 'dollarinferior',
++  'periodinferior', 'commainferior'
++];
 +
-     // clamp color values to [0,255] range
-     dest[destOffset] = r < 0 ? 0 : r > 1 ? 255 : r * 255;
-     dest[destOffset + 1] = g < 0 ? 0 : g > 1 ? 255 : g * 255;
-     dest[destOffset + 2] = b < 0 ? 0 : b > 1 ? 255 : b * 255;
-   }
 +
-   LabCS.prototype = {
-     getRgb: function LabCS_getRgb(src, srcOffset) {
-       var rgb = new Uint8Array(3);
-       convertToRgb(this, src, srcOffset, rgb, 0);
-       return rgb;
-     },
-     getRgbItem: function LabCS_getRgbItem(src, srcOffset, dest, destOffset) {
-       convertToRgb(this, src, srcOffset, dest, destOffset);
-     },
-     getOutputLength: function LabCS_getOutputLength(inputLength) {
-       return inputLength;
-     },
-     isPassthrough: ColorSpace.prototype.isPassthrough,
-     isDefaultDecode: function LabCS_isDefaultDecode(decodeMap) {
-       // From Table 90 in Adobe's:
-       // "Document management - Portable document format", 1st ed, 2008
-       if (decodeMap[0] === 0 && decodeMap[1] === 100 &&
-           decodeMap[2] === this.amin && decodeMap[3] === this.amax &&
-           decodeMap[4] === this.bmin && decodeMap[5] === this.bmax)
-         return true;
-       else
-         return false;
-     }
-   };
-   return LabCS;
- })();
++
++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 ARCFourCipher = (function ARCFourCipherClosure() {
 +  function ARCFourCipher(key) {
 +    this.a = 0;
 +    this.b = 0;
 +    var s = new Uint8Array(256);
 +    var i, j = 0, tmp, keyLength = key.length;
 +    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;
 +      s[i] = s[j];
 +      s[j] = tmp;
 +    }
 +    this.s = s;
 +  }
 +
 +  ARCFourCipher.prototype = {
 +    encryptBlock: function ARCFourCipher_encryptBlock(data) {
 +      var i, n = data.length, tmp, tmp2;
 +      var a = this.a, b = this.b, s = this.s;
 +      var output = new Uint8Array(n);
 +      for (i = 0; i < n; ++i) {
 +        a = (a + 1) & 0xFF;
 +        tmp = s[a];
 +        b = (b + tmp) & 0xFF;
 +        tmp2 = s[b];
 +        s[a] = tmp2;
 +        s[b] = tmp;
 +        output[i] = data[i] ^ s[(tmp + tmp2) & 0xFF];
 +      }
 +      this.a = a;
 +      this.b = b;
 +      return output;
 +    }
 +  };
 +  ARCFourCipher.prototype.decryptBlock = ARCFourCipher.prototype.encryptBlock;
 +
 +  return ARCFourCipher;
 +})();
 +
 +var calculateMD5 = (function calculateMD5Closure() {
 +  var r = new Uint8Array([
 +    7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
 +    5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
 +    4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
 +    6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21]);
 +
 +  var k = new Int32Array([
 +    -680876936, -389564586, 606105819, -1044525330, -176418897, 1200080426,
 +    -1473231341, -45705983, 1770035416, -1958414417, -42063, -1990404162,
 +    1804603682, -40341101, -1502002290, 1236535329, -165796510, -1069501632,
 +    643717713, -373897302, -701558691, 38016083, -660478335, -405537848,
 +    568446438, -1019803690, -187363961, 1163531501, -1444681467, -51403784,
 +    1735328473, -1926607734, -378558, -2022574463, 1839030562, -35309556,
 +    -1530992060, 1272893353, -155497632, -1094730640, 681279174, -358537222,
 +    -722521979, 76029189, -640364487, -421815835, 530742520, -995338651,
 +    -198630844, 1126891415, -1416354905, -57434055, 1700485571, -1894986606,
 +    -1051523, -2054922799, 1873313359, -30611744, -1560198380, 1309151649,
 +    -145523070, -1120210379, 718787259, -343485551]);
 +
 +  function hash(data, offset, length) {
 +    var h0 = 1732584193, h1 = -271733879, h2 = -1732584194, h3 = 271733878;
 +    // pre-processing
 +    var paddedLength = (length + 72) & ~63; // data + 9 extra bytes
 +    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++] = (length << 3) & 0xFF;
 +    padded[i++] = (length >> 5) & 0xFF;
 +    padded[i++] = (length >> 13) & 0xFF;
 +    padded[i++] = (length >> 21) & 0xFF;
 +    padded[i++] = (length >>> 29) & 0xFF;
 +    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));
 +      }
 +      var a = h0, b = h1, c = h2, d = h3, f, g;
 +      for (j = 0; j < 64; ++j) {
 +        if (j < 16) {
 +          f = (b & c) | ((~b) & d);
 +          g = j;
 +        } else if (j < 32) {
 +          f = (d & b) | ((~d) & c);
 +          g = (5 * j + 1) & 15;
 +        } else if (j < 48) {
 +          f = b ^ c ^ d;
 +          g = (3 * j + 5) & 15;
 +        } else {
 +          f = c ^ (b | (~d));
 +          g = (7 * j) & 15;
 +        }
 +        var tmp = d, rotateArg = (a + f + k[j] + w[g]) | 0, rotate = r[j];
 +        d = c;
 +        c = b;
 +        b = (b + ((rotateArg << rotate) | (rotateArg >>> (32 - rotate)))) | 0;
 +        a = tmp;
 +      }
 +      h0 = (h0 + a) | 0;
 +      h1 = (h1 + b) | 0;
 +      h2 = (h2 + c) | 0;
 +      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
 +    ]);
 +  }
 +  return hash;
 +})();
 +
 +var NullCipher = (function NullCipherClosure() {
 +  function NullCipher() {
 +  }
 +
 +  NullCipher.prototype = {
 +    decryptBlock: function NullCipher_decryptBlock(data) {
 +      return data;
 +    }
 +  };
 +
 +  return NullCipher;
 +})();
 +
 +var AES128Cipher = (function AES128CipherClosure() {
 +  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 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 expandKey128(cipherKey) {
 +    var b = 176, result = new Uint8Array(b);
 +    result.set(cipherKey);
 +    for (var j = 16, i = 1; j < b; ++i) {
 +      // 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 ^ 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++;
 +      }
 +    }
 +    return result;
 +  }
 +
 +  function decrypt128(input, key) {
 +    var state = new Uint8Array(16);
 +    state.set(input);
 +    var i, j, k;
 +    var t, u, v;
 +    // AddRoundKey
 +    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;
 +      // 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 AES128Cipher(key) {
 +    this.key = expandKey128(key);
 +    this.buffer = new Uint8Array(16);
 +    this.bufferPosition = 0;
 +  }
 +
-   function decryptBlock2(data) {
++  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 = decrypt128(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)
++    if (result.length === 0) {
 +      return new Uint8Array([]);
-     if (result.length == 1)
-       return result[0];
++    }
 +    // combining plain text blocks into one
-     var output = new Uint8Array(16 * result.length);
++    var outputLength = 16 * result.length;
++    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 output = new Uint8Array(outputLength);
 +    for (i = 0, j = 0, ii = result.length; i < ii; ++i, j += 16)
 +      output.set(result[i], j);
 +    return output;
 +  }
 +
 +  AES128Cipher.prototype = {
-     decryptBlock: function AES128Cipher_decryptBlock(data) {
++    decryptBlock: function AES128Cipher_decryptBlock(data, finalize) {
 +      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)
 +        buffer[bufferLength] = data[i];
 +      if (bufferLength < 16) {
 +        // need more data
 +        this.bufferLength = bufferLength;
 +        return new Uint8Array([]);
 +      }
 +      this.iv = buffer;
 +      this.buffer = new Uint8Array(16);
 +      this.bufferLength = 0;
 +      // starting decryption
 +      this.decryptBlock = decryptBlock2;
-       return this.decryptBlock(data.subarray(16));
++      return this.decryptBlock(data.subarray(16), finalize);
 +    }
 +  };
 +
 +  return AES128Cipher;
 +})();
 +
 +var CipherTransform = (function CipherTransformClosure() {
 +  function CipherTransform(stringCipherConstructor, streamCipherConstructor) {
 +    this.stringCipherConstructor = stringCipherConstructor;
 +    this.streamCipherConstructor = streamCipherConstructor;
 +  }
 +  CipherTransform.prototype = {
 +    createStream: function CipherTransform_createStream(stream) {
 +      var cipher = new this.streamCipherConstructor();
 +      return new DecryptStream(stream,
-         function cipherTransformDecryptStream(data) {
-           return cipher.decryptBlock(data);
++        function cipherTransformDecryptStream(data, finalize) {
++          return cipher.decryptBlock(data, finalize);
 +        }
 +      );
 +    },
 +    decryptString: function CipherTransform_decryptString(s) {
 +      var cipher = new this.stringCipherConstructor();
 +      var data = stringToBytes(s);
-       data = cipher.decryptBlock(data);
++      data = cipher.decryptBlock(data, true);
 +      return bytesToString(data);
 +    }
 +  };
 +  return CipherTransform;
 +})();
 +
 +var CipherTransformFactory = (function CipherTransformFactoryClosure() {
 +  var defaultPasswordBytes = new Uint8Array([
 +    0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41,
 +    0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA, 0x01, 0x08,
 +    0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80,
 +    0x2F, 0x0C, 0xA9, 0xFE, 0x64, 0x53, 0x69, 0x7A]);
 +
 +  function prepareKeyData(fileId, password, ownerPassword, userPassword,
 +                          flags, revision, keyLength, encryptMetadata) {
-     var hashData = new Uint8Array(100), i = 0, j, n;
++    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)
 +        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)
 +      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)
 +      hashData[i++] = fileId[j];
 +    if (revision >= 4 && !encryptMetadata) {
 +      hashData[i++] = 0xFF;
 +      hashData[i++] = 0xFF;
 +      hashData[i++] = 0xFF;
 +      hashData[i++] = 0xFF;
 +    }
 +    var hash = calculateMD5(hashData, 0, i);
 +    var keyLengthInBytes = keyLength >> 3;
 +    if (revision >= 3) {
 +      for (j = 0; j < 50; ++j) {
 +         hash = calculateMD5(hash, 0, keyLengthInBytes);
 +      }
 +    }
 +    var encryptionKey = hash.subarray(0, keyLengthInBytes);
 +    var cipher, checkData;
 +
 +    if (revision >= 3) {
 +      for (i = 0; i < 32; ++i)
 +        hashData[i] = defaultPasswordBytes[i];
 +      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));
 +      n = encryptionKey.length;
 +      var derivedKey = new Uint8Array(n), k;
 +      for (j = 1; j <= 19; ++j) {
 +        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])
 +          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])
 +          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)
 +      hashData[i] = password[i];
 +    j = 0;
 +    while (i < 32) {
 +      hashData[i++] = defaultPasswordBytes[j++];
 +    }
 +    var hash = calculateMD5(hashData, 0, i);
 +    var keyLengthInBytes = keyLength >> 3;
 +    if (revision >= 3) {
 +      for (j = 0; j < 50; ++j) {
 +         hash = calculateMD5(hash, 0, hash.length);
 +      }
 +    }
 +
 +    var cipher, userPassword;
 +    if (revision >= 3) {
 +      userPassword = ownerPassword;
 +      var derivedKey = new Uint8Array(keyLengthInBytes), k;
 +      for (j = 19; j >= 0; j--) {
 +        for (k = 0; k < keyLengthInBytes; ++k)
 +          derivedKey[k] = hash[k] ^ j;
 +        cipher = new ARCFourCipher(derivedKey);
 +        userPassword = cipher.encryptBlock(userPassword);
 +      }
-     } else {
-       cipher = new ARCFourCipher(hash.subarray(0, keyLengthInBytes));
-       userPassword = cipher.encryptBlock(ownerPassword);
++    } else {
++      cipher = new ARCFourCipher(hash.subarray(0, keyLengthInBytes));
++      userPassword = cipher.encryptBlock(ownerPassword);
++    }
++    return userPassword;
++  }
++
++  var identityName = Name.get('Identity');
++
++  function CipherTransformFactory(dict, fileId, password) {
++    var filter = dict.get('Filter');
++    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))
++      error('unsupported encryption algorithm');
++    this.algorithm = algorithm;
++    var keyLength = dict.get('Length') || 40;
++    if (!isInt(keyLength) ||
++      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
++    this.encryptMetadata = encryptMetadata;
++
++    var fileIdBytes = stringToBytes(fileId);
++    var passwordBytes;
++    if (password)
++      passwordBytes = stringToBytes(password);
++
++    var encryptionKey = prepareKeyData(fileIdBytes, passwordBytes,
++                                       ownerPassword, userPassword, flags,
++                                       revision, keyLength, encryptMetadata);
++    if (!encryptionKey && !password) {
++      throw new PasswordException('No password given',
++                                  PasswordResponses.NEED_PASSWORD);
++    } else if (!encryptionKey && password) {
++      // Attempting use the password as an owner password
++      var decodedPassword = decodeUserPassword(passwordBytes, ownerPassword,
++                                               revision, keyLength);
++      encryptionKey = prepareKeyData(fileIdBytes, decodedPassword,
++                                     ownerPassword, userPassword, flags,
++                                     revision, keyLength, encryptMetadata);
++    }
++
++    if (!encryptionKey)
++      throw new PasswordException('Incorrect Password',
++                                  PasswordResponses.INCORRECT_PASSWORD);
++
++    this.encryptionKey = encryptionKey;
++
++    if (algorithm == 4) {
++      this.cf = dict.get('CF');
++      this.stmf = dict.get('StmF') || identityName;
++      this.strf = dict.get('StrF') || identityName;
++      this.eff = dict.get('EFF') || this.strf;
++    }
++  }
++
++  function buildObjectKey(num, gen, encryptionKey, isAes) {
++    var key = new Uint8Array(encryptionKey.length + 9), i, n;
++    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;
++    key[i++] = gen & 0xFF;
++    key[i++] = (gen >> 8) & 0xFF;
++    if (isAes) {
++      key[i++] = 0x73;
++      key[i++] = 0x41;
++      key[i++] = 0x6C;
++      key[i++] = 0x54;
++    }
++    var hash = calculateMD5(key, 0, i);
++    return hash.subarray(0, Math.min(encryptionKey.length + 5, 16));
++  }
++
++  function buildCipherConstructor(cf, name, num, gen, key) {
++    var cryptFilter = cf.get(name.name);
++    var cfm;
++    if (cryptFilter !== null && cryptFilter !== undefined)
++      cfm = cryptFilter.get('CFM');
++    if (!cfm || cfm.name == 'None') {
++      return function cipherTransformFactoryBuildCipherConstructorNone() {
++        return new NullCipher();
++      };
++    }
++    if ('V2' == cfm.name) {
++      return function cipherTransformFactoryBuildCipherConstructorV2() {
++        return new ARCFourCipher(
++          buildObjectKey(num, gen, key, false));
++      };
++    }
++    if ('AESV2' == cfm.name) {
++      return function cipherTransformFactoryBuildCipherConstructorAESV2() {
++        return new AES128Cipher(
++          buildObjectKey(num, gen, key, true));
++      };
++    }
++    error('Unknown crypto method');
++  }
++
++  CipherTransformFactory.prototype = {
++    createCipherTransform:
++      function CipherTransformFactory_createCipherTransform(num, gen) {
++      if (this.algorithm == 4) {
++        return new CipherTransform(
++          buildCipherConstructor(this.cf, this.stmf,
++            num, gen, this.encryptionKey),
++          buildCipherConstructor(this.cf, this.strf,
++            num, gen, this.encryptionKey));
++      }
++      // algorithms 1 and 2
++      var key = buildObjectKey(num, gen, this.encryptionKey, false);
++      var cipherConstructor = function buildCipherCipherConstructor() {
++        return new ARCFourCipher(key);
++      };
++      return new CipherTransform(cipherConstructor, cipherConstructor);
++    }
++  };
++
++  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;
++    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.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;
++  }
++  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 = [];
++      for (var i = 0, j = 4; i < numComps; i++, j += 2) {
++        var ci = this.readBits(bitsPerComponent);
++        components.push(ci * scale * (decode[j + 1] - decode[j]) + decode[j]);
++      }
++      if (this.context.colorFn) {
++        components = this.context.colorFn(components);
++      }
++      return this.context.colorSpace.getRgb(components, 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();
 +    }
-     return userPassword;
++
++    var psPacked = new Int32Array(ps);
++
++    mesh.figures.push({
++      type: 'triangles',
++      coords: psPacked,
++      colors: psPacked
++    });
 +  }
 +
-   var identityName = new Name('Identity');
++  function decodeType5Shading(mesh, reader, verticesPerRow) {
++    var coords = mesh.coords;
++    var colors = mesh.colors;
++    var operators = [];
++    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
++    });
++  }
 +
-   function CipherTransformFactory(dict, fileId, password) {
-     var filter = dict.get('Filter');
-     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))
-       error('unsupported encryption algorithm');
-     this.algorithm = algorithm;
-     var keyLength = dict.get('Length') || 40;
-     if (!isInt(keyLength) ||
-       keyLength < 40 || (keyLength % 8) !== 0)
-       error('invalid key length');
-     // prepare keys
-     var ownerPassword = stringToBytes(dict.get('O'));
-     var userPassword = stringToBytes(dict.get('U'));
-     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
-     this.encryptMetadata = encryptMetadata;
++  var MIN_SPLIT_PATCH_CHUNKS_AMOUNT = 3;
++  var MAX_SPLIT_PATCH_CHUNKS_AMOUNT = 20;
 +
-     var fileIdBytes = stringToBytes(fileId);
-     var passwordBytes;
-     if (password)
-       passwordBytes = stringToBytes(password);
++  var TRIANGLE_DENSITY = 20; // count of triangles per entire mesh bounds
 +
-     var encryptionKey = prepareKeyData(fileIdBytes, passwordBytes,
-                                        ownerPassword, userPassword, flags,
-                                        revision, keyLength, encryptMetadata);
-     if (!encryptionKey && !password) {
-       throw new PasswordException('No password given', 'needpassword');
-     } else if (!encryptionKey && password) {
-       // Attempting use the password as an owner password
-       var decodedPassword = decodeUserPassword(passwordBytes, ownerPassword,
-                                                revision, keyLength);
-       encryptionKey = prepareKeyData(fileIdBytes, decodedPassword,
-                                      ownerPassword, userPassword, flags,
-                                      revision, keyLength, encryptMetadata);
++  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];
++    };
++  })();
 +
-     if (!encryptionKey)
-       throw new PasswordException('Incorrect Password', 'incorrectpassword');
- 
-     this.encryptionKey = encryptionKey;
++  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
++    };
++  }
 +
-     if (algorithm == 4) {
-       this.cf = dict.get('CF');
-       this.stmf = dict.get('StmF') || identityName;
-       this.strf = dict.get('StrF') || identityName;
-       this.eff = dict.get('EFF') || this.strf;
++  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 buildObjectKey(num, gen, encryptionKey, isAes) {
-     var key = new Uint8Array(encryptionKey.length + 9), i, n;
-     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;
-     key[i++] = gen & 0xFF;
-     key[i++] = (gen >> 8) & 0xFF;
-     if (isAes) {
-       key[i++] = 0x73;
-       key[i++] = 0x41;
-       key[i++] = 0x6C;
-       key[i++] = 0x54;
++  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)
++      });
 +    }
-     var hash = calculateMD5(key, 0, i);
-     return hash.subarray(0, Math.min(encryptionKey.length + 5, 16));
 +  }
 +
-   function buildCipherConstructor(cf, name, num, gen, key) {
-     var cryptFilter = cf.get(name.name);
-     var cfm;
-     if (cryptFilter !== null && cryptFilter !== undefined)
-       cfm = cryptFilter.get('CFM');
-     if (!cfm || cfm.name == 'None') {
-       return function cipherTransformFactoryBuildCipherConstructorNone() {
-         return new NullCipher();
++  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 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;
++    if (!fnObj) {
++      fn = null;
++    } else 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);
 +    }
-     if ('V2' == cfm.name) {
-       return function cipherTransformFactoryBuildCipherConstructorV2() {
-         return new ARCFourCipher(
-           buildObjectKey(num, gen, key, false));
-       };
++
++    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 ('AESV2' == cfm.name) {
-       return function cipherTransformFactoryBuildCipherConstructorAESV2() {
-         return new AES128Cipher(
-           buildObjectKey(num, gen, key, true));
-       };
++
++    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);
++      }
 +    }
-     error('Unknown crypto method');
++    // calculate bounds
++    updateBounds(this);
 +  }
 +
-   CipherTransformFactory.prototype = {
-     createCipherTransform:
-       function CipherTransformFactory_createCipherTransform(num, gen) {
-       if (this.algorithm == 4) {
-         return new CipherTransform(
-           buildCipherConstructor(this.cf, this.stmf,
-             num, gen, this.encryptionKey),
-           buildCipherConstructor(this.cf, this.strf,
-             num, gen, this.encryptionKey));
-       }
-       // algorithms 1 and 2
-       var key = buildObjectKey(num, gen, this.encryptionKey, false);
-       var cipherConstructor = function buildCipherCipherConstructor() {
-         return new ARCFourCipher(key);
-       };
-       return new CipherTransform(cipherConstructor, cipherConstructor);
++  Mesh.prototype = {
++    getIR: function Mesh_getIR() {
++      var type = this.shadingType;
++      var i, ii, j;
++      var coords = this.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];
++      }
++      var colors = this.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];
++      }
++      var figures = this.figures;
++      var bbox = this.bbox;
++      var bounds = this.bounds;
++      var matrix = this.matrix;
++      var background = this.background;
++
++      return ['Mesh', type, coordsPacked, colorsPacked, figures, bounds,
++        matrix, bbox, background];
 +    }
 +  };
 +
-   return CipherTransformFactory;
++  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(xref, handler, pageIndex, uniquePrefix) {
++  function PartialEvaluator(pdfManager, xref, handler, pageIndex,
++                            uniquePrefix, idCounters, fontCache) {
 +    this.state = new EvalState();
 +    this.stateStack = [];
 +
++    this.pdfManager = pdfManager;
 +    this.xref = xref;
 +    this.handler = handler;
 +    this.pageIndex = pageIndex;
 +    this.uniquePrefix = uniquePrefix;
-     this.objIdCounter = 0;
-     this.fontIdCounter = 0;
++    this.idCounters = idCounters;
++    this.fontCache = fontCache;
 +  }
 +
-   // Specifies properties for each command
-   //
-   // If variableArgs === true: [0, `numArgs`] expected
-   // If variableArgs === false: exactly `numArgs` expected
-   var OP_MAP = {
-     // Graphic state
-     w: { fnName: 'setLineWidth', numArgs: 1, variableArgs: false },
-     J: { fnName: 'setLineCap', numArgs: 1, variableArgs: false },
-     j: { fnName: 'setLineJoin', numArgs: 1, variableArgs: false },
-     M: { fnName: 'setMiterLimit', numArgs: 1, variableArgs: false },
-     d: { fnName: 'setDash', numArgs: 2, variableArgs: false },
-     ri: { fnName: 'setRenderingIntent', numArgs: 1, variableArgs: false },
-     i: { fnName: 'setFlatness', numArgs: 1, variableArgs: false },
-     gs: { fnName: 'setGState', numArgs: 1, variableArgs: false },
-     q: { fnName: 'save', numArgs: 0, variableArgs: false },
-     Q: { fnName: 'restore', numArgs: 0, variableArgs: false },
-     cm: { fnName: 'transform', numArgs: 6, variableArgs: false },
++  var TILING_PATTERN = 1, SHADING_PATTERN = 2;
 +
-     // Path
-     m: { fnName: 'moveTo', numArgs: 2, variableArgs: false },
-     l: { fnName: 'lineTo', numArgs: 2, variableArgs: false },
-     c: { fnName: 'curveTo', numArgs: 6, variableArgs: false },
-     v: { fnName: 'curveTo2', numArgs: 4, variableArgs: false },
-     y: { fnName: 'curveTo3', numArgs: 4, variableArgs: false },
-     h: { fnName: 'closePath', numArgs: 0, variableArgs: false },
-     re: { fnName: 'rectangle', numArgs: 4, variableArgs: false },
-     S: { fnName: 'stroke', numArgs: 0, variableArgs: false },
-     s: { fnName: 'closeStroke', numArgs: 0, variableArgs: false },
-     f: { fnName: 'fill', numArgs: 0, variableArgs: false },
-     F: { fnName: 'fill', numArgs: 0, variableArgs: false },
-     'f*': { fnName: 'eoFill', numArgs: 0, variableArgs: false },
-     B: { fnName: 'fillStroke', numArgs: 0, variableArgs: false },
-     'B*': { fnName: 'eoFillStroke', numArgs: 0, variableArgs: false },
-     b: { fnName: 'closeFillStroke', numArgs: 0, variableArgs: false },
-     'b*': { fnName: 'closeEOFillStroke', numArgs: 0, variableArgs: false },
-     n: { fnName: 'endPath', numArgs: 0, variableArgs: false },
++  PartialEvaluator.prototype = {
++    hasBlendModes: function PartialEvaluator_hasBlendModes(resources) {
++      if (!isDict(resources)) {
++        return false;
++      }
 +
-     // Clipping
-     W: { fnName: 'clip', numArgs: 0, variableArgs: false },
-     'W*': { fnName: 'eoClip', numArgs: 0, variableArgs: 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;
++    },
 +
-     // Text
-     BT: { fnName: 'beginText', numArgs: 0, variableArgs: false },
-     ET: { fnName: 'endText', numArgs: 0, variableArgs: false },
-     Tc: { fnName: 'setCharSpacing', numArgs: 1, variableArgs: false },
-     Tw: { fnName: 'setWordSpacing', numArgs: 1, variableArgs: false },
-     Tz: { fnName: 'setHScale', numArgs: 1, variableArgs: false },
-     TL: { fnName: 'setLeading', numArgs: 1, variableArgs: false },
-     Tf: { fnName: 'setFont', numArgs: 2, variableArgs: false },
-     Tr: { fnName: 'setTextRenderingMode', numArgs: 1, variableArgs: false },
-     Ts: { fnName: 'setTextRise', numArgs: 1, variableArgs: false },
-     Td: { fnName: 'moveText', numArgs: 2, variableArgs: false },
-     TD: { fnName: 'setLeadingMoveText', numArgs: 2, variableArgs: false },
-     Tm: { fnName: 'setTextMatrix', numArgs: 6, variableArgs: false },
-     'T*': { fnName: 'nextLine', numArgs: 0, variableArgs: false },
-     Tj: { fnName: 'showText', numArgs: 1, variableArgs: false },
-     TJ: { fnName: 'showSpacedText', numArgs: 1, variableArgs: false },
-     '\'': { fnName: 'nextLineShowText', numArgs: 1, variableArgs: false },
-     '"': { fnName: 'nextLineSetSpacingShowText', numArgs: 3,
-       variableArgs: false },
++    buildFormXObject: function PartialEvaluator_buildFormXObject(resources,
++                                                                 xobj, smask,
++                                                                 operatorList,
++                                                                 state) {
++      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
++        };
 +
-     // Type3 fonts
-     d0: { fnName: 'setCharWidth', numArgs: 2, variableArgs: false },
-     d1: { fnName: 'setCharWidthAndBounds', numArgs: 6, variableArgs: false },
++        var groupSubtype = group.get('S');
++        if (isName(groupSubtype) && groupSubtype.name === 'Transparency') {
++          groupOptions.isolated = group.get('I') || false;
++          groupOptions.knockout = group.get('K') || false;
++          var colorSpace = group.get('CS');
++          groupOptions.colorSpace = colorSpace ?
++            ColorSpace.parseToIR(colorSpace, this.xref, resources) : null;
++        }
++        operatorList.addOp(OPS.beginGroup, [groupOptions]);
++      }
 +
-     // Color
-     CS: { fnName: 'setStrokeColorSpace', numArgs: 1, variableArgs: false },
-     cs: { fnName: 'setFillColorSpace', numArgs: 1, variableArgs: false },
-     SC: { fnName: 'setStrokeColor', numArgs: 4, variableArgs: true },
-     SCN: { fnName: 'setStrokeColorN', numArgs: 33, variableArgs: true },
-     sc: { fnName: 'setFillColor', numArgs: 4, variableArgs: true },
-     scn: { fnName: 'setFillColorN', numArgs: 33, variableArgs: true },
-     G: { fnName: 'setStrokeGray', numArgs: 1, variableArgs: false },
-     g: { fnName: 'setFillGray', numArgs: 1, variableArgs: false },
-     RG: { fnName: 'setStrokeRGBColor', numArgs: 3, variableArgs: false },
-     rg: { fnName: 'setFillRGBColor', numArgs: 3, variableArgs: false },
-     K: { fnName: 'setStrokeCMYKColor', numArgs: 4, variableArgs: false },
-     k: { fnName: 'setFillCMYKColor', numArgs: 4, variableArgs: false },
++      operatorList.addOp(OPS.paintFormXObjectBegin, [matrix, bbox]);
 +
-     // Shading
-     sh: { fnName: 'shadingFill', numArgs: 1, variableArgs: false },
++      this.getOperatorList(xobj, xobj.dict.get('Resources') || resources,
++                           operatorList, state);
++      operatorList.addOp(OPS.paintFormXObjectEnd, []);
 +
-     // Images
-     BI: { fnName: 'beginInlineImage', numArgs: 0, variableArgs: false },
-     ID: { fnName: 'beginImageData', numArgs: 0, variableArgs: false },
-     EI: { fnName: 'endInlineImage', numArgs: 0, variableArgs: false },
++      if (group) {
++        operatorList.addOp(OPS.endGroup, [groupOptions]);
++      }
++    },
 +
-     // XObjects
-     Do: { fnName: 'paintXObject', numArgs: 1, variableArgs: false },
-     MP: { fnName: 'markPoint', numArgs: 1, variableArgs: false },
-     DP: { fnName: 'markPointProps', numArgs: 2, variableArgs: false },
-     BMC: { fnName: 'beginMarkedContent', numArgs: 1, variableArgs: false },
-     BDC: { fnName: 'beginMarkedContentProps', numArgs: 2, variableArgs: false },
-     EMC: { fnName: 'endMarkedContent', numArgs: 0, variableArgs: false },
++    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');
 +
-     // Compatibility
-     BX: { fnName: 'beginCompat', numArgs: 0, variableArgs: false },
-     EX: { fnName: 'endCompat', numArgs: 0, variableArgs: false },
++      if (PDFJS.maxImageSize !== -1 && w * h > PDFJS.maxImageSize) {
++        warn('Image exceeded maximum allowed size and was removed.');
++        return;
++      }
 +
-     // (reserved partial commands for the lexer)
-     BM: null,
-     BD: null,
-     'true': null,
-     fa: null,
-     fal: null,
-     fals: null,
-     'false': null,
-     nu: null,
-     nul: null,
-     'null': null
-   };
++      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;
++      }
 +
-   PartialEvaluator.prototype = {
-     loadFont: function PartialEvaluator_loadFont(fontName, font, xref,
-                                                  resources, dependency) {
-       var fontRes = resources.get('Font');
++      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.
++        var imgData = imageObj.createImageData(/* forceRGBA = */ true);
++        operatorList.addOp(OPS.paintInlineImageXObject, [imgData]);
++        return;
++      }
 +
-       assert(fontRes, 'fontRes not available');
++      // 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;
++      }
 +
-       ++this.fontIdCounter;
 +
-       font = xref.fetchIfRef(font) || fontRes.get(fontName);
-       if (!isDict(font)) {
-         return {
-           translated: new ErrorFont('Font ' + fontName + ' is not available'),
-           loadedName: 'g_font_' + this.uniquePrefix + this.fontIdCounter
-         };
-       }
++      PDFImage.buildImage(function(imageObj) {
++          var imgData = imageObj.createImageData(/* forceRGBA = */ false);
++          self.handler.send('obj', [objId, self.pageIndex, 'Image', imgData],
++                            null, [imgData.data.buffer]);
++        }, self.handler, self.xref, resources, image, inline);
 +
-       var loadedName = font.loadedName;
-       if (!loadedName) {
-         // keep track of each font we translated so the caller can
-         // load them asynchronously before calling display on a page
-         loadedName = 'g_font_' + this.uniquePrefix + this.fontIdCounter;
-         font.loadedName = loadedName;
++      operatorList.addOp(OPS.paintImageXObject, args);
++    },
 +
-         var translated;
-         try {
-           translated = this.translateFont(font, xref, resources,
-                                           dependency);
-         } catch (e) {
-           translated = new ErrorFont(e instanceof Error ? e.message : e);
-         }
-         font.translated = translated;
++    handleSMask: function PartialEvaluator_handleSmask(smask, resources,
++                                                       operatorList) {
++      var smaskContent = smask.get('G');
++      var smaskOptions = {
++        subtype: smask.get('S').name,
++        backdrop: smask.get('BC')
++      };
 +
-         var data = translated;
-         if (data.loadCharProcs) {
-           delete data.loadCharProcs;
++      this.buildFormXObject(resources, smaskContent, smaskOptions,
++                            operatorList);
++    },
 +
-           var charProcs = font.get('CharProcs').getAll();
-           var fontResources = font.get('Resources') || resources;
-           var charProcOperatorList = {};
-           for (var key in charProcs) {
-             var glyphStream = charProcs[key];
-             charProcOperatorList[key] =
-               this.getOperatorList(glyphStream, fontResources, dependency);
-           }
-           data.charProcOperatorList = charProcOperatorList;
-         }
-       }
-       return font;
++    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, getTilingPatternIR({
++                               fnArray: tilingOpList.fnArray,
++                               argsArray: tilingOpList.argsArray
++                              }, patternDict, args));
 +    },
 +
-     getOperatorList: function PartialEvaluator_getOperatorList(stream,
-                                                                resources,
-                                                                dependency,
-                                                                queue) {
++    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 xref = this.xref;
-       var handler = this.handler;
-       var pageIndex = this.pageIndex;
-       var uniquePrefix = this.uniquePrefix || '';
++      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();
 +
-       function insertDependency(depList) {
-         fnArray.push('dependency');
-         argsArray.push(depList);
-         for (var i = 0, ii = depList.length; i < ii; i++) {
-           var dep = depList[i];
-           if (dependency.indexOf(dep) == -1) {
-             dependency.push(depList[i]);
-           }
-         }
++        self.handler.send('commonobj', [
++          loadedName,
++          'Font',
++          fontData
++        ]);
++        font.sent = true;
 +      }
 +
-       function handleSetFont(fontName, font) {
-         font = self.loadFont(fontName, font, xref, resources, dependency);
- 
-         var loadedName = font.loadedName;
-         if (!font.sent) {
-           var data = font.translated.exportData();
++      return loadedName;
++    },
 +
-           handler.send('commonobj', [
-               loadedName,
-               'Font',
-               data
-           ]);
-           font.sent = true;
++    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
++            ]);
++          }
 +        }
- 
-         // Ensure the font is ready before the font is set
-         // and later on used for drawing.
-         // OPTIMIZE: This should get insert to the operatorList only once per
-         // page.
-         insertDependency([loadedName]);
-         return loadedName;
 +      }
 +
-       function buildFormXObject(xobj, smask) {
-         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
-           };
++      return glyphs;
++    },
 +
-           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.
-           }
-           fnArray.push('beginGroup');
-           argsArray.push([groupOptions]);
-         }
++    setGState: function PartialEvaluator_setGState(resources, gState,
++                                                   operatorList, xref) {
 +
-         fnArray.push('paintFormXObjectBegin');
-         argsArray.push([matrix, bbox]);
++      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':
++            if (isName(value) && value.name === 'None') {
++              gStateObj.push([key, false]);
++              break;
++            }
++            var dict = xref.fetchIfRef(value);
++            if (isDict(dict)) {
++              self.handleSMask(dict, resources, operatorList);
++              gStateObj.push([key, true]);
++            } else {
++              warn('Unsupported SMask type');
++            }
 +
-         // This adds the operatorList of the xObj to the current queue.
-         var depIdx = dependencyArray.length;
++            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;
++        }
++      }
 +
-         // Pass in the current `queue` object. That means the `fnArray`
-         // and the `argsArray` in this scope is reused and new commands
-         // are added to them.
-         self.getOperatorList(xobj,
-             xobj.dict.get('Resources') || resources,
-             dependencyArray, queue);
++      // 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);
++      }
 +
-         self.getOperatorList(xobj,
-                              xobj.dict.get('Resources') || resources,
-                              dependencyArray, queue);
++      operatorList.addOp(OPS.setGState, [gStateObj]);
++    },
 +
-         // Add the dependencies that are required to execute the
-         // operatorList.
-         insertDependency(dependencyArray.slice(depIdx));
++    loadFont: function PartialEvaluator_loadFont(fontName, font, xref,
++                                                 resources,
++                                                 parentOperatorList) {
 +
-         fnArray.push('paintFormXObjectEnd');
-         argsArray.push([]);
++      function errorFont() {
++        return {
++          translated: new ErrorFont('Font ' + fontName + ' is not available'),
++          loadedName: 'g_font_error'
++        };
++      }
 +
-         if (group) {
-           fnArray.push('endGroup');
-           argsArray.push([groupOptions]);
++      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);
++      }
 +
-       function buildPaintImageXObject(image, inline) {
-         var dict = image.dict;
-         var w = dict.get('Width', 'W');
-         var h = dict.get('Height', 'H');
- 
-         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;
- 
-           fn = 'paintImageMaskXObject';
-           args = [imgArray, inverseDecode, width, height];
-           return;
-         }
++      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);
++      }
 +
-         var softMask = dict.get('SMask', 'SM') || false;
-         var mask = dict.get('Mask') || false;
++      // 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));
 +
-         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(xref, resources, image,
-                                       inline, null, null);
-           var imgData = imageObj.getImageData();
-           fn = 'paintInlineImageXObject';
-           args = [imgData];
-           return;
++      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 there is no imageMask, create the PDFImage and a lot
-         // of image processing can be done here.
-         var objId = 'img_' + uniquePrefix + (++self.objIdCounter);
-         insertDependency([objId]);
-         args = [objId, w, h];
- 
-         if (!softMask && !mask && image instanceof JpegStream &&
-             image.isNativelySupported(xref, resources)) {
-           // These JPEGs don't need any more processing so we can just send it.
-           fn = 'paintJpegXObject';
-           handler.send('obj', [objId, pageIndex, 'JpegStream', image.getIR()]);
-           return;
++      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);
 +        }
- 
-         fn = 'paintImageXObject';
- 
-         PDFImage.buildImage(function(imageObj) {
-             var imgData = imageObj.getImageData();
-             handler.send('obj', [objId, pageIndex, 'Image', imgData]);
-           }, handler, xref, resources, image, inline);
++        font.translated.charProcOperatorList = charProcOperatorList;
++        font.loaded = true;
++      } else {
++        font.loaded = true;
 +      }
++      return font;
++    },
 +
-       if (!queue)
-         queue = {};
++    getOperatorList: function PartialEvaluator_getOperatorList(stream,
++                                                               resources,
++                                                               operatorList,
++                                                               evaluatorState) {
 +
-       if (!queue.argsArray) {
-         queue.argsArray = [];
-       }
-       if (!queue.fnArray) {
-         queue.fnArray = [];
-       }
++      var self = this;
++      var xref = this.xref;
++      var handler = this.handler;
 +
-       var fnArray = queue.fnArray, argsArray = queue.argsArray;
-       var dependencyArray = dependency || [];
++      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 res = resources;
-       var args = [], obj;
-       var TILING_PATTERN = 1, SHADING_PATTERN = 2;
- 
-       while (true) {
-         obj = parser.getObj();
-         if (isEOF(obj)) {
-           break;
-         }
- 
-         if (isCmd(obj)) {
-           var cmd = obj.cmd;
- 
-           // Check that the command is valid
-           var opSpec = OP_MAP[cmd];
-           if (!opSpec) {
-             warn('Unknown command "' + cmd + '"');
-             continue;
-           }
- 
-           var fn = opSpec.fnName;
++      var preprocessor = new EvaluatorPreprocessor(stream, xref);
++      if (evaluatorState) {
++        preprocessor.setState(evaluatorState);
++      }
 +
-           // 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');
-             }
-           } else {
-             if (args.length < opSpec.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 + ' args; skipping');
-               args = [];
-               continue;
-             } else if (args.length > opSpec.numArgs) {
-               info('Command ' + fn + ': expected ' + opSpec.numArgs +
-                   ' args, but received ' + args.length + ' args');
-             }
-           }
++      var promise = new LegacyPromise();
++      var operation;
++      while ((operation = preprocessor.read())) {
++          var args = operation.args;
++          var fn = operation.fn;
 +
-           // TODO figure out how to type-check vararg functions
++          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))) {
 +
-           if ((cmd == 'SCN' || cmd == 'scn') && !args[args.length - 1].code) {
-             // compile tiling patterns
-             var patternName = args[args.length - 1];
-             // SCN/scn applies patterns along with normal colors
-             if (isName(patternName)) {
-               var pattern = patterns.get(patternName.name);
-               if (pattern) {
 +                var dict = isStream(pattern) ? pattern.dict : pattern;
 +                var typeNum = dict.get('PatternType');
 +
 +                if (typeNum == TILING_PATTERN) {
-                   // Create an IR of the pattern code.
-                   var depIdx = dependencyArray.length;
-                   var operatorList = this.getOperatorList(pattern,
-                       dict.get('Resources') || resources, dependencyArray);
- 
-                   // Add the dependencies that are required to execute the
-                   // operatorList.
-                   insertDependency(dependencyArray.slice(depIdx));
- 
-                   args = TilingPattern.getIR(operatorList, dict, args);
-                 }
-                 else if (typeNum == SHADING_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,
-                                                      res);
++                                                      resources);
 +                  args = pattern.getIR();
 +                } else {
 +                  error('Unkown PatternType ' + typeNum);
 +                }
 +              }
-             }
-           } else if (cmd == 'Do' && !args[0].code) {
-             // 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) {
-                 buildFormXObject(xobj);
-                 args = [];
-                 continue;
-               } else if ('Image' == type.name) {
-                 buildPaintImageXObject(xobj, false);
-               } else {
-                 error('Unhandled XObject subtype ' + type.name);
++              break;
++            case OPS.paintXObject:
++              if (args[0].code) {
++                break;
 +              }
-             }
-           } else if (cmd == 'Tf') { // eagerly collect all fonts
-             args[0] = handleSetFont(args[0].name);
-           } else if (cmd == 'EI') {
-             buildPaintImageXObject(args[0], true);
-           }
++              // 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'
++                );
 +
-           switch (fn) {
++                if ('Form' == type.name) {
++                  self.buildFormXObject(resources, xobj, null, operatorList,
++                                        preprocessor.getState());
++                  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 'setFillColorSpace':
-             case 'setStrokeColorSpace':
++            case OPS.setFillColorSpace:
++            case OPS.setStrokeColorSpace:
 +              args = [ColorSpace.parseToIR(args[0], xref, resources)];
 +              break;
-             case 'shadingFill':
-               var shadingRes = res.get('Shading');
++            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, res);
++              var shadingFill = Pattern.parseShading(
++                  shading, null, xref, resources);
 +              var patternIR = shadingFill.getIR();
 +              args = [patternIR];
-               fn = 'shadingFill';
++              fn = OPS.shadingFill;
 +              break;
-             case 'setGState':
++            case OPS.setGState:
 +              var dictName = args[0];
 +              var extGState = resources.get('ExtGState');
 +
 +              if (!isDict(extGState) || !extGState.has(dictName.name))
 +                break;
 +
-               var gsState = extGState.get(dictName.name);
- 
-               // This array holds the converted/processed state data.
-               var gsStateObj = [];
- 
-               gsState.forEach(
-                 function canvasGraphicsSetGStateForEach(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':
-                     case 'BM':
-                       gsStateObj.push([key, value]);
-                       break;
-                     case 'Font':
-                       gsStateObj.push([
-                         'Font',
-                         handleSetFont(null, value[0]),
-                         value[1]
-                       ]);
-                       break;
-                     case 'SMask':
-                       // We support the default so don't trigger the TODO.
-                       if (!isName(value) || value.name != 'None')
-                         TODO('graphic state operator ' + key);
-                       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;
-                   }
-                 }
-               );
-               args = [gsStateObj];
-               break;
++              var gState = extGState.get(dictName.name);
++              self.setGState(resources, gState, operatorList, xref);
++              args = [];
++              continue;
 +          } // switch
 +
-           fnArray.push(fn);
-           argsArray.push(args);
-           args = [];
-         } else if (obj !== null && obj !== undefined) {
-           args.push(obj instanceof Dict ? obj.getAll() : obj);
-           assertWellFormed(args.length <= 33, 'Too many arguments');
-         }
++          operatorList.addOp(fn, args);
 +      }
 +
-       return queue;
-     },
- 
-     optimizeQueue: function PartialEvaluator_optimizeQueue(queue) {
-       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 = fnArray.length; i < ii; i++) {
-         if (fnArray[i] === 'paintInlineImageXObject' &&
-             fnArray[i - 2] === 'save' && fnArray[i - 1] === 'transform' &&
-             fnArray[i + 1] === '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
-           fnArray.splice(j, count * 4, ['paintInlineImageXObjectGroup']);
-           argsArray.splice(j, count * 4,
-             [{width: imgWidth, height: imgHeight, data: imgData}, map]);
-           i = j;
-           ii = fnArray.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 = fnArray.length; i < ii; i++) {
-         if (fnArray[i] === 'paintImageMaskXObject' &&
-             fnArray[i - 2] === 'save' && fnArray[i - 1] === 'transform' &&
-             fnArray[i + 1] === '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];
-             images.push({data: maskParams[0], width: maskParams[2],
-               height: maskParams[3], transform: transform,
-               inverseDecode: maskParams[1]});
-           }
-           // replacing queue items
-           fnArray.splice(j, count * 4, ['paintImageMaskXObjectGroup']);
-           argsArray.splice(j, count * 4, [images]);
-           i = j;
-           ii = fnArray.length;
-         }
++      // some pdf don't close all restores inside object/form
++      // closing those for them
++      for (var i = 0, ii = preprocessor.savedStatesDepth; i < ii; i++) {
++        operatorList.addOp(OPS.restore, []);
 +      }
++
++      return operatorList;
 +    },
 +
 +    getTextContent: function PartialEvaluator_getTextContent(
-                                                     stream, resources, state) {
-       var bidiTexts;
++                                                 stream, resources, textState) {
++
++      textState = textState || new TextState();
++
++      var bidiTexts = [];
 +      var SPACE_FACTOR = 0.35;
 +      var MULTI_SPACE_FACTOR = 1.5;
 +
-       if (!state) {
-         bidiTexts = [];
-         state = {
-           bidiTexts: bidiTexts
-         };
-       } else {
-         bidiTexts = state.bidiTexts;
-       }
- 
 +      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 preprocessor = new EvaluatorPreprocessor(stream, xref);
 +      var res = resources;
-       var args = [], obj;
 +
 +      var chunk = '';
 +      var font = null;
-       while (!isEOF(obj = parser.getObj())) {
-         if (isCmd(obj)) {
-           var cmd = obj.cmd;
-           switch (cmd) {
++      var charSpace = 0, wordSpace = 0;
++      var operation;
++      while ((operation = preprocessor.read())) {
++          var fn = operation.fn;
++          var args = operation.args;
++          switch (fn) {
 +            // TODO: Add support for SAVE/RESTORE and XFORM here.
-             case 'Tf':
++            case OPS.setFont:
 +              font = handleSetFont(args[0].name).translated;
++              textState.fontSize = args[1];
++              break;
++            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.translateTextMatrix(args[0], args[1]);
++              break;
++            case OPS.setLeadingMoveText:
++              textState.leading = -args[1];
++              textState.translateTextMatrix(args[0], args[1]);
++              break;
++            case OPS.nextLine:
++              textState.translateTextMatrix(0, -textState.leading);
++              break;
++            case OPS.setTextMatrix:
++              textState.setTextMatrix(args[0], args[1],
++                                       args[2], args[3], args[4], args[5]);
 +              break;
-             case 'TJ':
++            case OPS.setCharSpacing:
++              charSpace = args[0];
++              break;
++            case OPS.setWordSpacing:
++              wordSpace = args[0];
++              break;
++            case OPS.beginText:
++              textState.initialiseTextObj();
++              break;
++            case OPS.showSpacedText:
 +              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':
++            case OPS.showText:
 +              chunk += fontCharsToUnicode(args[0], font);
 +              break;
-             case '\'':
++            case OPS.nextLineShowText:
 +              // 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 '"':
++            case OPS.nextLineSetSpacingShowText:
 +              // Note comment in "'"
 +              chunk += fontCharsToUnicode(args[2], font);
 +              break;
-             case 'Do':
++            case OPS.paintXObject:
 +              // 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(
++              var formTexts = this.getTextContent(
 +                xobj,
 +                xobj.dict.get('Resources') || resources,
-                 state
++                textState
 +              );
++              Util.concatenateToArray(bidiTexts, formTexts);
 +              break;
-             case 'gs':
++            case OPS.setGState:
 +              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 bidiResult = PDFJS.bidi(chunk, -1, font.vertical);
++            var bidiText = {
++              str: bidiResult.str,
++              dir: bidiResult.dir
++            };
++            var renderParams = textState.calcRenderParams(preprocessor.ctm);
++            var fontHeight = textState.fontSize * renderParams.vScale;
++            var fontAscent = font.ascent ? font.ascent * fontHeight :
++              font.descent ? (1 + font.descent) * fontHeight : fontHeight;
++            bidiText.x = renderParams.renderMatrix[4] - (fontAscent *
++                           Math.sin(renderParams.angle));
++            bidiText.y = renderParams.renderMatrix[5] + (fontAscent *
++                           Math.cos(renderParams.angle));
++            if (bidiText.dir == 'ttb') {
++              bidiText.x += renderParams.vScale / 2;
++              bidiText.y -= renderParams.vScale;
++            }
++            bidiText.angle = renderParams.angle;
++            bidiText.size = fontHeight;
 +            bidiTexts.push(bidiText);
 +
 +            chunk = '';
 +          }
- 
-           args = [];
-         } else if (obj !== null && obj !== undefined) {
-           assertWellFormed(args.length <= 33, 'Too many arguments');
-           args.push(obj);
-         }
 +      } // while
 +
-       return state;
++      return bidiTexts;
 +    },
 +
 +    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 = Encodings.StandardEncoding;
++      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 also
++      // Heuristic: we have to check if the font is a standard one and has
++      // Symbolic font name
 +      if (!!(flags & FontFlags.Symbolic)) {
-         baseEncoding = !properties.file ? Encodings.symbolsEncoding :
-                                           Encodings.MacRomanEncoding;
++        baseEncoding = !properties.file && /Symbol/i.test(properties.name) ?
++          Encodings.SymbolSetEncoding : Encodings.MacRomanEncoding;
 +      }
-       var hasEncoding = dict.has('Encoding');
-       if (hasEncoding) {
++      if (dict.has('Encoding')) {
 +        var encoding = dict.get('Encoding');
 +        if (isDict(encoding)) {
 +          var baseName = encoding.get('BaseEncoding');
-           if (baseName)
++          if (baseName) {
++            overridableEncoding = false;
++            hasEncoding = true;
 +            baseEncoding = Encodings[baseName.name];
-           else
-             hasEncoding = false; // base encoding was not provided
++          }
 +
 +          // 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)) {
-           baseEncoding = Encodings[encoding.name];
++          overridableEncoding = false;
++          hasEncoding = true;
++          var currentEncoding = Encodings[encoding.name];
++
++          // Some bad PDF files contain fonts whose encoding name is not among
++          // the predefined encodings, causing baseEncoding to be undefined.
++          // In this case, fallback to using the baseEncoding as defined above
++          // and let the font override the encoding if one is available.
++          if (currentEncoding) {
++            baseEncoding = currentEncoding;
++          } else {
++            overridableEncoding = true;
++          }
 +        } else {
 +          error('Encoding is not a Name nor a Dict');
 +        }
 +      }
 +
 +      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 tokens = [];
-         var token = '';
-         var beginArrayToken = {};
- 
-         var cmap = cmapObj.getBytes(cmapObj.length);
-         for (var i = 0, ii = cmap.length; i < ii; i++) {
-           var octet = cmap[i];
-           if (octet == 0x20 || octet == 0x0D || octet == 0x0A ||
-               octet == 0x3C || octet == 0x5B || octet == 0x5D) {
-             switch (token) {
-               case 'usecmap':
-                 error('usecmap is not implemented');
-                 break;
- 
-               case 'beginbfchar':
-               case 'beginbfrange':
-               case 'begincidchar':
-               case 'begincidrange':
-                 token = '';
-                 tokens = [];
-                 break;
- 
-               case 'endcidrange':
-               case 'endbfrange':
-                 for (var j = 0, jj = tokens.length; j < jj; j += 3) {
-                   var startRange = tokens[j];
-                   var endRange = tokens[j + 1];
-                   var code = tokens[j + 2];
-                   if (code == 0xFFFF) {
-                     // CMap is broken, assuming code == startRange
-                     code = startRange;
-                   }
-                   if (isArray(code)) {
-                     var codeindex = 0;
-                     while (startRange <= endRange) {
-                       charToUnicode[startRange] = code[codeindex++];
-                       ++startRange;
-                     }
-                   } else {
-                     while (startRange <= endRange) {
-                       charToUnicode[startRange] = code++;
-                       ++startRange;
-                     }
-                   }
-                 }
-                 break;
- 
-               case 'endcidchar':
-               case 'endbfchar':
-                 for (var j = 0, jj = tokens.length; j < jj; j += 2) {
-                   var index = tokens[j];
-                   var code = tokens[j + 1];
-                   charToUnicode[index] = code;
-                 }
-                 break;
- 
-               case '':
-                 break;
- 
-               default:
-                 if (token[0] >= '0' && token[0] <= '9')
-                   token = parseInt(token, 10); // a number
-                 tokens.push(token);
-                 token = '';
-             }
-             switch (octet) {
-               case 0x5B:
-                 // begin list parsing
-                 tokens.push(beginArrayToken);
-                 break;
-               case 0x5D:
-                 // collect array items
-                 var items = [], item;
-                 while (tokens.length &&
-                        (item = tokens.pop()) != beginArrayToken)
-                   items.unshift(item);
-                 tokens.push(items);
-                 break;
-             }
-           } else if (octet == 0x3E) {
-             if (token.length) {
-               // Heuristic: guessing chars size by checking numbers sizes
-               // in the CMap entries.
-               if (token.length == 2 && properties.composite)
-                 properties.wideChars = false;
- 
-               if (token.length <= 4) {
-                 // parsing hex number
-                 tokens.push(parseInt(token, 16));
-                 token = '';
-               } else {
-                 // parsing hex UTF-16BE numbers
-                 var str = [];
-                 for (var k = 0, kk = token.length; k < kk; k += 4) {
-                   var b = parseInt(token.substr(k, 4), 16);
-                   if (b <= 0x10) {
-                     k += 4;
-                     b = (b << 16) | parseInt(token.substr(k, 4), 16);
-                     b -= 0x10000;
-                     str.push(0xD800 | (b >> 10));
-                     str.push(0xDC00 | (b & 0x3FF));
-                     break;
-                   }
-                   str.push(b);
-                 }
-                 tokens.push(String.fromCharCode.apply(String, str));
-                 token = '';
-               }
++        var cmap = CMapFactory.create(cmapObj).map;
++        // 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;
 +            }
-           } else {
-             token += String.fromCharCode(octet);
++            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;
 +          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,
-                                                            resources,
-                                                            dependency) {
++                                                           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));
++          descriptor.set('FontName', Name.get(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,
++            name: baseFontName,
 +            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);
++        fontName = Name.get(fontName);
 +      }
 +      if (isString(baseFont)) {
-         baseFont = new Name(baseFont);
++        baseFont = Name.get(baseFont);
 +      }
 +
 +      if (type.name !== 'Type3') {
 +        var fontNameStr = fontName && fontName.name;
 +        var baseFontStr = baseFont && baseFont.name;
 +        if (fontNameStr !== baseFontStr) {
-           warn('The FontDescriptor\'s FontName is "' + fontNameStr +
++          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,
++        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.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, kind: ImageKind.RGBA_32BPP,
++            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;
 +})();
 +
- var EvalState = (function EvalStateClosure() {
-   function EvalState() {
-     // Are soft masks and alpha values shapes or opacities?
-     this.alphaIsShape = false;
++var OperatorList = (function OperatorListClosure() {
++  var CHUNK_SIZE = 100;
++
++    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
++            transfers.push(arg.data.buffer);
++            break;
++        }
++      }
++      return transfers;
++    }
++
++
++    function OperatorList(intent, 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 = [];
++    }
++    this.argsArray = [];
++    this.dependencies = {};
++    this.pageIndex = pageIndex;
++    this.fnIndex = 0;
++    this.intent = intent;
++  }
++
++  OperatorList.prototype = {
++
++    get length() {
++      return this.argsArray.length;
++    },
++
++    addOp: function(fn, args) {
++      if (this.messageHandler) {
++        this.fnArray[this.fnIndex++] = fn;
++        this.argsArray.push(args);
++        if (this.fnIndex >= CHUNK_SIZE) {
++          this.flush();
++        }
++      } else {
++        this.fnArray.push(fn);
++        this.argsArray.push(args);
++      }
++    },
++
++    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,
++        intent: this.intent
++      }, null, transfers);
++      this.dependencies = [];
++      this.fnIndex = 0;
++      this.argsArray = [];
++    }
++  };
++
++  return OperatorList;
++})();
++
++var TextState = (function TextStateClosure() {
++  function TextState() {
 +    this.fontSize = 0;
-     this.textMatrix = IDENTITY_MATRIX;
++    this.textMatrix = [1, 0, 0, 1, 0, 0];
++    this.stateStack = [];
++    //textState variables
 +    this.leading = 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;
-     // Color spaces
-     this.fillColorSpace = null;
-     this.strokeColorSpace = null;
++    this.textRise = 0;
++  }
++  TextState.prototype = {
++    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;
++    },
++    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(cm) {
++      var tm = this.textMatrix;
++      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;
 +})();
 +
++var EvaluatorPreprocessor = (function EvaluatorPreprocessor() {
++  // Specifies properties for each command
++  //
++  // If variableArgs === true: [0, `numArgs`] expected
++  // If variableArgs === false: exactly `numArgs` expected
++  var OP_MAP = {
++    // Graphic state
++    w: { id: OPS.setLineWidth, numArgs: 1, variableArgs: false },
++    J: { id: OPS.setLineCap, numArgs: 1, variableArgs: false },
++    j: { id: OPS.setLineJoin, numArgs: 1, variableArgs: false },
++    M: { id: OPS.setMiterLimit, numArgs: 1, variableArgs: false },
++    d: { id: OPS.setDash, numArgs: 2, variableArgs: false },
++    ri: { id: OPS.setRenderingIntent, numArgs: 1, variableArgs: false },
++    i: { id: OPS.setFlatness, numArgs: 1, variableArgs: false },
++    gs: { id: OPS.setGState, numArgs: 1, variableArgs: false },
++    q: { id: OPS.save, numArgs: 0, variableArgs: false },
++    Q: { id: OPS.restore, numArgs: 0, variableArgs: false },
++    cm: { id: OPS.transform, numArgs: 6, variableArgs: false },
++
++    // Path
++    m: { id: OPS.moveTo, numArgs: 2, variableArgs: false },
++    l: { id: OPS.lineTo, numArgs: 2, variableArgs: false },
++    c: { id: OPS.curveTo, numArgs: 6, variableArgs: false },
++    v: { id: OPS.curveTo2, numArgs: 4, variableArgs: false },
++    y: { id: OPS.curveTo3, numArgs: 4, variableArgs: false },
++    h: { id: OPS.closePath, numArgs: 0, variableArgs: false },
++    re: { id: OPS.rectangle, numArgs: 4, variableArgs: false },
++    S: { id: OPS.stroke, numArgs: 0, variableArgs: false },
++    s: { id: OPS.closeStroke, numArgs: 0, variableArgs: false },
++    f: { id: OPS.fill, numArgs: 0, variableArgs: false },
++    F: { id: OPS.fill, numArgs: 0, variableArgs: false },
++    'f*': { id: OPS.eoFill, numArgs: 0, variableArgs: false },
++    B: { id: OPS.fillStroke, numArgs: 0, variableArgs: false },
++    'B*': { id: OPS.eoFillStroke, numArgs: 0, variableArgs: false },
++    b: { id: OPS.closeFillStroke, numArgs: 0, variableArgs: false },
++    'b*': { id: OPS.closeEOFillStroke, numArgs: 0, variableArgs: false },
++    n: { id: OPS.endPath, numArgs: 0, variableArgs: false },
++
++    // Clipping
++    W: { id: OPS.clip, numArgs: 0, variableArgs: false },
++    'W*': { id: OPS.eoClip, numArgs: 0, variableArgs: false },
++
++    // Text
++    BT: { id: OPS.beginText, numArgs: 0, variableArgs: false },
++    ET: { id: OPS.endText, numArgs: 0, variableArgs: false },
++    Tc: { id: OPS.setCharSpacing, numArgs: 1, variableArgs: false },
++    Tw: { id: OPS.setWordSpacing, numArgs: 1, variableArgs: false },
++    Tz: { id: OPS.setHScale, numArgs: 1, variableArgs: false },
++    TL: { id: OPS.setLeading, numArgs: 1, variableArgs: false },
++    Tf: { id: OPS.setFont, numArgs: 2, variableArgs: false },
++    Tr: { id: OPS.setTextRenderingMode, numArgs: 1, variableArgs: false },
++    Ts: { id: OPS.setTextRise, numArgs: 1, variableArgs: false },
++    Td: { id: OPS.moveText, numArgs: 2, variableArgs: false },
++    TD: { id: OPS.setLeadingMoveText, numArgs: 2, variableArgs: false },
++    Tm: { id: OPS.setTextMatrix, numArgs: 6, variableArgs: false },
++    'T*': { id: OPS.nextLine, numArgs: 0, variableArgs: false },
++    Tj: { id: OPS.showText, numArgs: 1, variableArgs: false },
++    TJ: { id: OPS.showSpacedText, numArgs: 1, variableArgs: false },
++    '\'': { id: OPS.nextLineShowText, numArgs: 1, variableArgs: false },
++    '"': { id: OPS.nextLineSetSpacingShowText, numArgs: 3,
++      variableArgs: false },
++
++    // Type3 fonts
++    d0: { id: OPS.setCharWidth, numArgs: 2, variableArgs: false },
++    d1: { id: OPS.setCharWidthAndBounds, numArgs: 6, variableArgs: false },
++
++    // Color
++    CS: { id: OPS.setStrokeColorSpace, numArgs: 1, variableArgs: false },
++    cs: { id: OPS.setFillColorSpace, numArgs: 1, variableArgs: false },
++    SC: { id: OPS.setStrokeColor, numArgs: 4, variableArgs: true },
++    SCN: { id: OPS.setStrokeColorN, numArgs: 33, variableArgs: true },
++    sc: { id: OPS.setFillColor, numArgs: 4, variableArgs: true },
++    scn: { id: OPS.setFillColorN, numArgs: 33, variableArgs: true },
++    G: { id: OPS.setStrokeGray, numArgs: 1, variableArgs: false },
++    g: { id: OPS.setFillGray, numArgs: 1, variableArgs: false },
++    RG: { id: OPS.setStrokeRGBColor, numArgs: 3, variableArgs: false },
++    rg: { id: OPS.setFillRGBColor, numArgs: 3, variableArgs: false },
++    K: { id: OPS.setStrokeCMYKColor, numArgs: 4, variableArgs: false },
++    k: { id: OPS.setFillCMYKColor, numArgs: 4, variableArgs: false },
++
++    // Shading
++    sh: { id: OPS.shadingFill, numArgs: 1, variableArgs: false },
++
++    // Images
++    BI: { id: OPS.beginInlineImage, numArgs: 0, variableArgs: false },
++    ID: { id: OPS.beginImageData, numArgs: 0, variableArgs: false },
++    EI: { id: OPS.endInlineImage, numArgs: 1, variableArgs: false },
++
++    // XObjects
++    Do: { id: OPS.paintXObject, numArgs: 1, variableArgs: false },
++    MP: { id: OPS.markPoint, numArgs: 1, variableArgs: false },
++    DP: { id: OPS.markPointProps, numArgs: 2, variableArgs: false },
++    BMC: { id: OPS.beginMarkedContent, numArgs: 1, variableArgs: false },
++    BDC: { id: OPS.beginMarkedContentProps, numArgs: 2,
++      variableArgs: false },
++    EMC: { id: OPS.endMarkedContent, numArgs: 0, variableArgs: false },
++
++    // Compatibility
++    BX: { id: OPS.beginCompat, numArgs: 0, variableArgs: false },
++    EX: { id: OPS.endCompat, numArgs: 0, variableArgs: false },
++
++    // (reserved partial commands for the lexer)
++    BM: null,
++    BD: null,
++    'true': null,
++    fa: null,
++    fal: null,
++    fals: null,
++    'false': null,
++    nu: null,
++    nul: null,
++    'null': null
++  };
++
++  function EvaluatorPreprocessor(stream, xref) {
++    // TODO(mduan): pass array of knownCommands rather than OP_MAP
++    // dictionary
++    this.parser = new Parser(new Lexer(stream, OP_MAP), false, xref);
++    this.ctm = new Float32Array([1, 0, 0, 1, 0, 0]);
++    this.savedStates = [];
++  }
++  EvaluatorPreprocessor.prototype = {
++    get savedStatesDepth() {
++      return this.savedStates.length;
++    },
++    read: function EvaluatorPreprocessor_read() {
++      var args = [];
++      while (true) {
++        var obj = this.parser.getObj();
++        if (isEOF(obj)) {
++          return null; // no more commands
++        }
++        if (!isCmd(obj)) {
++          // argument
++          if (obj !== null && obj !== undefined) {
++            args.push(obj instanceof Dict ? obj.getAll() : obj);
++            assertWellFormed(args.length <= 33, 'Too many arguments');
++          }
++          continue;
++        }
++
++        var cmd = obj.cmd;
++        // Check that the command is valid
++        var opSpec = OP_MAP[cmd];
++        if (!opSpec) {
++          warn('Unknown command "' + cmd + '"');
++          continue;
++        }
++
++        var fn = opSpec.id;
++
++        // 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');
++          }
++        } else {
++          if (args.length < opSpec.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 +
++              ' args; skipping');
++            args = [];
++            continue;
++          } else if (args.length > opSpec.numArgs) {
++            info('Command ' + fn + ': expected ' + opSpec.numArgs +
++              ' args, but received ' + args.length + ' args');
++          }
++        }
++
++        // TODO figure out how to type-check vararg functions
++
++        this.preprocessCommand(fn, args);
++
++        return {fn: fn, args: args};
++      }
++    },
++    getState: function EvaluatorPreprocessor_getState() {
++      return {
++        ctm: this.ctm
++      };
++    },
++    setState: function EvaluatorPreprocessor_setState(state) {
++      this.ctm = state.ctm;
++    },
++    preprocessCommand: function EvaluatorPreprocessor_preprocessCommand(fn,
++                                                                        args) {
++      switch (fn | 0) {
++        case OPS.save:
++          this.savedStates.push(this.getState());
++          break;
++        case OPS.restore:
++          var previousState = this.savedStates.pop();
++          if (previousState) {
++            this.setState(previousState);
++          }
++          break;
++        case OPS.transform:
++          var ctm = this.ctm;
++          var m = new Float32Array(6);
++          m[0] = ctm[0] * args[0] + ctm[2] * args[1];
++          m[1] = ctm[1] * args[0] + ctm[3] * args[1];
++          m[2] = ctm[0] * args[2] + ctm[2] * args[3];
++          m[3] = ctm[1] * args[2] + ctm[3] * args[3];
++          m[4] = ctm[0] * args[4] + ctm[2] * args[5] + ctm[4];
++          m[5] = ctm[1] * args[4] + ctm[3] * args[5] + ctm[5];
++          this.ctm = m;
++          break;
++      }
++    }
++  };
++  return EvaluatorPreprocessor;
++})();
 +
 +
 +// Unicode Private Use Area
 +var CMAP_GLYPH_OFFSET = 0xE000;
 +var GLYPH_AREA_SIZE = 0x1900;
 +var SYMBOLIC_FONT_GLYPH_OFFSET = 0xF000;
 +
 +// PDF Glyph Space Units are one Thousandth of a TextSpace Unit
 +// except for Type 3 fonts
 +var PDF_GLYPH_SPACE_UNITS = 1000;
 +
 +// Hinting is currently disabled due to unknown problems on windows
 +// in tracemonkey and various other pdfs with type1 fonts.
 +var HINTING_ENABLED = false;
 +
 +// Accented charactars are not displayed properly on windows, using this flag
 +// to control analysis of seac charstrings.
 +var SEAC_ANALYSIS_ENABLED = false;
 +
- var FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0];
- 
 +var FontFlags = {
 +  FixedPitch: 1,
 +  Serif: 2,
 +  Symbolic: 4,
 +  Script: 8,
 +  Nonsymbolic: 32,
 +  Italic: 64,
 +  AllCap: 65536,
 +  SmallCap: 131072,
 +  ForceBold: 262144
 +};
 +
 +var Encodings = {
 +  ExpertEncoding: ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
 +    '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
 +    'space', 'exclamsmall', 'Hungarumlautsmall', '', 'dollaroldstyle',
 +    'dollarsuperior', 'ampersandsmall', 'Acutesmall', 'parenleftsuperior',
 +    'parenrightsuperior', 'twodotenleader', 'onedotenleader', 'comma',
 +    'hyphen', 'period', 'fraction', 'zerooldstyle', 'oneoldstyle',
 +    'twooldstyle', 'threeoldstyle', 'fouroldstyle', 'fiveoldstyle',
 +    'sixoldstyle', 'sevenoldstyle', 'eightoldstyle', 'nineoldstyle', 'colon',
 +    'semicolon', 'commasuperior', 'threequartersemdash', 'periodsuperior',
 +    'questionsmall', '', 'asuperior', 'bsuperior', 'centsuperior', 'dsuperior',
 +    'esuperior', '', '', 'isuperior', '', '', 'lsuperior', 'msuperior',
 +    'nsuperior', 'osuperior', '', '', 'rsuperior', 'ssuperior', 'tsuperior',
 +    '', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'parenleftinferior', '',
 +    'parenrightinferior', 'Circumflexsmall', 'hyphensuperior', 'Gravesmall',
 +    'Asmall', 'Bsmall', 'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall',
 +    'Hsmall', 'Ismall', 'Jsmall', 'Ksmall', 'Lsmall', 'Msmall', 'Nsmall',
 +    'Osmall', 'Psmall', 'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall',
 +    'Vsmall', 'Wsmall', 'Xsmall', 'Ysmall', 'Zsmall', 'colonmonetary',
 +    'onefitted', 'rupiah', 'Tildesmall', '', '', '', '', '', '', '', '', '',
 +    '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
 +    '', '', '', '', '', '', 'exclamdownsmall', 'centoldstyle', 'Lslashsmall',
 +    '', '', 'Scaronsmall', 'Zcaronsmall', 'Dieresissmall', 'Brevesmall',
 +    'Caronsmall', '', 'Dotaccentsmall', '', '', 'Macronsmall', '', '',
 +    'figuredash', 'hypheninferior', '', '', 'Ogoneksmall', 'Ringsmall',
 +    'Cedillasmall', '', '', '', 'onequarter', 'onehalf', 'threequarters',
 +    'questiondownsmall', 'oneeighth', 'threeeighths', 'fiveeighths',
 +    'seveneighths', 'onethird', 'twothirds', '', '', 'zerosuperior',
 +    'onesuperior', 'twosuperior', 'threesuperior', 'foursuperior',
 +    'fivesuperior', 'sixsuperior', 'sevensuperior', 'eightsuperior',
 +    'ninesuperior', 'zeroinferior', 'oneinferior', 'twoinferior',
 +    'threeinferior', 'fourinferior', 'fiveinferior', 'sixinferior',
 +    'seveninferior', 'eightinferior', 'nineinferior', 'centinferior',
 +    'dollarinferior', 'periodinferior', 'commainferior', 'Agravesmall',
 +    'Aacutesmall', 'Acircumflexsmall', 'Atildesmall', 'Adieresissmall',
 +    'Aringsmall', 'AEsmall', 'Ccedillasmall', 'Egravesmall', 'Eacutesmall',
 +    'Ecircumflexsmall', 'Edieresissmall', 'Igravesmall', 'Iacutesmall',
 +    'Icircumflexsmall', 'Idieresissmall', 'Ethsmall', 'Ntildesmall',
 +    'Ogravesmall', 'Oacutesmall', 'Ocircumflexsmall', 'Otildesmall',
 +    'Odieresissmall', 'OEsmall', 'Oslashsmall', 'Ugravesmall', 'Uacutesmall',
 +    'Ucircumflexsmall', 'Udieresissmall', 'Yacutesmall', 'Thornsmall',
 +    'Ydieresissmall'],
 +  MacExpertEncoding: ['', '', '', '', '', '', '', '', '', '', '', '', '', '',
 +    '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
 +    'space', 'exclamsmall', 'Hungarumlautsmall', 'centoldstyle',
 +    'dollaroldstyle', 'dollarsuperior', 'ampersandsmall', 'Acutesmall',
 +    'parenleftsuperior', 'parenrightsuperior', 'twodotenleader',
 +    'onedotenleader', 'comma', 'hyphen', 'period', 'fraction', 'zerooldstyle',
 +    'oneoldstyle', 'twooldstyle', 'threeoldstyle', 'fouroldstyle',
 +    'fiveoldstyle', 'sixoldstyle', 'sevenoldstyle', 'eightoldstyle',
 +    'nineoldstyle', 'colon', 'semicolon', '', 'threequartersemdash', '',
 +    'questionsmall', '', '', '', '', 'Ethsmall', '', '', 'onequarter',
 +    'onehalf', 'threequarters', 'oneeighth', 'threeeighths', 'fiveeighths',
 +    'seveneighths', 'onethird', 'twothirds', '', '', '', '', '', '', 'ff',
 +    'fi', 'fl', 'ffi', 'ffl', 'parenleftinferior', '', 'parenrightinferior',
 +    'Circumflexsmall', 'hypheninferior', 'Gravesmall', 'Asmall', 'Bsmall',
 +    'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall', 'Hsmall', 'Ismall',
 +    'Jsmall', 'Ksmall', 'Lsmall', 'Msmall', 'Nsmall', 'Osmall', 'Psmall',
 +    'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall', 'Vsmall', 'Wsmall',
 +    'Xsmall', 'Ysmall', 'Zsmall', 'colonmonetary', 'onefitted', 'rupiah',
 +    'Tildesmall', '', '', 'asuperior', 'centsuperior', '', '', '', '',
 +    'Aacutesmall', 'Agravesmall', 'Acircumflexsmall', 'Adieresissmall',
 +    'Atildesmall', 'Aringsmall', 'Ccedillasmall', 'Eacutesmall', 'Egravesmall',
 +    'Ecircumflexsmall', 'Edieresissmall', 'Iacutesmall', 'Igravesmall',
 +    'Icircumflexsmall', 'Idieresissmall', 'Ntildesmall', 'Oacutesmall',
 +    'Ogravesmall', 'Ocircumflexsmall', 'Odieresissmall', 'Otildesmall',
 +    'Uacutesmall', 'Ugravesmall', 'Ucircumflexsmall', 'Udieresissmall', '',
 +    'eightsuperior', 'fourinferior', 'threeinferior', 'sixinferior',
 +    'eightinferior', 'seveninferior', 'Scaronsmall', '', 'centinferior',
 +    'twoinferior', '', 'Dieresissmall', '', 'Caronsmall', 'osuperior',
 +    'fiveinferior', '', 'commainferior', 'periodinferior', 'Yacutesmall', '',
 +    'dollarinferior', '', 'Thornsmall', '', 'nineinferior', 'zeroinferior',
 +    'Zcaronsmall', 'AEsmall', 'Oslashsmall', 'questiondownsmall',
 +    'oneinferior', 'Lslashsmall', '', '', '', '', '', '', 'Cedillasmall', '',
 +    '', '', '', '', 'OEsmall', 'figuredash', 'hyphensuperior', '', '', '', '',
 +    'exclamdownsmall', '', 'Ydieresissmall', '', 'onesuperior', 'twosuperior',
 +    'threesuperior', 'foursuperior', 'fivesuperior', 'sixsuperior',
 +    'sevensuperior', 'ninesuperior', 'zerosuperior', '', 'esuperior',
 +    'rsuperior', 'tsuperior', '', '', 'isuperior', 'ssuperior', 'dsuperior',
 +    '', '', '', '', '', 'lsuperior', 'Ogoneksmall', 'Brevesmall',
 +    'Macronsmall', 'bsuperior', 'nsuperior', 'msuperior', 'commasuperior',
 +    'periodsuperior', 'Dotaccentsmall', 'Ringsmall'],
 +  MacRomanEncoding: ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
 +    '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
 +    'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent',
 +    'ampersand', 'quotesingle', 'parenleft', 'parenright', 'asterisk', 'plus',
 +    'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 'two', 'three',
 +    'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon',
 +    'less', 'equal', 'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F',
 +    'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U',
 +    'V', 'W', 'X', 'Y', 'Z', 'bracketleft', 'backslash', 'bracketright',
 +    'asciicircum', 'underscore', 'grave', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
 +    'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
 +    'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright', 'asciitilde', '',
 +    'Adieresis', 'Aring', 'Ccedilla', 'Eacute', 'Ntilde', 'Odieresis',
 +    'Udieresis', 'aacute', 'agrave', 'acircumflex', 'adieresis', 'atilde',
 +    'aring', 'ccedilla', 'eacute', 'egrave', 'ecircumflex', 'edieresis',
 +    'iacute', 'igrave', 'icircumflex', 'idieresis', 'ntilde', 'oacute',
 +    'ograve', 'ocircumflex', 'odieresis', 'otilde', 'uacute', 'ugrave',
 +    'ucircumflex', 'udieresis', 'dagger', 'degree', 'cent', 'sterling',
 +    'section', 'bullet', 'paragraph', 'germandbls', 'registered', 'copyright',
 +    'trademark', 'acute', 'dieresis', 'notequal', 'AE', 'Oslash', 'infinity',
 +    'plusminus', 'lessequal', 'greaterequal', 'yen', 'mu', 'partialdiff',
 +    'summation', 'product', 'pi', 'integral', 'ordfeminine', 'ordmasculine',
 +    'Omega', 'ae', 'oslash', 'questiondown', 'exclamdown', 'logicalnot',
 +    'radical', 'florin', 'approxequal', 'Delta', 'guillemotleft',
 +    'guillemotright', 'ellipsis', '', 'Agrave', 'Atilde', 'Otilde', 'OE',
 +    'oe', 'endash', 'emdash', 'quotedblleft', 'quotedblright', 'quoteleft',
 +    'quoteright', 'divide', 'lozenge', 'ydieresis', 'Ydieresis', 'fraction',
 +    'currency', 'guilsinglleft', 'guilsinglright', 'fi', 'fl', 'daggerdbl',
 +    'periodcentered', 'quotesinglbase', 'quotedblbase', 'perthousand',
 +    'Acircumflex', 'Ecircumflex', 'Aacute', 'Edieresis', 'Egrave', 'Iacute',
 +    'Icircumflex', 'Idieresis', 'Igrave', 'Oacute', 'Ocircumflex', 'apple',
 +    'Ograve', 'Uacute', 'Ucircumflex', 'Ugrave', 'dotlessi', 'circumflex',
 +    'tilde', 'macron', 'breve', 'dotaccent', 'ring', 'cedilla', 'hungarumlaut',
 +    'ogonek', 'caron'],
 +  StandardEncoding: ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
 +    '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
 +    'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent',
 +    'ampersand', 'quoteright', 'parenleft', 'parenright', 'asterisk', 'plus',
 +    'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 'two', 'three',
 +    'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon',
 +    'less', 'equal', 'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F',
 +    'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U',
 +    'V', 'W', 'X', 'Y', 'Z', 'bracketleft', 'backslash', 'bracketright',
 +    'asciicircum', 'underscore', 'quoteleft', 'a', 'b', 'c', 'd', 'e', 'f',
 +    'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u',
 +    'v', 'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright', 'asciitilde',
 +    '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
 +    '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'exclamdown',
 +    'cent', 'sterling', 'fraction', 'yen', 'florin', 'section', 'currency',
 +    'quotesingle', 'quotedblleft', 'guillemotleft', 'guilsinglleft',
 +    'guilsinglright', 'fi', 'fl', '', 'endash', 'dagger', 'daggerdbl',
 +    'periodcentered', '', 'paragraph', 'bullet', 'quotesinglbase',
 +    'quotedblbase', 'quotedblright', 'guillemotright', 'ellipsis',
 +    'perthousand', '', 'questiondown', '', 'grave', 'acute', 'circumflex',
 +    'tilde', 'macron', 'breve', 'dotaccent', 'dieresis', '', 'ring', 'cedilla',
 +    '', 'hungarumlaut', 'ogonek', 'caron', 'emdash', '', '', '', '', '', '',
 +    '', '', '', '', '', '', '', '', '', '', 'AE', '', 'ordfeminine', '', '',
 +    '', '', 'Lslash', 'Oslash', 'OE', 'ordmasculine', '', '', '', '', '', 'ae',
 +    '', '', '', 'dotlessi', '', '', 'lslash', 'oslash', 'oe', 'germandbls'],
 +  WinAnsiEncoding: ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
 +    '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
 +    'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent',
 +    'ampersand', 'quotesingle', 'parenleft', 'parenright', 'asterisk', 'plus',
 +    'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 'two', 'three',
 +    'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon',
 +    'less', 'equal', 'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F',
 +    'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U',
 +    'V', 'W', 'X', 'Y', 'Z', 'bracketleft', 'backslash', 'bracketright',
 +    'asciicircum', 'underscore', 'grave', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
 +    'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
 +    'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright', 'asciitilde',
 +    'bullet', 'Euro', 'bullet', 'quotesinglbase', 'florin', 'quotedblbase',
 +    'ellipsis', 'dagger', 'daggerdbl', 'circumflex', 'perthousand', 'Scaron',
 +    'guilsinglleft', 'OE', 'bullet', 'Zcaron', 'bullet', 'bullet', 'quoteleft',
 +    'quoteright', 'quotedblleft', 'quotedblright', 'bullet', 'endash',
 +    'emdash', 'tilde', 'trademark', 'scaron', 'guilsinglright', 'oe', 'bullet',
 +    'zcaron', 'Ydieresis', '', 'exclamdown', 'cent', 'sterling',
 +    'currency', 'yen', 'brokenbar', 'section', 'dieresis', 'copyright',
 +    'ordfeminine', 'guillemotleft', 'logicalnot', 'hyphen', 'registered',
 +    'macron', 'degree', 'plusminus', 'twosuperior', 'threesuperior', 'acute',
 +    'mu', 'paragraph', 'periodcentered', 'cedilla', 'onesuperior',
 +    'ordmasculine', 'guillemotright', 'onequarter', 'onehalf', 'threequarters',
 +    'questiondown', 'Agrave', 'Aacute', 'Acircumflex', 'Atilde', 'Adieresis',
 +    'Aring', 'AE', 'Ccedilla', 'Egrave', 'Eacute', 'Ecircumflex', 'Edieresis',
 +    'Igrave', 'Iacute', 'Icircumflex', 'Idieresis', 'Eth', 'Ntilde', 'Ograve',
 +    'Oacute', 'Ocircumflex', 'Otilde', 'Odieresis', 'multiply', 'Oslash',
 +    'Ugrave', 'Uacute', 'Ucircumflex', 'Udieresis', 'Yacute', 'Thorn',
 +    'germandbls', 'agrave', 'aacute', 'acircumflex', 'atilde', 'adieresis',
 +    'aring', 'ae', 'ccedilla', 'egrave', 'eacute', 'ecircumflex', 'edieresis',
 +    'igrave', 'iacute', 'icircumflex', 'idieresis', 'eth', 'ntilde', 'ograve',
 +    'oacute', 'ocircumflex', 'otilde', 'odieresis', 'divide', 'oslash',
 +    'ugrave', 'uacute', 'ucircumflex', 'udieresis', 'yacute', 'thorn',
 +    'ydieresis'],
-   symbolsEncoding: ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
-     '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
++  SymbolSetEncoding: ['', '', '', '', '', '', '', '', '', '', '', '', '', '',
++    '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
 +    'space', 'exclam', 'universal', 'numbersign', 'existential', 'percent',
 +    'ampersand', 'suchthat', 'parenleft', 'parenright', 'asteriskmath', 'plus',
 +    'comma', 'minus', 'period', 'slash', 'zero', 'one', 'two', 'three', 'four',
 +    'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon', 'less',
 +    'equal', 'greater', 'question', 'congruent', 'Alpha', 'Beta', 'Chi',
 +    'Delta', 'Epsilon', 'Phi', 'Gamma', 'Eta', 'Iota', 'theta1', 'Kappa',
 +    'Lambda', 'Mu', 'Nu', 'Omicron', 'Pi', 'Theta', 'Rho', 'Sigma', 'Tau',
 +    'Upsilon', 'sigma1', 'Omega', 'Xi', 'Psi', 'Zeta', 'bracketleft',
 +    'therefore', 'bracketright', 'perpendicular', 'underscore', 'radicalex',
 +    'alpha', 'beta', 'chi', 'delta', 'epsilon', 'phi', 'gamma', 'eta', 'iota',
 +    'phi1', 'kappa', 'lambda', 'mu', 'nu', 'omicron', 'pi', 'theta', 'rho',
 +    'sigma', 'tau', 'upsilon', 'omega1', 'omega', 'xi', 'psi', 'zeta',
 +    'braceleft', 'bar', 'braceright', 'similar', '', '', '', '', '', '', '',
 +    '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
 +    '', '', '', '', '', '', '', 'Euro', 'Upsilon1', 'minute', 'lessequal',
 +    'fraction', 'infinity', 'florin', 'club', 'diamond', 'heart', 'spade',
 +    'arrowboth', 'arrowleft', 'arrowup', 'arrowright', 'arrowdown', 'degree',
 +    'plusminus', 'second', 'greaterequal', 'multiply', 'proportional',
 +    'partialdiff', 'bullet', 'divide', 'notequal', 'equivalence',
 +    'approxequal', 'ellipsis', 'arrowvertex', 'arrowhorizex', 'carriagereturn',
 +    'aleph', 'Ifraktur', 'Rfraktur', 'weierstrass', 'circlemultiply',
 +    'circleplus', 'emptyset', 'intersection', 'union', 'propersuperset',
 +    'reflexsuperset', 'notsubset', 'propersubset', 'reflexsubset', 'element',
 +    'notelement', 'angle', 'gradient', 'registerserif', 'copyrightserif',
 +    'trademarkserif', 'product', 'radical', 'dotmath', 'logicalnot',
 +    'logicaland', 'logicalor', 'arrowdblboth', 'arrowdblleft', 'arrowdblup',
 +    'arrowdblright', 'arrowdbldown', 'lozenge', 'angleleft', 'registersans',
 +    'copyrightsans', 'trademarksans', 'summation', 'parenlefttp',
 +    'parenleftex', 'parenleftbt', 'bracketlefttp', 'bracketleftex',
 +    'bracketleftbt', 'bracelefttp', 'braceleftmid', 'braceleftbt', 'braceex',
 +    '', 'angleright', 'integral', 'integraltp', 'integralex', 'integralbt',
 +    'parenrighttp', 'parenrightex', 'parenrightbt', 'bracketrighttp',
 +    'bracketrightex', 'bracketrightbt', 'bracerighttp', 'bracerightmid',
 +    'bracerightbt'],
 +  zapfDingbatsEncoding: ['', '', '', '', '', '', '', '', '', '', '', '', '', '',
 +    '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
 +    'space', 'a1', 'a2', 'a202', 'a3', 'a4', 'a5', 'a119', 'a118', 'a117',
 +    'a11', 'a12', 'a13', 'a14', 'a15', 'a16', 'a105', 'a17', 'a18', 'a19',
 +    'a20', 'a21', 'a22', 'a23', 'a24', 'a25', 'a26', 'a27', 'a28', 'a6', 'a7',
 +    'a8', 'a9', 'a10', 'a29', 'a30', 'a31', 'a32', 'a33', 'a34', 'a35', 'a36',
 +    'a37', 'a38', 'a39', 'a40', 'a41', 'a42', 'a43', 'a44', 'a45', 'a46',
 +    'a47', 'a48', 'a49', 'a50', 'a51', 'a52', 'a53', 'a54', 'a55', 'a56',
 +    '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']
 +};
 +
 +/**
 + * Hold a map of decoded fonts and of the standard fourteen Type1
 + * fonts and their acronyms.
 + */
 +var stdFontMap = {
 +  'ArialNarrow': 'Helvetica',
 +  'ArialNarrow-Bold': 'Helvetica-Bold',
 +  'ArialNarrow-BoldItalic': 'Helvetica-BoldOblique',
 +  'ArialNarrow-Italic': 'Helvetica-Oblique',
 +  'ArialBlack': 'Helvetica',
 +  'ArialBlack-Bold': 'Helvetica-Bold',
 +  'ArialBlack-BoldItalic': 'Helvetica-BoldOblique',
 +  'ArialBlack-Italic': 'Helvetica-Oblique',
 +  'Arial': 'Helvetica',
 +  'Arial-Bold': 'Helvetica-Bold',
 +  'Arial-BoldItalic': 'Helvetica-BoldOblique',
 +  'Arial-Italic': 'Helvetica-Oblique',
 +  'Arial-BoldItalicMT': 'Helvetica-BoldOblique',
 +  'Arial-BoldMT': 'Helvetica-Bold',
 +  'Arial-ItalicMT': 'Helvetica-Oblique',
 +  'ArialMT': 'Helvetica',
 +  'Courier-Bold': 'Courier-Bold',
 +  'Courier-BoldItalic': 'Courier-BoldOblique',
 +  'Courier-Italic': 'Courier-Oblique',
 +  'CourierNew': 'Courier',
 +  'CourierNew-Bold': 'Courier-Bold',
 +  'CourierNew-BoldItalic': 'Courier-BoldOblique',
 +  'CourierNew-Italic': 'Courier-Oblique',
 +  'CourierNewPS-BoldItalicMT': 'Courier-BoldOblique',
 +  'CourierNewPS-BoldMT': 'Courier-Bold',
 +  'CourierNewPS-ItalicMT': 'Courier-Oblique',
 +  'CourierNewPSMT': 'Courier',
 +  'Helvetica-Bold': 'Helvetica-Bold',
 +  'Helvetica-BoldItalic': 'Helvetica-BoldOblique',
 +  'Helvetica-Italic': 'Helvetica-Oblique',
 +  'Symbol-Bold': 'Symbol',
 +  'Symbol-BoldItalic': 'Symbol',
 +  'Symbol-Italic': 'Symbol',
 +  'TimesNewRoman': 'Times-Roman',
 +  'TimesNewRoman-Bold': 'Times-Bold',
 +  'TimesNewRoman-BoldItalic': 'Times-BoldItalic',
 +  'TimesNewRoman-Italic': 'Times-Italic',
 +  'TimesNewRomanPS': 'Times-Roman',
 +  'TimesNewRomanPS-Bold': 'Times-Bold',
 +  'TimesNewRomanPS-BoldItalic': 'Times-BoldItalic',
 +  'TimesNewRomanPS-BoldItalicMT': 'Times-BoldItalic',
 +  'TimesNewRomanPS-BoldMT': 'Times-Bold',
 +  'TimesNewRomanPS-Italic': 'Times-Italic',
 +  'TimesNewRomanPS-ItalicMT': 'Times-Italic',
 +  'TimesNewRomanPSMT': 'Times-Roman',
 +  'TimesNewRomanPSMT-Bold': 'Times-Bold',
 +  'TimesNewRomanPSMT-BoldItalic': 'Times-BoldItalic',
 +  'TimesNewRomanPSMT-Italic': 'Times-Italic'
 +};
 +
 +/**
 + * Holds the map of the non-standard fonts that might be included as a standard
 + * fonts without glyph data.
 + */
 +var nonStdFontMap = {
 +  'ComicSansMS': 'Comic Sans MS',
 +  'ComicSansMS-Bold': 'Comic Sans MS-Bold',
 +  'ComicSansMS-BoldItalic': 'Comic Sans MS-BoldItalic',
 +  'ComicSansMS-Italic': 'Comic Sans MS-Italic',
 +  'LucidaConsole': 'Courier',
 +  'LucidaConsole-Bold': 'Courier-Bold',
 +  'LucidaConsole-BoldItalic': 'Courier-BoldOblique',
 +  'LucidaConsole-Italic': 'Courier-Oblique',
 +  'MS-Gothic': 'MS Gothic',
 +  'MS-Gothic-Bold': 'MS Gothic-Bold',
 +  'MS-Gothic-BoldItalic': 'MS Gothic-BoldItalic',
 +  'MS-Gothic-Italic': 'MS Gothic-Italic',
 +  'MS-Mincho': 'MS Mincho',
 +  'MS-Mincho-Bold': 'MS Mincho-Bold',
 +  'MS-Mincho-BoldItalic': 'MS Mincho-BoldItalic',
 +  'MS-Mincho-Italic': 'MS Mincho-Italic',
 +  'MS-PGothic': 'MS PGothic',
 +  'MS-PGothic-Bold': 'MS PGothic-Bold',
 +  'MS-PGothic-BoldItalic': 'MS PGothic-BoldItalic',
 +  'MS-PGothic-Italic': 'MS PGothic-Italic',
 +  'MS-PMincho': 'MS PMincho',
 +  'MS-PMincho-Bold': 'MS PMincho-Bold',
 +  'MS-PMincho-BoldItalic': 'MS PMincho-BoldItalic',
 +  'MS-PMincho-Italic': 'MS PMincho-Italic',
 +};
 +
 +var serifFonts = {
 +  'Adobe Jenson': true, 'Adobe Text': true, 'Albertus': true,
 +  'Aldus': true, 'Alexandria': true, 'Algerian': true,
 +  'American Typewriter': true, 'Antiqua': true, 'Apex': true,
 +  'Arno': true, 'Aster': true, 'Aurora': true,
 +  'Baskerville': true, 'Bell': true, 'Bembo': true,
 +  'Bembo Schoolbook': true, 'Benguiat': true, 'Berkeley Old Style': true,
 +  'Bernhard Modern': true, 'Berthold City': true, 'Bodoni': true,
 +  'Bauer Bodoni': true, 'Book Antiqua': true, 'Bookman': true,
 +  'Bordeaux Roman': true, 'Californian FB': true, 'Calisto': true,
 +  'Calvert': true, 'Capitals': true, 'Cambria': true,
 +  'Cartier': true, 'Caslon': true, 'Catull': true,
 +  'Centaur': true, 'Century Old Style': true, 'Century Schoolbook': true,
 +  'Chaparral': true, 'Charis SIL': true, 'Cheltenham': true,
 +  'Cholla Slab': true, 'Clarendon': true, 'Clearface': true,
 +  'Cochin': true, 'Colonna': true, 'Computer Modern': true,
 +  'Concrete Roman': true, 'Constantia': true, 'Cooper Black': true,
 +  'Corona': true, 'Ecotype': true, 'Egyptienne': true,
 +  'Elephant': true, 'Excelsior': true, 'Fairfield': true,
 +  'FF Scala': true, 'Folkard': true, 'Footlight': true,
 +  'FreeSerif': true, 'Friz Quadrata': true, 'Garamond': true,
 +  'Gentium': true, 'Georgia': true, 'Gloucester': true,
 +  'Goudy Old Style': true, 'Goudy Schoolbook': true, 'Goudy Pro Font': true,
 +  'Granjon': true, 'Guardian Egyptian': true, 'Heather': true,
 +  'Hercules': true, 'High Tower Text': true, 'Hiroshige': true,
 +  'Hoefler Text': true, 'Humana Serif': true, 'Imprint': true,
 +  'Ionic No. 5': true, 'Janson': true, 'Joanna': true,
 +  'Korinna': true, 'Lexicon': true, 'Liberation Serif': true,
 +  'Linux Libertine': true, 'Literaturnaya': true, 'Lucida': true,
 +  'Lucida Bright': true, 'Melior': true, 'Memphis': true,
 +  'Miller': true, 'Minion': true, 'Modern': true,
 +  'Mona Lisa': true, 'Mrs Eaves': true, 'MS Serif': true,
 +  'Museo Slab': true, 'New York': true, 'Nimbus Roman': true,
 +  'NPS Rawlinson Roadway': true, 'Palatino': true, 'Perpetua': true,
 +  'Plantin': true, 'Plantin Schoolbook': true, 'Playbill': true,
 +  'Poor Richard': true, 'Rawlinson Roadway': true, 'Renault': true,
 +  'Requiem': true, 'Rockwell': true, 'Roman': true,
 +  'Rotis Serif': true, 'Sabon': true, 'Scala': true,
 +  'Seagull': true, 'Sistina': true, 'Souvenir': true,
 +  'STIX': true, 'Stone Informal': true, 'Stone Serif': true,
 +  'Sylfaen': true, 'Times': true, 'Trajan': true,
 +  'Trinité': true, 'Trump Mediaeval': true, 'Utopia': true,
 +  'Vale Type': true, 'Bitstream Vera': true, 'Vera Serif': true,
 +  'Versailles': true, 'Wanted': true, 'Weiss': true,
 +  'Wide Latin': true, 'Windsor': true, 'XITS': true
 +};
 +
 +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,
++  '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,
++  '38': 67, '39': 68, '40': 69, '41': 70, '42': 71, '43': 72, '44': 73,
++  '45': 74, '46': 75, '47': 76, '48': 77, '49': 78, '50': 79, '51': 80,
++  '52': 81, '53': 82, '54': 83, '55': 84, '56': 85, '57': 86, '58': 87,
++  '59': 88, '60': 89, '61': 90, '62': 91, '63': 92, '64': 93, '65': 94,
++  '66': 95, '67': 96, '68': 97, '69': 98, '70': 99, '71': 100, '72': 101,
++  '73': 102, '74': 103, '75': 104, '76': 105, '77': 106, '78': 107, '79': 108,
++  '80': 109, '81': 110, '82': 111, '83': 112, '84': 113, '85': 114, '86': 115,
++  '87': 116, '88': 117, '89': 118, '90': 119, '91': 120, '92': 121, '93': 122,
++  '94': 123, '95': 124, '96': 125, '97': 126, '98': 196, '99': 197, '100': 199,
++  '101': 201, '102': 209, '103': 214, '104': 220, '105': 225, '106': 224,
++  '107': 226, '108': 228, '109': 227, '110': 229, '111': 231, '112': 233,
++  '113': 232, '114': 234, '115': 235, '116': 237, '117': 236, '118': 238,
++  '119': 239, '120': 241, '121': 243, '122': 242, '123': 244, '124': 246,
++  '125': 245, '126': 250, '127': 249, '128': 251, '129': 252, '130': 8224,
++  '131': 176, '132': 162, '133': 163, '134': 167, '135': 8226, '136': 182,
++  '137': 223, '138': 174, '139': 169, '140': 8482, '141': 180, '142': 168,
++  '143': 8800, '144': 198, '145': 216, '146': 8734, '147': 177, '148': 8804,
++  '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,
++  '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,
++  '763': 1778, '775': 1652, '777': 1764, '778': 1780, '779': 1781, '780': 1782,
++  '782': 771, '783': 64726, '786': 8363, '788': 8532, '790': 768, '791': 769,
++  '792': 768, '795': 803, '797': 64336, '798': 64337, '799': 64342,
++  '800': 64343, '801': 64344, '802': 64345, '803': 64362, '804': 64363,
++  '805': 64364, '2424': 7821, '2425': 7822, '2426': 7823, '2427': 7824,
++  '2428': 7825, '2429': 7826, '2430': 7827, '2433': 7682, '2678': 8045,
++  '2679': 8046, '2830': 1552, '2838': 686, '2840': 751, '2842': 753,
++  '2843': 754, '2844': 755, '2846': 757, '2856': 767, '2857': 848, '2858': 849,
++  '2862': 853, '2863': 854, '2864': 855, '2865': 861, '2866': 862, '2906': 7460,
++  '2908': 7462, '2909': 7463, '2910': 7464, '2912': 7466, '2913': 7467,
++  '2914': 7468, '2916': 7470, '2917': 7471, '2918': 7472, '2920': 7474,
++  '2921': 7475, '2922': 7476, '2924': 7478, '2925': 7479, '2926': 7480,
++  '2928': 7482, '2929': 7483, '2930': 7484, '2932': 7486, '2933': 7487,
++  '2934': 7488, '2936': 7490, '2937': 7491, '2938': 7492, '2940': 7494,
++  '2941': 7495, '2942': 7496, '2944': 7498, '2946': 7500, '2948': 7502,
++  '2950': 7504, '2951': 7505, '2952': 7506, '2954': 7508, '2955': 7509,
++  '2956': 7510, '2958': 7512, '2959': 7513, '2960': 7514, '2962': 7516,
++  '2963': 7517, '2964': 7518, '2966': 7520, '2967': 7521, '2968': 7522,
++  '2970': 7524, '2971': 7525, '2972': 7526, '2974': 7528, '2975': 7529,
++  '2976': 7530, '2978': 1537, '2979': 1538, '2980': 1539, '2982': 1549,
++  '2983': 1551, '2984': 1552, '2986': 1554, '2987': 1555, '2988': 1556,
++  '2990': 1623, '2991': 1624, '2995': 1775, '2999': 1791, '3002': 64290,
++  '3003': 64291, '3004': 64292, '3006': 64294, '3007': 64295, '3008': 64296,
++  '3011': 1900, '3014': 8223, '3015': 8244, '3017': 7532, '3018': 7533,
++  '3019': 7534, '3075': 7590, '3076': 7591, '3079': 7594, '3080': 7595,
++  '3083': 7598, '3084': 7599, '3087': 7602, '3088': 7603, '3091': 7606,
++  '3092': 7607, '3095': 7610, '3096': 7611, '3099': 7614, '3100': 7615,
++  '3103': 7618, '3104': 7619, '3107': 8337, '3108': 8338, '3116': 1884,
++  '3119': 1885, '3120': 1885, '3123': 1886, '3124': 1886, '3127': 1887,
++  '3128': 1887, '3131': 1888, '3132': 1888, '3135': 1889, '3136': 1889,
++  '3139': 1890, '3140': 1890, '3143': 1891, '3144': 1891, '3147': 1892,
++  '3148': 1892, '3153': 580, '3154': 581, '3157': 584, '3158': 585, '3161': 588,
++  '3162': 589, '3165': 891, '3166': 892, '3169': 1274, '3170': 1275,
++  '3173': 1278, '3174': 1279, '3181': 7622, '3182': 7623, '3282': 11799,
++  '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) {
-     TODO('Unsupported 83pv character found');
++    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) {
-     TODO('Unsupported 90pv character found');
++    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
 +// 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 FontLoader = {
-   loadingContext: {
-     requests: [],
-     nextRequestId: 0
-   },
- 
-   isSyncFontLoadingSupported: (function detectSyncFontLoadingSupport() {
-     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)
-       return true;
-     // TODO other browsers
-     return false;
-   })(),
- 
-   bind: function fontLoaderBind(fonts, callback) {
-     assert(!isWorker, 'bind() shall be called from main thread');
- 
-     var rules = [], fontsToLoad = [];
-     for (var i = 0, ii = fonts.length; i < ii; i++) {
-       var font = fonts[i];
- 
-       // Add the font to the DOM only once or skip if the font
-       // is already loaded.
-       if (font.attached || font.loading === false) {
-         continue;
-       }
-       font.attached = true;
- 
-       var rule = font.bindDOM();
-       if (rule) {
-         rules.push(rule);
-         fontsToLoad.push(font);
-       }
-     }
- 
-     var request = FontLoader.queueLoadingCallback(callback);
-     if (rules.length > 0 && !this.isSyncFontLoadingSupported) {
-       FontLoader.prepareFontLoadEvent(rules, fontsToLoad, request);
-     } else {
-       request.complete();
-     }
-   },
- 
-   queueLoadingCallback: function FontLoader_queueLoadingCallback(callback) {
-     function LoadLoader_completeRequest() {
-       assert(!request.end, 'completeRequest() cannot be called twice');
-       request.end = Date.now();
- 
-       // sending all completed requests in order how they were queued
-       while (context.requests.length > 0 && context.requests[0].end) {
-         var otherRequest = context.requests.shift();
-         setTimeout(otherRequest.callback, 0);
-       }
-     }
- 
-     var context = FontLoader.loadingContext;
-     var requestId = 'pdfjs-font-loading-' + (context.nextRequestId++);
-     var request = {
-       id: requestId,
-       complete: LoadLoader_completeRequest,
-       callback: callback,
-       started: Date.now()
-     };
-     context.requests.push(request);
-     return request;
-   },
- 
-   // Set things up so that at least one pdfjsFontLoad event is
-   // dispatched when all the @font-face |rules| for |fonts| have been
-   // loaded in a subdocument.  It's expected that the load of |rules|
-   // has already started in this (outer) document, so that they should
-   // be ordered before the load in the subdocument.
-   prepareFontLoadEvent: function fontLoaderPrepareFontLoadEvent(rules,
-                                                                 fonts,
-                                                                 request) {
-       /** Hack begin */
-       // There's no event when a font has finished downloading so the
-       // following code is a dirty hack to 'guess' when a font is
-       // ready.  This code will be obsoleted by Mozilla bug 471915.
-       //
-       // The only reliable way to know if a font is loaded in Gecko
-       // (at the moment) is document.onload in a document with
-       // a @font-face rule defined in a "static" stylesheet.  We use a
-       // subdocument in an <iframe>, set up properly, to know when
-       // our @font-face rule was loaded.  However, the subdocument and
-       // outer document can't share CSS rules, so the inner document
-       // is only part of the puzzle.  The second piece is an invisible
-       // div created in order to force loading of the @font-face in
-       // the *outer* document.  (The font still needs to be loaded for
-       // its metrics, for reflow).  We create the div first for the
-       // outer document, then create the iframe.  Unless something
-       // goes really wonkily, we expect the @font-face for the outer
-       // document to be processed before the inner.  That's still
-       // fragile, but seems to work in practice.
-       //
-       // The postMessage() hackery was added to work around chrome bug
-       // 82402.
- 
-       var requestId = request.id;
-       // Validate the requestId parameter -- the value used to construct HTML.
-       if (!/^[\w\-]+$/.test(requestId)) {
-         error('Invalid request id: ' + requestId);
- 
-         // Normally the error-function throws. But if a malicious code
-         // intercepts the function call then the return is needed.
-         return;
-       }
- 
-       var names = [];
-       for (var i = 0, ii = fonts.length; i < ii; i++)
-         names.push(fonts[i].loadedName);
++    case 0xF8E8: // registersans
++    case 0xF6DA: // registerserif
++      return 0x00AE; // registered
 +
-       // Validate the names parameter -- the values can used to construct HTML.
-       if (!/^\w+$/.test(names.join(''))) {
-         error('Invalid font name(s): ' + names.join());
- 
-         // Normally the error-function throws. But if a malicious code
-         // intercepts the function call then the return is needed.
-         return;
-       }
- 
-       var div = document.createElement('div');
-       div.setAttribute('style',
-                        'visibility: hidden;' +
-                        'width: 10px; height: 10px;' +
-                        'position: absolute; top: 0px; left: 0px;');
-       var html = '';
-       for (var i = 0, ii = names.length; i < ii; ++i) {
-         html += '<span style="font-family:' + names[i] + '">Hi</span>';
-       }
-       div.innerHTML = html;
-       document.body.appendChild(div);
- 
-       window.addEventListener(
-         'message',
-         function fontLoaderMessage(e) {
-           if (e.data !== requestId)
-             return;
-           for (var i = 0, ii = fonts.length; i < ii; ++i) {
-             var font = fonts[i];
-             font.loading = false;
-           }
-           request.complete();
-           // cleanup
-           if (frame) {
-             document.body.removeChild(frame);
-           }
-           window.removeEventListener('message', fontLoaderMessage, false);
-         },
-         false);
- 
-       // XXX we should have a time-out here too, and maybe fire
-       // pdfjsFontLoadFailed?
-       var src = '<!DOCTYPE HTML><html><head><meta charset="utf-8">';
-       src += '<style type="text/css">';
-       for (var i = 0, ii = rules.length; i < ii; ++i) {
-         src += rules[i];
-       }
-       src += '</style>';
-       src += '<script type="application/javascript">';
-       src += '  window.onload = function fontLoaderOnload() {\n';
-       src += '    parent.postMessage("' + requestId + '", "*");\n';
-       // Chrome stuck on loading (see chrome issue 145227) - resetting url
-       src += '    window.location = "about:blank";\n';
-       src += '  }';
-       // Hack so the end script tag isn't counted if this is inline JS.
-       src += '</scr' + 'ipt></head><body>';
-       for (var i = 0, ii = names.length; i < ii; ++i) {
-         src += '<p style="font-family:\'' + names[i] + '\'">Hi</p>';
-       }
-       src += '</body></html>';
- 
-       var MAX_IFRAME_SRC_LENGTH = 1000000, IFRAME_TIMEOUT = 2000;
-       // Chrome fails for long src attributes (see issue 174023)
-       if (src.length > MAX_IFRAME_SRC_LENGTH) {
-         // ... waiting for some fixed period of time instead
-         window.setTimeout(function() {
-           window.postMessage(requestId, '*');
-         }, IFRAME_TIMEOUT);
-         return;
-       }
++    case 0xF8EA: // trademarksans
++    case 0xF6DB: // trademarkserif
++      return 0x2122; // trademark
 +
-       var frame = document.createElement('iframe');
-       frame.src = 'data:text/html,' + src;
-       frame.setAttribute('style',
-                          'visibility: hidden;' +
-                          'width: 10px; height: 10px;' +
-                          'position: absolute; top: 0px; left: 0px;');
-       document.body.appendChild(frame);
-       /** Hack end */
++    default:
++      return code;
 +  }
- };
++}
 +
 +var UnicodeRanges = [
 +  { 'begin': 0x0000, 'end': 0x007F }, // Basic Latin
 +  { 'begin': 0x0080, 'end': 0x00FF }, // Latin-1 Supplement
 +  { 'begin': 0x0100, 'end': 0x017F }, // Latin Extended-A
 +  { 'begin': 0x0180, 'end': 0x024F }, // Latin Extended-B
 +  { 'begin': 0x0250, 'end': 0x02AF }, // IPA Extensions
 +  { 'begin': 0x02B0, 'end': 0x02FF }, // Spacing Modifier Letters
 +  { 'begin': 0x0300, 'end': 0x036F }, // Combining Diacritical Marks
 +  { 'begin': 0x0370, 'end': 0x03FF }, // Greek and Coptic
 +  { 'begin': 0x2C80, 'end': 0x2CFF }, // Coptic
 +  { 'begin': 0x0400, 'end': 0x04FF }, // Cyrillic
 +  { 'begin': 0x0530, 'end': 0x058F }, // Armenian
 +  { 'begin': 0x0590, 'end': 0x05FF }, // Hebrew
 +  { 'begin': 0xA500, 'end': 0xA63F }, // Vai
 +  { 'begin': 0x0600, 'end': 0x06FF }, // Arabic
 +  { 'begin': 0x07C0, 'end': 0x07FF }, // NKo
 +  { 'begin': 0x0900, 'end': 0x097F }, // Devanagari
 +  { 'begin': 0x0980, 'end': 0x09FF }, // Bengali
 +  { 'begin': 0x0A00, 'end': 0x0A7F }, // Gurmukhi
 +  { 'begin': 0x0A80, 'end': 0x0AFF }, // Gujarati
 +  { 'begin': 0x0B00, 'end': 0x0B7F }, // Oriya
 +  { 'begin': 0x0B80, 'end': 0x0BFF }, // Tamil
 +  { 'begin': 0x0C00, 'end': 0x0C7F }, // Telugu
 +  { 'begin': 0x0C80, 'end': 0x0CFF }, // Kannada
 +  { 'begin': 0x0D00, 'end': 0x0D7F }, // Malayalam
 +  { 'begin': 0x0E00, 'end': 0x0E7F }, // Thai
 +  { 'begin': 0x0E80, 'end': 0x0EFF }, // Lao
 +  { 'begin': 0x10A0, 'end': 0x10FF }, // Georgian
 +  { 'begin': 0x1B00, 'end': 0x1B7F }, // Balinese
 +  { 'begin': 0x1100, 'end': 0x11FF }, // Hangul Jamo
 +  { 'begin': 0x1E00, 'end': 0x1EFF }, // Latin Extended Additional
 +  { 'begin': 0x1F00, 'end': 0x1FFF }, // Greek Extended
 +  { 'begin': 0x2000, 'end': 0x206F }, // General Punctuation
 +  { 'begin': 0x2070, 'end': 0x209F }, // Superscripts And Subscripts
 +  { 'begin': 0x20A0, 'end': 0x20CF }, // Currency Symbol
 +  { 'begin': 0x20D0, 'end': 0x20FF }, // Combining Diacritical Marks For Symbols
 +  { 'begin': 0x2100, 'end': 0x214F }, // Letterlike Symbols
 +  { 'begin': 0x2150, 'end': 0x218F }, // Number Forms
 +  { 'begin': 0x2190, 'end': 0x21FF }, // Arrows
 +  { 'begin': 0x2200, 'end': 0x22FF }, // Mathematical Operators
 +  { 'begin': 0x2300, 'end': 0x23FF }, // Miscellaneous Technical
 +  { 'begin': 0x2400, 'end': 0x243F }, // Control Pictures
 +  { 'begin': 0x2440, 'end': 0x245F }, // Optical Character Recognition
 +  { 'begin': 0x2460, 'end': 0x24FF }, // Enclosed Alphanumerics
 +  { 'begin': 0x2500, 'end': 0x257F }, // Box Drawing
 +  { 'begin': 0x2580, 'end': 0x259F }, // Block Elements
 +  { 'begin': 0x25A0, 'end': 0x25FF }, // Geometric Shapes
 +  { 'begin': 0x2600, 'end': 0x26FF }, // Miscellaneous Symbols
 +  { 'begin': 0x2700, 'end': 0x27BF }, // Dingbats
 +  { 'begin': 0x3000, 'end': 0x303F }, // CJK Symbols And Punctuation
 +  { 'begin': 0x3040, 'end': 0x309F }, // Hiragana
 +  { 'begin': 0x30A0, 'end': 0x30FF }, // Katakana
 +  { 'begin': 0x3100, 'end': 0x312F }, // Bopomofo
 +  { 'begin': 0x3130, 'end': 0x318F }, // Hangul Compatibility Jamo
 +  { 'begin': 0xA840, 'end': 0xA87F }, // Phags-pa
 +  { 'begin': 0x3200, 'end': 0x32FF }, // Enclosed CJK Letters And Months
 +  { 'begin': 0x3300, 'end': 0x33FF }, // CJK Compatibility
 +  { 'begin': 0xAC00, 'end': 0xD7AF }, // Hangul Syllables
 +  { 'begin': 0xD800, 'end': 0xDFFF }, // Non-Plane 0 *
 +  { 'begin': 0x10900, 'end': 0x1091F }, // Phoenicia
 +  { 'begin': 0x4E00, 'end': 0x9FFF }, // CJK Unified Ideographs
 +  { 'begin': 0xE000, 'end': 0xF8FF }, // Private Use Area (plane 0)
 +  { 'begin': 0x31C0, 'end': 0x31EF }, // CJK Strokes
 +  { 'begin': 0xFB00, 'end': 0xFB4F }, // Alphabetic Presentation Forms
 +  { 'begin': 0xFB50, 'end': 0xFDFF }, // Arabic Presentation Forms-A
 +  { 'begin': 0xFE20, 'end': 0xFE2F }, // Combining Half Marks
 +  { 'begin': 0xFE10, 'end': 0xFE1F }, // Vertical Forms
 +  { 'begin': 0xFE50, 'end': 0xFE6F }, // Small Form Variants
 +  { 'begin': 0xFE70, 'end': 0xFEFF }, // Arabic Presentation Forms-B
 +  { 'begin': 0xFF00, 'end': 0xFFEF }, // Halfwidth And Fullwidth Forms
 +  { 'begin': 0xFFF0, 'end': 0xFFFF }, // Specials
 +  { 'begin': 0x0F00, 'end': 0x0FFF }, // Tibetan
 +  { 'begin': 0x0700, 'end': 0x074F }, // Syriac
 +  { 'begin': 0x0780, 'end': 0x07BF }, // Thaana
 +  { 'begin': 0x0D80, 'end': 0x0DFF }, // Sinhala
 +  { 'begin': 0x1000, 'end': 0x109F }, // Myanmar
 +  { 'begin': 0x1200, 'end': 0x137F }, // Ethiopic
 +  { 'begin': 0x13A0, 'end': 0x13FF }, // Cherokee
 +  { 'begin': 0x1400, 'end': 0x167F }, // Unified Canadian Aboriginal Syllabics
 +  { 'begin': 0x1680, 'end': 0x169F }, // Ogham
 +  { 'begin': 0x16A0, 'end': 0x16FF }, // Runic
 +  { 'begin': 0x1780, 'end': 0x17FF }, // Khmer
 +  { 'begin': 0x1800, 'end': 0x18AF }, // Mongolian
 +  { 'begin': 0x2800, 'end': 0x28FF }, // Braille Patterns
 +  { 'begin': 0xA000, 'end': 0xA48F }, // Yi Syllables
 +  { 'begin': 0x1700, 'end': 0x171F }, // Tagalog
 +  { 'begin': 0x10300, 'end': 0x1032F }, // Old Italic
 +  { 'begin': 0x10330, 'end': 0x1034F }, // Gothic
 +  { 'begin': 0x10400, 'end': 0x1044F }, // Deseret
 +  { 'begin': 0x1D000, 'end': 0x1D0FF }, // Byzantine Musical Symbols
 +  { 'begin': 0x1D400, 'end': 0x1D7FF }, // Mathematical Alphanumeric Symbols
 +  { 'begin': 0xFF000, 'end': 0xFFFFD }, // Private Use (plane 15)
 +  { 'begin': 0xFE00, 'end': 0xFE0F }, // Variation Selectors
 +  { 'begin': 0xE0000, 'end': 0xE007F }, // Tags
 +  { 'begin': 0x1900, 'end': 0x194F }, // Limbu
 +  { 'begin': 0x1950, 'end': 0x197F }, // Tai Le
 +  { 'begin': 0x1980, 'end': 0x19DF }, // New Tai Lue
 +  { 'begin': 0x1A00, 'end': 0x1A1F }, // Buginese
 +  { 'begin': 0x2C00, 'end': 0x2C5F }, // Glagolitic
 +  { 'begin': 0x2D30, 'end': 0x2D7F }, // Tifinagh
 +  { 'begin': 0x4DC0, 'end': 0x4DFF }, // Yijing Hexagram Symbols
 +  { 'begin': 0xA800, 'end': 0xA82F }, // Syloti Nagri
 +  { 'begin': 0x10000, 'end': 0x1007F }, // Linear B Syllabary
 +  { 'begin': 0x10140, 'end': 0x1018F }, // Ancient Greek Numbers
 +  { 'begin': 0x10380, 'end': 0x1039F }, // Ugaritic
 +  { 'begin': 0x103A0, 'end': 0x103DF }, // Old Persian
 +  { 'begin': 0x10450, 'end': 0x1047F }, // Shavian
 +  { 'begin': 0x10480, 'end': 0x104AF }, // Osmanya
 +  { 'begin': 0x10800, 'end': 0x1083F }, // Cypriot Syllabary
 +  { 'begin': 0x10A00, 'end': 0x10A5F }, // Kharoshthi
 +  { 'begin': 0x1D300, 'end': 0x1D35F }, // Tai Xuan Jing Symbols
 +  { 'begin': 0x12000, 'end': 0x123FF }, // Cuneiform
 +  { 'begin': 0x1D360, 'end': 0x1D37F }, // Counting Rod Numerals
 +  { 'begin': 0x1B80, 'end': 0x1BBF }, // Sundanese
 +  { 'begin': 0x1C00, 'end': 0x1C4F }, // Lepcha
 +  { 'begin': 0x1C50, 'end': 0x1C7F }, // Ol Chiki
 +  { 'begin': 0xA880, 'end': 0xA8DF }, // Saurashtra
 +  { 'begin': 0xA900, 'end': 0xA92F }, // Kayah Li
 +  { 'begin': 0xA930, 'end': 0xA95F }, // Rejang
 +  { 'begin': 0xAA00, 'end': 0xAA5F }, // Cham
 +  { 'begin': 0x10190, 'end': 0x101CF }, // Ancient Symbols
 +  { 'begin': 0x101D0, 'end': 0x101FF }, // Phaistos Disc
 +  { 'begin': 0x102A0, 'end': 0x102DF }, // Carian
 +  { 'begin': 0x1F030, 'end': 0x1F09F }  // Domino Tiles
 +];
 +
 +var MacStandardGlyphOrdering = [
 +  '.notdef', '.null', 'nonmarkingreturn', 'space', 'exclam', 'quotedbl',
 +  'numbersign', 'dollar', 'percent', 'ampersand', 'quotesingle', 'parenleft',
 +  'parenright', 'asterisk', 'plus', 'comma', 'hyphen', 'period', 'slash',
 +  'zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight',
 +  'nine', 'colon', 'semicolon', 'less', 'equal', 'greater', 'question', 'at',
 +  'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
 +  'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'bracketleft',
 +  'backslash', 'bracketright', 'asciicircum', 'underscore', 'grave', 'a', 'b',
 +  'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
 +  'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright',
 +  'asciitilde', 'Adieresis', 'Aring', 'Ccedilla', 'Eacute', 'Ntilde',
 +  'Odieresis', 'Udieresis', 'aacute', 'agrave', 'acircumflex', 'adieresis',
 +  'atilde', 'aring', 'ccedilla', 'eacute', 'egrave', 'ecircumflex', 'edieresis',
 +  'iacute', 'igrave', 'icircumflex', 'idieresis', 'ntilde', 'oacute', 'ograve',
 +  'ocircumflex', 'odieresis', 'otilde', 'uacute', 'ugrave', 'ucircumflex',
 +  'udieresis', 'dagger', 'degree', 'cent', 'sterling', 'section', 'bullet',
 +  'paragraph', 'germandbls', 'registered', 'copyright', 'trademark', 'acute',
 +  'dieresis', 'notequal', 'AE', 'Oslash', 'infinity', 'plusminus', 'lessequal',
 +  'greaterequal', 'yen', 'mu', 'partialdiff', 'summation', 'product', 'pi',
 +  'integral', 'ordfeminine', 'ordmasculine', 'Omega', 'ae', 'oslash',
 +  'questiondown', 'exclamdown', 'logicalnot', 'radical', 'florin',
 +  'approxequal', 'Delta', 'guillemotleft', 'guillemotright', 'ellipsis',
 +  'nonbreakingspace', 'Agrave', 'Atilde', 'Otilde', 'OE', 'oe', 'endash',
 +  'emdash', 'quotedblleft', 'quotedblright', 'quoteleft', 'quoteright',
 +  'divide', 'lozenge', 'ydieresis', 'Ydieresis', 'fraction', 'currency',
 +  'guilsinglleft', 'guilsinglright', 'fi', 'fl', 'daggerdbl', 'periodcentered',
 +  'quotesinglbase', 'quotedblbase', 'perthousand', 'Acircumflex',
 +  'Ecircumflex', 'Aacute', 'Edieresis', 'Egrave', 'Iacute', 'Icircumflex',
 +  'Idieresis', 'Igrave', 'Oacute', 'Ocircumflex', 'apple', 'Ograve', 'Uacute',
 +  'Ucircumflex', 'Ugrave', 'dotlessi', 'circumflex', 'tilde', 'macron',
 +  'breve', 'dotaccent', 'ring', 'cedilla', 'hungarumlaut', 'ogonek', 'caron',
 +  'Lslash', 'lslash', 'Scaron', 'scaron', 'Zcaron', 'zcaron', 'brokenbar',
 +  'Eth', 'eth', 'Yacute', 'yacute', 'Thorn', 'thorn', 'minus', 'multiply',
 +  'onesuperior', 'twosuperior', 'threesuperior', 'onehalf', 'onequarter',
 +  'threequarters', 'franc', 'Gbreve', 'gbreve', 'Idotaccent', 'Scedilla',
 +  'scedilla', 'Cacute', 'cacute', 'Ccaron', 'ccaron', 'dcroat'];
 +
 +function getUnicodeRangeFor(value) {
 +  for (var i = 0, ii = UnicodeRanges.length; i < ii; i++) {
 +    var range = UnicodeRanges[i];
 +    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)
 +    return true;
 +  range = UnicodeRanges[11];
 +  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 <compat> entries.
 +var NormalizedUnicodes = {
 +  '\u00A8': '\u0020\u0308',
 +  '\u00AF': '\u0020\u0304',
 +  '\u00B4': '\u0020\u0301',
 +  '\u00B5': '\u03BC',
 +  '\u00B8': '\u0020\u0327',
 +  '\u0132': '\u0049\u004A',
 +  '\u0133': '\u0069\u006A',
 +  '\u013F': '\u004C\u00B7',
 +  '\u0140': '\u006C\u00B7',
 +  '\u0149': '\u02BC\u006E',
 +  '\u017F': '\u0073',
 +  '\u01C4': '\u0044\u017D',
 +  '\u01C5': '\u0044\u017E',
 +  '\u01C6': '\u0064\u017E',
 +  '\u01C7': '\u004C\u004A',
 +  '\u01C8': '\u004C\u006A',
 +  '\u01C9': '\u006C\u006A',
 +  '\u01CA': '\u004E\u004A',
 +  '\u01CB': '\u004E\u006A',
 +  '\u01CC': '\u006E\u006A',
 +  '\u01F1': '\u0044\u005A',
 +  '\u01F2': '\u0044\u007A',
 +  '\u01F3': '\u0064\u007A',
 +  '\u02D8': '\u0020\u0306',
 +  '\u02D9': '\u0020\u0307',
 +  '\u02DA': '\u0020\u030A',
 +  '\u02DB': '\u0020\u0328',
 +  '\u02DC': '\u0020\u0303',
 +  '\u02DD': '\u0020\u030B',
 +  '\u037A': '\u0020\u0345',
 +  '\u0384': '\u0020\u0301',
 +  '\u03D0': '\u03B2',
 +  '\u03D1': '\u03B8',
 +  '\u03D2': '\u03A5',
 +  '\u03D5': '\u03C6',
 +  '\u03D6': '\u03C0',
 +  '\u03F0': '\u03BA',
 +  '\u03F1': '\u03C1',
 +  '\u03F2': '\u03C2',
 +  '\u03F4': '\u0398',
 +  '\u03F5': '\u03B5',
 +  '\u03F9': '\u03A3',
 +  '\u0587': '\u0565\u0582',
 +  '\u0675': '\u0627\u0674',
 +  '\u0676': '\u0648\u0674',
 +  '\u0677': '\u06C7\u0674',
 +  '\u0678': '\u064A\u0674',
 +  '\u0E33': '\u0E4D\u0E32',
 +  '\u0EB3': '\u0ECD\u0EB2',
 +  '\u0EDC': '\u0EAB\u0E99',
 +  '\u0EDD': '\u0EAB\u0EA1',
 +  '\u0F77': '\u0FB2\u0F81',
 +  '\u0F79': '\u0FB3\u0F81',
 +  '\u1E9A': '\u0061\u02BE',
 +  '\u1FBD': '\u0020\u0313',
 +  '\u1FBF': '\u0020\u0313',
 +  '\u1FC0': '\u0020\u0342',
 +  '\u1FFE': '\u0020\u0314',
 +  '\u2002': '\u0020',
 +  '\u2003': '\u0020',
 +  '\u2004': '\u0020',
 +  '\u2005': '\u0020',
 +  '\u2006': '\u0020',
 +  '\u2008': '\u0020',
 +  '\u2009': '\u0020',
 +  '\u200A': '\u0020',
 +  '\u2017': '\u0020\u0333',
 +  '\u2024': '\u002E',
 +  '\u2025': '\u002E\u002E',
 +  '\u2026': '\u002E\u002E\u002E',
 +  '\u2033': '\u2032\u2032',
 +  '\u2034': '\u2032\u2032\u2032',
 +  '\u2036': '\u2035\u2035',
 +  '\u2037': '\u2035\u2035\u2035',
 +  '\u203C': '\u0021\u0021',
 +  '\u203E': '\u0020\u0305',
 +  '\u2047': '\u003F\u003F',
 +  '\u2048': '\u003F\u0021',
 +  '\u2049': '\u0021\u003F',
 +  '\u2057': '\u2032\u2032\u2032\u2032',
 +  '\u205F': '\u0020',
 +  '\u20A8': '\u0052\u0073',
 +  '\u2100': '\u0061\u002F\u0063',
 +  '\u2101': '\u0061\u002F\u0073',
 +  '\u2103': '\u00B0\u0043',
 +  '\u2105': '\u0063\u002F\u006F',
 +  '\u2106': '\u0063\u002F\u0075',
 +  '\u2107': '\u0190',
 +  '\u2109': '\u00B0\u0046',
 +  '\u2116': '\u004E\u006F',
 +  '\u2121': '\u0054\u0045\u004C',
 +  '\u2135': '\u05D0',
 +  '\u2136': '\u05D1',
 +  '\u2137': '\u05D2',
 +  '\u2138': '\u05D3',
 +  '\u213B': '\u0046\u0041\u0058',
 +  '\u2160': '\u0049',
 +  '\u2161': '\u0049\u0049',
 +  '\u2162': '\u0049\u0049\u0049',
 +  '\u2163': '\u0049\u0056',
 +  '\u2164': '\u0056',
 +  '\u2165': '\u0056\u0049',
 +  '\u2166': '\u0056\u0049\u0049',
 +  '\u2167': '\u0056\u0049\u0049\u0049',
 +  '\u2168': '\u0049\u0058',
 +  '\u2169': '\u0058',
 +  '\u216A': '\u0058\u0049',
 +  '\u216B': '\u0058\u0049\u0049',
 +  '\u216C': '\u004C',
 +  '\u216D': '\u0043',
 +  '\u216E': '\u0044',
 +  '\u216F': '\u004D',
 +  '\u2170': '\u0069',
 +  '\u2171': '\u0069\u0069',
 +  '\u2172': '\u0069\u0069\u0069',
 +  '\u2173': '\u0069\u0076',
 +  '\u2174': '\u0076',
 +  '\u2175': '\u0076\u0069',
 +  '\u2176': '\u0076\u0069\u0069',
 +  '\u2177': '\u0076\u0069\u0069\u0069',
 +  '\u2178': '\u0069\u0078',
 +  '\u2179': '\u0078',
 +  '\u217A': '\u0078\u0069',
 +  '\u217B': '\u0078\u0069\u0069',
 +  '\u217C': '\u006C',
 +  '\u217D': '\u0063',
 +  '\u217E': '\u0064',
 +  '\u217F': '\u006D',
 +  '\u222C': '\u222B\u222B',
 +  '\u222D': '\u222B\u222B\u222B',
 +  '\u222F': '\u222E\u222E',
 +  '\u2230': '\u222E\u222E\u222E',
 +  '\u2474': '\u0028\u0031\u0029',
 +  '\u2475': '\u0028\u0032\u0029',
 +  '\u2476': '\u0028\u0033\u0029',
 +  '\u2477': '\u0028\u0034\u0029',
 +  '\u2478': '\u0028\u0035\u0029',
 +  '\u2479': '\u0028\u0036\u0029',
 +  '\u247A': '\u0028\u0037\u0029',
 +  '\u247B': '\u0028\u0038\u0029',
 +  '\u247C': '\u0028\u0039\u0029',
 +  '\u247D': '\u0028\u0031\u0030\u0029',
 +  '\u247E': '\u0028\u0031\u0031\u0029',
 +  '\u247F': '\u0028\u0031\u0032\u0029',
 +  '\u2480': '\u0028\u0031\u0033\u0029',
 +  '\u2481': '\u0028\u0031\u0034\u0029',
 +  '\u2482': '\u0028\u0031\u0035\u0029',
 +  '\u2483': '\u0028\u0031\u0036\u0029',
 +  '\u2484': '\u0028\u0031\u0037\u0029',
 +  '\u2485': '\u0028\u0031\u0038\u0029',
 +  '\u2486': '\u0028\u0031\u0039\u0029',
 +  '\u2487': '\u0028\u0032\u0030\u0029',
 +  '\u2488': '\u0031\u002E',
 +  '\u2489': '\u0032\u002E',
 +  '\u248A': '\u0033\u002E',
 +  '\u248B': '\u0034\u002E',
 +  '\u248C': '\u0035\u002E',
 +  '\u248D': '\u0036\u002E',
 +  '\u248E': '\u0037\u002E',
 +  '\u248F': '\u0038\u002E',
 +  '\u2490': '\u0039\u002E',
 +  '\u2491': '\u0031\u0030\u002E',
 +  '\u2492': '\u0031\u0031\u002E',
 +  '\u2493': '\u0031\u0032\u002E',
 +  '\u2494': '\u0031\u0033\u002E',
 +  '\u2495': '\u0031\u0034\u002E',
 +  '\u2496': '\u0031\u0035\u002E',
 +  '\u2497': '\u0031\u0036\u002E',
 +  '\u2498': '\u0031\u0037\u002E',
 +  '\u2499': '\u0031\u0038\u002E',
 +  '\u249A': '\u0031\u0039\u002E',
 +  '\u249B': '\u0032\u0030\u002E',
 +  '\u249C': '\u0028\u0061\u0029',
 +  '\u249D': '\u0028\u0062\u0029',
 +  '\u249E': '\u0028\u0063\u0029',
 +  '\u249F': '\u0028\u0064\u0029',
 +  '\u24A0': '\u0028\u0065\u0029',
 +  '\u24A1': '\u0028\u0066\u0029',
 +  '\u24A2': '\u0028\u0067\u0029',
 +  '\u24A3': '\u0028\u0068\u0029',
 +  '\u24A4': '\u0028\u0069\u0029',
 +  '\u24A5': '\u0028\u006A\u0029',
 +  '\u24A6': '\u0028\u006B\u0029',
 +  '\u24A7': '\u0028\u006C\u0029',
 +  '\u24A8': '\u0028\u006D\u0029',
 +  '\u24A9': '\u0028\u006E\u0029',
 +  '\u24AA': '\u0028\u006F\u0029',
 +  '\u24AB': '\u0028\u0070\u0029',
 +  '\u24AC': '\u0028\u0071\u0029',
 +  '\u24AD': '\u0028\u0072\u0029',
 +  '\u24AE': '\u0028\u0073\u0029',
 +  '\u24AF': '\u0028\u0074\u0029',
 +  '\u24B0': '\u0028\u0075\u0029',
 +  '\u24B1': '\u0028\u0076\u0029',
 +  '\u24B2': '\u0028\u0077\u0029',
 +  '\u24B3': '\u0028\u0078\u0029',
 +  '\u24B4': '\u0028\u0079\u0029',
 +  '\u24B5': '\u0028\u007A\u0029',
 +  '\u2A0C': '\u222B\u222B\u222B\u222B',
 +  '\u2A74': '\u003A\u003A\u003D',
 +  '\u2A75': '\u003D\u003D',
 +  '\u2A76': '\u003D\u003D\u003D',
 +  '\u2E9F': '\u6BCD',
 +  '\u2EF3': '\u9F9F',
 +  '\u2F00': '\u4E00',
 +  '\u2F01': '\u4E28',
 +  '\u2F02': '\u4E36',
 +  '\u2F03': '\u4E3F',
 +  '\u2F04': '\u4E59',
 +  '\u2F05': '\u4E85',
 +  '\u2F06': '\u4E8C',
 +  '\u2F07': '\u4EA0',
 +  '\u2F08': '\u4EBA',
 +  '\u2F09': '\u513F',
 +  '\u2F0A': '\u5165',
 +  '\u2F0B': '\u516B',
 +  '\u2F0C': '\u5182',
 +  '\u2F0D': '\u5196',
 +  '\u2F0E': '\u51AB',
 +  '\u2F0F': '\u51E0',
 +  '\u2F10': '\u51F5',
 +  '\u2F11': '\u5200',
 +  '\u2F12': '\u529B',
 +  '\u2F13': '\u52F9',
 +  '\u2F14': '\u5315',
 +  '\u2F15': '\u531A',
 +  '\u2F16': '\u5338',
 +  '\u2F17': '\u5341',
 +  '\u2F18': '\u535C',
 +  '\u2F19': '\u5369',
 +  '\u2F1A': '\u5382',
 +  '\u2F1B': '\u53B6',
 +  '\u2F1C': '\u53C8',
 +  '\u2F1D': '\u53E3',
 +  '\u2F1E': '\u56D7',
 +  '\u2F1F': '\u571F',
 +  '\u2F20': '\u58EB',
 +  '\u2F21': '\u5902',
 +  '\u2F22': '\u590A',
 +  '\u2F23': '\u5915',
 +  '\u2F24': '\u5927',
 +  '\u2F25': '\u5973',
 +  '\u2F26': '\u5B50',
 +  '\u2F27': '\u5B80',
 +  '\u2F28': '\u5BF8',
 +  '\u2F29': '\u5C0F',
 +  '\u2F2A': '\u5C22',
 +  '\u2F2B': '\u5C38',
 +  '\u2F2C': '\u5C6E',
 +  '\u2F2D': '\u5C71',
 +  '\u2F2E': '\u5DDB',
 +  '\u2F2F': '\u5DE5',
 +  '\u2F30': '\u5DF1',
 +  '\u2F31': '\u5DFE',
 +  '\u2F32': '\u5E72',
 +  '\u2F33': '\u5E7A',
 +  '\u2F34': '\u5E7F',
 +  '\u2F35': '\u5EF4',
 +  '\u2F36': '\u5EFE',
 +  '\u2F37': '\u5F0B',
 +  '\u2F38': '\u5F13',
 +  '\u2F39': '\u5F50',
 +  '\u2F3A': '\u5F61',
 +  '\u2F3B': '\u5F73',
 +  '\u2F3C': '\u5FC3',
 +  '\u2F3D': '\u6208',
 +  '\u2F3E': '\u6236',
 +  '\u2F3F': '\u624B',
 +  '\u2F40': '\u652F',
 +  '\u2F41': '\u6534',
 +  '\u2F42': '\u6587',
 +  '\u2F43': '\u6597',
 +  '\u2F44': '\u65A4',
 +  '\u2F45': '\u65B9',
 +  '\u2F46': '\u65E0',
 +  '\u2F47': '\u65E5',
 +  '\u2F48': '\u66F0',
 +  '\u2F49': '\u6708',
 +  '\u2F4A': '\u6728',
 +  '\u2F4B': '\u6B20',
 +  '\u2F4C': '\u6B62',
 +  '\u2F4D': '\u6B79',
 +  '\u2F4E': '\u6BB3',
 +  '\u2F4F': '\u6BCB',
 +  '\u2F50': '\u6BD4',
 +  '\u2F51': '\u6BDB',
 +  '\u2F52': '\u6C0F',
 +  '\u2F53': '\u6C14',
 +  '\u2F54': '\u6C34',
 +  '\u2F55': '\u706B',
 +  '\u2F56': '\u722A',
 +  '\u2F57': '\u7236',
 +  '\u2F58': '\u723B',
 +  '\u2F59': '\u723F',
 +  '\u2F5A': '\u7247',
 +  '\u2F5B': '\u7259',
 +  '\u2F5C': '\u725B',
 +  '\u2F5D': '\u72AC',
 +  '\u2F5E': '\u7384',
 +  '\u2F5F': '\u7389',
 +  '\u2F60': '\u74DC',
 +  '\u2F61': '\u74E6',
 +  '\u2F62': '\u7518',
 +  '\u2F63': '\u751F',
 +  '\u2F64': '\u7528',
 +  '\u2F65': '\u7530',
 +  '\u2F66': '\u758B',
 +  '\u2F67': '\u7592',
 +  '\u2F68': '\u7676',
 +  '\u2F69': '\u767D',
 +  '\u2F6A': '\u76AE',
 +  '\u2F6B': '\u76BF',
 +  '\u2F6C': '\u76EE',
 +  '\u2F6D': '\u77DB',
 +  '\u2F6E': '\u77E2',
 +  '\u2F6F': '\u77F3',
 +  '\u2F70': '\u793A',
 +  '\u2F71': '\u79B8',
 +  '\u2F72': '\u79BE',
 +  '\u2F73': '\u7A74',
 +  '\u2F74': '\u7ACB',
 +  '\u2F75': '\u7AF9',
 +  '\u2F76': '\u7C73',
 +  '\u2F77': '\u7CF8',
 +  '\u2F78': '\u7F36',
 +  '\u2F79': '\u7F51',
 +  '\u2F7A': '\u7F8A',
 +  '\u2F7B': '\u7FBD',
 +  '\u2F7C': '\u8001',
 +  '\u2F7D': '\u800C',
 +  '\u2F7E': '\u8012',
 +  '\u2F7F': '\u8033',
 +  '\u2F80': '\u807F',
 +  '\u2F81': '\u8089',
 +  '\u2F82': '\u81E3',
 +  '\u2F83': '\u81EA',
 +  '\u2F84': '\u81F3',
 +  '\u2F85': '\u81FC',
 +  '\u2F86': '\u820C',
 +  '\u2F87': '\u821B',
 +  '\u2F88': '\u821F',
 +  '\u2F89': '\u826E',
 +  '\u2F8A': '\u8272',
 +  '\u2F8B': '\u8278',
 +  '\u2F8C': '\u864D',
 +  '\u2F8D': '\u866B',
 +  '\u2F8E': '\u8840',
 +  '\u2F8F': '\u884C',
 +  '\u2F90': '\u8863',
 +  '\u2F91': '\u897E',
 +  '\u2F92': '\u898B',
 +  '\u2F93': '\u89D2',
 +  '\u2F94': '\u8A00',
 +  '\u2F95': '\u8C37',
 +  '\u2F96': '\u8C46',
 +  '\u2F97': '\u8C55',
 +  '\u2F98': '\u8C78',
 +  '\u2F99': '\u8C9D',
 +  '\u2F9A': '\u8D64',
 +  '\u2F9B': '\u8D70',
 +  '\u2F9C': '\u8DB3',
 +  '\u2F9D': '\u8EAB',
 +  '\u2F9E': '\u8ECA',
 +  '\u2F9F': '\u8F9B',
 +  '\u2FA0': '\u8FB0',
 +  '\u2FA1': '\u8FB5',
 +  '\u2FA2': '\u9091',
 +  '\u2FA3': '\u9149',
 +  '\u2FA4': '\u91C6',
 +  '\u2FA5': '\u91CC',
 +  '\u2FA6': '\u91D1',
 +  '\u2FA7': '\u9577',
 +  '\u2FA8': '\u9580',
 +  '\u2FA9': '\u961C',
 +  '\u2FAA': '\u96B6',
 +  '\u2FAB': '\u96B9',
 +  '\u2FAC': '\u96E8',
 +  '\u2FAD': '\u9751',
 +  '\u2FAE': '\u975E',
 +  '\u2FAF': '\u9762',
 +  '\u2FB0': '\u9769',
 +  '\u2FB1': '\u97CB',
 +  '\u2FB2': '\u97ED',
 +  '\u2FB3': '\u97F3',
 +  '\u2FB4': '\u9801',
 +  '\u2FB5': '\u98A8',
 +  '\u2FB6': '\u98DB',
 +  '\u2FB7': '\u98DF',
 +  '\u2FB8': '\u9996',
 +  '\u2FB9': '\u9999',
 +  '\u2FBA': '\u99AC',
 +  '\u2FBB': '\u9AA8',
 +  '\u2FBC': '\u9AD8',
 +  '\u2FBD': '\u9ADF',
 +  '\u2FBE': '\u9B25',
 +  '\u2FBF': '\u9B2F',
 +  '\u2FC0': '\u9B32',
 +  '\u2FC1': '\u9B3C',
 +  '\u2FC2': '\u9B5A',
 +  '\u2FC3': '\u9CE5',
 +  '\u2FC4': '\u9E75',
 +  '\u2FC5': '\u9E7F',
 +  '\u2FC6': '\u9EA5',
 +  '\u2FC7': '\u9EBB',
 +  '\u2FC8': '\u9EC3',
 +  '\u2FC9': '\u9ECD',
 +  '\u2FCA': '\u9ED1',
 +  '\u2FCB': '\u9EF9',
 +  '\u2FCC': '\u9EFD',
 +  '\u2FCD': '\u9F0E',
 +  '\u2FCE': '\u9F13',
 +  '\u2FCF': '\u9F20',
 +  '\u2FD0': '\u9F3B',
 +  '\u2FD1': '\u9F4A',
 +  '\u2FD2': '\u9F52',
 +  '\u2FD3': '\u9F8D',
 +  '\u2FD4': '\u9F9C',
 +  '\u2FD5': '\u9FA0',
 +  '\u3036': '\u3012',
 +  '\u3038': '\u5341',
 +  '\u3039': '\u5344',
 +  '\u303A': '\u5345',
 +  '\u309B': '\u0020\u3099',
 +  '\u309C': '\u0020\u309A',
 +  '\u3131': '\u1100',
 +  '\u3132': '\u1101',
 +  '\u3133': '\u11AA',
 +  '\u3134': '\u1102',
 +  '\u3135': '\u11AC',
 +  '\u3136': '\u11AD',
 +  '\u3137': '\u1103',
 +  '\u3138': '\u1104',
 +  '\u3139': '\u1105',
 +  '\u313A': '\u11B0',
 +  '\u313B': '\u11B1',
 +  '\u313C': '\u11B2',
 +  '\u313D': '\u11B3',
 +  '\u313E': '\u11B4',
 +  '\u313F': '\u11B5',
 +  '\u3140': '\u111A',
 +  '\u3141': '\u1106',
 +  '\u3142': '\u1107',
 +  '\u3143': '\u1108',
 +  '\u3144': '\u1121',
 +  '\u3145': '\u1109',
 +  '\u3146': '\u110A',
 +  '\u3147': '\u110B',
 +  '\u3148': '\u110C',
 +  '\u3149': '\u110D',
 +  '\u314A': '\u110E',
 +  '\u314B': '\u110F',
 +  '\u314C': '\u1110',
 +  '\u314D': '\u1111',
 +  '\u314E': '\u1112',
 +  '\u314F': '\u1161',
 +  '\u3150': '\u1162',
 +  '\u3151': '\u1163',
 +  '\u3152': '\u1164',
 +  '\u3153': '\u1165',
 +  '\u3154': '\u1166',
 +  '\u3155': '\u1167',
 +  '\u3156': '\u1168',
 +  '\u3157': '\u1169',
 +  '\u3158': '\u116A',
 +  '\u3159': '\u116B',
 +  '\u315A': '\u116C',
 +  '\u315B': '\u116D',
 +  '\u315C': '\u116E',
 +  '\u315D': '\u116F',
 +  '\u315E': '\u1170',
 +  '\u315F': '\u1171',
 +  '\u3160': '\u1172',
 +  '\u3161': '\u1173',
 +  '\u3162': '\u1174',
 +  '\u3163': '\u1175',
 +  '\u3164': '\u1160',
 +  '\u3165': '\u1114',
 +  '\u3166': '\u1115',
 +  '\u3167': '\u11C7',
 +  '\u3168': '\u11C8',
 +  '\u3169': '\u11CC',
 +  '\u316A': '\u11CE',
 +  '\u316B': '\u11D3',
 +  '\u316C': '\u11D7',
 +  '\u316D': '\u11D9',
 +  '\u316E': '\u111C',
 +  '\u316F': '\u11DD',
 +  '\u3170': '\u11DF',
 +  '\u3171': '\u111D',
 +  '\u3172': '\u111E',
 +  '\u3173': '\u1120',
 +  '\u3174': '\u1122',
 +  '\u3175': '\u1123',
 +  '\u3176': '\u1127',
 +  '\u3177': '\u1129',
 +  '\u3178': '\u112B',
 +  '\u3179': '\u112C',
 +  '\u317A': '\u112D',
 +  '\u317B': '\u112E',
 +  '\u317C': '\u112F',
 +  '\u317D': '\u1132',
 +  '\u317E': '\u1136',
 +  '\u317F': '\u1140',
 +  '\u3180': '\u1147',
 +  '\u3181': '\u114C',
 +  '\u3182': '\u11F1',
 +  '\u3183': '\u11F2',
 +  '\u3184': '\u1157',
 +  '\u3185': '\u1158',
 +  '\u3186': '\u1159',
 +  '\u3187': '\u1184',
 +  '\u3188': '\u1185',
 +  '\u3189': '\u1188',
 +  '\u318A': '\u1191',
 +  '\u318B': '\u1192',
 +  '\u318C': '\u1194',
 +  '\u318D': '\u119E',
 +  '\u318E': '\u11A1',
 +  '\u3200': '\u0028\u1100\u0029',
 +  '\u3201': '\u0028\u1102\u0029',
 +  '\u3202': '\u0028\u1103\u0029',
 +  '\u3203': '\u0028\u1105\u0029',
 +  '\u3204': '\u0028\u1106\u0029',
 +  '\u3205': '\u0028\u1107\u0029',
 +  '\u3206': '\u0028\u1109\u0029',
 +  '\u3207': '\u0028\u110B\u0029',
 +  '\u3208': '\u0028\u110C\u0029',
 +  '\u3209': '\u0028\u110E\u0029',
 +  '\u320A': '\u0028\u110F\u0029',
 +  '\u320B': '\u0028\u1110\u0029',
 +  '\u320C': '\u0028\u1111\u0029',
 +  '\u320D': '\u0028\u1112\u0029',
 +  '\u320E': '\u0028\u1100\u1161\u0029',
 +  '\u320F': '\u0028\u1102\u1161\u0029',
 +  '\u3210': '\u0028\u1103\u1161\u0029',
 +  '\u3211': '\u0028\u1105\u1161\u0029',
 +  '\u3212': '\u0028\u1106\u1161\u0029',
 +  '\u3213': '\u0028\u1107\u1161\u0029',
 +  '\u3214': '\u0028\u1109\u1161\u0029',
 +  '\u3215': '\u0028\u110B\u1161\u0029',
 +  '\u3216': '\u0028\u110C\u1161\u0029',
 +  '\u3217': '\u0028\u110E\u1161\u0029',
 +  '\u3218': '\u0028\u110F\u1161\u0029',
 +  '\u3219': '\u0028\u1110\u1161\u0029',
 +  '\u321A': '\u0028\u1111\u1161\u0029',
 +  '\u321B': '\u0028\u1112\u1161\u0029',
 +  '\u321C': '\u0028\u110C\u116E\u0029',
 +  '\u321D': '\u0028\u110B\u1169\u110C\u1165\u11AB\u0029',
 +  '\u321E': '\u0028\u110B\u1169\u1112\u116E\u0029',
 +  '\u3220': '\u0028\u4E00\u0029',
 +  '\u3221': '\u0028\u4E8C\u0029',
 +  '\u3222': '\u0028\u4E09\u0029',
 +  '\u3223': '\u0028\u56DB\u0029',
 +  '\u3224': '\u0028\u4E94\u0029',
 +  '\u3225': '\u0028\u516D\u0029',
 +  '\u3226': '\u0028\u4E03\u0029',
 +  '\u3227': '\u0028\u516B\u0029',
 +  '\u3228': '\u0028\u4E5D\u0029',
 +  '\u3229': '\u0028\u5341\u0029',
 +  '\u322A': '\u0028\u6708\u0029',
 +  '\u322B': '\u0028\u706B\u0029',
 +  '\u322C': '\u0028\u6C34\u0029',
 +  '\u322D': '\u0028\u6728\u0029',
 +  '\u322E': '\u0028\u91D1\u0029',
 +  '\u322F': '\u0028\u571F\u0029',
 +  '\u3230': '\u0028\u65E5\u0029',
 +  '\u3231': '\u0028\u682A\u0029',
 +  '\u3232': '\u0028\u6709\u0029',
 +  '\u3233': '\u0028\u793E\u0029',
 +  '\u3234': '\u0028\u540D\u0029',
 +  '\u3235': '\u0028\u7279\u0029',
 +  '\u3236': '\u0028\u8CA1\u0029',
 +  '\u3237': '\u0028\u795D\u0029',
 +  '\u3238': '\u0028\u52B4\u0029',
 +  '\u3239': '\u0028\u4EE3\u0029',
 +  '\u323A': '\u0028\u547C\u0029',
 +  '\u323B': '\u0028\u5B66\u0029',
 +  '\u323C': '\u0028\u76E3\u0029',
 +  '\u323D': '\u0028\u4F01\u0029',
 +  '\u323E': '\u0028\u8CC7\u0029',
 +  '\u323F': '\u0028\u5354\u0029',
 +  '\u3240': '\u0028\u796D\u0029',
 +  '\u3241': '\u0028\u4F11\u0029',
 +  '\u3242': '\u0028\u81EA\u0029',
 +  '\u3243': '\u0028\u81F3\u0029',
 +  '\u32C0': '\u0031\u6708',
 +  '\u32C1': '\u0032\u6708',
 +  '\u32C2': '\u0033\u6708',
 +  '\u32C3': '\u0034\u6708',
 +  '\u32C4': '\u0035\u6708',
 +  '\u32C5': '\u0036\u6708',
 +  '\u32C6': '\u0037\u6708',
 +  '\u32C7': '\u0038\u6708',
 +  '\u32C8': '\u0039\u6708',
 +  '\u32C9': '\u0031\u0030\u6708',
 +  '\u32CA': '\u0031\u0031\u6708',
 +  '\u32CB': '\u0031\u0032\u6708',
 +  '\u3358': '\u0030\u70B9',
 +  '\u3359': '\u0031\u70B9',
 +  '\u335A': '\u0032\u70B9',
 +  '\u335B': '\u0033\u70B9',
 +  '\u335C': '\u0034\u70B9',
 +  '\u335D': '\u0035\u70B9',
 +  '\u335E': '\u0036\u70B9',
 +  '\u335F': '\u0037\u70B9',
 +  '\u3360': '\u0038\u70B9',
 +  '\u3361': '\u0039\u70B9',
 +  '\u3362': '\u0031\u0030\u70B9',
 +  '\u3363': '\u0031\u0031\u70B9',
 +  '\u3364': '\u0031\u0032\u70B9',
 +  '\u3365': '\u0031\u0033\u70B9',
 +  '\u3366': '\u0031\u0034\u70B9',
 +  '\u3367': '\u0031\u0035\u70B9',
 +  '\u3368': '\u0031\u0036\u70B9',
 +  '\u3369': '\u0031\u0037\u70B9',
 +  '\u336A': '\u0031\u0038\u70B9',
 +  '\u336B': '\u0031\u0039\u70B9',
 +  '\u336C': '\u0032\u0030\u70B9',
 +  '\u336D': '\u0032\u0031\u70B9',
 +  '\u336E': '\u0032\u0032\u70B9',
 +  '\u336F': '\u0032\u0033\u70B9',
 +  '\u3370': '\u0032\u0034\u70B9',
 +  '\u33E0': '\u0031\u65E5',
 +  '\u33E1': '\u0032\u65E5',
 +  '\u33E2': '\u0033\u65E5',
 +  '\u33E3': '\u0034\u65E5',
 +  '\u33E4': '\u0035\u65E5',
 +  '\u33E5': '\u0036\u65E5',
 +  '\u33E6': '\u0037\u65E5',
 +  '\u33E7': '\u0038\u65E5',
 +  '\u33E8': '\u0039\u65E5',
 +  '\u33E9': '\u0031\u0030\u65E5',
 +  '\u33EA': '\u0031\u0031\u65E5',
 +  '\u33EB': '\u0031\u0032\u65E5',
 +  '\u33EC': '\u0031\u0033\u65E5',
 +  '\u33ED': '\u0031\u0034\u65E5',
 +  '\u33EE': '\u0031\u0035\u65E5',
 +  '\u33EF': '\u0031\u0036\u65E5',
 +  '\u33F0': '\u0031\u0037\u65E5',
 +  '\u33F1': '\u0031\u0038\u65E5',
 +  '\u33F2': '\u0031\u0039\u65E5',
 +  '\u33F3': '\u0032\u0030\u65E5',
 +  '\u33F4': '\u0032\u0031\u65E5',
 +  '\u33F5': '\u0032\u0032\u65E5',
 +  '\u33F6': '\u0032\u0033\u65E5',
 +  '\u33F7': '\u0032\u0034\u65E5',
 +  '\u33F8': '\u0032\u0035\u65E5',
 +  '\u33F9': '\u0032\u0036\u65E5',
 +  '\u33FA': '\u0032\u0037\u65E5',
 +  '\u33FB': '\u0032\u0038\u65E5',
 +  '\u33FC': '\u0032\u0039\u65E5',
 +  '\u33FD': '\u0033\u0030\u65E5',
 +  '\u33FE': '\u0033\u0031\u65E5',
 +  '\uFB00': '\u0066\u0066',
 +  '\uFB01': '\u0066\u0069',
 +  '\uFB02': '\u0066\u006C',
 +  '\uFB03': '\u0066\u0066\u0069',
 +  '\uFB04': '\u0066\u0066\u006C',
 +  '\uFB05': '\u017F\u0074',
 +  '\uFB06': '\u0073\u0074',
 +  '\uFB13': '\u0574\u0576',
 +  '\uFB14': '\u0574\u0565',
 +  '\uFB15': '\u0574\u056B',
 +  '\uFB16': '\u057E\u0576',
 +  '\uFB17': '\u0574\u056D',
 +  '\uFB4F': '\u05D0\u05DC',
 +  '\uFB50': '\u0671',
 +  '\uFB51': '\u0671',
 +  '\uFB52': '\u067B',
 +  '\uFB53': '\u067B',
 +  '\uFB54': '\u067B',
 +  '\uFB55': '\u067B',
 +  '\uFB56': '\u067E',
 +  '\uFB57': '\u067E',
 +  '\uFB58': '\u067E',
 +  '\uFB59': '\u067E',
 +  '\uFB5A': '\u0680',
 +  '\uFB5B': '\u0680',
 +  '\uFB5C': '\u0680',
 +  '\uFB5D': '\u0680',
 +  '\uFB5E': '\u067A',
 +  '\uFB5F': '\u067A',
 +  '\uFB60': '\u067A',
 +  '\uFB61': '\u067A',
 +  '\uFB62': '\u067F',
 +  '\uFB63': '\u067F',
 +  '\uFB64': '\u067F',
 +  '\uFB65': '\u067F',
 +  '\uFB66': '\u0679',
 +  '\uFB67': '\u0679',
 +  '\uFB68': '\u0679',
 +  '\uFB69': '\u0679',
 +  '\uFB6A': '\u06A4',
 +  '\uFB6B': '\u06A4',
 +  '\uFB6C': '\u06A4',
 +  '\uFB6D': '\u06A4',
 +  '\uFB6E': '\u06A6',
 +  '\uFB6F': '\u06A6',
 +  '\uFB70': '\u06A6',
 +  '\uFB71': '\u06A6',
 +  '\uFB72': '\u0684',
 +  '\uFB73': '\u0684',
 +  '\uFB74': '\u0684',
 +  '\uFB75': '\u0684',
 +  '\uFB76': '\u0683',
 +  '\uFB77': '\u0683',
 +  '\uFB78': '\u0683',
 +  '\uFB79': '\u0683',
 +  '\uFB7A': '\u0686',
 +  '\uFB7B': '\u0686',
 +  '\uFB7C': '\u0686',
 +  '\uFB7D': '\u0686',
 +  '\uFB7E': '\u0687',
 +  '\uFB7F': '\u0687',
 +  '\uFB80': '\u0687',
 +  '\uFB81': '\u0687',
 +  '\uFB82': '\u068D',
 +  '\uFB83': '\u068D',
 +  '\uFB84': '\u068C',
 +  '\uFB85': '\u068C',
 +  '\uFB86': '\u068E',
 +  '\uFB87': '\u068E',
 +  '\uFB88': '\u0688',
 +  '\uFB89': '\u0688',
 +  '\uFB8A': '\u0698',
 +  '\uFB8B': '\u0698',
 +  '\uFB8C': '\u0691',
 +  '\uFB8D': '\u0691',
 +  '\uFB8E': '\u06A9',
 +  '\uFB8F': '\u06A9',
 +  '\uFB90': '\u06A9',
 +  '\uFB91': '\u06A9',
 +  '\uFB92': '\u06AF',
 +  '\uFB93': '\u06AF',
 +  '\uFB94': '\u06AF',
 +  '\uFB95': '\u06AF',
 +  '\uFB96': '\u06B3',
 +  '\uFB97': '\u06B3',
 +  '\uFB98': '\u06B3',
 +  '\uFB99': '\u06B3',
 +  '\uFB9A': '\u06B1',
 +  '\uFB9B': '\u06B1',
 +  '\uFB9C': '\u06B1',
 +  '\uFB9D': '\u06B1',
 +  '\uFB9E': '\u06BA',
 +  '\uFB9F': '\u06BA',
 +  '\uFBA0': '\u06BB',
 +  '\uFBA1': '\u06BB',
 +  '\uFBA2': '\u06BB',
 +  '\uFBA3': '\u06BB',
 +  '\uFBA4': '\u06C0',
 +  '\uFBA5': '\u06C0',
 +  '\uFBA6': '\u06C1',
 +  '\uFBA7': '\u06C1',
 +  '\uFBA8': '\u06C1',
 +  '\uFBA9': '\u06C1',
 +  '\uFBAA': '\u06BE',
 +  '\uFBAB': '\u06BE',
 +  '\uFBAC': '\u06BE',
 +  '\uFBAD': '\u06BE',
 +  '\uFBAE': '\u06D2',
 +  '\uFBAF': '\u06D2',
 +  '\uFBB0': '\u06D3',
 +  '\uFBB1': '\u06D3',
 +  '\uFBD3': '\u06AD',
 +  '\uFBD4': '\u06AD',
 +  '\uFBD5': '\u06AD',
 +  '\uFBD6': '\u06AD',
 +  '\uFBD7': '\u06C7',
 +  '\uFBD8': '\u06C7',
 +  '\uFBD9': '\u06C6',
 +  '\uFBDA': '\u06C6',
 +  '\uFBDB': '\u06C8',
 +  '\uFBDC': '\u06C8',
 +  '\uFBDD': '\u0677',
 +  '\uFBDE': '\u06CB',
 +  '\uFBDF': '\u06CB',
 +  '\uFBE0': '\u06C5',
 +  '\uFBE1': '\u06C5',
 +  '\uFBE2': '\u06C9',
 +  '\uFBE3': '\u06C9',
 +  '\uFBE4': '\u06D0',
 +  '\uFBE5': '\u06D0',
 +  '\uFBE6': '\u06D0',
 +  '\uFBE7': '\u06D0',
 +  '\uFBE8': '\u0649',
 +  '\uFBE9': '\u0649',
 +  '\uFBEA': '\u0626\u0627',
 +  '\uFBEB': '\u0626\u0627',
 +  '\uFBEC': '\u0626\u06D5',
 +  '\uFBED': '\u0626\u06D5',
 +  '\uFBEE': '\u0626\u0648',
 +  '\uFBEF': '\u0626\u0648',
 +  '\uFBF0': '\u0626\u06C7',
 +  '\uFBF1': '\u0626\u06C7',
 +  '\uFBF2': '\u0626\u06C6',
 +  '\uFBF3': '\u0626\u06C6',
 +  '\uFBF4': '\u0626\u06C8',
 +  '\uFBF5': '\u0626\u06C8',
 +  '\uFBF6': '\u0626\u06D0',
 +  '\uFBF7': '\u0626\u06D0',
 +  '\uFBF8': '\u0626\u06D0',
 +  '\uFBF9': '\u0626\u0649',
 +  '\uFBFA': '\u0626\u0649',
 +  '\uFBFB': '\u0626\u0649',
 +  '\uFBFC': '\u06CC',
 +  '\uFBFD': '\u06CC',
 +  '\uFBFE': '\u06CC',
 +  '\uFBFF': '\u06CC',
 +  '\uFC00': '\u0626\u062C',
 +  '\uFC01': '\u0626\u062D',
 +  '\uFC02': '\u0626\u0645',
 +  '\uFC03': '\u0626\u0649',
 +  '\uFC04': '\u0626\u064A',
 +  '\uFC05': '\u0628\u062C',
 +  '\uFC06': '\u0628\u062D',
 +  '\uFC07': '\u0628\u062E',
 +  '\uFC08': '\u0628\u0645',
 +  '\uFC09': '\u0628\u0649',
 +  '\uFC0A': '\u0628\u064A',
 +  '\uFC0B': '\u062A\u062C',
 +  '\uFC0C': '\u062A\u062D',
 +  '\uFC0D': '\u062A\u062E',
 +  '\uFC0E': '\u062A\u0645',
 +  '\uFC0F': '\u062A\u0649',
 +  '\uFC10': '\u062A\u064A',
 +  '\uFC11': '\u062B\u062C',
 +  '\uFC12': '\u062B\u0645',
 +  '\uFC13': '\u062B\u0649',
 +  '\uFC14': '\u062B\u064A',
 +  '\uFC15': '\u062C\u062D',
 +  '\uFC16': '\u062C\u0645',
 +  '\uFC17': '\u062D\u062C',
 +  '\uFC18': '\u062D\u0645',
 +  '\uFC19': '\u062E\u062C',
 +  '\uFC1A': '\u062E\u062D',
 +  '\uFC1B': '\u062E\u0645',
 +  '\uFC1C': '\u0633\u062C',
 +  '\uFC1D': '\u0633\u062D',
 +  '\uFC1E': '\u0633\u062E',
 +  '\uFC1F': '\u0633\u0645',
 +  '\uFC20': '\u0635\u062D',
 +  '\uFC21': '\u0635\u0645',
 +  '\uFC22': '\u0636\u062C',
 +  '\uFC23': '\u0636\u062D',
 +  '\uFC24': '\u0636\u062E',
 +  '\uFC25': '\u0636\u0645',
 +  '\uFC26': '\u0637\u062D',
 +  '\uFC27': '\u0637\u0645',
 +  '\uFC28': '\u0638\u0645',
 +  '\uFC29': '\u0639\u062C',
 +  '\uFC2A': '\u0639\u0645',
 +  '\uFC2B': '\u063A\u062C',
 +  '\uFC2C': '\u063A\u0645',
 +  '\uFC2D': '\u0641\u062C',
 +  '\uFC2E': '\u0641\u062D',
 +  '\uFC2F': '\u0641\u062E',
 +  '\uFC30': '\u0641\u0645',
 +  '\uFC31': '\u0641\u0649',
 +  '\uFC32': '\u0641\u064A',
 +  '\uFC33': '\u0642\u062D',
 +  '\uFC34': '\u0642\u0645',
 +  '\uFC35': '\u0642\u0649',
 +  '\uFC36': '\u0642\u064A',
 +  '\uFC37': '\u0643\u0627',
 +  '\uFC38': '\u0643\u062C',
 +  '\uFC39': '\u0643\u062D',
 +  '\uFC3A': '\u0643\u062E',
 +  '\uFC3B': '\u0643\u0644',
 +  '\uFC3C': '\u0643\u0645',
 +  '\uFC3D': '\u0643\u0649',
 +  '\uFC3E': '\u0643\u064A',
 +  '\uFC3F': '\u0644\u062C',
 +  '\uFC40': '\u0644\u062D',
 +  '\uFC41': '\u0644\u062E',
 +  '\uFC42': '\u0644\u0645',
 +  '\uFC43': '\u0644\u0649',
 +  '\uFC44': '\u0644\u064A',
 +  '\uFC45': '\u0645\u062C',
 +  '\uFC46': '\u0645\u062D',
 +  '\uFC47': '\u0645\u062E',
 +  '\uFC48': '\u0645\u0645',
 +  '\uFC49': '\u0645\u0649',
 +  '\uFC4A': '\u0645\u064A',
 +  '\uFC4B': '\u0646\u062C',
 +  '\uFC4C': '\u0646\u062D',
 +  '\uFC4D': '\u0646\u062E',
 +  '\uFC4E': '\u0646\u0645',
 +  '\uFC4F': '\u0646\u0649',
 +  '\uFC50': '\u0646\u064A',
 +  '\uFC51': '\u0647\u062C',
 +  '\uFC52': '\u0647\u0645',
 +  '\uFC53': '\u0647\u0649',
 +  '\uFC54': '\u0647\u064A',
 +  '\uFC55': '\u064A\u062C',
 +  '\uFC56': '\u064A\u062D',
 +  '\uFC57': '\u064A\u062E',
 +  '\uFC58': '\u064A\u0645',
 +  '\uFC59': '\u064A\u0649',
 +  '\uFC5A': '\u064A\u064A',
 +  '\uFC5B': '\u0630\u0670',
 +  '\uFC5C': '\u0631\u0670',
 +  '\uFC5D': '\u0649\u0670',
 +  '\uFC5E': '\u0020\u064C\u0651',
 +  '\uFC5F': '\u0020\u064D\u0651',
 +  '\uFC60': '\u0020\u064E\u0651',
 +  '\uFC61': '\u0020\u064F\u0651',
 +  '\uFC62': '\u0020\u0650\u0651',
 +  '\uFC63': '\u0020\u0651\u0670',
 +  '\uFC64': '\u0626\u0631',
 +  '\uFC65': '\u0626\u0632',
 +  '\uFC66': '\u0626\u0645',
 +  '\uFC67': '\u0626\u0646',
 +  '\uFC68': '\u0626\u0649',
 +  '\uFC69': '\u0626\u064A',
 +  '\uFC6A': '\u0628\u0631',
 +  '\uFC6B': '\u0628\u0632',
 +  '\uFC6C': '\u0628\u0645',
 +  '\uFC6D': '\u0628\u0646',
 +  '\uFC6E': '\u0628\u0649',
 +  '\uFC6F': '\u0628\u064A',
 +  '\uFC70': '\u062A\u0631',
 +  '\uFC71': '\u062A\u0632',
 +  '\uFC72': '\u062A\u0645',
 +  '\uFC73': '\u062A\u0646',
 +  '\uFC74': '\u062A\u0649',
 +  '\uFC75': '\u062A\u064A',
 +  '\uFC76': '\u062B\u0631',
 +  '\uFC77': '\u062B\u0632',
 +  '\uFC78': '\u062B\u0645',
 +  '\uFC79': '\u062B\u0646',
 +  '\uFC7A': '\u062B\u0649',
 +  '\uFC7B': '\u062B\u064A',
 +  '\uFC7C': '\u0641\u0649',
 +  '\uFC7D': '\u0641\u064A',
 +  '\uFC7E': '\u0642\u0649',
 +  '\uFC7F': '\u0642\u064A',
 +  '\uFC80': '\u0643\u0627',
 +  '\uFC81': '\u0643\u0644',
 +  '\uFC82': '\u0643\u0645',
 +  '\uFC83': '\u0643\u0649',
 +  '\uFC84': '\u0643\u064A',
 +  '\uFC85': '\u0644\u0645',
 +  '\uFC86': '\u0644\u0649',
 +  '\uFC87': '\u0644\u064A',
 +  '\uFC88': '\u0645\u0627',
 +  '\uFC89': '\u0645\u0645',
 +  '\uFC8A': '\u0646\u0631',
 +  '\uFC8B': '\u0646\u0632',
 +  '\uFC8C': '\u0646\u0645',
 +  '\uFC8D': '\u0646\u0646',
 +  '\uFC8E': '\u0646\u0649',
 +  '\uFC8F': '\u0646\u064A',
 +  '\uFC90': '\u0649\u0670',
 +  '\uFC91': '\u064A\u0631',
 +  '\uFC92': '\u064A\u0632',
 +  '\uFC93': '\u064A\u0645',
 +  '\uFC94': '\u064A\u0646',
 +  '\uFC95': '\u064A\u0649',
 +  '\uFC96': '\u064A\u064A',
 +  '\uFC97': '\u0626\u062C',
 +  '\uFC98': '\u0626\u062D',
 +  '\uFC99': '\u0626\u062E',
 +  '\uFC9A': '\u0626\u0645',
 +  '\uFC9B': '\u0626\u0647',
 +  '\uFC9C': '\u0628\u062C',
 +  '\uFC9D': '\u0628\u062D',
 +  '\uFC9E': '\u0628\u062E',
 +  '\uFC9F': '\u0628\u0645',
 +  '\uFCA0': '\u0628\u0647',
 +  '\uFCA1': '\u062A\u062C',
 +  '\uFCA2': '\u062A\u062D',
 +  '\uFCA3': '\u062A\u062E',
 +  '\uFCA4': '\u062A\u0645',
 +  '\uFCA5': '\u062A\u0647',
 +  '\uFCA6': '\u062B\u0645',
 +  '\uFCA7': '\u062C\u062D',
 +  '\uFCA8': '\u062C\u0645',
 +  '\uFCA9': '\u062D\u062C',
 +  '\uFCAA': '\u062D\u0645',
 +  '\uFCAB': '\u062E\u062C',
 +  '\uFCAC': '\u062E\u0645',
 +  '\uFCAD': '\u0633\u062C',
 +  '\uFCAE': '\u0633\u062D',
 +  '\uFCAF': '\u0633\u062E',
 +  '\uFCB0': '\u0633\u0645',
 +  '\uFCB1': '\u0635\u062D',
 +  '\uFCB2': '\u0635\u062E',
 +  '\uFCB3': '\u0635\u0645',
 +  '\uFCB4': '\u0636\u062C',
 +  '\uFCB5': '\u0636\u062D',
 +  '\uFCB6': '\u0636\u062E',
 +  '\uFCB7': '\u0636\u0645',
 +  '\uFCB8': '\u0637\u062D',
 +  '\uFCB9': '\u0638\u0645',
 +  '\uFCBA': '\u0639\u062C',
 +  '\uFCBB': '\u0639\u0645',
 +  '\uFCBC': '\u063A\u062C',
 +  '\uFCBD': '\u063A\u0645',
 +  '\uFCBE': '\u0641\u062C',
 +  '\uFCBF': '\u0641\u062D',
 +  '\uFCC0': '\u0641\u062E',
 +  '\uFCC1': '\u0641\u0645',
 +  '\uFCC2': '\u0642\u062D',
 +  '\uFCC3': '\u0642\u0645',
 +  '\uFCC4': '\u0643\u062C',
 +  '\uFCC5': '\u0643\u062D',
 +  '\uFCC6': '\u0643\u062E',
 +  '\uFCC7': '\u0643\u0644',
 +  '\uFCC8': '\u0643\u0645',
 +  '\uFCC9': '\u0644\u062C',
 +  '\uFCCA': '\u0644\u062D',
 +  '\uFCCB': '\u0644\u062E',
 +  '\uFCCC': '\u0644\u0645',
 +  '\uFCCD': '\u0644\u0647',
 +  '\uFCCE': '\u0645\u062C',
 +  '\uFCCF': '\u0645\u062D',
 +  '\uFCD0': '\u0645\u062E',
 +  '\uFCD1': '\u0645\u0645',
 +  '\uFCD2': '\u0646\u062C',
 +  '\uFCD3': '\u0646\u062D',
 +  '\uFCD4': '\u0646\u062E',
 +  '\uFCD5': '\u0646\u0645',
 +  '\uFCD6': '\u0646\u0647',
 +  '\uFCD7': '\u0647\u062C',
 +  '\uFCD8': '\u0647\u0645',
 +  '\uFCD9': '\u0647\u0670',
 +  '\uFCDA': '\u064A\u062C',
 +  '\uFCDB': '\u064A\u062D',
 +  '\uFCDC': '\u064A\u062E',
 +  '\uFCDD': '\u064A\u0645',
 +  '\uFCDE': '\u064A\u0647',
 +  '\uFCDF': '\u0626\u0645',
 +  '\uFCE0': '\u0626\u0647',
 +  '\uFCE1': '\u0628\u0645',
 +  '\uFCE2': '\u0628\u0647',
 +  '\uFCE3': '\u062A\u0645',
 +  '\uFCE4': '\u062A\u0647',
 +  '\uFCE5': '\u062B\u0645',
 +  '\uFCE6': '\u062B\u0647',
 +  '\uFCE7': '\u0633\u0645',
 +  '\uFCE8': '\u0633\u0647',
 +  '\uFCE9': '\u0634\u0645',
 +  '\uFCEA': '\u0634\u0647',
 +  '\uFCEB': '\u0643\u0644',
 +  '\uFCEC': '\u0643\u0645',
 +  '\uFCED': '\u0644\u0645',
 +  '\uFCEE': '\u0646\u0645',
 +  '\uFCEF': '\u0646\u0647',
 +  '\uFCF0': '\u064A\u0645',
 +  '\uFCF1': '\u064A\u0647',
 +  '\uFCF2': '\u0640\u064E\u0651',
 +  '\uFCF3': '\u0640\u064F\u0651',
 +  '\uFCF4': '\u0640\u0650\u0651',
 +  '\uFCF5': '\u0637\u0649',
 +  '\uFCF6': '\u0637\u064A',
 +  '\uFCF7': '\u0639\u0649',
 +  '\uFCF8': '\u0639\u064A',
 +  '\uFCF9': '\u063A\u0649',
 +  '\uFCFA': '\u063A\u064A',
 +  '\uFCFB': '\u0633\u0649',
 +  '\uFCFC': '\u0633\u064A',
 +  '\uFCFD': '\u0634\u0649',
 +  '\uFCFE': '\u0634\u064A',
 +  '\uFCFF': '\u062D\u0649',
 +  '\uFD00': '\u062D\u064A',
 +  '\uFD01': '\u062C\u0649',
 +  '\uFD02': '\u062C\u064A',
 +  '\uFD03': '\u062E\u0649',
 +  '\uFD04': '\u062E\u064A',
 +  '\uFD05': '\u0635\u0649',
 +  '\uFD06': '\u0635\u064A',
 +  '\uFD07': '\u0636\u0649',
 +  '\uFD08': '\u0636\u064A',
 +  '\uFD09': '\u0634\u062C',
 +  '\uFD0A': '\u0634\u062D',
 +  '\uFD0B': '\u0634\u062E',
 +  '\uFD0C': '\u0634\u0645',
 +  '\uFD0D': '\u0634\u0631',
 +  '\uFD0E': '\u0633\u0631',
 +  '\uFD0F': '\u0635\u0631',
 +  '\uFD10': '\u0636\u0631',
 +  '\uFD11': '\u0637\u0649',
 +  '\uFD12': '\u0637\u064A',
 +  '\uFD13': '\u0639\u0649',
 +  '\uFD14': '\u0639\u064A',
 +  '\uFD15': '\u063A\u0649',
 +  '\uFD16': '\u063A\u064A',
 +  '\uFD17': '\u0633\u0649',
 +  '\uFD18': '\u0633\u064A',
 +  '\uFD19': '\u0634\u0649',
 +  '\uFD1A': '\u0634\u064A',
 +  '\uFD1B': '\u062D\u0649',
 +  '\uFD1C': '\u062D\u064A',
 +  '\uFD1D': '\u062C\u0649',
 +  '\uFD1E': '\u062C\u064A',
 +  '\uFD1F': '\u062E\u0649',
 +  '\uFD20': '\u062E\u064A',
 +  '\uFD21': '\u0635\u0649',
 +  '\uFD22': '\u0635\u064A',
 +  '\uFD23': '\u0636\u0649',
 +  '\uFD24': '\u0636\u064A',
 +  '\uFD25': '\u0634\u062C',
 +  '\uFD26': '\u0634\u062D',
 +  '\uFD27': '\u0634\u062E',
 +  '\uFD28': '\u0634\u0645',
 +  '\uFD29': '\u0634\u0631',
 +  '\uFD2A': '\u0633\u0631',
 +  '\uFD2B': '\u0635\u0631',
 +  '\uFD2C': '\u0636\u0631',
 +  '\uFD2D': '\u0634\u062C',
 +  '\uFD2E': '\u0634\u062D',
 +  '\uFD2F': '\u0634\u062E',
 +  '\uFD30': '\u0634\u0645',
 +  '\uFD31': '\u0633\u0647',
 +  '\uFD32': '\u0634\u0647',
 +  '\uFD33': '\u0637\u0645',
 +  '\uFD34': '\u0633\u062C',
 +  '\uFD35': '\u0633\u062D',
 +  '\uFD36': '\u0633\u062E',
 +  '\uFD37': '\u0634\u062C',
 +  '\uFD38': '\u0634\u062D',
 +  '\uFD39': '\u0634\u062E',
 +  '\uFD3A': '\u0637\u0645',
 +  '\uFD3B': '\u0638\u0645',
 +  '\uFD3C': '\u0627\u064B',
 +  '\uFD3D': '\u0627\u064B',
 +  '\uFD50': '\u062A\u062C\u0645',
 +  '\uFD51': '\u062A\u062D\u062C',
 +  '\uFD52': '\u062A\u062D\u062C',
 +  '\uFD53': '\u062A\u062D\u0645',
 +  '\uFD54': '\u062A\u062E\u0645',
 +  '\uFD55': '\u062A\u0645\u062C',
 +  '\uFD56': '\u062A\u0645\u062D',
 +  '\uFD57': '\u062A\u0645\u062E',
 +  '\uFD58': '\u062C\u0645\u062D',
 +  '\uFD59': '\u062C\u0645\u062D',
 +  '\uFD5A': '\u062D\u0645\u064A',
 +  '\uFD5B': '\u062D\u0645\u0649',
 +  '\uFD5C': '\u0633\u062D\u062C',
 +  '\uFD5D': '\u0633\u062C\u062D',
 +  '\uFD5E': '\u0633\u062C\u0649',
 +  '\uFD5F': '\u0633\u0645\u062D',
 +  '\uFD60': '\u0633\u0645\u062D',
 +  '\uFD61': '\u0633\u0645\u062C',
 +  '\uFD62': '\u0633\u0645\u0645',
 +  '\uFD63': '\u0633\u0645\u0645',
 +  '\uFD64': '\u0635\u062D\u062D',
 +  '\uFD65': '\u0635\u062D\u062D',
 +  '\uFD66': '\u0635\u0645\u0645',
 +  '\uFD67': '\u0634\u062D\u0645',
 +  '\uFD68': '\u0634\u062D\u0645',
 +  '\uFD69': '\u0634\u062C\u064A',
 +  '\uFD6A': '\u0634\u0645\u062E',
 +  '\uFD6B': '\u0634\u0645\u062E',
 +  '\uFD6C': '\u0634\u0645\u0645',
 +  '\uFD6D': '\u0634\u0645\u0645',
 +  '\uFD6E': '\u0636\u062D\u0649',
 +  '\uFD6F': '\u0636\u062E\u0645',
 +  '\uFD70': '\u0636\u062E\u0645',
 +  '\uFD71': '\u0637\u0645\u062D',
 +  '\uFD72': '\u0637\u0645\u062D',
 +  '\uFD73': '\u0637\u0645\u0645',
 +  '\uFD74': '\u0637\u0645\u064A',
 +  '\uFD75': '\u0639\u062C\u0645',
 +  '\uFD76': '\u0639\u0645\u0645',
 +  '\uFD77': '\u0639\u0645\u0645',
 +  '\uFD78': '\u0639\u0645\u0649',
 +  '\uFD79': '\u063A\u0645\u0645',
 +  '\uFD7A': '\u063A\u0645\u064A',
 +  '\uFD7B': '\u063A\u0645\u0649',
 +  '\uFD7C': '\u0641\u062E\u0645',
 +  '\uFD7D': '\u0641\u062E\u0645',
 +  '\uFD7E': '\u0642\u0645\u062D',
 +  '\uFD7F': '\u0642\u0645\u0645',
 +  '\uFD80': '\u0644\u062D\u0645',
 +  '\uFD81': '\u0644\u062D\u064A',
 +  '\uFD82': '\u0644\u062D\u0649',
 +  '\uFD83': '\u0644\u062C\u062C',
 +  '\uFD84': '\u0644\u062C\u062C',
 +  '\uFD85': '\u0644\u062E\u0645',
 +  '\uFD86': '\u0644\u062E\u0645',
 +  '\uFD87': '\u0644\u0645\u062D',
 +  '\uFD88': '\u0644\u0645\u062D',
 +  '\uFD89': '\u0645\u062D\u062C',
 +  '\uFD8A': '\u0645\u062D\u0645',
 +  '\uFD8B': '\u0645\u062D\u064A',
 +  '\uFD8C': '\u0645\u062C\u062D',
 +  '\uFD8D': '\u0645\u062C\u0645',
 +  '\uFD8E': '\u0645\u062E\u062C',
 +  '\uFD8F': '\u0645\u062E\u0645',
 +  '\uFD92': '\u0645\u062C\u062E',
 +  '\uFD93': '\u0647\u0645\u062C',
 +  '\uFD94': '\u0647\u0645\u0645',
 +  '\uFD95': '\u0646\u062D\u0645',
 +  '\uFD96': '\u0646\u062D\u0649',
 +  '\uFD97': '\u0646\u062C\u0645',
 +  '\uFD98': '\u0646\u062C\u0645',
 +  '\uFD99': '\u0646\u062C\u0649',
 +  '\uFD9A': '\u0646\u0645\u064A',
 +  '\uFD9B': '\u0646\u0645\u0649',
 +  '\uFD9C': '\u064A\u0645\u0645',
 +  '\uFD9D': '\u064A\u0645\u0645',
 +  '\uFD9E': '\u0628\u062E\u064A',
 +  '\uFD9F': '\u062A\u062C\u064A',
 +  '\uFDA0': '\u062A\u062C\u0649',
 +  '\uFDA1': '\u062A\u062E\u064A',
 +  '\uFDA2': '\u062A\u062E\u0649',
 +  '\uFDA3': '\u062A\u0645\u064A',
 +  '\uFDA4': '\u062A\u0645\u0649',
 +  '\uFDA5': '\u062C\u0645\u064A',
 +  '\uFDA6': '\u062C\u062D\u0649',
 +  '\uFDA7': '\u062C\u0645\u0649',
 +  '\uFDA8': '\u0633\u062E\u0649',
 +  '\uFDA9': '\u0635\u062D\u064A',
 +  '\uFDAA': '\u0634\u062D\u064A',
 +  '\uFDAB': '\u0636\u062D\u064A',
 +  '\uFDAC': '\u0644\u062C\u064A',
 +  '\uFDAD': '\u0644\u0645\u064A',
 +  '\uFDAE': '\u064A\u062D\u064A',
 +  '\uFDAF': '\u064A\u062C\u064A',
 +  '\uFDB0': '\u064A\u0645\u064A',
 +  '\uFDB1': '\u0645\u0645\u064A',
 +  '\uFDB2': '\u0642\u0645\u064A',
 +  '\uFDB3': '\u0646\u062D\u064A',
 +  '\uFDB4': '\u0642\u0645\u062D',
 +  '\uFDB5': '\u0644\u062D\u0645',
 +  '\uFDB6': '\u0639\u0645\u064A',
 +  '\uFDB7': '\u0643\u0645\u064A',
 +  '\uFDB8': '\u0646\u062C\u062D',
 +  '\uFDB9': '\u0645\u062E\u064A',
 +  '\uFDBA': '\u0644\u062C\u0645',
 +  '\uFDBB': '\u0643\u0645\u0645',
 +  '\uFDBC': '\u0644\u062C\u0645',
 +  '\uFDBD': '\u0646\u062C\u062D',
 +  '\uFDBE': '\u062C\u062D\u064A',
 +  '\uFDBF': '\u062D\u062C\u064A',
 +  '\uFDC0': '\u0645\u062C\u064A',
 +  '\uFDC1': '\u0641\u0645\u064A',
 +  '\uFDC2': '\u0628\u062D\u064A',
 +  '\uFDC3': '\u0643\u0645\u0645',
 +  '\uFDC4': '\u0639\u062C\u0645',
 +  '\uFDC5': '\u0635\u0645\u0645',
 +  '\uFDC6': '\u0633\u062E\u064A',
 +  '\uFDC7': '\u0646\u062C\u064A',
 +  '\uFE49': '\u203E',
 +  '\uFE4A': '\u203E',
 +  '\uFE4B': '\u203E',
 +  '\uFE4C': '\u203E',
 +  '\uFE4D': '\u005F',
 +  '\uFE4E': '\u005F',
 +  '\uFE4F': '\u005F',
 +  '\uFE80': '\u0621',
 +  '\uFE81': '\u0622',
 +  '\uFE82': '\u0622',
 +  '\uFE83': '\u0623',
 +  '\uFE84': '\u0623',
 +  '\uFE85': '\u0624',
 +  '\uFE86': '\u0624',
 +  '\uFE87': '\u0625',
 +  '\uFE88': '\u0625',
 +  '\uFE89': '\u0626',
 +  '\uFE8A': '\u0626',
 +  '\uFE8B': '\u0626',
 +  '\uFE8C': '\u0626',
 +  '\uFE8D': '\u0627',
 +  '\uFE8E': '\u0627',
 +  '\uFE8F': '\u0628',
 +  '\uFE90': '\u0628',
 +  '\uFE91': '\u0628',
 +  '\uFE92': '\u0628',
 +  '\uFE93': '\u0629',
 +  '\uFE94': '\u0629',
 +  '\uFE95': '\u062A',
 +  '\uFE96': '\u062A',
 +  '\uFE97': '\u062A',
 +  '\uFE98': '\u062A',
 +  '\uFE99': '\u062B',
 +  '\uFE9A': '\u062B',
 +  '\uFE9B': '\u062B',
 +  '\uFE9C': '\u062B',
 +  '\uFE9D': '\u062C',
 +  '\uFE9E': '\u062C',
 +  '\uFE9F': '\u062C',
 +  '\uFEA0': '\u062C',
 +  '\uFEA1': '\u062D',
 +  '\uFEA2': '\u062D',
 +  '\uFEA3': '\u062D',
 +  '\uFEA4': '\u062D',
 +  '\uFEA5': '\u062E',
 +  '\uFEA6': '\u062E',
 +  '\uFEA7': '\u062E',
 +  '\uFEA8': '\u062E',
 +  '\uFEA9': '\u062F',
 +  '\uFEAA': '\u062F',
 +  '\uFEAB': '\u0630',
 +  '\uFEAC': '\u0630',
 +  '\uFEAD': '\u0631',
 +  '\uFEAE': '\u0631',
 +  '\uFEAF': '\u0632',
 +  '\uFEB0': '\u0632',
 +  '\uFEB1': '\u0633',
 +  '\uFEB2': '\u0633',
 +  '\uFEB3': '\u0633',
 +  '\uFEB4': '\u0633',
 +  '\uFEB5': '\u0634',
 +  '\uFEB6': '\u0634',
 +  '\uFEB7': '\u0634',
 +  '\uFEB8': '\u0634',
 +  '\uFEB9': '\u0635',
 +  '\uFEBA': '\u0635',
 +  '\uFEBB': '\u0635',
 +  '\uFEBC': '\u0635',
 +  '\uFEBD': '\u0636',
 +  '\uFEBE': '\u0636',
 +  '\uFEBF': '\u0636',
 +  '\uFEC0': '\u0636',
 +  '\uFEC1': '\u0637',
 +  '\uFEC2': '\u0637',
 +  '\uFEC3': '\u0637',
 +  '\uFEC4': '\u0637',
 +  '\uFEC5': '\u0638',
 +  '\uFEC6': '\u0638',
 +  '\uFEC7': '\u0638',
 +  '\uFEC8': '\u0638',
 +  '\uFEC9': '\u0639',
 +  '\uFECA': '\u0639',
 +  '\uFECB': '\u0639',
 +  '\uFECC': '\u0639',
 +  '\uFECD': '\u063A',
 +  '\uFECE': '\u063A',
 +  '\uFECF': '\u063A',
 +  '\uFED0': '\u063A',
 +  '\uFED1': '\u0641',
 +  '\uFED2': '\u0641',
 +  '\uFED3': '\u0641',
 +  '\uFED4': '\u0641',
 +  '\uFED5': '\u0642',
 +  '\uFED6': '\u0642',
 +  '\uFED7': '\u0642',
 +  '\uFED8': '\u0642',
 +  '\uFED9': '\u0643',
 +  '\uFEDA': '\u0643',
 +  '\uFEDB': '\u0643',
 +  '\uFEDC': '\u0643',
 +  '\uFEDD': '\u0644',
 +  '\uFEDE': '\u0644',
 +  '\uFEDF': '\u0644',
 +  '\uFEE0': '\u0644',
 +  '\uFEE1': '\u0645',
 +  '\uFEE2': '\u0645',
 +  '\uFEE3': '\u0645',
 +  '\uFEE4': '\u0645',
 +  '\uFEE5': '\u0646',
 +  '\uFEE6': '\u0646',
 +  '\uFEE7': '\u0646',
 +  '\uFEE8': '\u0646',
 +  '\uFEE9': '\u0647',
 +  '\uFEEA': '\u0647',
 +  '\uFEEB': '\u0647',
 +  '\uFEEC': '\u0647',
 +  '\uFEED': '\u0648',
 +  '\uFEEE': '\u0648',
 +  '\uFEEF': '\u0649',
 +  '\uFEF0': '\u0649',
 +  '\uFEF1': '\u064A',
 +  '\uFEF2': '\u064A',
 +  '\uFEF3': '\u064A',
 +  '\uFEF4': '\u064A',
 +  '\uFEF5': '\u0644\u0622',
 +  '\uFEF6': '\u0644\u0622',
 +  '\uFEF7': '\u0644\u0623',
 +  '\uFEF8': '\u0644\u0623',
 +  '\uFEF9': '\u0644\u0625',
 +  '\uFEFA': '\u0644\u0625',
 +  '\uFEFB': '\u0644\u0627',
 +  '\uFEFC': '\u0644\u0627'
 +};
 +
 +function reverseIfRtl(chars) {
 +  var charsLength = chars.length;
 +  //reverse an arabic ligature
 +  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;
 +}
 +
 +function adjustWidths(properties) {
 +  if (properties.fontMatrix[0] === FONT_IDENTITY_MATRIX[0]) {
 +    return;
 +  }
 +  // adjusting width to fontMatrix scale
 +  var scale = 0.001 / properties.fontMatrix[0];
 +  var glyphsWidths = properties.widths;
 +  for (var glyph in glyphsWidths) {
 +    glyphsWidths[glyph] *= scale;
 +  }
 +  properties.defaultWidth *= scale;
 +}
 +
 +/**
 + * '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).
 + *
 + * For example to read a Type1 font and to attach it to the document:
 + *   var type1Font = new Font("MyFontName", binaryFile, propertiesObject);
 + *   type1Font.bind();
 + */
 +var Font = (function FontClosure() {
 +  function Font(name, file, properties) {
-     if (arguments.length === 1) {
-       // importing translated data
-       var data = arguments[0];
-       for (var i in data) {
-         this[i] = data[i];
-       }
-       return;
-     }
 +
 +    this.name = name;
 +    this.loadedName = properties.loadedName;
 +    this.coded = properties.coded;
 +    this.loadCharProcs = properties.coded;
 +    this.sizes = [];
 +
 +    var names = name.split('+');
 +    names = names.length > 1 ? names[1] : names[0];
 +    names = names.split(/[-,_]/g)[0];
 +    this.isSerifFont = !!(properties.flags & FontFlags.Serif);
 +    this.isSymbolicFont = !!(properties.flags & FontFlags.Symbolic);
 +    this.isMonospace = !!(properties.flags & FontFlags.FixedPitch);
 +
 +    var type = properties.type;
 +    this.type = type;
 +
 +    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.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;
 +      return;
 +    }
 +
 +    // Trying to fix encoding using glyph CIDSystemInfo.
 +    this.loadCidToUnicode(properties);
 +    this.cidEncoding = properties.cidEncoding;
 +    this.vertical = properties.vertical;
 +    if (this.vertical) {
 +      this.vmetrics = properties.vmetrics;
 +      this.defaultVMetrics = properties.defaultVMetrics;
 +    }
 +
 +    if (properties.toUnicode && properties.toUnicode.length > 0)
 +      this.toUnicode = properties.toUnicode;
 +    else
 +      this.rebuildToUnicode(properties);
 +
 +    this.toFontChar = this.buildToFontChar(this.toUnicode);
 +
 +    if (!file) {
 +      // 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);
 +
 +      // 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);
 +
++      // 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.
++        // Building one based on GlyphMapForStandardFonts.
++        var map = [];
++        for (var code in GlyphMapForStandardFonts) {
++          map[+code] = GlyphMapForStandardFonts[code];
++        }
++        this.toFontChar = map;
++        this.toUnicode = map;
++      }
 +      this.loadedName = fontName.split('-')[0];
 +      this.loading = false;
 +      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')
 +      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') {
 +      type = 'OpenType';
 +    }
 +
 +    var data;
 +    switch (type) {
 +      case 'Type1':
 +      case 'CIDFontType0':
 +        this.mimetype = 'font/opentype';
 +
 +        var cff = (subtype == 'Type1C' || subtype == 'CIDFontType0C') ?
 +          new CFFFont(file, properties) : new Type1Font(name, file, properties);
 +
 +        adjustWidths(properties);
 +
 +        // Wrap the CFF data inside an OTF font file
 +        data = this.convert(name, cff, properties);
 +        break;
 +
++      case 'OpenType':
 +      case 'TrueType':
 +      case 'CIDFontType2':
 +        this.mimetype = 'font/opentype';
 +
 +        // Repair the TrueType file. It is can be damaged in the point of
 +        // view of the sanitizer
 +        data = this.checkAndRepair(name, file, properties);
-         if (!data) {
-           // TrueType data is not found, e.g. when the font is an OpenType font
-           warn('Font is not a TrueType font');
-         }
 +        break;
 +
 +      default:
-         warn('Font ' + type + ' is not supported');
++        error('Font ' + type + ' is not supported');
 +        break;
 +    }
 +
 +    this.data = data;
 +
 +    // Transfer some properties again that could change during font conversion
 +    this.fontMatrix = properties.fontMatrix;
 +    this.widths = properties.widths;
 +    this.defaultWidth = properties.defaultWidth;
 +    this.encoding = properties.baseEncoding;
 +    this.seacMap = properties.seacMap;
 +
 +    this.loading = true;
 +  }
 +
 +  var numFonts = 0;
 +  function getUniqueName() {
 +    return 'pdfFont' + numFonts++;
 +  }
 +
 +  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;
++    var strBuf = [];
++    for (var i = 0, ii = arr.length; i < ii; ++i) {
++      strBuf.push(String.fromCharCode(arr[i]));
++    }
++    return strBuf.join('');
 +  }
 +
 +  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 string16(value) {
 +    return String.fromCharCode((value >> 8) & 0xff) +
 +           String.fromCharCode(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);
 +  }
 +
 +  function string32(value) {
 +    return String.fromCharCode((value >> 24) & 0xff) +
 +           String.fromCharCode((value >> 16) & 0xff) +
 +           String.fromCharCode((value >> 8) & 0xff) +
 +           String.fromCharCode(value & 0xff);
 +  }
 +
 +  function createOpenTypeHeader(sfnt, file, numTables) {
 +    // Windows hates the Mac TrueType sfnt version number
 +    if (sfnt == 'true')
 +      sfnt = string32(0x00010000);
 +
 +    // sfnt version (4 bytes)
 +    var header = sfnt;
 +
 +    // numTables (2 bytes)
 +    header += string16(numTables);
 +
 +    // 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;
 +  }
 +
 +  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) {
++  function getRanges(glyphs, deltas) {
 +    // 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 });
 +    codes.sort(function fontGetRangesSort(a, b) {
 +      return a.unicode - b.unicode;
 +    });
 +
 +    // Split the sorted codes into ranges.
 +    var ranges = [];
 +    for (var n = 0; n < length; ) {
 +      var start = codes[n].unicode;
-       var codeIndices = [codes[n].code];
++      var codeIndices = [deltas ? deltas[codes[n].code] : codes[n].code + 1];
 +      ++n;
 +      var end = start;
 +      while (n < length && end + 1 == codes[n].unicode) {
-         codeIndices.push(codes[n].code);
++        codeIndices.push(deltas ? deltas[codes[n].code] : codes[n].code + 1);
 +        ++end;
 +        ++n;
-         if (end === 0x10000) { break; }
++        if (end === 0xFFFF) { break; }
 +      }
 +      ranges.push([start, end, codeIndices]);
 +    }
 +
 +    return ranges;
 +  }
 +
 +  function createCmapTable(glyphs, deltas) {
-     var ranges = getRanges(glyphs);
++    var ranges = getRanges(glyphs, deltas);
 +
 +    var numTables = ranges[ranges.length - 1][1] > 0xFFFF ? 2 : 1;
 +    var cmap = '\x00\x00' + // version
 +               string16(numTables) +  // numTables
 +               '\x00\x03' + // platformID
 +               '\x00\x01' + // encodingID
 +               string32(4 + numTables * 8); // start of the table record
 +
 +    for (var i = ranges.length - 1; i >= 0; --i) {
 +      if (ranges[i][0] <= 0xFFFF) { break; }
 +    }
 +    var bmpLength = i + 1;
 +
-     if (ranges[i][1] === 0xFFFF) { ranges[i][1] = 0xFFFE; }
-     var segCount = bmpLength + 1;
++    if (ranges[i][0] < 0xFFFF && ranges[i][1] === 0xFFFF) {
++      ranges[i][1] = 0xFFFE;
++    }
++    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;
 +
 +    // Fill up the 4 parallel arrays describing the segments.
 +    var startCount = '';
 +    var endCount = '';
 +    var idDeltas = '';
 +    var idRangeOffsets = '';
 +    var glyphsIds = '';
 +    var bias = 0;
 +
-     if (deltas) {
-       for (var i = 0, ii = bmpLength; i < ii; i++) {
-         var range = ranges[i];
-         var start = range[0];
-         var end = range[1];
++    for (var i = 0, ii = bmpLength; i < ii; i++) {
++      var range = ranges[i];
++      var start = range[0];
++      var end = range[1];
++      startCount += string16(start);
++      endCount += string16(end);
++      var codes = range[2];
++      var contiguous = true;
++      for (var j = 1, jj = codes.length; j < jj; ++j) {
++        if (codes[j] !== codes[j - 1] + 1) {
++          contiguous = false;
++          break;
++        }
++      }
++      if (!contiguous) {
 +        var offset = (segCount - i) * 2 + bias * 2;
 +        bias += (end - start + 1);
 +
-         startCount += string16(start);
-         endCount += string16(end);
 +        idDeltas += string16(0);
 +        idRangeOffsets += string16(offset);
 +
-         var codes = range[2];
-         for (var j = 0, jj = codes.length; j < jj; ++j)
-           glyphsIds += string16(deltas[codes[j]]);
-       }
-     } else {
-       for (var i = 0, ii = bmpLength; i < ii; i++) {
-         var range = ranges[i];
-         var start = range[0];
-         var end = range[1];
-         var startCode = range[2][0];
++        for (var j = 0, jj = codes.length; j < jj; ++j) {
++          glyphsIds += string16(codes[j]);
++        }
++      } else {
++        var startCode = codes[0];
 +
-         startCount += string16(start);
-         endCount += string16(end);
-         idDeltas += string16((startCode - start + 1) & 0xFFFF);
++        idDeltas += string16((startCode - start) & 0xFFFF);
 +        idRangeOffsets += string16(0);
 +      }
 +    }
 +
-     endCount += '\xFF\xFF';
-     startCount += '\xFF\xFF';
-     idDeltas += '\x00\x01';
-     idRangeOffsets += '\x00\x00';
++    if (trailingRangesCount > 0) {
++      endCount += '\xFF\xFF';
++      startCount += '\xFF\xFF';
++      idDeltas += '\x00\x01';
++      idRangeOffsets += '\x00\x00';
++    }
 +
 +    var format314 = '\x00\x00' + // language
 +                    string16(segCount2) +
 +                    string16(searchRange) +
 +                    string16(searchEntry) +
 +                    string16(rangeShift) +
 +                    endCount + '\x00\x00' + startCount +
 +                    idDeltas + idRangeOffsets + glyphsIds;
 +
 +    var format31012 = '';
 +    var header31012 = '';
 +    if (numTables > 1) {
 +      cmap += '\x00\x03' + // platformID
 +              '\x00\x0A' + // encodingID
 +              string32(4 + numTables * 8 +
 +                       4 + format314.length); // start of the table record
 +      format31012 = '';
-       if (deltas) {
-         for (var i = 0, ii = ranges.length; i < ii; i++) {
-           var range = ranges[i];
-           var start = range[0];
-           var codes = range[2];
-           var code = deltas[codes[0]];
-           for (var j = 1, jj = codes.length; j < jj; ++j) {
-             if (deltas[codes[j]] !== deltas[codes[j - 1]] + 1) {
-               var end = range[0] + j - 1;
-               format31012 += string32(start) + // startCharCode
-                              string32(end) + // endCharCode
-                              string32(code); // startGlyphID
-               start = end + 1;
-               code = deltas[codes[j]];
-             }
-           }
-           format31012 += string32(start) + // startCharCode
-                          string32(range[1]) + // endCharCode
-                          string32(code); // startGlyphID
-         }
-       } else {
-         for (var i = 0, ii = ranges.length; i < ii; i++) {
-           var range = ranges[i];
-           var start = range[0];
-           var codes = range[2];
-           var code = codes[0];
-           for (var j = 1, jj = codes.length; j < jj; ++j) {
-             if (codes[j] !== codes[j - 1] + 1) {
-               var end = range[0] + j - 1;
-               format31012 += string32(start) + // startCharCode
-                              string32(end) + // endCharCode
-                              string32(code); // startGlyphID
-               start = end + 1;
-               code = codes[j];
-             }
++      for (var i = 0, ii = ranges.length; i < ii; i++) {
++        var range = ranges[i];
++        var start = range[0];
++        var codes = range[2];
++        var code = codes[0];
++        for (var j = 1, jj = codes.length; j < jj; ++j) {
++          if (codes[j] !== codes[j - 1] + 1) {
++            var end = range[0] + j - 1;
++            format31012 += string32(start) + // startCharCode
++                           string32(end) + // endCharCode
++                           string32(code); // startGlyphID
++            start = end + 1;
++            code = codes[j];
 +          }
-           format31012 += string32(start) + // startCharCode
-                          string32(range[1]) + // endCharCode
-                          string32(code); // startGlyphID
 +        }
++        format31012 += string32(start) + // startCharCode
++                       string32(range[1]) + // endCharCode
++                       string32(code); // startGlyphID
 +      }
 +      header31012 = '\x00\x0C' + // format
 +                    '\x00\x00' + // reserved
 +                    string32(format31012.length + 16) + // length
 +                    '\x00\x00\x00\x00' + // language
 +                    string32(format31012.length / 12); // nGroups
 +    }
 +
 +    return stringToArray(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));
 +    // 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));
 +    if (version < 4 && (selection & 0x0300)) {
 +      return false;
 +    }
 +    var firstChar = int16(stream.getBytes(2));
 +    var lastChar = int16(stream.getBytes(2));
 +    if (firstChar > lastChar) {
 +      return false;
 +    }
 +    stream.getBytes(6); // skipping sTypoAscender/Descender/LineGap
 +    var usWinAscent = int16(stream.getBytes(2));
 +    if (usWinAscent === 0) { // makes font unreadable by windows
 +      return false;
 +    }
 +
 +    // OS/2 appears to be valid, resetting some fields
 +    os2.data[8] = os2.data[9] = 0; // IE rejects fonts if fsType != 0
 +    return true;
 +  }
 +
 +  function createOS2Table(properties, charstrings, override) {
 +    override = override || {
 +      unitsPerEm: 0,
 +      yMax: 0,
 +      yMin: 0,
 +      ascent: 0,
 +      descent: 0
 +    };
 +
 +    var ulUnicodeRange1 = 0;
 +    var ulUnicodeRange2 = 0;
 +    var ulUnicodeRange3 = 0;
 +    var ulUnicodeRange4 = 0;
 +
 +    var firstCharIndex = null;
 +    var lastCharIndex = 0;
 +
 +    if (charstrings) {
 +      for (var i = 0; i < charstrings.length; ++i) {
 +        var code = charstrings[i].unicode;
 +        if (firstCharIndex > code || !firstCharIndex)
 +          firstCharIndex = code;
 +        if (lastCharIndex < code)
 +          lastCharIndex = code;
 +
 +        var position = getUnicodeRangeFor(code);
 +        if (position < 32) {
 +          ulUnicodeRange1 |= 1 << position;
 +        } else if (position < 64) {
 +          ulUnicodeRange2 |= 1 << position - 32;
 +        } else if (position < 96) {
 +          ulUnicodeRange3 |= 1 << position - 64;
 +        } else if (position < 123) {
 +          ulUnicodeRange4 |= 1 << position - 96;
 +        } else {
 +          error('Unicode ranges Bits > 123 are reserved for internal usage');
 +        }
 +      }
 +    } else {
 +      // TODO
 +      firstCharIndex = 0;
 +      lastCharIndex = 255;
 +    }
 +
 +    var bbox = properties.bbox || [0, 0, 0, 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 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
 +    }
 +    var winAscent = override.yMax || typoAscent;
 +    var winDescent = -override.yMin || -typoDescent;
 +
 +    return '\x00\x03' + // version
 +           '\x02\x24' + // xAvgCharWidth
 +           '\x01\xF4' + // usWeightClass
 +           '\x00\x05' + // usWidthClass
 +           '\x00\x00' + // fstype (0 to let the font loads via font-face on IE)
 +           '\x02\x8A' + // ySubscriptXSize
 +           '\x02\xBB' + // ySubscriptYSize
 +           '\x00\x00' + // ySubscriptXOffset
 +           '\x00\x8C' + // ySubscriptYOffset
 +           '\x02\x8A' + // ySuperScriptXSize
 +           '\x02\xBB' + // ySuperScriptYSize
 +           '\x00\x00' + // ySuperScriptXOffset
 +           '\x01\xDF' + // ySuperScriptYOffset
 +           '\x00\x31' + // yStrikeOutSize
 +           '\x01\x02' + // yStrikeOutPosition
 +           '\x00\x00' + // sFamilyClass
 +           '\x00\x00\x06' +
 +           String.fromCharCode(properties.fixedPitch ? 0x09 : 0x00) +
 +           '\x00\x00\x00\x00\x00\x00' + // Panose
 +           string32(ulUnicodeRange1) + // ulUnicodeRange1 (Bits 0-31)
 +           string32(ulUnicodeRange2) + // ulUnicodeRange2 (Bits 32-63)
 +           string32(ulUnicodeRange3) + // ulUnicodeRange3 (Bits 64-95)
 +           string32(ulUnicodeRange4) + // ulUnicodeRange4 (Bits 96-127)
 +           '\x2A\x32\x31\x2A' + // achVendID
 +           string16(properties.italicAngle ? 1 : 0) + // fsSelection
 +           string16(firstCharIndex ||
 +                    properties.firstChar) + // usFirstCharIndex
 +           string16(lastCharIndex || properties.lastChar) +  // usLastCharIndex
 +           string16(typoAscent) + // sTypoAscender
 +           string16(typoDescent) + // sTypoDescender
 +           '\x00\x64' + // sTypoLineGap (7%-10% of the unitsPerEM value)
 +           string16(winAscent) + // usWinAscent
 +           string16(winDescent) + // usWinDescent
 +           '\x00\x00\x00\x00' + // ulCodePageRange1 (Bits 0-31)
 +           '\x00\x00\x00\x00' + // ulCodePageRange2 (Bits 32-63)
 +           string16(properties.xHeight) + // sxHeight
 +           string16(properties.capHeight) + // sCapHeight
 +           string16(0) + // usDefaultChar
 +           string16(firstCharIndex || properties.firstChar) + // usBreakChar
 +           '\x00\x03';  // usMaxContext
 +  }
 +
 +  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
 +  }
 +
 +  function createNameTable(name, proto) {
 +    if (!proto) {
 +      proto = [[], []]; // no strings and unicode strings
 +    }
 +
 +    var strings = [
 +      proto[0][0] || 'Original licence',  // 0.Copyright
 +      proto[0][1] || name,                // 1.Font family
 +      proto[0][2] || 'Unknown',           // 2.Font subfamily (font weight)
 +      proto[0][3] || 'uniqueID',          // 3.Unique ID
 +      proto[0][4] || name,                // 4.Full font name
 +      proto[0][5] || 'Version 0.11',      // 5.Version
 +      proto[0][6] || '',                  // 6.Postscript name
 +      proto[0][7] || 'Unknown',           // 7.Trademark
 +      proto[0][8] || 'Unknown',           // 8.Manufacturer
 +      proto[0][9] || 'Unknown'            // 9.Designer
 +    ];
 +
 +    // 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 strUnicode = '';
-       for (var j = 0, jj = str.length; j < jj; j++)
-         strUnicode += string16(str.charCodeAt(j));
-       stringsUnicode.push(strUnicode);
++      var strBufUnicode = [];
++      for (var j = 0, jj = str.length; j < jj; j++) {
++        strBufUnicode.push(string16(str.charCodeAt(j)));
++      }
++      stringsUnicode.push(strBufUnicode.join(''));
 +    }
 +
 +    var names = [strings, stringsUnicode];
 +    var platforms = ['\x00\x01', '\x00\x03'];
 +    var encodings = ['\x00\x00', '\x00\x01'];
 +    var languages = ['\x00\x00', '\x04\x09'];
 +
 +    var namesRecordCount = strings.length * platforms.length;
 +    var nameTable =
 +      '\x00\x00' +                           // format
 +      string16(namesRecordCount) +           // Number of names Record
 +      string16(namesRecordCount * 12 + 6);   // Storage
 +
 +    // Build the name records field
 +    var strOffset = 0;
 +    for (var 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];
 +        var nameRecord =
 +          platforms[i] + // platform ID
 +          encodings[i] + // encoding ID
 +          languages[i] + // language ID
 +          string16(j) + // name ID
 +          string16(str.length) +
 +          string16(strOffset);
 +        nameTable += nameRecord;
 +        strOffset += str.length;
 +      }
 +    }
 +
 +    nameTable += strings.join('') + stringsUnicode.join('');
 +    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,
 +    mimetype: null,
 +    encoding: null,
++    get renderer() {
++      var renderer = FontRendererFactory.create(this);
++      return shadow(this, 'renderer', renderer);
++    },
 +
 +    exportData: function Font_exportData() {
 +      var data = {};
 +      for (var i in this) {
 +        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 checksum = int32(file.getBytes(4));
 +        var offset = int32(file.getBytes(4));
 +        var length = int32(file.getBytes(4));
 +
 +        // Read the table associated data
 +        var previousPosition = file.pos;
 +        file.pos = file.start ? file.start : 0;
 +        file.skip(offset);
 +        var data = file.getBytes(length);
 +        file.pos = previousPosition;
 +
 +        if (tag == 'head') {
 +          // clearing checksum adjustment
 +          data[8] = data[9] = data[10] = data[11] = 0;
 +          data[17] |= 0x20; //Set font optimized for cleartype flag
 +        }
 +
 +        return {
 +          tag: tag,
 +          checksum: checksum,
 +          length: length,
 +          offset: offset,
 +          data: data
 +        };
 +      }
 +
 +      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))
 +        };
 +      }
 +
 +      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.hasEncoding)
++        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) {
 +        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 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.
 +        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 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) {
 +            useTable = true;
 +            canBreak = true;
 +            foundPreferredTable = true;
 +          } else if (hasEncoding && platformId === 3 && encodingId === 1) {
 +            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
 +            };
 +          }
 +          if (canBreak) {
 +            break;
 +          }
 +        }
 +
 +        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;
 +        }
 +
 +        font.pos = start + potentialTable.offset;
 +        var format = int16(font.getBytes(2));
 +        var length = int16(font.getBytes(2));
 +        var language = int16(font.getBytes(2));
 +
 +        var hasShortCmap = false;
 +        var mappings = [];
 +
 +        // TODO(mack): refactor this cmap subtable reading logic out
 +        if (format === 0) {
 +          for (var j = 0; j < 256; j++) {
 +            var index = font.getByte();
 +            if (!index) {
 +              continue;
 +            }
 +            mappings.push({
 +              charcode: j,
 +              glyphId: index
 +            });
 +          }
 +          hasShortCmap = true;
 +        } else if (format === 4) {
 +          // re-creating the table in format 4 since the encoding
 +          // might be changed
 +          var segCount = (int16(font.getBytes(2)) >> 1);
 +          font.getBytes(6); // skipping range fields
 +          var segIndex, segments = [];
 +          for (segIndex = 0; segIndex < segCount; segIndex++) {
 +            segments.push({ end: int16(font.getBytes(2)) });
 +          }
 +          font.getBytes(2);
 +          for (segIndex = 0; segIndex < segCount; segIndex++) {
 +            segments[segIndex].start = int16(font.getBytes(2));
 +          }
 +
 +          for (segIndex = 0; segIndex < segCount; segIndex++) {
 +            segments[segIndex].delta = int16(font.getBytes(2));
 +          }
 +
 +          var offsetsCount = 0;
 +          for (segIndex = 0; segIndex < segCount; segIndex++) {
 +            var segment = segments[segIndex];
 +            var rangeOffset = int16(font.getBytes(2));
 +            if (!rangeOffset) {
 +              segment.offsetIndex = -1;
 +              continue;
 +            }
 +
 +            var offsetIndex = (rangeOffset >> 1) - (segCount - segIndex);
 +            segment.offsetIndex = offsetIndex;
 +            offsetsCount = Math.max(offsetsCount, offsetIndex +
 +              segment.end - segment.start + 1);
 +          }
 +
 +          var offsets = [];
 +          for (var j = 0; j < offsetsCount; j++) {
 +            offsets.push(int16(font.getBytes(2)));
 +          }
 +
 +          for (segIndex = 0; segIndex < segCount; segIndex++) {
 +            var segment = segments[segIndex];
 +            var start = segment.start, end = segment.end;
 +            var delta = segment.delta, offsetIndex = segment.offsetIndex;
 +
 +            for (var j = start; j <= end; j++) {
 +              if (j == 0xFFFF) {
 +                continue;
 +              }
 +
 +              var glyphId = offsetIndex < 0 ? j :
 +                offsets[offsetIndex + j - start];
 +              glyphId = (glyphId + delta) & 0xFFFF;
 +              if (glyphId === 0) {
 +                continue;
 +              }
 +              mappings.push({
 +                charcode: j,
 +                glyphId: glyphId
 +              });
 +            }
 +          }
 +        } 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 glyphs = [];
 +          var ids = [];
 +          for (var j = 0; j < entryCount; j++) {
 +            var glyphId = int16(font.getBytes(2));
 +            var charcode = firstCode + j;
 +
 +            mappings.push({
 +              charcode: charcode,
 +              glyphId: glyphId
 +            });
 +          }
 +        } else {
 +          error('cmap table has unsupported format: ' + format);
 +        }
 +
++        // removing duplicate entries
++        mappings.sort(function (a, b) {
++          return a.charcode - b.charcode;
++        });
++        for (var i = 1; i < mappings.length; i++) {
++          if (mappings[i - 1].charcode === mappings[i].charcode) {
++            mappings.splice(i, 1);
++            i--;
++          }
++        }
++
 +        return {
 +          platformId: potentialTable.platformId,
 +          encodingId: potentialTable.encodingId,
 +          isSymbolicFont: potentialTable.isSymbolicFont,
 +          mappings: mappings,
 +          hasShortCmap: hasShortCmap
 +        };
 +      }
 +
 +      function sanitizeMetrics(font, header, metrics, numGlyphs) {
 +        if (!header) {
 +          if (metrics) {
 +            metrics.data = null;
 +          }
 +          return;
 +        }
 +
 +        font.pos = (font.start ? font.start : 0) + header.offset;
 +        font.pos += header.length - 2;
 +        var numOfMetrics = int16(font.getBytes(2));
 +
 +        if (numOfMetrics > numGlyphs) {
 +          info('The numOfMetrics (' + numOfMetrics + ') should not be ' +
 +               'greater than the numGlyphs (' + numGlyphs + ')');
 +          // Reduce numOfMetrics if it is greater than numGlyphs
 +          numOfMetrics = numGlyphs;
 +          header.data[34] = (numOfMetrics & 0xff00) >> 8;
 +          header.data[35] = numOfMetrics & 0x00ff;
 +        }
 +
 +        var numOfSidebearings = numGlyphs - numOfMetrics;
 +        var numMissing = numOfSidebearings -
 +          ((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);
 +        }
 +      }
 +
-       function sanitizeGlyph(source, sourceStart, sourceEnd, dest, destStart) {
++      function sanitizeGlyph(source, sourceStart, sourceEnd, dest, destStart,
++                             hintsValid) {
 +        if (sourceEnd - sourceStart <= 12) {
 +          // glyph with data less than 12 is invalid one
 +          return 0;
 +        }
 +        var glyf = source.subarray(sourceStart, sourceEnd);
 +        var contoursCount = (glyf[0] << 8) | glyf[1];
 +        if (contoursCount & 0x8000) {
 +          // complex glyph, writing as is
 +          dest.set(glyf, destStart);
 +          return glyf.length;
 +        }
 +
 +        var j = 10, flagsCount = 0;
 +        for (var i = 0; i < contoursCount; i++) {
 +          var endPoint = (glyf[j] << 8) | glyf[j + 1];
 +          flagsCount = endPoint + 1;
 +          j += 2;
 +        }
 +        // skipping instructions
++        var instructionsStart = j;
 +        var instructionsLength = (glyf[j] << 8) | glyf[j + 1];
 +        j += 2 + instructionsLength;
++        var instructionsEnd = j;
 +        // validating flags
 +        var coordinatesLength = 0;
 +        for (var i = 0; i < flagsCount; i++) {
 +          var flag = glyf[j++];
 +          if (flag & 0xC0) {
-             // reserved flags must be zero, rejecting
-             return 0;
++            // reserved flags must be zero, cleaning up
++            glyf[j - 1] = flag & 0x3F;
 +          }
 +          var xyLength = ((flag & 2) ? 1 : (flag & 16) ? 0 : 2) +
 +                         ((flag & 4) ? 1 : (flag & 32) ? 0 : 2);
 +          coordinatesLength += xyLength;
 +          if (flag & 8) {
 +            var repeat = glyf[j++];
 +            i += repeat;
 +            coordinatesLength += repeat * xyLength;
 +          }
 +        }
++        // glyph without coordinates will be rejected
++        if (coordinatesLength === 0) {
++          return 0;
++        }
 +        var glyphDataLength = j + coordinatesLength;
 +        if (glyphDataLength > glyf.length) {
 +          // not enough data for coordinates
 +          return 0;
 +        }
++        if (!hintsValid && instructionsLength > 0) {
++          dest.set(glyf.subarray(0, instructionsStart), destStart);
++          dest.set([0, 0], destStart + instructionsStart);
++          dest.set(glyf.subarray(instructionsEnd, glyphDataLength),
++                   destStart + instructionsStart + 2);
++          glyphDataLength -= instructionsLength;
++          if (glyf.length - glyphDataLength > 3) {
++            glyphDataLength = (glyphDataLength + 3) & ~3;
++          }
++          return glyphDataLength;
++        }
 +        if (glyf.length - glyphDataLength > 3) {
 +          // truncating and aligning to 4 bytes the long glyph data
 +          glyphDataLength = (glyphDataLength + 3) & ~3;
 +          dest.set(glyf.subarray(0, glyphDataLength), destStart);
 +          return glyphDataLength;
 +        }
 +        // glyph data is fine
 +        dest.set(glyf, destStart);
 +        return glyf.length;
 +      }
 +
 +      function sanitizeHead(head, numGlyphs, locaLength) {
 +        var data = head.data;
 +
 +        // Validate version:
 +        // Should always be 0x00010000
 +        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;
 +          data[1] = 1;
 +          data[2] = 0;
 +          data[3] = 0;
 +        }
 +
 +        var indexToLocFormat = int16([data[50], data[51]]);
 +        if (indexToLocFormat < 0 || indexToLocFormat > 1) {
 +          info('Attempting to fix invalid indexToLocFormat in head table: ' +
 +               indexToLocFormat);
 +
 +          // The value of indexToLocFormat should be 0 if the loca table
 +          // consists of short offsets, and should be 1 if the loca table
 +          // consists of long offsets.
 +          //
 +          // The number of entries in the loca table should be numGlyphs + 1.
 +          //
 +          // Using this information, we can work backwards to deduce if the
 +          // size of each offset in the loca table, and thus figure out the
 +          // appropriate value for indexToLocFormat.
 +
 +          var numGlyphsPlusOne = numGlyphs + 1;
 +          if (locaLength === numGlyphsPlusOne << 1) {
 +            // 0x0000 indicates the loca table consists of short offsets
 +            data[50] = 0;
 +            data[51] = 0;
 +          } else if (locaLength === numGlyphsPlusOne << 2) {
 +            // 0x0001 indicates the loca table consists of long offsets
 +            data[50] = 0;
 +            data[51] = 1;
 +          } else {
 +            warn('Could not fix indexToLocFormat: ' + indexToLocFormat);
 +          }
 +        }
 +      }
 +
 +      function sanitizeGlyphLocations(loca, glyf, numGlyphs,
-                                       isGlyphLocationsLong) {
++                                      isGlyphLocationsLong, hintsValid,
++                                      dupFirstEntry) {
 +        var itemSize, itemDecode, itemEncode;
 +        if (isGlyphLocationsLong) {
 +          itemSize = 4;
 +          itemDecode = function fontItemDecodeLong(data, offset) {
 +            return (data[offset] << 24) | (data[offset + 1] << 16) |
 +                   (data[offset + 2] << 8) | data[offset + 3];
 +          };
 +          itemEncode = function fontItemEncodeLong(data, offset, value) {
 +            data[offset] = (value >>> 24) & 0xFF;
 +            data[offset + 1] = (value >> 16) & 0xFF;
 +            data[offset + 2] = (value >> 8) & 0xFF;
 +            data[offset + 3] = value & 0xFF;
 +          };
 +        } else {
 +          itemSize = 2;
 +          itemDecode = function fontItemDecode(data, offset) {
 +            return (data[offset] << 9) | (data[offset + 1] << 1);
 +          };
 +          itemEncode = function fontItemEncode(data, offset, value) {
 +            data[offset] = (value >> 9) & 0xFF;
 +            data[offset + 1] = (value >> 1) & 0xFF;
 +          };
 +        }
 +        var locaData = loca.data;
++        var locaDataSize = itemSize * (1 + numGlyphs);
++        // is loca.data too short or long?
++        if (locaData.length !== locaDataSize) {
++          locaData = new Uint8Array(locaDataSize);
++          locaData.set(loca.data.subarray(0, locaDataSize));
++          loca.data = locaData;
++        }
 +        // removing the invalid glyphs
 +        var oldGlyfData = glyf.data;
 +        var oldGlyfDataLength = oldGlyfData.length;
 +        var newGlyfData = new Uint8Array(oldGlyfDataLength);
 +        var startOffset = itemDecode(locaData, 0);
 +        var writeOffset = 0;
 +        itemEncode(locaData, 0, writeOffset);
 +        for (var i = 0, j = itemSize; i < numGlyphs; i++, j += itemSize) {
 +          var endOffset = itemDecode(locaData, j);
 +          if (endOffset > oldGlyfDataLength) {
 +            // glyph end offset points outside glyf data, rejecting the glyph
 +            itemEncode(locaData, j, writeOffset);
 +            startOffset = endOffset;
 +            continue;
 +          }
 +
 +          var newLength = sanitizeGlyph(oldGlyfData, startOffset, endOffset,
-                                         newGlyfData, writeOffset);
++                                        newGlyfData, writeOffset, hintsValid);
 +          writeOffset += newLength;
 +          itemEncode(locaData, j, writeOffset);
 +          startOffset = endOffset;
 +        }
 +
 +        if (writeOffset === 0) {
 +          // glyf table cannot be empty -- redoing the glyf and loca tables
 +          // 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)
 +            itemEncode(locaData, j, simpleGlyph.length);
 +          glyf.data = simpleGlyph;
 +          return;
 +        }
 +
-         glyf.data = newGlyfData.subarray(0, writeOffset);
-       }
- 
-       function findEmptyGlyphs(locaTable, isGlyphLocationsLong, emptyGlyphIds) {
-         var itemSize, itemDecode;
-         if (isGlyphLocationsLong) {
-           itemSize = 4;
-           itemDecode = function fontItemDecodeLong(data, offset) {
-             return (data[offset] << 24) | (data[offset + 1] << 16) |
-                    (data[offset + 2] << 8) | data[offset + 3];
-           };
++        if (dupFirstEntry) {
++          var firstEntryLength = itemDecode(locaData, itemSize);
++          if (newGlyfData.length > firstEntryLength + writeOffset) {
++            glyf.data = newGlyfData.subarray(0, firstEntryLength + writeOffset);
++          } else {
++            glyf.data = new Uint8Array(firstEntryLength + writeOffset);
++            glyf.data.set(newGlyfData.subarray(0, writeOffset));
++          }
++          glyf.data.set(newGlyfData.subarray(0, firstEntryLength), writeOffset);
++          itemEncode(loca.data, locaData.length - itemSize,
++                     writeOffset + firstEntryLength);
 +        } else {
-           itemSize = 2;
-           itemDecode = function fontItemDecode(data, offset) {
-             return (data[offset] << 9) | (data[offset + 1] << 1);
-           };
-         }
-         var data = locaTable.data, length = data.length;
-         var lastOffset = itemDecode(data, 0);
-         for (var i = itemSize, j = 0; i < length; i += itemSize, j++) {
-           var offset = itemDecode(data, i);
-           if (offset == lastOffset)
-             emptyGlyphIds[j] = true;
-           lastOffset = offset;
++          glyf.data = newGlyfData.subarray(0, writeOffset);
 +        }
 +      }
 +
 +      function readPostScriptTable(post, properties, maxpNumGlyphs) {
 +        var start = (font.start ? font.start : 0) + post.offset;
 +        font.pos = start;
 +
 +        var length = post.length, end = start + length;
 +        var version = int32(font.getBytes(4));
 +        // skip rest to the tables
 +        font.getBytes(28);
 +
 +        var glyphNames;
 +        var valid = true;
 +        switch (version) {
 +          case 0x00010000:
 +            glyphNames = MacStandardGlyphOrdering;
 +            break;
 +          case 0x00020000:
 +            var numGlyphs = int16(font.getBytes(2));
 +            if (numGlyphs != maxpNumGlyphs) {
 +              valid = false;
 +              break;
 +            }
 +            var glyphNameIndexes = [];
 +            for (var i = 0; i < numGlyphs; ++i) {
 +              var index = int16(font.getBytes(2));
 +              if (index >= 32768) {
 +                valid = false;
 +                break;
 +              }
 +              glyphNameIndexes.push(index);
 +            }
 +            if (!valid) {
 +              break;
 +            }
 +            var customNames = [];
 +            while (font.pos < end) {
 +              var stringLength = font.getByte();
 +              var string = '';
-               for (var i = 0; i < stringLength; ++i)
-                 string += font.getChar();
++              for (var i = 0; i < stringLength; ++i) {
++                string += String.fromCharCode(font.getByte());
++              }
 +              customNames.push(string);
 +            }
 +            glyphNames = [];
 +            for (var i = 0; i < numGlyphs; ++i) {
 +              var j = glyphNameIndexes[i];
 +              if (j < 258) {
 +                glyphNames.push(MacStandardGlyphOrdering[j]);
 +                continue;
 +              }
 +              glyphNames.push(customNames[j - 258]);
 +            }
 +            break;
 +          case 0x00030000:
 +            break;
 +          default:
 +            warn('Unknown/unsupported post table version ' + version);
 +            valid = false;
 +            break;
 +        }
 +        properties.glyphNames = glyphNames;
 +        return valid;
 +      }
 +
 +      function readNameTable(nameTable) {
 +        var start = (font.start ? font.start : 0) + nameTable.offset;
 +        font.pos = start;
 +
 +        var names = [[], []];
 +        var length = nameTable.length, end = start + length;
 +        var format = int16(font.getBytes(2));
 +        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 records = [];
 +        var NAME_RECORD_LENGTH = 12;
 +        for (var 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))
 +          };
 +          // 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)) {
 +            records.push(r);
 +          }
 +        }
 +        for (var i = 0, ii = records.length; i < ii; i++) {
 +          var record = records[i];
 +          var pos = start + stringsStart + record.offset;
 +          if (pos + record.length > end) {
 +            continue; // outside of name table, ignoring
 +          }
 +          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)));
 +            }
 +            names[1][nameIndex] = str;
 +          } else {
 +            names[0][nameIndex] = bytesToString(font.getBytes(record.length));
 +          }
 +        }
 +        return names;
 +      }
 +
 +      var TTOpsStackDeltas = [
 +        0, 0, 0, 0, 0, 0, 0, 0, -2, -2, -2, -2, 0, 0, -2, -5,
 +        -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, -1, 0, -1, -1, -1, -1,
-         1, -1, -999, 0, 1, 0, 0, -2, 0, -1, -2, -1, -999, -999, -1, -1,
-         0, 0, -999, -999, -1, -1, -1, -1, -2, -999, -2, -2, -2, 0, -2, -2,
++        1, -1, -999, 0, 1, 0, -1, -2, 0, -1, -2, -1, -1, 0, -1, -1,
++        0, 0, -999, -999, -1, -1, -1, -1, -2, -999, -2, -2, -999, 0, -2, -2,
 +        0, 0, -2, 0, -2, 0, 0, 0, -2, -1, -1, 1, 1, 0, 0, -1,
 +        -1, -1, -1, -1, -1, -1, 0, 0, -1, 0, -1, -1, 0, -999, -1, -1,
-         -1, -1, -1, -1, 0, 0, 0, 0, -1, -1, 0, 0, 0, 0, 0, 0,
++        -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 +        -2, -999, -999, -999, -999, -999, -1, -1, -2, -2, 0, 0, 0, 0, -1, -1,
-         -999, -2, -2, 0, 0, -1, -2, -2, 0, -999, 0, 0, 0, -1, -2];
++        -999, -2, -2, 0, 0, -1, -2, -2, 0, 0, 0, -1, -1, -1, -2];
 +        // 0xC0-DF == -1 and 0xE0-FF == -2
 +
 +      function sanitizeTTProgram(table, ttContext) {
 +        var data = table.data;
 +        var i = 0, n, lastEndf = 0, lastDeff = 0;
 +        var stack = [];
++        var callstack = [];
++        var functionsCalled = [];
 +        var tooComplexToFollowFunctions =
 +          ttContext.tooComplexToFollowFunctions;
++        var inFDEF = false, ifLevel = 0, inELSE = 0;
 +        for (var ii = data.length; i < ii;) {
 +          var op = data[i++];
 +          // The TrueType instruction set docs can be found at
 +          // https://developer.apple.com/fonts/TTRefMan/RM05/Chap5.html
 +          if (op === 0x40) { // NPUSHB - pushes n bytes
 +            n = data[i++];
-             for (var j = 0; j < n; j++) {
-               stack.push(data[i++]);
++            if (inFDEF || inELSE) {
++              i += n;
++            } else {
++              for (var j = 0; j < n; j++) {
++                stack.push(data[i++]);
++              }
 +            }
 +          } else if (op === 0x41) { // NPUSHW - pushes n words
 +            n = data[i++];
-             for (var j = 0; j < n; j++) {
-               var b = data[i++];
-               stack.push((b << 8) | data[i++]);
++            if (inFDEF || inELSE) {
++              i += n * 2;
++            } else {
++              for (var j = 0; j < n; j++) {
++                var b = data[i++];
++                stack.push((b << 8) | data[i++]);
++              }
 +            }
 +          } else if ((op & 0xF8) === 0xB0) { // PUSHB - pushes bytes
 +            n = op - 0xB0 + 1;
-             for (var j = 0; j < n; j++) {
-               stack.push(data[i++]);
++            if (inFDEF || inELSE) {
++              i += n;
++            } else {
++              for (var j = 0; j < n; j++) {
++                stack.push(data[i++]);
++              }
 +            }
 +          } else if ((op & 0xF8) === 0xB8) { // PUSHW - pushes words
 +            n = op - 0xB8 + 1;
-             for (var j = 0; j < n; j++) {
-               var b = data[i++];
-               stack.push((b << 8) | data[i++]);
++            if (inFDEF || inELSE) {
++              i += n * 2;
++            } else {
++              for (var j = 0; j < n; j++) {
++                var b = data[i++];
++                stack.push((b << 8) | data[i++]);
++              }
 +            }
 +          } else if (op === 0x2B && !tooComplexToFollowFunctions) { // CALL
-             // collecting inforamtion about which functions are used
-             var funcId = stack[stack.length - 1];
-             ttContext.functionsUsed[funcId] = true;
-             if (i >= 2 && data[i - 2] === 0x2B) {
-               // all data in stack, calls are performed in sequence
-               tooComplexToFollowFunctions = true;
++            if (!inFDEF && !inELSE) {
++              // collecting inforamtion about which functions are used
++              var funcId = stack[stack.length - 1];
++              ttContext.functionsUsed[funcId] = true;
++              if (funcId in ttContext.functionsStackDeltas) {
++                stack.length += ttContext.functionsStackDeltas[funcId];
++              } else if (funcId in ttContext.functionsDefined &&
++                         functionsCalled.indexOf(funcId) < 0) {
++                callstack.push({data: data, i: i, stackTop: stack.length - 1});
++                functionsCalled.push(funcId);
++                var pc = ttContext.functionsDefined[funcId];
++                if (!pc) {
++                  warn('TT: CALL non-existent function');
++                  ttContext.hintsValid = false;
++                  return;
++                }
++                data = pc.data;
++                i = pc.i;
++              }
 +            }
 +          } else if (op === 0x2C && !tooComplexToFollowFunctions) { // FDEF
-             // collecting inforamtion about which functions are defined
-             lastDeff = i;
-             var funcId = stack[stack.length - 1];
-             ttContext.functionsDefined[funcId] = true;
-             if (i >= 2 && data[i - 2] === 0x2D) {
-               // all function ids in stack, FDEF/ENDF perfomed in sequence
++            if (inFDEF || inELSE) {
++              warn('TT: nested FDEFs not allowed');
 +              tooComplexToFollowFunctions = true;
 +            }
++            inFDEF = true;
++            // collecting inforamtion about which functions are defined
++            lastDeff = i;
++            var funcId = stack.pop();
++            ttContext.functionsDefined[funcId] = {data: data, i: i};
 +          } else if (op === 0x2D) { // ENDF - end of function
-             lastEndf = i;
++            if (inFDEF) {
++              inFDEF = false;
++              lastEndf = i;
++            } else {
++              var pc = callstack.pop();
++              if (!pc) {
++                warn('TT: ENDF bad stack');
++                ttContext.hintsValid = false;
++                return;
++              }
++              var funcId = functionsCalled.pop();
++              data = pc.data;
++              i = pc.i;
++              ttContext.functionsStackDeltas[funcId] =
++                stack.length - pc.stackTop;
++            }
 +          } else if (op === 0x89) { // IDEF - instruction definition
++            if (inFDEF || inELSE) {
++              warn('TT: nested IDEFs not allowed');
++              tooComplexToFollowFunctions = true;
++            }
++            inFDEF = true;
 +            // recording it as a function to track ENDF
 +            lastDeff = i;
++          } else if (op === 0x58) { // IF
++            ++ifLevel;
++          } else if (op === 0x1B) { // ELSE
++            inELSE = ifLevel;
++          } else if (op === 0x59) { // EIF
++            if (inELSE === ifLevel) {
++              inELSE = 0;
++            }
++            --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; }
 +          }
 +          // Adjusting stack not extactly, but just enough to get function id
-           var stackDelta = op <= 0x8E ? TTOpsStackDeltas[op] :
-             op >= 0xC0 && op <= 0xDF ? -1 : op >= 0xE0 ? -2 : 0;
-           while (stackDelta < 0 && stack.length > 0) {
-             stack.pop();
-             stackDelta++;
-           }
-           while (stackDelta > 0) {
-             stack.push(NaN); // pushing any number into stack
-             stackDelta--;
++          if (!inFDEF && !inELSE) {
++            var stackDelta = op <= 0x8E ? TTOpsStackDeltas[op] :
++              op >= 0xC0 && op <= 0xDF ? -1 : op >= 0xE0 ? -2 : 0;
++            if (op >= 0x71 && op <= 0x75) {
++              n = stack.pop();
++              if (n === n) {
++                stackDelta = -n * 2;
++              }
++            }
++            while (stackDelta < 0 && stack.length > 0) {
++              stack.pop();
++              stackDelta++;
++            }
++            while (stackDelta > 0) {
++              stack.push(NaN); // pushing any number into stack
++              stackDelta--;
++            }
 +          }
 +        }
 +        ttContext.tooComplexToFollowFunctions = tooComplexToFollowFunctions;
 +        var content = [data];
 +        if (i > data.length) {
 +          content.push(new Uint8Array(i - data.length));
 +        }
 +        if (lastDeff > lastEndf) {
++          warn('TT: complementing a missing function tail');
 +          // new function definition started, but not finished
 +          // complete function by [CLEAR, ENDF]
 +          content.push(new Uint8Array([0x22, 0x2D]));
 +        }
-         if (ttContext.defineMissingFunctions && !tooComplexToFollowFunctions) {
-           for (var j = 0, jj = ttContext.functionsUsed.length; j < jj; j++) {
-             if (!ttContext.functionsUsed[j] || ttContext.functionsDefined[j]) {
-               continue;
-             }
-             // function is used, but not defined
-             // creating empty one [PUSHB, function-id, FDEF, ENDF]
-             content.push(new Uint8Array([0xB0, j, 0x2C, 0x2D]));
++        foldTTTable(table, content);
++      }
++
++      function checkInvalidFunctions(ttContext, maxFunctionDefs) {
++        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);
++            ttContext.hintsValid = false;
++            return;
++          }
++          if (ttContext.functionsUsed[j] && !ttContext.functionsDefined[j]) {
++            warn('TT: undefined function: ' + j);
++            ttContext.hintsValid = false;
++            return;
 +          }
 +        }
++      }
++
++      function foldTTTable(table, content) {
 +        if (content.length > 1) {
 +          // concatenating the content items
 +          var newLength = 0;
 +          for (var 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++) {
 +            result.set(content[j], pos);
 +            pos += content[j].length;
 +          }
 +          table.data = result;
 +          table.length = newLength;
 +        }
 +      }
 +
-       function sanitizeTTPrograms(fpgm, prep) {
++      function sanitizeTTPrograms(fpgm, prep, cvt) {
 +        var ttContext = {
 +          functionsDefined: [],
 +          functionsUsed: [],
-           tooComplexToFollowFunctions: false
++          functionsStackDeltas: [],
++          tooComplexToFollowFunctions: false,
++          hintsValid: true
 +        };
++        if (fpgm) {
++          sanitizeTTProgram(fpgm, ttContext);
++        }
 +        if (prep) {
-           // collecting prep functions info first
 +          sanitizeTTProgram(prep, ttContext);
 +        }
 +        if (fpgm) {
-           ttContext.defineMissingFunctions = true;
-           sanitizeTTProgram(fpgm, ttContext);
++          checkInvalidFunctions(ttContext, maxFunctionDefs);
++        }
++        if (cvt && (cvt.length & 1)) {
++          var cvtData = new Uint8Array(cvt.length + 1);
++          cvtData.set(cvt.data);
++          cvt.data = cvtData;
 +        }
++        return ttContext.hintsValid;
 +      }
 +
-       // Check that required tables are present
-       var requiredTables = ['OS/2', 'cmap', 'head', 'hhea',
-                              'hmtx', 'maxp', 'name', 'post'];
++      // The following steps modify the original font data, making copy
++      font = new Stream(new Uint8Array(font.getBytes()));
++
++      var VALID_TABLES = ['OS/2', 'cmap', 'head', 'hhea', 'hmtx', 'maxp',
++        'name', 'post', 'loca', 'glyf', 'fpgm', 'prep', 'cvt ', 'CFF '];
 +
 +      var header = readOpenTypeHeader(font);
 +      var numTables = header.numTables;
 +
-       var cmap, post, maxp, hhea, hmtx, head, os2;
-       var glyf, fpgm, loca, prep, cvt;
-       var tables = [];
++      var tables = { 'OS/2': null, cmap: null, head: null, hhea: null,
++                     hmtx: null, maxp: null, name: null, post: null};
 +      for (var i = 0; i < numTables; i++) {
 +        var table = readTableEntry(font);
-         var index = requiredTables.indexOf(table.tag);
-         if (index != -1) {
-           if (table.tag == 'cmap')
-             cmap = table;
-           else if (table.tag == 'post')
-             post = table;
-           else if (table.tag == 'maxp')
-             maxp = table;
-           else if (table.tag == 'hhea')
-             hhea = table;
-           else if (table.tag == 'hmtx')
-             hmtx = table;
-           else if (table.tag == 'head')
-             head = table;
-           else if (table.tag == 'OS/2')
-             os2 = table;
- 
-           requiredTables.splice(index, 1);
-         } else {
-           if (table.tag == 'loca')
-             loca = table;
-           else if (table.tag == 'glyf')
-             glyf = table;
-           else if (table.tag == 'fpgm')
-             fpgm = table;
-           else if (table.tag == 'prep')
-             prep = table;
-           else if (table.tag == 'cvt ')
-             cvt = table;
-           else if (table.tag == 'CFF ')
-             return null; // XXX: OpenType font is found, stopping
-           else // skipping table if it's not a required or optional table
-             continue;
++        if (VALID_TABLES.indexOf(table.tag) < 0) {
++          continue; // skipping table if it's not a required or optional table
++        }
++        if (table.length === 0) {
++          continue; // skipping empty tables
 +        }
-         tables.push(table);
++        tables[table.tag] = table;
 +      }
 +
-       var numTables = tables.length + requiredTables.length;
++      var isTrueType = !tables['CFF '];
++      if (!isTrueType) {
++        // 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);
++
++          return this.convert(name, cff, properties);
++        }
++
++        delete tables.glyf;
++        delete tables.loca;
++        delete tables.fpgm;
++        delete tables.prep;
++        delete tables['cvt '];
++      } else {
++        if (!tables.glyf || !tables.loca) {
++          error('Required "glyf" or "loca" tables are not found');
++        }
++      }
++
++      if (!tables.maxp) {
++        error('Required "maxp" table is not found');
++      }
++
++      font.pos = (font.start || 0) + tables.maxp.offset;
++      var version = int32(font.getBytes(4));
++      var numGlyphs = int16(font.getBytes(2));
++      var maxFunctionDefs = 0;
++      if (version >= 0x00010000 && tables.maxp.length >= 22) {
++        // maxZones can be invalid
++        font.pos += 8;
++        var maxZones = int16(font.getBytes(2));
++        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));
++      }
++
++      var dupFirstEntry = false;
++      if (properties.type == 'CIDFontType2' && properties.toUnicode &&
++          properties.toUnicode[0] > '\u0000') {
++        // oracle's defect (see 3427), duplicating first entry
++        dupFirstEntry = true;
++        numGlyphs++;
++        tables.maxp.data[4] = numGlyphs >> 8;
++        tables.maxp.data[5] = numGlyphs & 255;
++      }
++
++      var hintsValid = sanitizeTTPrograms(tables.fpgm, tables.prep,
++                                          tables['cvt '], maxFunctionDefs);
++      if (!hintsValid) {
++        delete tables.fpgm;
++        delete tables.prep;
++        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
-       font.pos = (font.start || 0) + maxp.offset;
-       var version = int16(font.getBytes(4));
-       var numGlyphs = int16(font.getBytes(2));
++      sanitizeMetrics(font, tables.hhea, tables.hmtx, numGlyphs);
 +
-       sanitizeMetrics(font, hhea, hmtx, numGlyphs);
++      if (!tables.head) {
++        error('Required "head" table is not found');
++      }
 +
-       sanitizeTTPrograms(fpgm, prep);
++      sanitizeHead(tables.head, numGlyphs, isTrueType ? tables.loca.length : 0);
 +
-       if (head) {
-         sanitizeHead(head, numGlyphs, loca.length);
++      if (isTrueType) {
++        var isGlyphLocationsLong = int16([tables.head.data[50],
++                                          tables.head.data[51]]);
++        sanitizeGlyphLocations(tables.loca, tables.glyf, numGlyphs,
++                               isGlyphLocationsLong, hintsValid, dupFirstEntry);
 +      }
 +
-       var isGlyphLocationsLong = int16([head.data[50], head.data[51]]);
-       if (head && loca && glyf) {
-         sanitizeGlyphLocations(loca, glyf, numGlyphs, isGlyphLocationsLong);
++      if (!tables.hhea) {
++        error('Required "hhea" table is not found');
 +      }
 +
-       var emptyGlyphIds = [];
-       if (glyf)
-         findEmptyGlyphs(loca, isGlyphLocationsLong, emptyGlyphIds);
- 
 +      // Sanitizer reduces the glyph advanceWidth to the maxAdvanceWidth
 +      // Sometimes it's 0. That needs to be fixed
-       if (hhea.data[10] === 0 && hhea.data[11] === 0) {
-         hhea.data[10] = 0xFF;
-         hhea.data[11] = 0xFF;
++      if (tables.hhea.data[10] === 0 && tables.hhea.data[11] === 0) {
++        tables.hhea.data[10] = 0xFF;
++        tables.hhea.data[11] = 0xFF;
 +      }
 +
 +      // The 'post' table has glyphs names.
-       if (post) {
-         var valid = readPostScriptTable(post, properties, numGlyphs);
++      if (tables.post) {
++        var valid = readPostScriptTable(tables.post, properties, numGlyphs);
 +        if (!valid) {
-           tables.splice(tables.indexOf(post), 1);
-           post = null;
++          tables.post = null;
 +        }
 +      }
 +
 +      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 (!cmap) {
-           cmap = {
++        if (!tables.cmap) {
++          tables.cmap = {
 +            tag: 'cmap',
 +            data: null
 +          };
-           tables.push(cmap);
 +        }
 +
 +        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;
 +          }
 +          // 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] || 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] || i;
++            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);
 +          }
 +        }
 +      } 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(cmap, font, this.hasEncoding,
++        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 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);
 +
 +          if (!unicode) {
 +            // TODO(mack): gotta check if skipping mappings where we cannot find
 +            // a unicode is the correct behaviour
 +            continue;
 +          }
 +          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)) {
 +              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];
 +            }
 +
 +            // Finally, any undefined entries in the table shall be filled
 +            // using StandardEncoding
 +            if (!glyphName) {
 +              glyphName = Encodings.StandardEncoding[charcode];
 +            }
 +
 +            // 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;
 +          }
 +        }
 +        this.toFontChar = toFontChar = newToFontChar;
 +
 +        createGlyphNameMap(glyphs, ids, properties);
 +        this.glyphNameMap = properties.glyphNameMap;
 +      }
 +
 +      if (glyphs.length === 0) {
 +        // defines at least one glyph
 +        glyphs.push({ unicode: 0xF000, code: 0xF000, glyph: '.notdef' });
 +        ids.push(0);
 +      }
 +
 +      // Converting glyphs and ids into font's cmap table
-       cmap.data = createCmapTable(glyphs, ids);
++      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;
 +
-       if (os2 && !validateOS2Table(os2)) {
-         tables.splice(tables.indexOf(os2), 1);
-         os2 = null;
-       }
- 
-       if (!os2) {
++      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([head.data[18], head.data[19]]),
-           yMax: int16([head.data[42], head.data[43]]),
-           yMin: int16([head.data[38], head.data[39]]) - 0x10000,
-           ascent: int16([hhea.data[4], hhea.data[5]]),
-           descent: int16([hhea.data[6], 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.push({
++        tables['OS/2'] = {
 +          tag: 'OS/2',
 +          data: stringToArray(createOS2Table(properties, glyphs, override))
-         });
++        };
 +      }
 +
 +      // Rewrite the 'post' table if needed
-       if (!post) {
-         tables.push({
++      if (!tables.post) {
++        tables.post = {
 +          tag: 'post',
 +          data: stringToArray(createPostTable(properties))
-         });
++        };
++      }
++
++      if (!isTrueType) {
++        try {
++          // Trying to repair CFF file
++          var cffFile = new Stream(tables['CFF '].data);
++          var parser = new CFFParser(cffFile, properties);
++          var cff = parser.parse();
++          var compiler = new CFFCompiler(cff);
++          tables['CFF '].data = compiler.compile();
++        } catch (e) {
++          warn('Failed to compile font ' + properties.loadedName);
++        }
 +      }
 +
 +      // Re-creating 'name' table
-       if (requiredTables.indexOf('name') != -1) {
-         tables.push({
++      if (!tables.name) {
++        tables.name = {
 +          tag: 'name',
 +          data: stringToArray(createNameTable(this.name))
-         });
++        };
 +      } else {
 +        // ... using existing 'name' table as prototype
-         for (var i = 0, ii = tables.length; i < ii; i++) {
-           var table = tables[i];
-           if (table.tag === 'name') {
-             var namePrototype = readNameTable(table);
-             table.data = stringToArray(createNameTable(name, namePrototype));
-             break;
-           }
-         }
++        var namePrototype = readNameTable(tables.name);
++        tables.name.data = stringToArray(createNameTable(name, namePrototype));
 +      }
 +
-       // Tables needs to be written by ascendant alphabetic order
-       tables.sort(function tables_sort(a, b) {
-         return (a.tag > b.tag) - (a.tag < b.tag);
-       });
- 
 +      // rewrite the tables but tweak offsets
-       for (var i = 0, ii = tables.length; i < ii; i++) {
-         var table = tables[i];
++      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);
 +      }
 +
 +      // Add the table datas
-       for (var i = 0, ii = tables.length; i < ii; i++) {
-         var table = tables[i];
++      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);
 +    },
 +
 +    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;
 +        }
 +        return true;
 +      }
 +
 +      // 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;
 +      }
 +      this.glyphNameMap = glyphNameMap;
 +
 +      var seacs = font.seacs;
 +      if (SEAC_ANALYSIS_ENABLED && seacs) {
 +        var seacMap = [];
 +        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 baseGlyphName = Encodings.StandardEncoding[seac[2]];
 +          var baseUnicode = glyphNameMap[baseGlyphName];
 +          var accentGlyphName = Encodings.StandardEncoding[seac[3]];
 +          var accentUnicode = glyphNameMap[accentGlyphName];
 +          if (!baseUnicode || !accentUnicode) {
 +            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
 +          };
 +        }
 +        properties.seacMap = seacMap;
 +      }
 +
-       if (!properties.hasEncoding && (properties.subtype == 'Type1C' ||
++      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,
 +
 +        // OS/2 and Windows Specific metrics
 +        'OS/2': stringToArray(createOS2Table(properties, charstrings)),
 +
 +        // 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() {
 +          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;
 +            hmtx += string16(width) + string16(0);
 +          }
 +          return stringToArray(hmtx);
 +        })(),
 +
 +        // Maximum profile
 +        'maxp': (function fontFieldsMaxp() {
 +          return stringToArray(
 +              '\x00\x00\x50\x00' + // Version number
 +             string16(charstrings.length + 1)); // Num of glyphs
 +        })(),
 +
 +        // Naming tables
 +        'name': stringToArray(createNameTable(fontName)),
 +
 +        // PostScript informations
 +        'post': stringToArray(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);
 +    },
 +
 +    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 (typeof unicode !== 'undefined') {
++          if (isString(fontCharCode) && fontCharCode.length === 1) {
++            fontCharCode = fontCharCode.charCodeAt(0);
++          }
 +          result[i] = fontCharCode;
++        }
 +      }
 +      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 ? i : toUnicode[i];
++          map[i] = isIdentityMap ? String.fromCharCode(i) : toUnicode[i];
 +        }
 +      } 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] = GlyphsUnicode[glyph];
++            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) {
-           TODO('Need to create a reverse mapping from \'ToUnicode\' CMap');
++          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;
 +            }
 +          }
 +          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;
 +              }
 +              cid++;
 +              k++;
 +            }
 +          } else
 +            cid += unicode.s;
 +        } else if (unicode) {
 +          cidToUnicodeMap[cid] = unicode;
 +          if (!unicodeToCIDMap[unicode] || overwrite) {
 +            unicodeToCIDMap[unicode] = cid;
 +          }
 +          cid++;
 +        } else
 +          cid++;
 +      }
 +
 +      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 = [];
 +      }
 +    },
 +
-     bindDOM: function Font_bindDOM() {
-       if (!this.data)
-         return null;
- 
-       var data = bytesToString(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 + '}';
- 
-       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);
-       }
- 
-       var styleSheet = styleElement.sheet;
-       styleSheet.insertRule(rule, styleSheet.cssRules.length);
- 
-       if (PDFJS.pdfBug && 'FontInspector' in globalScope &&
-           globalScope['FontInspector'].enabled)
-         globalScope['FontInspector'].fontAdded(this, url);
- 
-       return rule;
-     },
- 
 +    get spaceWidth() {
 +      if ('_shadowWidth' in this) {
 +        return this._shadowWidth;
 +      }
 +
 +      // trying to estimate space character width
 +      var possibleSpaceReplacements = ['space', 'minus', 'one', 'i'];
 +      var width;
 +      for (var i = 0, ii = possibleSpaceReplacements.length; i < ii; i++) {
 +        var glyphName = possibleSpaceReplacements[i];
 +        // if possible, getting width by glyph name
 +        if (glyphName in this.widths) {
 +          width = this.widths[glyphName];
 +          break;
 +        }
 +        var glyphUnicode = GlyphsUnicode[glyphName];
 +        // finding the charcode via unicodeToCID map
 +        var charcode = 0;
 +        if (this.composite)
 +          charcode = this.unicodeToCID[glyphUnicode];
 +        // ... via toUnicode map
 +        if (!charcode && 'toUnicode' in this)
 +          charcode = this.toUnicode.indexOf(glyphUnicode);
 +        // setting it to unicode if negative or undefined
 +        if (charcode <= 0)
 +          charcode = glyphUnicode;
 +        // trying to get width via charcode
 +        width = this.widths[charcode];
 +        if (width)
 +          break; // the non-zero width found
 +      }
 +      width = width || this.defaultWidth;
 +      // Do not shadow the property here. See discussion:
 +      // https://github.com/mozilla/pdf.js/pull/2127#discussion_r1662280
 +      this._shadowWidth = width;
 +      return width;
 +    },
 +
 +    charToGlyph: function Font_charToGlyph(charcode) {
 +      var fontCharCode, width, operatorList, disabled;
 +
 +      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 unicodeChars = !('toUnicode' in this) ? charcode :
 +        this.toUnicode[charcode] || charcode;
 +      if (typeof unicodeChars === 'number') {
 +        unicodeChars = String.fromCharCode(unicodeChars);
 +      }
 +
 +      width = isNum(width) ? width : this.defaultWidth;
 +      disabled = this.unicodeIsEnabled ?
 +        !this.unicodeIsEnabled[fontCharCode] : false;
 +
 +      var accent = null;
 +      if (this.seacMap && this.seacMap[fontCharCode]) {
 +        var seac = this.seacMap[fontCharCode];
 +        fontCharCode = seac.baseUnicode;
 +        accent = {
 +          fontChar: String.fromCharCode(seac.accentUnicode),
 +          offset: seac.accentOffset
 +        };
 +      }
 +
 +      return {
 +        fontChar: String.fromCharCode(fontCharCode),
 +        unicode: unicodeChars,
 +        accent: accent,
 +        width: width,
 +        vmetric: vmetric,
 +        disabled: disabled,
 +        operatorList: operatorList
 +      };
 +    },
 +
 +    charsToGlyphs: function Font_charsToGlyphs(chars) {
 +      var charsCache = this.charsCache;
 +      var glyphs;
 +
 +      // if we translated this string before, just grab it from the cache
 +      if (charsCache) {
 +        glyphs = charsCache[chars];
 +        if (glyphs)
 +          return glyphs;
 +      }
 +
 +      // lazily create the translation cache
 +      if (!charsCache)
 +        charsCache = this.charsCache = Object.create(null);
 +
 +      glyphs = [];
 +      var charsCacheKey = chars;
 +
 +      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.wideChars) {
++      if (!converter && this.cmap) {
++        var i = 0;
 +        // composite fonts have multi-byte strings convert the string from
 +        // single-byte to multi-byte
-         // XXX assuming CIDFonts are two-byte - later need to extract the
-         // correct byte encoding according to the PDF spec
-         var length = chars.length - 1; // looping over two bytes at a time so
-                                        // loop should never end on the last byte
-         for (var i = 0; i < length; i++) {
-           var charcode = int16([chars.charCodeAt(i++), chars.charCodeAt(i)]);
++        while (i < chars.length) {
++          var c = this.cmap.readCharCode(chars, i);
++          var charcode = c[0];
++          var length = c[1];
++          i += length;
 +          var glyph = this.charToGlyph(charcode);
 +          glyphs.push(glyph);
 +          // placing null after each word break charcode (ASCII SPACE)
-           if (charcode == 0x20)
++          // Ignore occurences of 0x20 in multiple-byte codes.
++          if (length === 1 && chars.charCodeAt(i - 1) === 0x20) {
 +            glyphs.push(null);
++          }
 +        }
 +      }
 +      else {
 +        for (var i = 0, ii = chars.length; i < ii; ++i) {
 +          var charcode = chars.charCodeAt(i);
 +          var glyph = this.charToGlyph(charcode);
 +          glyphs.push(glyph);
 +          if (charcode == 0x20)
 +            glyphs.push(null);
 +        }
 +      }
 +
 +      // Enter the translated string into the cache
 +      return (charsCache[charsCacheKey] = glyphs);
 +    }
 +  };
 +
 +  return Font;
 +})();
 +
 +var ErrorFont = (function ErrorFontClosure() {
 +  function ErrorFont(error) {
 +    this.error = error;
 +  }
 +
 +  ErrorFont.prototype = {
 +    charsToGlyphs: function ErrorFont_charsToGlyphs() {
 +      return [];
 +    },
 +    exportData: function ErrorFont_exportData() {
 +      return {error: this.error};
 +    }
 +  };
 +
 +  return ErrorFont;
 +})();
 +
 +/*
 + * CharStrings are encoded following the the CharString Encoding sequence
 + * describe in Chapter 6 of the "Adobe Type1 Font Format" specification.
 + * The value in a byte indicates a command, a number, or subsequent bytes
 + * that are to be interpreted in a special way.
 + *
 + * CharString Number Encoding:
 + *  A CharString byte containing the values from 32 through 255 inclusive
 + *  indicate an integer. These values are decoded in four ranges.
 + *
 + * 1. A CharString byte containing a value, v, between 32 and 246 inclusive,
 + * indicate the integer v - 139. Thus, the integer values from -107 through
 + * 107 inclusive may be encoded in single byte.
 + *
 + * 2. A CharString byte containing a value, v, between 247 and 250 inclusive,
 + * indicates an integer involving the next byte, w, according to the formula:
 + * [(v - 247) x 256] + w + 108
 + *
 + * 3. A CharString byte containing a value, v, between 251 and 254 inclusive,
 + * indicates an integer involving the next byte, w, according to the formula:
 + * -[(v - 251) * 256] - w - 108
 + *
 + * 4. A CharString containing the value 255 indicates that the next 4 bytes
 + * are a two complement signed integer. The first of these bytes contains the
 + * highest order bits, the second byte contains the next higher order bits
 + * and the fourth byte contain the lowest order bits.
 + *
 + *
 + * CharString Command Encoding:
 + *  CharStrings commands are encoded in 1 or 2 bytes.
 + *
 + *  Single byte commands are encoded in 1 byte that contains a value between
 + *  0 and 31 inclusive.
 + *  If a command byte contains the value 12, then the value in the next byte
 + *  indicates a command. This "escape" mechanism allows many extra commands
 + * to be encoded and this encoding technique helps to minimize the length of
 + * the charStrings.
 + */
 +var Type1CharString = (function Type1CharStringClosure() {
 +  var COMMAND_MAP = {
 +    'hstem': [1],
 +    'vstem': [3],
 +    'vmoveto': [4],
 +    'rlineto': [5],
 +    'hlineto': [6],
 +    'vlineto': [7],
 +    'rrcurveto': [8],
 +    'callsubr': [10],
 +    'flex': [12, 35],
 +    'drop' : [12, 18],
 +    'endchar': [14],
 +    'rmoveto': [21],
 +    'hmoveto': [22],
 +    'vhcurveto': [30],
 +    'hvcurveto': [31]
 +  };
 +
 +  function Type1CharString() {
 +    this.width = 0;
 +    this.lsb = 0;
 +    this.flexing = false;
 +    this.output = [];
 +    this.stack = [];
 +  }
 +
 +  Type1CharString.prototype = {
 +    convert: function Type1CharString_convert(encoded, subrs) {
 +      var count = encoded.length;
 +      var error = false;
 +      for (var i = 0; i < count; i++) {
 +        var value = encoded[i];
 +        if (value < 32) {
 +          if (value === 12) {
 +            value = (value << 8) + encoded[++i];
 +          }
 +          switch (value) {
 +            case 1: // hstem
 +              if (!HINTING_ENABLED) {
 +                this.stack = [];
 +                break;
 +              }
 +              error = this.executeCommand(2, COMMAND_MAP.hstem);
 +              break;
 +            case 3: // vstem
 +              if (!HINTING_ENABLED) {
 +                this.stack = [];
 +                break;
 +              }
 +              error = this.executeCommand(2, COMMAND_MAP.vstem);
 +              break;
 +            case 4: // vmoveto
 +              if (this.flexing) {
 +                if (this.stack.length < 1) {
 +                  error = true;
 +                  break;
 +                }
 +                // Add the dx for flex and but also swap the values so they are
 +                // the right order.
 +                var dy = this.stack.pop();
 +                this.stack.push(0, dy);
 +                break;
 +              }
 +              error = this.executeCommand(1, COMMAND_MAP.vmoveto);
 +              break;
 +            case 5: // rlineto
 +              error = this.executeCommand(2, COMMAND_MAP.rlineto);
 +              break;
 +            case 6: // hlineto
 +              error = this.executeCommand(1, COMMAND_MAP.hlineto);
 +              break;
 +            case 7: // vlineto
 +              error = this.executeCommand(1, COMMAND_MAP.vlineto);
 +              break;
 +            case 8: // rrcurveto
 +              error = this.executeCommand(6, COMMAND_MAP.rrcurveto);
 +              break;
 +            case 9: // closepath
 +              // closepath is a Type1 command that does not take argument and is
 +              // useless in Type2 and it can simply be ignored.
 +              this.stack = [];
 +              break;
 +            case 10: // callsubr
 +              if (this.stack.length < 1) {
 +                error = true;
 +                break;
 +              }
 +              var subrNumber = this.stack.pop();
 +              error = this.convert(subrs[subrNumber], subrs);
 +              break;
 +            case 11: // return
 +              return error;
 +            case 13: // hsbw
 +              if (this.stack.length < 2) {
 +                error = true;
 +                break;
 +              }
 +              // 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();
 +              this.lsb = sbx;
 +              this.width = wx;
 +              this.stack.push(sbx);
 +              error = this.executeCommand(1, COMMAND_MAP.hmoveto);
 +              break;
 +            case 14: // endchar
 +              this.output.push(COMMAND_MAP.endchar[0]);
 +              break;
 +            case 21: // rmoveto
 +              if (this.flexing) {
 +                break;
 +              }
 +              error = this.executeCommand(2, COMMAND_MAP.rmoveto);
 +              break;
 +            case 22: // hmoveto
 +              if (this.flexing) {
 +                // Add the dy for flex.
 +                this.stack.push(0);
 +                break;
 +              }
 +              error = this.executeCommand(1, COMMAND_MAP.hmoveto);
 +              break;
 +            case 30: // vhcurveto
 +              error = this.executeCommand(4, COMMAND_MAP.vhcurveto);
 +              break;
 +            case 31: // hvcurveto
 +              error = this.executeCommand(4, COMMAND_MAP.hvcurveto);
 +              break;
 +            case (12 << 8) + 0: // dotsection
 +              // dotsection is a Type1 command to specify some hinting feature
 +              // for dots that do not take a parameter and it can safely be
 +              // ignored for Type2.
 +              this.stack = [];
 +              break;
 +            case (12 << 8) + 1: // vstem3
 +              if (!HINTING_ENABLED) {
 +                this.stack = [];
 +                break;
 +              }
 +              // [vh]stem3 are Type1 only and Type2 supports [vh]stem with
 +              // multiple parameters, so instead of returning [vh]stem3 take a
 +              // shortcut and return [vhstem] instead.
 +              error = this.executeCommand(2, COMMAND_MAP.vstem);
 +              break;
 +            case (12 << 8) + 2: // hstem3
 +              if (!HINTING_ENABLED) {
 +                 this.stack = [];
 +                break;
 +              }
 +              // See vstem3.
 +              error = this.executeCommand(2, COMMAND_MAP.hstem);
 +              break;
 +            case (12 << 8) + 6: // seac
 +              // seac is like type 2's special endchar but it doesn't use the
 +              // first argument asb, so remove it.
 +              if (SEAC_ANALYSIS_ENABLED) {
 +                this.seac = this.stack.splice(-4, 4);
 +                error = this.executeCommand(0, COMMAND_MAP.endchar);
 +              } else {
 +                error = this.executeCommand(4, COMMAND_MAP.endchar);
 +              }
 +              break;
 +            case (12 << 8) + 7: // sbw
 +              if (this.stack.length < 4) {
 +                error = true;
 +                break;
 +              }
 +              // To convert to type2 we have to move the width value to the
 +              // first part of the charstring and then use rmoveto with
 +              // (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();
 +              var sby = this.stack.pop();
 +              var sbx = this.stack.pop();
 +              this.lsb = sbx;
 +              this.width = wx;
 +              this.stack.push(sbx, sby);
 +              error = this.executeCommand(2, COMMAND_MAP.rmoveto);
 +              break;
 +            case (12 << 8) + 12: // div
 +              if (this.stack.length < 2) {
 +                error = true;
 +                break;
 +              }
 +              var num2 = this.stack.pop();
 +              var num1 = this.stack.pop();
 +              this.stack.push(num1 / num2);
 +              break;
 +            case (12 << 8) + 16: // callothersubr
 +              if (this.stack.length < 2) {
 +                error = true;
 +                break;
 +              }
 +              var subrNumber = this.stack.pop();
 +              var numArgs = this.stack.pop();
 +              if (subrNumber === 0 && numArgs === 3) {
 +                var flexArgs = this.stack.splice(this.stack.length - 17, 17);
 +                this.stack.push(
 +                  flexArgs[2] + flexArgs[0], // bcp1x + rpx
 +                  flexArgs[3] + flexArgs[1], // bcp1y + rpy
 +                  flexArgs[4], // bcp2x
 +                  flexArgs[5], // bcp2y
 +                  flexArgs[6], // p2x
 +                  flexArgs[7], // p2y
 +                  flexArgs[8], // bcp3x
 +                  flexArgs[9], // bcp3y
 +                  flexArgs[10], // bcp4x
 +                  flexArgs[11], // bcp4y
 +                  flexArgs[12], // p3x
 +                  flexArgs[13], // p3y
 +                  flexArgs[14] // flexDepth
 +                  // 15 = finalx unused by flex
 +                  // 16 = finaly unused by flex
 +                );
 +                error = this.executeCommand(13, COMMAND_MAP.flex, true);
 +                this.flexing = false;
 +                this.stack.push(flexArgs[15], flexArgs[16]);
 +              } else if (subrNumber === 1 && numArgs === 0) {
 +                this.flexing = true;
 +              }
 +              break;
 +            case (12 << 8) + 17: // pop
 +              // Ignore this since it is only used with othersubr.
 +              break;
 +            case (12 << 8) + 33: // setcurrentpoint
 +              // Ignore for now.
 +              this.stack = [];
 +              break;
 +            default:
 +              warn('Unknown type 1 charstring command of "' + value + '"');
 +              break;
 +          }
 +          if (error) {
 +            break;
 +          }
 +          continue;
 +        } else if (value <= 246) {
 +          value = value - 139;
 +        } else if (value <= 250) {
 +          value = ((value - 247) * 256) + encoded[++i] + 108;
 +        } else if (value <= 254) {
 +          value = -((value - 251) * 256) - encoded[++i] - 108;
 +        } else {
 +          value = (encoded[++i] & 0xff) << 24 | (encoded[++i] & 0xff) << 16 |
 +                  (encoded[++i] & 0xff) << 8 | (encoded[++i] & 0xff) << 0;
 +        }
 +        this.stack.push(value);
 +      }
 +      return error;
 +    },
 +
 +    executeCommand: function(howManyArgs, command, keepStack) {
 +      var stackLength = this.stack.length;
 +      if (howManyArgs > stackLength) {
 +        return true;
 +      }
 +      var start = stackLength - howManyArgs;
 +      for (var i = start; i < stackLength; i++) {
 +        var value = this.stack[i];
 +        if (value === (value | 0)) { // int
 +          this.output.push(28, (value >> 8) & 0xff, value & 0xff);
 +        } else { // fixed point
 +          value = (65536 * value) | 0;
 +          this.output.push(255,
 +                           (value >> 24) & 0xFF,
 +                           (value >> 16) & 0xFF,
 +                           (value >> 8) & 0xFF,
 +                           value & 0xFF);
 +        }
 +      }
 +      this.output.push.apply(this.output, command);
 +      if (keepStack) {
 +        this.stack.splice(start, howManyArgs);
 +      } else {
 +        this.stack = [];
 +      }
 +      return false;
 +    }
 +  };
 +
 +  return Type1CharString;
 +})();
 +
 +/*
 + * Type1Parser encapsulate the needed code for parsing a Type1 font
 + * program. Some of its logic depends on the Type2 charstrings
 + * structure.
++ * Note: this doesn't really parse the font since that would require evaluation
++ * of PostScript, but it is possible in most cases to extract what we need
++ * without a full parse.
 + */
- var Type1Parser = function type1Parser() {
++var Type1Parser = (function Type1ParserClosure() {
 +  /*
 +   * Decrypt a Sequence of Ciphertext Bytes to Produce the Original Sequence
 +   * of Plaintext Bytes. The function took a key as a parameter which can be
 +   * for decrypting the eexec block of for decoding charStrings.
 +   */
 +  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 = [];
 +
 +    var value = '';
 +    var count = stream.length;
 +    for (var i = 0; i < count; i++) {
 +      value = stream[i];
 +      decryptedString[i] = value ^ (r >> 8);
 +      r = ((value + r) * c1 + c2) & ((1 << 16) - 1);
 +    }
 +    return decryptedString.slice(discardNumber);
 +  }
 +
-   /*
-    * Returns an object containing a Subrs array and a CharStrings
-    * array extracted from and eexec encrypted block of data
-    */
-   function readNumberArray(str, index) {
-     var start = index;
-     while (str[index++] != '[')
-       start++;
-     start++;
- 
-     var count = 0;
-     while (str[index++] != ']')
-       count++;
- 
-     str = str.substr(start, count);
- 
-     str = str.trim();
-     // Remove adjacent spaces
-     str = str.replace(/\s+/g, ' ');
- 
-     var array = str.split(' ');
-     for (var i = 0, ii = array.length; i < ii; i++)
-       array[i] = parseFloat(array[i] || 0);
-     return array;
++  function isSpecial(c) {
++    return c === 0x2F || // '/'
++           c === 0x5B || c === 0x5D || // '[', ']'
++           c === 0x7B || c === 0x7D || // '{', '}'
++           c === 0x28 || c === 0x29; // '(', ')'
 +  }
 +
-   function readNumber(str, index) {
-     while (str[index] == ' ')
-       index++;
- 
-     var start = index;
- 
-     var count = 0;
-     while (str[index++] != ' ')
-       count++;
- 
-     return parseFloat(str.substr(start, count) || 0);
++  function Type1Parser(stream, encrypted) {
++    if (encrypted) {
++      stream = new Stream(decrypt(stream.getBytes(), EEXEC_ENCRYPT_KEY, 4));
++    }
++    this.stream = stream;
++    this.nextChar();
 +  }
 +
-   function readBoolean(str, index) {
-     while (str[index] == ' ')
-       index++;
++  Type1Parser.prototype = {
++    readNumberArray: function Type1Parser_readNumberArray() {
++      this.getToken(); // read '[' or '{' (arrays can start with either)
++      var array = [];
++      while (true) {
++        var token = this.getToken();
++        if (token === null || token === ']' || token === '}') {
++          break;
++        }
++        array.push(parseFloat(token || 0));
++      }
++      return array;
++    },
 +
-     var start = index;
++    readNumber: function Type1Parser_readNumber() {
++      var token = this.getToken();
++      return parseFloat(token || 0);
++    },
 +
-     var count = 0;
-     var length = str.length;
-     while (index < length && str[index++] != ' ') {
-       count++;
-     }
++    readInt: function Type1Parser_readInt() {
++      // Use '| 0' to prevent setting a double into length such as the double
++      // does not flow into the loop variable.
++      var token = this.getToken();
++      return parseInt(token || 0, 10) | 0;
++    },
 +
-     // Use 1 and 0 since that's what type2 charstrings use.
-     return str.substr(start, count) === 'true' ? 1 : 0;
-   }
++    readBoolean: function Type1Parser_readBoolean() {
++      var token = this.getToken();
 +
++      // Use 1 and 0 since that's what type2 charstrings use.
++      return token === 'true' ? 1 : 0;
++    },
 +
-   function isSeparator(c) {
-     return c == ' ' || c == '\n' || c == '\x0d';
-   }
++    nextChar : function Type1_nextChar() {
++      return (this.currentChar = this.stream.getByte());
++    },
 +
-   this.extractFontProgram = function Type1Parser_extractFontProgram(stream) {
-     var eexec = decrypt(stream, EEXEC_ENCRYPT_KEY, 4);
-     var eexecStr = '';
-     for (var i = 0, ii = eexec.length; i < ii; i++)
-       eexecStr += String.fromCharCode(eexec[i]);
++    getToken: function Type1Parser_getToken() {
++      // Eat whitespace and comments.
++      var comment = false;
++      var ch = this.currentChar;
++      while (true) {
++        if (ch === -1) {
++          return null;
++        }
 +
-     var glyphsSection = false, subrsSection = false;
-     var subrs = [], charstrings = [];
-     var program = {
-       subrs: [],
-       charstrings: [],
-       properties: {
-         'privateData': {
-           'lenIV': 4
++        if (comment) {
++          if (ch === 0x0A || ch === 0x0D) {
++            comment = false;
++          }
++        } else if (ch === 0x25) { // '%'
++          comment = true;
++        } else if (!Lexer.isSpace(ch)) {
++          break;
 +        }
++        ch = this.nextChar();
 +      }
-     };
- 
-     var glyph = '';
-     var token = '';
-     var length = 0;
- 
-     var c = '';
-     var count = eexecStr.length;
-     for (var i = 0; i < count; i++) {
-       var getToken = function getToken() {
-         while (i < count && isSeparator(eexecStr[i]))
-           ++i;
++      if (isSpecial(ch)) {
++        this.nextChar();
++        return String.fromCharCode(ch);
++      }
++      var token = '';
++      do {
++        token += String.fromCharCode(ch);
++        ch = this.nextChar();
++      } while (ch >= 0 && !Lexer.isSpace(ch) && !isSpecial(ch));
++      return token;
++    },
 +
-         var token = '';
-         while (i < count && !isSeparator(eexecStr[i]))
-           token += eexecStr[i++];
++    /*
++     * Returns an object containing a Subrs array and a CharStrings
++     * array extracted from and eexec encrypted block of data
++     */
++    extractFontProgram: function Type1Parser_extractFontProgram() {
++      var stream = this.stream;
 +
-         return token;
++      var subrs = [], charstrings = [];
++      var program = {
++        subrs: [],
++        charstrings: [],
++        properties: {
++          'privateData': {
++            'lenIV': 4
++          }
++        }
 +      };
-       var c = eexecStr[i];
- 
-       if ((glyphsSection || subrsSection) &&
-           (token == 'RD' || token == '-|')) {
-         i++;
-         var data = eexec.slice(i, i + length);
-         var lenIV = program.properties.privateData['lenIV'];
-         var encoded = decrypt(data, CHAR_STRS_ENCRYPT_KEY, lenIV);
++      var token;
++      while ((token = this.getToken()) !== null) {
++        if (token !== '/') {
++          continue;
++        }
++        token = this.getToken();
++        switch (token) {
++          case 'CharStrings':
++            // The number immediately following CharStrings must be greater or
++            // equal to the number of CharStrings.
++            this.getToken();
++            this.getToken(); // read in 'dict'
++            this.getToken(); // read in 'dup'
++            this.getToken(); // read in 'begin'
++            while(true) {
++              token = this.getToken();
++              if (token === null || token === 'end') {
++                break;
++              }
 +
-         if (glyphsSection) {
-           charstrings.push({
-             glyph: glyph,
-             encoded: encoded
-           });
-         } else {
-           subrs.push(encoded);
-         }
-         i += length;
-         token = '';
-       } else if (isSeparator(c)) {
-         // Use '| 0' to prevent setting a double into length such as the double
-         // does not flow into the loop variable.
-         length = parseInt(token, 10) | 0;
-         token = '';
-       } else {
-         token += c;
-         if (!glyphsSection) {
-           switch (token) {
-             case '/CharString':
-               glyphsSection = true;
-               break;
-             case '/Subrs':
-               ++i;
-               var num = parseInt(getToken(), 10);
-               getToken(); // read in 'array'
-               for (var j = 0; j < num; ++j) {
-                 var t = getToken(); // read in 'dup'
-                 if (t == 'ND' || t == '|-' || t == 'noaccess')
-                   break;
-                 var index = parseInt(getToken(), 10);
-                 if (index > j)
-                   j = index;
-                 var length = parseInt(getToken(), 10);
-                 getToken(); // read in 'RD'
-                 var data = eexec.slice(i + 1, i + 1 + length);
-                 var lenIV = program.properties.privateData['lenIV'];
-                 var encoded = decrypt(data, CHAR_STRS_ENCRYPT_KEY, lenIV);
-                 i = i + 1 + length;
-                 t = getToken(); // read in 'NP'
-                 if (t == 'noaccess')
-                   getToken(); // read in 'put'
-                 subrs[index] = encoded;
++              if (token !== '/') {
++                continue;
 +              }
-               break;
-             case '/BlueValues':
-             case '/OtherBlues':
-             case '/FamilyBlues':
-             case '/FamilyOtherBlues':
-               var blueArray = readNumberArray(eexecStr, i + 1);
-               // *Blue* values may contain invalid data: disables reading of
-               // those values when hinting is disabled.
-               if (blueArray.length > 0 && (blueArray.length % 2) === 0 &&
-                   HINTING_ENABLED) {
-                 program.properties.privateData[token.substring(1)] = blueArray;
++              var glyph = this.getToken();
++              var 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);
++              // Skip past the required space and binary data.
++              stream.skip(length);
++              this.nextChar();
++              token = this.getToken(); // read in 'ND' or '|-'
++              if (token === 'noaccess') {
++                this.getToken(); // read in 'def'
 +              }
-               break;
-             case '/StemSnapH':
-             case '/StemSnapV':
-               program.properties.privateData[token.substring(1)] =
-                 readNumberArray(eexecStr, i + 1);
-               break;
-             case '/StdHW':
-             case '/StdVW':
-               program.properties.privateData[token.substring(1)] =
-                 readNumberArray(eexecStr, i + 1)[0];
-               break;
-             case '/BlueShift':
-             case '/lenIV':
-             case '/BlueFuzz':
-             case '/BlueScale':
-             case '/LanguageGroup':
-             case '/ExpansionFactor':
-               program.properties.privateData[token.substring(1)] =
-                 readNumber(eexecStr, i + 1);
-               break;
-             case '/ForceBold':
-               program.properties.privateData[token.substring(1)] =
-                 readBoolean(eexecStr, i + 1);
-               break;
-           }
-         } else if (c == '/') {
-           token = glyph = '';
-           while ((c = eexecStr[++i]) != ' ')
-             glyph += c;
++              charstrings.push({
++                glyph: glyph,
++                encoded: encoded
++              });
++            }
++            break;
++          case 'Subrs':
++            var num = this.readInt();
++            this.getToken(); // read in 'array'
++            while ((token = this.getToken()) === 'dup') {
++              var index = this.readInt();
++              var 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);
++              // Skip past the required space and binary data.
++              stream.skip(length);
++              this.nextChar();
++              token = this.getToken(); // read in 'NP' or '|'
++              if (token === 'noaccess') {
++                this.getToken(); // read in 'put'
++              }
++              subrs[index] = encoded;
++            }
++            break;
++          case 'BlueValues':
++          case 'OtherBlues':
++          case 'FamilyBlues':
++          case 'FamilyOtherBlues':
++            var blueArray = this.readNumberArray();
++            // *Blue* values may contain invalid data: disables reading of
++            // those values when hinting is disabled.
++            if (blueArray.length > 0 && (blueArray.length % 2) === 0 &&
++                HINTING_ENABLED) {
++              program.properties.privateData[token] = blueArray;
++            }
++            break;
++          case 'StemSnapH':
++          case 'StemSnapV':
++            program.properties.privateData[token] = this.readNumberArray();
++            break;
++          case 'StdHW':
++          case 'StdVW':
++            program.properties.privateData[token] =
++              this.readNumberArray()[0];
++            break;
++          case 'BlueShift':
++          case 'lenIV':
++          case 'BlueFuzz':
++          case 'BlueScale':
++          case 'LanguageGroup':
++          case 'ExpansionFactor':
++            program.properties.privateData[token] = this.readNumber();
++            break;
++          case 'ForceBold':
++            program.properties.privateData[token] = this.readBoolean();
++            break;
 +        }
 +      }
-     }
 +
-     for (var i = 0; i < charstrings.length; i++) {
-       var glyph = charstrings[i].glyph;
-       var encoded = charstrings[i].encoded;
-       var charString = new Type1CharString();
-       var error = charString.convert(encoded, subrs);
-       var output = charString.output;
-       if (error) {
-         // It seems when FreeType encounters an error while evaluating a glyph
-         // that it completely ignores the glyph so we'll mimic that behaviour
-         // here and put an endchar to make the validator happy.
-         output = [14];
++      for (var i = 0; i < charstrings.length; i++) {
++        var glyph = charstrings[i].glyph;
++        var encoded = charstrings[i].encoded;
++        var charString = new Type1CharString();
++        var error = charString.convert(encoded, subrs);
++        var output = charString.output;
++        if (error) {
++          // It seems when FreeType encounters an error while evaluating a glyph
++          // that it completely ignores the glyph so we'll mimic that behaviour
++          // here and put an endchar to make the validator happy.
++          output = [14];
++        }
++        program.charstrings.push({
++          glyph: glyph,
++          data: output,
++          seac: charString.seac,
++          lsb: charString.lsb,
++          width: charString.width
++        });
 +      }
-       program.charstrings.push({
-         glyph: glyph,
-         data: output,
-         seac: charString.seac,
-         lsb: charString.lsb,
-         width: charString.width
-       });
-     }
- 
-     return program;
-   };
- 
-   this.extractFontHeader = function Type1Parser_extractFontHeader(stream,
-                                                                   properties) {
-     var headerString = '';
-     for (var i = 0, ii = stream.length; i < ii; i++)
-       headerString += String.fromCharCode(stream[i]);
 +
-     var token = '';
-     var count = headerString.length;
-     for (var i = 0; i < count; i++) {
-       var getToken = function getToken() {
-         var character = headerString[i];
-         while (i < count && (isSeparator(character) || character == '/'))
-           character = headerString[++i];
++      return program;
++    },
 +
-         var token = '';
-         while (i < count && !(isSeparator(character) || character == '/')) {
-           token += character;
-           character = headerString[++i];
++    extractFontHeader: function Type1Parser_extractFontHeader(properties) {
++      var token;
++      while ((token = this.getToken()) !== null) {
++        if (token !== '/') {
++          continue;
 +        }
- 
-         return token;
-       };
- 
-       var c = headerString[i];
-       if (isSeparator(c)) {
++        token = this.getToken();
 +        switch (token) {
-           case '/FontMatrix':
-             var matrix = readNumberArray(headerString, i + 1);
++          case 'FontMatrix':
++            var matrix = this.readNumberArray();
 +            properties.fontMatrix = matrix;
 +            break;
-           case '/Encoding':
-             var encodingArg = getToken();
++          case 'Encoding':
++            var encodingArg = this.getToken();
 +            var encoding;
 +            if (!/^\d+$/.test(encodingArg)) {
 +              // encoding name is specified
 +              encoding = Encodings[encodingArg];
 +            } else {
 +              encoding = [];
-               var size = parseInt(encodingArg, 10);
-               getToken(); // read in 'array'
++              var size = parseInt(encodingArg, 10) | 0;
++              this.getToken(); // read in 'array'
 +
 +              for (var j = 0; j < size; j++) {
-                 var token = getToken();
-                 if (token == 'dup') {
-                   var index = parseInt(getToken(), 10);
-                   var glyph = getToken();
-                   encoding[index] = glyph;
-                   getToken(); // read the in 'put'
++                var token = this.getToken();
++                // skipping till first dup or def (e.g. ignoring for statement)
++                while (token !== 'dup' && token !== 'def') {
++                  token = this.getToken();
++                  if (token === null) {
++                    return; // invalid header
++                  }
 +                }
++                if (token === 'def') {
++                  break; // read all array data
++                }
++                var index = this.readInt();
++                this.getToken(); // read in '/'
++                var glyph = this.getToken();
++                encoding[index] = glyph;
++                this.getToken(); // read the in 'put'
 +              }
 +            }
-             if (!properties.hasEncoding && encoding) {
++            if (properties.overridableEncoding && encoding) {
 +              properties.baseEncoding = encoding;
 +              break;
 +            }
 +            break;
++          case 'FontBBox':
++            var fontBBox = this.readNumberArray();
++            // adjusting ascent/descent
++            properties.ascent = fontBBox[3];
++            properties.descent = fontBBox[1];
++            properties.ascentScaled = true;
++            break;
 +        }
-         token = '';
-       } else {
-         token += c;
 +      }
 +    }
 +  };
- };
++
++  return Type1Parser;
++})();
 +
 +/**
 + * The CFF class takes a Type1 file and wrap it into a
 + * 'Compact Font Format' which itself embed Type2 charstrings.
 + */
 +var CFFStandardStrings = [
 +  '.notdef', 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent',
 +  'ampersand', 'quoteright', 'parenleft', 'parenright', 'asterisk', 'plus',
 +  'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 'two', 'three', 'four',
 +  'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon', 'less',
 +  'equal', 'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
 +  'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
 +  'X', 'Y', 'Z', 'bracketleft', 'backslash', 'bracketright', 'asciicircum',
 +  'underscore', 'quoteleft', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
 +  'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y',
 +  'z', 'braceleft', 'bar', 'braceright', 'asciitilde', 'exclamdown', 'cent',
 +  'sterling', 'fraction', 'yen', 'florin', 'section', 'currency',
 +  'quotesingle', 'quotedblleft', 'guillemotleft', 'guilsinglleft',
 +  'guilsinglright', 'fi', 'fl', 'endash', 'dagger', 'daggerdbl',
 +  'periodcentered', 'paragraph', 'bullet', 'quotesinglbase', 'quotedblbase',
 +  'quotedblright', 'guillemotright', 'ellipsis', 'perthousand', 'questiondown',
 +  'grave', 'acute', 'circumflex', 'tilde', 'macron', 'breve', 'dotaccent',
 +  'dieresis', 'ring', 'cedilla', 'hungarumlaut', 'ogonek', 'caron', 'emdash',
 +  'AE', 'ordfeminine', 'Lslash', 'Oslash', 'OE', 'ordmasculine', 'ae',
 +  'dotlessi', 'lslash', 'oslash', 'oe', 'germandbls', 'onesuperior',
 +  'logicalnot', 'mu', 'trademark', 'Eth', 'onehalf', 'plusminus', 'Thorn',
 +  'onequarter', 'divide', 'brokenbar', 'degree', 'thorn', 'threequarters',
 +  'twosuperior', 'registered', 'minus', 'eth', 'multiply', 'threesuperior',
 +  'copyright', 'Aacute', 'Acircumflex', 'Adieresis', 'Agrave', 'Aring',
 +  'Atilde', 'Ccedilla', 'Eacute', 'Ecircumflex', 'Edieresis', 'Egrave',
 +  'Iacute', 'Icircumflex', 'Idieresis', 'Igrave', 'Ntilde', 'Oacute',
 +  'Ocircumflex', 'Odieresis', 'Ograve', 'Otilde', 'Scaron', 'Uacute',
 +  'Ucircumflex', 'Udieresis', 'Ugrave', 'Yacute', 'Ydieresis', 'Zcaron',
 +  'aacute', 'acircumflex', 'adieresis', 'agrave', 'aring', 'atilde',
 +  'ccedilla', 'eacute', 'ecircumflex', 'edieresis', 'egrave', 'iacute',
 +  'icircumflex', 'idieresis', 'igrave', 'ntilde', 'oacute', 'ocircumflex',
 +  'odieresis', 'ograve', 'otilde', 'scaron', 'uacute', 'ucircumflex',
 +  'udieresis', 'ugrave', 'yacute', 'ydieresis', 'zcaron', 'exclamsmall',
 +  'Hungarumlautsmall', 'dollaroldstyle', 'dollarsuperior', 'ampersandsmall',
 +  'Acutesmall', 'parenleftsuperior', 'parenrightsuperior', '266 ff',
 +  'onedotenleader', 'zerooldstyle', 'oneoldstyle', 'twooldstyle',
 +  'threeoldstyle', 'fouroldstyle', 'fiveoldstyle', 'sixoldstyle',
 +  'sevenoldstyle', 'eightoldstyle', 'nineoldstyle', 'commasuperior',
 +  'threequartersemdash', 'periodsuperior', 'questionsmall', 'asuperior',
 +  'bsuperior', 'centsuperior', 'dsuperior', 'esuperior', 'isuperior',
 +  'lsuperior', 'msuperior', 'nsuperior', 'osuperior', 'rsuperior', 'ssuperior',
 +  'tsuperior', 'ff', 'ffi', 'ffl', 'parenleftinferior', 'parenrightinferior',
 +  'Circumflexsmall', 'hyphensuperior', 'Gravesmall', 'Asmall', 'Bsmall',
 +  'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall', 'Hsmall', 'Ismall',
 +  'Jsmall', 'Ksmall', 'Lsmall', 'Msmall', 'Nsmall', 'Osmall', 'Psmall',
 +  'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall', 'Vsmall', 'Wsmall',
 +  'Xsmall', 'Ysmall', 'Zsmall', 'colonmonetary', 'onefitted', 'rupiah',
 +  'Tildesmall', 'exclamdownsmall', 'centoldstyle', 'Lslashsmall',
 +  'Scaronsmall', 'Zcaronsmall', 'Dieresissmall', 'Brevesmall', 'Caronsmall',
 +  'Dotaccentsmall', 'Macronsmall', 'figuredash', 'hypheninferior',
 +  'Ogoneksmall', 'Ringsmall', 'Cedillasmall', 'questiondownsmall', 'oneeighth',
 +  'threeeighths', 'fiveeighths', 'seveneighths', 'onethird', 'twothirds',
 +  'zerosuperior', 'foursuperior', 'fivesuperior', 'sixsuperior',
 +  'sevensuperior', 'eightsuperior', 'ninesuperior', 'zeroinferior',
 +  'oneinferior', 'twoinferior', 'threeinferior', 'fourinferior',
 +  'fiveinferior', 'sixinferior', 'seveninferior', 'eightinferior',
 +  'nineinferior', 'centinferior', 'dollarinferior', 'periodinferior',
 +  'commainferior', 'Agravesmall', 'Aacutesmall', 'Acircumflexsmall',
 +  'Atildesmall', 'Adieresissmall', 'Aringsmall', 'AEsmall', 'Ccedillasmall',
 +  'Egravesmall', 'Eacutesmall', 'Ecircumflexsmall', 'Edieresissmall',
 +  'Igravesmall', 'Iacutesmall', 'Icircumflexsmall', 'Idieresissmall',
 +  'Ethsmall', 'Ntildesmall', 'Ogravesmall', 'Oacutesmall', 'Ocircumflexsmall',
 +  'Otildesmall', 'Odieresissmall', 'OEsmall', 'Oslashsmall', 'Ugravesmall',
 +  'Uacutesmall', 'Ucircumflexsmall', 'Udieresissmall', 'Yacutesmall',
 +  'Thornsmall', 'Ydieresissmall', '001.000', '001.001', '001.002', '001.003',
 +  'Black', 'Bold', 'Book', 'Light', 'Medium', 'Regular', 'Roman', 'Semibold'
 +];
 +
- var type1Parser = new Type1Parser();
- 
 +// Type1Font is also a CIDFontType0.
 +var Type1Font = function Type1Font(name, file, properties) {
++  // Some bad generators embed pfb file as is, we have to strip 6-byte headers.
++  // Also, length1 and length2 might be off by 6 bytes as well.
++  // http://www.math.ubc.ca/~cass/piscript/type1.pdf
++  var PFB_HEADER_SIZE = 6;
++  var headerBlockLength = properties.length1;
++  var eexecBlockLength = properties.length2;
++  var pfbHeader = file.peekBytes(PFB_HEADER_SIZE);
++  var pfbHeaderPresent = pfbHeader[0] == 0x80 && pfbHeader[1] == 0x01;
++  if (pfbHeaderPresent) {
++    file.skip(PFB_HEADER_SIZE);
++    headerBlockLength = (pfbHeader[5] << 24) | (pfbHeader[4] << 16) |
++                        (pfbHeader[3] << 8) | pfbHeader[2];
++  }
++
 +  // Get the data block containing glyphs and subrs informations
-   var headerBlock = file.getBytes(properties.length1);
-   type1Parser.extractFontHeader(headerBlock, properties);
++  var headerBlock = new Stream(file.getBytes(headerBlockLength));
++  var headerBlockParser = new Type1Parser(headerBlock);
++  headerBlockParser.extractFontHeader(properties);
++
++  if (pfbHeaderPresent) {
++    pfbHeader = file.getBytes(PFB_HEADER_SIZE);
++    eexecBlockLength = (pfbHeader[5] << 24) | (pfbHeader[4] << 16) |
++                       (pfbHeader[3] << 8) | pfbHeader[2];
++  }
 +
 +  // Decrypt the data blocks and retrieve it's content
-   var eexecBlock = file.getBytes(properties.length2);
-   var data = type1Parser.extractFontProgram(eexecBlock);
++  var eexecBlock = new Stream(file.getBytes(eexecBlockLength));
++  var eexecBlockParser = new Type1Parser(eexecBlock, true);
++  var data = eexecBlockParser.extractFontProgram();
 +  for (var info in data.properties)
 +    properties[info] = data.properties[info];
 +
 +  var charstrings = this.getOrderedCharStrings(data.charstrings, properties);
 +  var type2Charstrings = this.getType2Charstrings(charstrings);
 +  var subrs = this.getType2Subrs(data.subrs);
 +
 +  this.charstrings = charstrings;
 +  this.data = this.wrap(name, type2Charstrings, this.charstrings,
 +                        subrs, properties);
 +  this.seacs = this.getSeacs(data.charstrings);
 +};
 +
 +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++;
 +      }
 +      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;
 +  },
 +
 +  getSeacs: function Type1Font_getSeacs(charstrings) {
 +    var i, ii;
 +    var seacMap = [];
 +    for (i = 0, ii = charstrings.length; i < ii; i++) {
 +      var charstring = charstrings[i];
 +      if (charstring.seac) {
 +        seacMap[i] = charstring.seac;
 +      }
 +    }
 +    return seacMap;
 +  },
 +
 +  getType2Charstrings: function Type1Font_getType2Charstrings(
 +                                  type1Charstrings) {
 +    var type2Charstrings = [];
 +    for (var i = 0, ii = type1Charstrings.length; i < ii; i++) {
 +      type2Charstrings.push(type1Charstrings[i].charstring);
 +    }
 +    return type2Charstrings;
 +  },
 +
 +  getType2Subrs: function Type1Font_getType2Subrs(type1Subrs) {
 +    var bias = 0;
 +    var count = type1Subrs.length;
 +    if (count < 1133)
 +      bias = 107;
 +    else if (count < 33769)
 +      bias = 1131;
 +    else
 +      bias = 32768;
 +
 +    // Add a bunch of empty subrs to deal with the Type2 bias
 +    var type2Subrs = [];
 +    for (var i = 0; i < bias; i++)
 +      type2Subrs.push([0x0B]);
 +
 +    for (var i = 0; i < count; i++) {
 +      type2Subrs.push(type1Subrs[i]);
 +    }
 +
 +    return type2Subrs;
 +  },
 +
 +  wrap: function Type1Font_wrap(name, glyphs, charstrings, subrs, properties) {
 +    var cff = new CFF();
 +    cff.header = new CFFHeader(1, 0, 4, 4);
 +
 +    cff.names = [name];
 +
 +    var topDict = new CFFTopDict();
 +    // CFF strings IDs 0...390 are predefined names, so refering
 +    // to entries in our own String INDEX starts at SID 391.
 +    topDict.setByName('version', 391);
 +    topDict.setByName('Notice', 392);
 +    topDict.setByName('FullName', 393);
 +    topDict.setByName('FamilyName', 394);
 +    topDict.setByName('Weight', 395);
 +    topDict.setByName('Encoding', null); // placeholder
 +    topDict.setByName('FontMatrix', properties.fontMatrix);
 +    topDict.setByName('FontBBox', properties.bbox);
 +    topDict.setByName('charset', null); // placeholder
 +    topDict.setByName('CharStrings', null); // placeholder
 +    topDict.setByName('Private', null); // placeholder
 +    cff.topDict = topDict;
 +
 +    var strings = new CFFStrings();
 +    strings.add('Version 0.11'); // Version
 +    strings.add('See original notice'); // Notice
 +    strings.add(name); // FullName
 +    strings.add(name); // FamilyName
 +    strings.add('Medium'); // Weight
 +    cff.strings = strings;
 +
 +    cff.globalSubrIndex = new CFFIndex();
 +
 +    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)
 +        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++) {
 +      charStringsIndex.add(glyphs[i]);
 +    }
 +    cff.charStrings = charStringsIndex;
 +
 +    var privateDict = new CFFPrivateDict();
 +    privateDict.setByName('Subrs', null); // placeholder
 +    var fields = [
 +      'BlueValues',
 +      'OtherBlues',
 +      'FamilyBlues',
 +      'FamilyOtherBlues',
 +      'StemSnapH',
 +      'StemSnapV',
 +      'BlueShift',
 +      'BlueFuzz',
 +      'BlueScale',
 +      'LanguageGroup',
 +      'ExpansionFactor',
 +      'ForceBold',
 +      'StdHW',
 +      'StdVW'
 +    ];
 +    for (var i = 0, ii = fields.length; i < ii; i++) {
 +      var field = fields[i];
 +      if (!properties.privateData.hasOwnProperty(field))
 +        continue;
-       privateDict.setByName(field, properties.privateData[field]);
++      var value = properties.privateData[field];
++      if (isArray(value)) {
++        // All of the private dictionary array data in CFF must be stored as
++        // "delta-encoded" numbers.
++        for (var j = value.length - 1; j > 0; j--) {
++          value[j] -= value[j - 1]; // ... difference from previous value
++        }
++      }
++      privateDict.setByName(field, value);
 +    }
 +    cff.topDict.privateDict = privateDict;
 +
 +    var subrIndex = new CFFIndex();
 +    for (var i = 0, ii = subrs.length; i < ii; i++) {
 +      subrIndex.add(subrs[i]);
 +    }
 +    privateDict.subrsIndex = subrIndex;
 +
 +    var compiler = new CFFCompiler(cff);
 +    return compiler.compile();
 +  }
 +};
 +
 +var CFFFont = (function CFFFontClosure() {
 +  function CFFFont(file, properties) {
 +    this.properties = properties;
 +
 +    var parser = new CFFParser(file, properties);
-     var cff = parser.parse();
-     var compiler = new CFFCompiler(cff);
-     this.readExtra(cff);
++    this.cff = parser.parse();
++    var compiler = new CFFCompiler(this.cff);
++    this.readExtra();
 +    try {
 +      this.data = compiler.compile();
 +    } catch (e) {
 +      warn('Failed to compile font ' + properties.loadedName);
 +      // There may have just been an issue with the compiler, set the data
 +      // anyway and hope the font loaded.
 +      this.data = file;
 +    }
 +  }
 +
 +  CFFFont.prototype = {
-     readExtra: function CFFFont_readExtra(cff) {
++    readExtra: function CFFFont_readExtra() {
 +      // charstrings contains info about glyphs (one element per glyph
 +      // containing mappings for {unicode, width})
-       var charset = cff.charset.charset;
-       var encoding = cff.encoding ? cff.encoding.encoding : null;
-       var charstrings = this.getCharStrings(charset, encoding);
++      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 = cff.seacs;
++      this.seacs = this.cff.seacs;
 +    },
-     getCharStrings: function CFFFont_getCharStrings(charsets, encoding) {
++    getCharStrings: function CFFFont_getCharStrings() {
++      var cff = this.cff;
++      var charsets = cff.charset.charset;
++      var encoding = cff.encoding ? cff.encoding.encoding : null;
 +      var charstrings = [];
 +      var unicodeUsed = [];
 +      var unassignedUnicodeItems = [];
 +      var inverseEncoding = [];
-       // CID fonts don't have an encoding.
-       if (encoding !== null)
-         for (var charcode in encoding)
-           inverseEncoding[encoding[charcode]] = charcode | 0;
-       else
-         inverseEncoding = charsets;
-       var i = charsets[0] == '.notdef' ? 1 : 0;
-       for (var ii = charsets.length; i < ii; i++) {
++      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) {
++          // If the font is actually a CID font then we should use the charset
++          // to map CIDs to GIDs.
++          inverseEncoding = charsets;
++        } 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 (var i = gidStart, ii = charsets.length; i < ii; i++) {
 +        var glyph = charsets[i];
 +
-         var code = inverseEncoding[i];
-         if (!code || isSpecialUnicode(code)) {
-           unassignedUnicodeItems.push(i);
-           continue;
++        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;
 +        }
-         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) {
++      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: inverseEncoding[i] || 0,
++          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;
 +    }
 +  };
 +
 +  return CFFFont;
 +})();
 +
 +var CFFParser = (function CFFParserClosure() {
 +  var CharstringValidationData = [
 +    null,
 +    { id: 'hstem', min: 2, resetStack: true, stem: true },
 +    null,
 +    { id: 'vstem', min: 2, resetStack: true, stem: true },
 +    { id: 'vmoveto', min: 1, resetStack: true },
 +    { id: 'rlineto', min: 2, resetStack: true },
 +    { id: 'hlineto', min: 1, resetStack: true },
 +    { id: 'vlineto', min: 1, resetStack: true },
 +    { id: 'rrcurveto', min: 6, resetStack: true },
 +    null,
 +    { id: 'callsubr', min: 1, undefStack: true },
 +    { id: 'return', min: 0, undefStack: true },
 +    null, // 12
 +    null,
 +    null, // endchar
 +    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: 'rcurveline', min: 8, resetStack: true },
 +    { id: 'rlinecurve', min: 8, resetStack: true },
 +    { id: 'vvcurveto', min: 4, resetStack: true },
 +    { id: 'hhcurveto', min: 4, resetStack: true },
 +    null, // shortint
 +    { id: 'callgsubr', min: 1, undefStack: true },
 +    { id: 'vhcurveto', min: 4, resetStack: true },
 +    { id: 'hvcurveto', min: 4, resetStack: true }
 +  ];
 +  var CharstringValidationData12 = [
 +    null,
 +    null,
 +    null,
 +    { id: 'and', min: 2, stackDelta: -1 },
 +    { id: 'or', min: 2, stackDelta: -1 },
 +    { id: 'not', min: 1, stackDelta: 0 },
 +    null,
 +    null,
 +    null,
 +    { id: 'abs', min: 1, stackDelta: 0 },
 +    { id: 'add', min: 2, stackDelta: -1,
 +      stackFn: function stack_div(stack, index) {
 +        stack[index - 2] = stack[index - 2] + stack[index - 1];
 +      }
 +    },
 +    { id: 'sub', min: 2, stackDelta: -1,
 +      stackFn: function stack_div(stack, index) {
 +        stack[index - 2] = stack[index - 2] - stack[index - 1];
 +      }
 +    },
 +    { id: 'div', min: 2, stackDelta: -1,
 +      stackFn: function stack_div(stack, index) {
 +        stack[index - 2] = stack[index - 2] / stack[index - 1];
 +      }
 +    },
 +    null,
 +    { id: 'neg', min: 1, stackDelta: 0,
 +      stackFn: function stack_div(stack, index) {
 +        stack[index - 1] = -stack[index - 1];
 +      }
 +    },
 +    { id: 'eq', min: 2, stackDelta: -1 },
 +    null,
 +    null,
 +    { id: 'drop', min: 1, stackDelta: -1 },
 +    null,
 +    { id: 'put', min: 2, stackDelta: -2 },
 +    { id: 'get', min: 1, stackDelta: 0 },
 +    { id: 'ifelse', min: 4, stackDelta: -3 },
 +    { id: 'random', min: 0, stackDelta: 1 },
 +    { id: 'mul', min: 2, stackDelta: -1,
 +      stackFn: function stack_div(stack, index) {
 +        stack[index - 2] = stack[index - 2] * stack[index - 1];
 +      }
 +    },
 +    null,
 +    { id: 'sqrt', min: 1, stackDelta: 0 },
 +    { id: 'dup', min: 1, stackDelta: 1 },
 +    { id: 'exch', min: 2, stackDelta: 0 },
 +    { id: 'index', min: 2, stackDelta: 0 },
 +    { id: 'roll', min: 3, stackDelta: -2 },
 +    null,
 +    null,
 +    null,
 +    { id: 'hflex', min: 7, resetStack: true },
 +    { id: 'flex', min: 13, resetStack: true },
 +    { id: 'hflex1', min: 9, resetStack: true },
 +    { id: 'flex1', min: 11, resetStack: true }
 +  ];
 +
 +  function CFFParser(file, properties) {
 +    this.bytes = file.getBytes();
 +    this.properties = properties;
 +  }
 +  CFFParser.prototype = {
 +    parse: function CFFParser_parse() {
 +      var properties = this.properties;
 +      var cff = new CFF();
 +      this.cff = cff;
 +
 +      // The first five sections must be in order, all the others are reached
 +      // via offsets contained in one of the below.
 +      var header = this.parseHeader();
 +      var nameIndex = this.parseIndex(header.endPos);
 +      var topDictIndex = this.parseIndex(nameIndex.endPos);
 +      var stringIndex = this.parseIndex(topDictIndex.endPos);
 +      var globalSubrIndex = this.parseIndex(stringIndex.endPos);
 +
 +      var topDictParsed = this.parseDict(topDictIndex.obj.get(0));
 +      var topDict = this.createDict(CFFTopDict, topDictParsed, cff.strings);
 +
 +      cff.header = header.obj;
 +      cff.names = this.parseNameIndex(nameIndex.obj);
 +      cff.strings = this.parseStringIndex(stringIndex.obj);
 +      cff.topDict = topDict;
 +      cff.globalSubrIndex = globalSubrIndex.obj;
 +
 +      this.parsePrivateDict(cff.topDict);
 +
 +      cff.isCIDFont = topDict.hasName('ROS');
 +
 +      var charStringOffset = topDict.getByName('CharStrings');
 +      var charStringsAndSeacs = this.parseCharStrings(charStringOffset);
 +      cff.charStrings = charStringsAndSeacs.charStrings;
 +      cff.seacs = charStringsAndSeacs.seacs;
 +
 +      var fontMatrix = topDict.getByName('FontMatrix');
 +      if (fontMatrix) {
 +        properties.fontMatrix = fontMatrix;
 +      }
 +
 +      var fontBBox = topDict.getByName('FontBBox');
 +      if (fontBBox) {
 +        // adjusting ascent/descent
 +        properties.ascent = fontBBox[3];
 +        properties.descent = fontBBox[1];
 +        properties.ascentScaled = true;
 +      }
 +
 +      var charset, encoding;
 +      if (cff.isCIDFont) {
 +        var fdArrayIndex = this.parseIndex(topDict.getByName('FDArray')).obj;
 +        for (var i = 0, ii = fdArrayIndex.count; i < ii; ++i) {
 +          var dictRaw = fdArrayIndex.get(i);
 +          var fontDict = this.createDict(CFFTopDict, this.parseDict(dictRaw),
 +                                         cff.strings);
 +          this.parsePrivateDict(fontDict);
 +          cff.fdArray.push(fontDict);
 +        }
 +        // cid fonts don't have an encoding
 +        encoding = null;
 +        charset = this.parseCharsets(topDict.getByName('charset'),
 +                                     cff.charStrings.count, cff.strings, true);
 +        cff.fdSelect = this.parseFDSelect(topDict.getByName('FDSelect'),
 +                                             cff.charStrings.count);
 +      } else {
 +        charset = this.parseCharsets(topDict.getByName('charset'),
 +                                     cff.charStrings.count, cff.strings, false);
 +        encoding = this.parseEncoding(topDict.getByName('Encoding'),
 +                                      properties,
 +                                      cff.strings, charset.charset);
 +      }
 +      cff.charset = charset;
 +      cff.encoding = encoding;
 +
 +      return cff;
 +    },
 +    parseHeader: function CFFParser_parseHeader() {
 +      var bytes = this.bytes;
 +      var offset = 0;
 +
 +      while (bytes[offset] != 1)
 +        ++offset;
 +
 +      if (offset !== 0) {
 +        info('cff data is shifted');
 +        bytes = bytes.subarray(offset);
 +        this.bytes = bytes;
 +      }
 +      var major = bytes[0];
 +      var minor = bytes[1];
 +      var hdrSize = bytes[2];
 +      var offSize = bytes[3];
 +      var header = new CFFHeader(major, minor, hdrSize, offSize);
 +      return {obj: header, endPos: hdrSize};
 +    },
 +    parseDict: function CFFParser_parseDict(dict) {
 +      var pos = 0;
 +
 +      function parseOperand() {
 +        var value = dict[pos++];
 +        if (value === 30) {
 +          return parseFloatOperand(pos);
 +        } else if (value === 28) {
 +          value = dict[pos++];
 +          value = ((value << 24) | (dict[pos++] << 16)) >> 16;
 +          return value;
 +        } else if (value === 29) {
 +          value = dict[pos++];
 +          value = (value << 8) | dict[pos++];
 +          value = (value << 8) | dict[pos++];
 +          value = (value << 8) | dict[pos++];
 +          return value;
 +        } else if (value >= 32 && value <= 246) {
 +          return value - 139;
 +        } else if (value >= 247 && value <= 250) {
 +          return ((value - 247) * 256) + dict[pos++] + 108;
 +        } else if (value >= 251 && value <= 254) {
 +          return -((value - 251) * 256) - dict[pos++] - 108;
 +        } else {
 +          error('255 is not a valid DICT command');
 +        }
 +        return -1;
 +      }
 +
 +      function parseFloatOperand() {
 +        var str = '';
 +        var eof = 15;
 +        var lookup = ['0', '1', '2', '3', '4', '5', '6', '7', '8',
 +            '9', '.', 'E', 'E-', null, '-'];
 +        var length = dict.length;
 +        while (pos < length) {
 +          var b = dict[pos++];
 +          var b1 = b >> 4;
 +          var b2 = b & 15;
 +
 +          if (b1 == eof)
 +            break;
 +          str += lookup[b1];
 +
 +          if (b2 == eof)
 +            break;
 +          str += lookup[b2];
 +        }
 +        return parseFloat(str);
 +      }
 +
 +      var operands = [];
 +      var entries = [];
 +
 +      var pos = 0;
 +      var end = dict.length;
 +      while (pos < end) {
 +        var b = dict[pos];
 +        if (b <= 21) {
 +          if (b === 12)
 +            b = (b << 8) | dict[++pos];
 +          entries.push([b, operands]);
 +          operands = [];
 +          ++pos;
 +        } else {
 +          operands.push(parseOperand());
 +        }
 +      }
 +      return entries;
 +    },
 +    parseIndex: function CFFParser_parseIndex(pos) {
 +      var cffIndex = new CFFIndex();
 +      var bytes = this.bytes;
 +      var count = (bytes[pos++] << 8) | bytes[pos++];
 +      var offsets = [];
 +      var start = pos;
 +      var end = pos;
 +
 +      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) {
 +          var offset = 0;
 +          for (var j = 0; j < offsetSize; ++j) {
 +            offset <<= 8;
 +            offset += bytes[pos++];
 +          }
 +          offsets.push(startPos + offset);
 +        }
 +        end = offsets[count];
 +      }
 +      for (var i = 0, ii = offsets.length - 1; i < ii; ++i) {
 +        var offsetStart = offsets[i];
 +        var offsetEnd = offsets[i + 1];
 +        cffIndex.add(bytes.subarray(offsetStart, offsetEnd));
 +      }
 +      return {obj: cffIndex, endPos: end};
 +    },
 +    parseNameIndex: function CFFParser_parseNameIndex(index) {
 +      var names = [];
 +      for (var i = 0, ii = index.count; i < ii; ++i) {
 +        var name = index.get(i);
 +        // OTS doesn't allow names to be over 127 characters.
 +        var length = Math.min(name.length, 127);
 +        var data = [];
 +        // OTS also only permits certain characters in the name.
 +        for (var j = 0; j < length; ++j) {
 +          var c = name[j];
 +          if (j === 0 && c === 0) {
 +            data[j] = c;
 +            continue;
 +          }
 +          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 /* % */) {
 +            data[j] = 95;
 +            continue;
 +          }
 +          data[j] = c;
 +        }
 +        names.push(String.fromCharCode.apply(null, data));
 +      }
 +      return names;
 +    },
 +    parseStringIndex: function CFFParser_parseStringIndex(index) {
 +      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));
 +      }
 +      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];
 +        var value = pair[1];
 +        cffDict.setByKey(key, value);
 +      }
 +      return cffDict;
 +    },
 +    parseCharStrings: function CFFParser_parseCharStrings(charStringOffset) {
 +      var charStrings = this.parseIndex(charStringOffset).obj;
 +      var seacs = [];
 +      var count = charStrings.count;
 +      for (var i = 0; i < count; i++) {
 +        var charstring = charStrings.get(i);
 +
 +        var stackSize = 0;
 +        var stack = [];
 +        var undefStack = true;
 +        var hints = 0;
 +        var valid = true;
 +        var data = charstring;
 +        var length = data.length;
 +        for (var j = 0; j < length;) {
 +          var value = data[j++];
 +          var validationCommand = null;
 +          if (value == 12) {
 +            var q = data[j++];
 +            if (q === 0) {
 +              // The CFF specification state that the 'dotsection' command
 +              // (12, 0) is deprecated and treated as a no-op, but all Type2
 +              // charstrings processors should support them. Unfortunately
 +              // the font sanitizer don't. As a workaround the sequence (12, 0)
 +              // is replaced by a useless (0, hmoveto).
 +              data[j - 2] = 139;
 +              data[j - 1] = 22;
 +              stackSize = 0;
 +            } else {
 +              validationCommand = CharstringValidationData12[q];
 +            }
 +          } else if (value === 28) { // number (16 bit)
 +            stack[stackSize] = ((data[j] << 24) | (data[j + 1] << 16)) >> 16;
 +            j += 2;
 +            stackSize++;
 +          } else if (value == 14) {
 +            if (stackSize >= 4) {
 +              stackSize -= 4;
 +              if (SEAC_ANALYSIS_ENABLED) {
 +                seacs[i] = stack.slice(stackSize, stackSize + 4);
 +                valid = false;
 +              }
 +            }
 +          } 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;
 +            j++;
 +            stackSize++;
 +          } else if (value == 255) {  // number (32 bit)
 +            stack[stackSize] = ((data[j] << 24) | (data[j + 1] << 16) |
 +              (data[j + 2] << 8) | data[j + 3]) / 65536;
 +            j += 4;
 +            stackSize++;
 +          } else if (value == 19 || value == 20) {
 +            hints += stackSize >> 1;
 +            j += (hints + 7) >> 3; // skipping right amount of hints flag data
 +            stackSize = 0;
 +          } else {
 +            validationCommand = CharstringValidationData[value];
 +          }
 +          if (validationCommand) {
 +            if (validationCommand.stem) {
 +              hints += stackSize >> 1;
 +            }
 +            if ('min' in validationCommand) {
 +              if (!undefStack && stackSize < validationCommand.min) {
 +                warn('Not enough parameters for ' + validationCommand.id +
 +                     '; actual: ' + stackSize +
 +                     ', expected: ' + validationCommand.min);
 +                valid = false;
 +                break;
 +              }
 +            }
 +            if ('stackDelta' in validationCommand) {
 +              if ('stackFn' in validationCommand) {
 +                validationCommand.stackFn(stack, stackSize);
 +              }
 +              stackSize += validationCommand.stackDelta;
 +            } else if (validationCommand.resetStack) {
 +              stackSize = 0;
 +              undefStack = false;
 +            } else if (validationCommand.undefStack) {
 +              stackSize = 0;
 +              undefStack = true;
 +            }
 +          }
 +        }
 +        if (!valid) {
 +          // resetting invalid charstring to single 'endchar'
 +          charStrings.set(i, new Uint8Array([14]));
 +        }
 +      }
 +      return { charStrings: charStrings, seacs: seacs };
 +    },
 +    emptyPrivateDictionary:
 +      function CFFParser_emptyPrivateDictionary(parentDict) {
 +      var privateDict = this.createDict(CFFPrivateDict, [],
 +                                        parentDict.strings);
 +      parentDict.setByKey(18, [0, 0]);
 +      parentDict.privateDict = privateDict;
 +    },
 +    parsePrivateDict: function CFFParser_parsePrivateDict(parentDict) {
 +      // no private dict, do nothing
 +      if (!parentDict.hasName('Private')) {
 +        this.emptyPrivateDictionary(parentDict);
 +        return;
 +      }
 +      var privateOffset = parentDict.getByName('Private');
 +      // make sure the params are formatted correctly
 +      if (!isArray(privateOffset) || privateOffset.length !== 2) {
 +        parentDict.removeByName('Private');
 +        return;
 +      }
 +      var size = privateOffset[0];
 +      var offset = privateOffset[1];
 +      // remove empty dicts or ones that refer to invalid location
 +      if (size === 0 || offset >= this.bytes.length) {
 +        this.emptyPrivateDictionary(parentDict);
 +        return;
 +      }
 +
 +      var privateDictEnd = offset + size;
 +      var dictData = this.bytes.subarray(offset, privateDictEnd);
 +      var dict = this.parseDict(dictData);
 +      var privateDict = this.createDict(CFFPrivateDict, dict,
 +                                        parentDict.strings);
 +      parentDict.privateDict = privateDict;
 +
 +      // Parse the Subrs index also since it's relative to the private dict.
 +      if (!privateDict.getByName('Subrs'))
 +        return;
 +      var subrsOffset = privateDict.getByName('Subrs');
 +      var relativeOffset = offset + subrsOffset;
 +      // Validate the offset.
 +      if (subrsOffset === 0 || relativeOffset >= this.bytes.length) {
 +        this.emptyPrivateDictionary(parentDict);
 +        return;
 +      }
 +      var subrsIndex = this.parseIndex(relativeOffset);
 +      privateDict.subrsIndex = subrsIndex.obj;
 +    },
 +    parseCharsets: function CFFParser_parseCharsets(pos, length, strings, cid) {
 +      if (pos === 0) {
 +        return new CFFCharset(true, CFFCharsetPredefinedTypes.ISO_ADOBE,
 +                              ISOAdobeCharset);
 +      } else if (pos == 1) {
 +        return new CFFCharset(true, CFFCharsetPredefinedTypes.EXPERT,
 +                              ExpertCharset);
 +      } else if (pos == 2) {
 +        return new CFFCharset(true, CFFCharsetPredefinedTypes.EXPERT_SUBSET,
 +                              ExpertSubsetCharset);
 +      }
 +
 +      var bytes = this.bytes;
 +      var start = pos;
 +      var format = bytes[pos++];
 +      var charset = ['.notdef'];
 +
 +      // 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++];
 +            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++)
 +              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++)
 +              charset.push(cid ? id++ : strings.get(id++));
 +          }
 +          break;
 +        default:
 +          error('Unknown charset format');
 +      }
 +      // Raw won't be needed if we actually compile the charset.
 +      var end = pos;
 +      var raw = bytes.subarray(start, end);
 +
 +      return new CFFCharset(false, format, charset, raw);
 +    },
 +    parseEncoding: function CFFParser_parseEncoding(pos,
 +                                                    properties,
 +                                                    strings,
 +                                                    charset) {
 +      var encoding = {};
 +      var bytes = this.bytes;
 +      var predefined = false;
 +      var hasSupplement = false;
 +      var format;
 +      var raw = null;
 +
 +      function readSupplement() {
 +        var supplementsCount = bytes[pos++];
 +        for (var i = 0; i < supplementsCount; i++) {
 +          var code = bytes[pos++];
 +          var sid = (bytes[pos++] << 8) + (bytes[pos++] & 0xff);
-           encoding[code] = properties.differences.indexOf(strings.get(sid));
++          encoding[code] = charset.indexOf(strings.get(sid));
 +        }
 +      }
 +
 +      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++) {
 +          var index = baseEncoding.indexOf(charset[i]);
 +          if (index != -1) {
 +            encoding[index] = i;
 +          }
 +        }
 +      } else {
 +        var dataStart = pos;
 +        var format = bytes[pos++];
 +        switch (format & 0x7f) {
 +          case 0:
 +            var glyphsCount = bytes[pos++];
 +            for (var 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++) {
 +              var start = bytes[pos++];
 +              var left = bytes[pos++];
 +              for (var j = start; j <= start + left; j++)
 +                encoding[j] = gid++;
 +            }
 +            break;
 +
 +          default:
 +            error('Unknow encoding format: ' + format + ' in CFF');
 +            break;
 +        }
 +        var dataEnd = pos;
 +        if (format & 0x80) {
 +          // The font sanitizer does not support CFF encoding with a
 +          // supplement, since the encoding is not really used to map
 +          // between gid to glyph, let's overwrite what is declared in
 +          // the top dictionary to let the sanitizer think the font use
 +          // StandardEncoding, that's a lie but that's ok.
 +          bytes[dataStart] &= 0x7f;
 +          readSupplement();
 +          hasSupplement = true;
 +        }
 +        raw = bytes.subarray(dataStart, dataEnd);
 +      }
 +      format = format & 0x7f;
 +      return new CFFEncoding(predefined, format, encoding, raw);
 +    },
 +    parseFDSelect: function CFFParser_parseFDSelect(pos, length) {
 +      var start = pos;
 +      var bytes = this.bytes;
 +      var format = bytes[pos++];
 +      var fdSelect = [];
 +      switch (format) {
 +        case 0:
 +          for (var 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) {
 +            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)
 +              fdSelect.push(fdIndex);
 +          }
 +          // Advance past the sentinel(next).
 +          pos += 2;
 +          break;
 +        default:
 +          error('Unknown fdselect format ' + format);
 +          break;
 +      }
 +      var end = pos;
 +      return new CFFFDSelect(fdSelect, bytes.subarray(start, end));
 +    }
 +  };
 +  return CFFParser;
 +})();
 +
 +// Compact Font Format
 +var CFF = (function CFFClosure() {
 +  function CFF() {
 +    this.header = null;
 +    this.names = [];
 +    this.topDict = null;
 +    this.strings = new CFFStrings();
 +    this.globalSubrIndex = null;
 +
 +    // The following could really be per font, but since we only have one font
 +    // store them here.
 +    this.encoding = null;
 +    this.charset = null;
 +    this.charStrings = null;
 +    this.fdArray = [];
 +    this.fdSelect = null;
 +
 +    this.isCIDFont = false;
 +  }
 +  return CFF;
 +})();
 +
 +var CFFHeader = (function CFFHeaderClosure() {
 +  function CFFHeader(major, minor, hdrSize, offSize) {
 +    this.major = major;
 +    this.minor = minor;
 +    this.hdrSize = hdrSize;
 +    this.offSize = offSize;
 +  }
 +  return CFFHeader;
 +})();
 +
 +var CFFStrings = (function CFFStringsClosure() {
 +  function CFFStrings() {
 +    this.strings = [];
 +  }
 +  CFFStrings.prototype = {
 +    get: function CFFStrings_get(index) {
 +      if (index >= 0 && index <= 390)
 +        return CFFStandardStrings[index];
 +      if (index - 391 <= this.strings.length)
 +        return this.strings[index - 391];
 +      return CFFStandardStrings[0];
 +    },
 +    add: function CFFStrings_add(value) {
 +      this.strings.push(value);
 +    },
 +    get count() {
 +      return this.strings.length;
 +    }
 +  };
 +  return CFFStrings;
 +})();
 +
 +var CFFIndex = (function CFFIndexClosure() {
 +  function CFFIndex() {
 +    this.objects = [];
 +    this.length = 0;
 +  }
 +  CFFIndex.prototype = {
 +    add: function CFFIndex_add(data) {
 +      this.length += data.length;
 +      this.objects.push(data);
 +    },
 +    set: function CFFIndex_set(index, data) {
 +      this.length += data.length - this.objects[index].length;
 +      this.objects[index] = data;
 +    },
 +    get: function CFFIndex_get(index) {
 +      return this.objects[index];
 +    },
 +    get count() {
 +      return this.objects.length;
 +    }
 +  };
 +  return CFFIndex;
 +})();
 +
 +var CFFDict = (function CFFDictClosure() {
 +  function CFFDict(tables, strings) {
 +    this.keyToNameMap = tables.keyToNameMap;
 +    this.nameToKeyMap = tables.nameToKeyMap;
 +    this.defaults = tables.defaults;
 +    this.types = tables.types;
 +    this.opcodes = tables.opcodes;
 +    this.order = tables.order;
 +    this.strings = strings;
 +    this.values = {};
 +  }
 +  CFFDict.prototype = {
 +    // value should always be an array
 +    setByKey: function CFFDict_setByKey(key, value) {
 +      if (!(key in this.keyToNameMap))
 +        return false;
 +      // ignore empty values
 +      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')
 +        value = value[0];
 +      this.values[key] = value;
 +      return true;
 +    },
 +    setByName: function CFFDict_setByName(name, value) {
 +      if (!(name in this.nameToKeyMap)) {
 +        error('Invalid dictionary name "' + name + '"');
 +      }
 +      this.values[this.nameToKeyMap[name]] = value;
 +    },
 +    hasName: function CFFDict_hasName(name) {
 +      return this.nameToKeyMap[name] in this.values;
 +    },
 +    getByName: function CFFDict_getByName(name) {
 +      if (!(name in this.nameToKeyMap))
 +        error('Invalid dictionary name "' + name + '"');
 +      var key = this.nameToKeyMap[name];
 +      if (!(key in this.values))
 +        return this.defaults[key];
 +      return this.values[key];
 +    },
 +    removeByName: function CFFDict_removeByName(name) {
 +      delete this.values[this.nameToKeyMap[name]];
 +    }
 +  };
 +  CFFDict.createTables = function CFFDict_createTables(layout) {
 +    var tables = {
 +      keyToNameMap: {},
 +      nameToKeyMap: {},
 +      defaults: {},
 +      types: {},
 +      opcodes: {},
 +      order: []
 +    };
 +    for (var i = 0, ii = layout.length; i < ii; ++i) {
 +      var entry = layout[i];
 +      var key = isArray(entry[0]) ? (entry[0][0] << 8) + entry[0][1] : entry[0];
 +      tables.keyToNameMap[key] = entry[1];
 +      tables.nameToKeyMap[entry[1]] = key;
 +      tables.types[key] = entry[2];
 +      tables.defaults[key] = entry[3];
 +      tables.opcodes[key] = isArray(entry[0]) ? entry[0] : [entry[0]];
 +      tables.order.push(key);
 +    }
 +    return tables;
 +  };
 +  return CFFDict;
 +})();
 +
 +var CFFTopDict = (function CFFTopDictClosure() {
 +  var layout = [
 +    [[12, 30], 'ROS', ['sid', 'sid', 'num'], null],
 +    [[12, 20], 'SyntheticBase', 'num', null],
 +    [0, 'version', 'sid', null],
 +    [1, 'Notice', 'sid', null],
 +    [[12, 0], 'Copyright', 'sid', null],
 +    [2, 'FullName', 'sid', null],
 +    [3, 'FamilyName', 'sid', null],
 +    [4, 'Weight', 'sid', null],
 +    [[12, 1], 'isFixedPitch', 'num', 0],
 +    [[12, 2], 'ItalicAngle', 'num', 0],
 +    [[12, 3], 'UnderlinePosition', 'num', -100],
 +    [[12, 4], 'UnderlineThickness', 'num', 50],
 +    [[12, 5], 'PaintType', 'num', 0],
 +    [[12, 6], 'CharstringType', 'num', 2],
 +    [[12, 7], 'FontMatrix', ['num', 'num', 'num', 'num', 'num', 'num'],
 +                            [0.001, 0, 0, 0.001, 0, 0]],
 +    [13, 'UniqueID', 'num', null],
 +    [5, 'FontBBox', ['num', 'num', 'num', 'num'], [0, 0, 0, 0]],
 +    [[12, 8], 'StrokeWidth', 'num', 0],
 +    [14, 'XUID', 'array', null],
 +    [15, 'charset', 'offset', 0],
 +    [16, 'Encoding', 'offset', 0],
 +    [17, 'CharStrings', 'offset', 0],
 +    [18, 'Private', ['offset', 'offset'], null],
 +    [[12, 21], 'PostScript', 'sid', null],
 +    [[12, 22], 'BaseFontName', 'sid', null],
 +    [[12, 23], 'BaseFontBlend', 'delta', null],
 +    [[12, 31], 'CIDFontVersion', 'num', 0],
 +    [[12, 32], 'CIDFontRevision', 'num', 0],
 +    [[12, 33], 'CIDFontType', 'num', 0],
 +    [[12, 34], 'CIDCount', 'num', 8720],
 +    [[12, 35], 'UIDBase', 'num', null],
 +    // XXX: CID Fonts on DirectWrite 6.1 only seem to work if FDSelect comes
 +    // before FDArray.
 +    [[12, 37], 'FDSelect', 'offset', null],
 +    [[12, 36], 'FDArray', 'offset', null],
 +    [[12, 38], 'FontName', 'sid', null]
 +  ];
 +  var tables = null;
 +  function CFFTopDict(strings) {
 +    if (tables === null)
 +      tables = CFFDict.createTables(layout);
 +    CFFDict.call(this, tables, strings);
 +    this.privateDict = null;
 +  }
 +  CFFTopDict.prototype = Object.create(CFFDict.prototype);
 +  return CFFTopDict;
 +})();
 +
 +var CFFPrivateDict = (function CFFPrivateDictClosure() {
 +  var layout = [
 +    [6, 'BlueValues', 'delta', null],
 +    [7, 'OtherBlues', 'delta', null],
 +    [8, 'FamilyBlues', 'delta', null],
 +    [9, 'FamilyOtherBlues', 'delta', null],
 +    [[12, 9], 'BlueScale', 'num', 0.039625],
 +    [[12, 10], 'BlueShift', 'num', 7],
 +    [[12, 11], 'BlueFuzz', 'num', 1],
 +    [10, 'StdHW', 'num', null],
 +    [11, 'StdVW', 'num', null],
 +    [[12, 12], 'StemSnapH', 'delta', null],
 +    [[12, 13], 'StemSnapV', 'delta', null],
 +    [[12, 14], 'ForceBold', 'num', 0],
 +    [[12, 17], 'LanguageGroup', 'num', 0],
 +    [[12, 18], 'ExpansionFactor', 'num', 0.06],
 +    [[12, 19], 'initialRandomSeed', 'num', 0],
 +    [20, 'defaultWidthX', 'num', 0],
 +    [21, 'nominalWidthX', 'num', 0],
 +    [19, 'Subrs', 'offset', null]
 +  ];
 +  var tables = null;
 +  function CFFPrivateDict(strings) {
 +    if (tables === null)
 +      tables = CFFDict.createTables(layout);
 +    CFFDict.call(this, tables, strings);
 +    this.subrsIndex = null;
 +  }
 +  CFFPrivateDict.prototype = Object.create(CFFDict.prototype);
 +  return CFFPrivateDict;
 +})();
 +
 +var CFFCharsetPredefinedTypes = {
 +  ISO_ADOBE: 0,
 +  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;
 +    this.format = format;
 +    this.charset = charset;
 +    this.raw = raw;
 +  }
 +  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;
 +    this.format = format;
 +    this.encoding = encoding;
 +    this.raw = raw;
 +  }
 +  return CFFEncoding;
 +})();
 +
 +var CFFFDSelect = (function CFFFDSelectClosure() {
 +  function CFFFDSelect(fdSelect, raw) {
 +    this.fdSelect = fdSelect;
 +    this.raw = raw;
 +  }
 +  return CFFFDSelect;
 +})();
 +
 +// Helper class to keep track of where an offset is within the data and helps
 +// filling in that offset once it's known.
 +var CFFOffsetTracker = (function CFFOffsetTrackerClosure() {
 +  function CFFOffsetTracker() {
 +    this.offsets = {};
 +  }
 +  CFFOffsetTracker.prototype = {
 +    isTracking: function CFFOffsetTracker_isTracking(key) {
 +      return key in this.offsets;
 +    },
 +    track: function CFFOffsetTracker_track(key, location) {
 +      if (key in this.offsets)
 +        error('Already tracking location of ' + key);
 +      this.offsets[key] = location;
 +    },
 +    offset: function CFFOffsetTracker_offset(value) {
 +      for (var key in this.offsets) {
 +        this.offsets[key] += value;
 +      }
 +    },
 +    setEntryLocation: function CFFOffsetTracker_setEntryLocation(key,
 +                                                                 values,
 +                                                                 output) {
 +      if (!(key in this.offsets))
 +        error('Not tracking location of ' + key);
 +      var data = output.data;
 +      var dataOffset = this.offsets[key];
 +      var size = 5;
 +      for (var i = 0, ii = values.length; i < ii; ++i) {
 +        var offset0 = i * size + dataOffset;
 +        var offset1 = offset0 + 1;
 +        var offset2 = offset0 + 2;
 +        var offset3 = offset0 + 3;
 +        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)
 +          error('writing to an offset that is not empty');
 +        var value = values[i];
 +        data[offset0] = 0x1d;
 +        data[offset1] = (value >> 24) & 0xFF;
 +        data[offset2] = (value >> 16) & 0xFF;
 +        data[offset3] = (value >> 8) & 0xFF;
 +        data[offset4] = value & 0xFF;
 +      }
 +    }
 +  };
 +  return CFFOffsetTracker;
 +})();
 +
 +// 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;
 +  }
 +  CFFCompiler.prototype = {
 +    compile: function CFFCompiler_compile() {
 +      var cff = this.cff;
 +      var output = {
 +        data: [],
 +        length: 0,
 +        add: function CFFCompiler_add(data) {
 +          this.data = this.data.concat(data);
 +          this.length = this.data.length;
 +        }
 +      };
 +
 +      // Compile the five entries that must be in order.
 +      var header = this.compileHeader(cff.header);
 +      output.add(header);
 +
 +      var nameIndex = this.compileNameIndex(cff.names);
 +      output.add(nameIndex);
 +
++      if (cff.isCIDFont) {
++        // The spec is unclear on how font matrices should relate to each other
++        // when there is one in the main top dict and the sub top dicts.
++        // Windows handles this differently than linux and osx so we have to
++        // normalize to work on all.
++        // Rules based off of some mailing list discussions:
++        // - If main font has a matrix and subfont doesn't, use the main matrix.
++        // - If no main font matrix and there is a subfont matrix, use the
++        //   subfont matrix.
++        // - If both have matrices, concat together.
++        // - If neither have matrices, use default.
++        // To make this work on all platforms we move the top matrix into each
++        // sub top dict and concat if necessary.
++        if (cff.topDict.hasName('FontMatrix')) {
++          var base = cff.topDict.getByName('FontMatrix');
++          cff.topDict.removeByName('FontMatrix');
++          for (var i = 0, ii = cff.fdArray.length; i < ii; i++) {
++            var subDict = cff.fdArray[i];
++            var matrix = base.slice(0);
++            if (subDict.hasName('FontMatrix')) {
++              matrix = Util.transform(matrix, subDict.getByName('FontMatrix'));
++            }
++            subDict.setByName('FontMatrix', matrix);
++          }
++        }
++      }
++
 +      var compiled = this.compileTopDicts([cff.topDict],
 +                                          output.length,
 +                                          cff.isCIDFont);
 +      output.add(compiled.output);
 +      var topDictTracker = compiled.trackers[0];
 +
 +      var stringIndex = this.compileStringIndex(cff.strings.strings);
 +      output.add(stringIndex);
 +
 +      var globalSubrIndex = this.compileIndex(cff.globalSubrIndex);
 +      output.add(globalSubrIndex);
 +
 +      // Now start on the other entries that have no specfic order.
 +      if (cff.encoding && cff.topDict.hasName('Encoding')) {
 +        if (cff.encoding.predefined) {
 +          topDictTracker.setEntryLocation('Encoding', [cff.encoding.format],
 +                                          output);
 +        } else {
 +          var encoding = this.compileEncoding(cff.encoding);
 +          topDictTracker.setEntryLocation('Encoding', [output.length], output);
 +          output.add(encoding);
 +        }
 +      }
 +
 +      if (cff.charset && cff.topDict.hasName('charset')) {
 +        if (cff.charset.predefined) {
 +          topDictTracker.setEntryLocation('charset', [cff.charset.format],
 +                                          output);
 +        } else {
 +          var charset = this.compileCharset(cff.charset);
 +          topDictTracker.setEntryLocation('charset', [output.length], output);
 +          output.add(charset);
 +        }
 +      }
 +
 +      var charStrings = this.compileCharStrings(cff.charStrings);
 +      topDictTracker.setEntryLocation('CharStrings', [output.length], output);
 +      output.add(charStrings);
 +
 +      if (cff.isCIDFont) {
 +        // For some reason FDSelect must be in front of FDArray on windows. OSX
 +        // and linux don't seem to care.
 +        topDictTracker.setEntryLocation('FDSelect', [output.length], output);
 +        var fdSelect = this.compileFDSelect(cff.fdSelect.raw);
 +        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);
 +        topDictTracker.setEntryLocation('FDArray', [output.length], output);
 +        output.add(compiled.output);
 +        var fontDictTrackers = compiled.trackers;
 +
 +        this.compilePrivateDicts(cff.fdArray, fontDictTrackers, output);
 +      }
 +
 +      this.compilePrivateDicts([cff.topDict], [topDictTracker], output);
 +
 +      // If the font data ends with INDEX whose object data is zero-length,
 +      // the sanitizer will bail out. Add a dummy byte to avoid that.
 +      output.add([0]);
 +
 +      return output.data;
 +    },
 +    encodeNumber: function CFFCompiler_encodeNumber(value) {
 +      if (parseFloat(value) == parseInt(value, 10) && !isNaN(value)) // isInt
 +        return this.encodeInteger(value);
 +      else
 +        return this.encodeFloat(value);
 +    },
 +    encodeFloat: function CFFCompiler_encodeFloat(num) {
 +      var value = num.toString();
++
++      // rounding inaccurate doubles
++      var m = /\.(\d*?)(?:9{5,20}|0{5,20})\d{0,2}(?:e(.+)|$)/.exec(value);
++      if (m) {
++        var epsilon = parseFloat('1e' + ((m[2] ? +m[2] : 0) + m[1].length));
++        value = (Math.round(num * epsilon) / epsilon).toString();
++      }
++
 +      var nibbles = '';
 +      for (var i = 0, ii = value.length; i < ii; ++i) {
 +        var a = value[i];
 +        if (a === 'e') {
 +          nibbles += value[++i] === '-' ? 'c' : 'b';
 +        } else if (a === '.') {
 +          nibbles += 'a';
 +        } else if (a === '-') {
 +          nibbles += 'e';
 +        } else {
 +          nibbles += a;
 +        }
 +      }
 +      nibbles += (nibbles.length & 1) ? 'f' : 'ff';
 +      var out = [30];
 +      for (var i = 0, ii = nibbles.length; i < ii; i += 2) {
 +        out.push(parseInt(nibbles.substr(i, 2), 16));
 +      }
 +      return out;
 +    },
 +    encodeInteger: function CFFCompiler_encodeInteger(value) {
 +      var code;
 +      if (value >= -107 && value <= 107) {
 +        code = [value + 139];
 +      } else if (value >= 108 && value <= 1131) {
 +        value = [value - 108];
 +        code = [(value >> 8) + 247, value & 0xFF];
 +      } else if (value >= -1131 && value <= -108) {
 +        value = -value - 108;
 +        code = [(value >> 8) + 251, value & 0xFF];
 +      } else if (value >= -32768 && value <= 32767) {
 +        code = [0x1c, (value >> 8) & 0xFF, value & 0xFF];
 +      } else {
 +        code = [0x1d,
 +                (value >> 24) & 0xFF,
 +                (value >> 16) & 0xFF,
 +                (value >> 8) & 0xFF,
 +                 value & 0xFF];
 +      }
 +      return code;
 +    },
 +    compileHeader: function CFFCompiler_compileHeader(header) {
 +      return [
 +        header.major,
 +        header.minor,
 +        header.hdrSize,
 +        header.offSize
 +      ];
 +    },
 +    compileNameIndex: function CFFCompiler_compileNameIndex(names) {
 +      var nameIndex = new CFFIndex();
 +      for (var i = 0, ii = names.length; i < ii; ++i)
 +        nameIndex.add(stringToArray(names[i]));
 +      return this.compileIndex(nameIndex);
 +    },
 +    compileTopDicts: function CFFCompiler_compileTopDicts(dicts,
 +                                                          length,
 +                                                          removeCidKeys) {
 +      var fontDictTrackers = [];
 +      var fdArrayIndex = new CFFIndex();
 +      for (var i = 0, ii = dicts.length; i < ii; ++i) {
 +        var fontDict = dicts[i];
 +        if (removeCidKeys) {
 +          fontDict.removeByName('CIDFontVersion');
 +          fontDict.removeByName('CIDFontRevision');
 +          fontDict.removeByName('CIDFontType');
 +          fontDict.removeByName('CIDCount');
 +          fontDict.removeByName('UIDBase');
 +        }
 +        var fontDictTracker = new CFFOffsetTracker();
 +        var fontDictData = this.compileDict(fontDict, fontDictTracker);
 +        fontDictTrackers.push(fontDictTracker);
 +        fdArrayIndex.add(fontDictData);
 +        fontDictTracker.offset(length);
 +      }
 +      fdArrayIndex = this.compileIndex(fdArrayIndex, fontDictTrackers);
 +      return {
 +        trackers: fontDictTrackers,
 +        output: fdArrayIndex
 +      };
 +    },
 +    compilePrivateDicts: function CFFCompiler_compilePrivateDicts(dicts,
 +                                                                  trackers,
 +                                                                  output) {
 +      for (var i = 0, ii = dicts.length; i < ii; ++i) {
 +        var fontDict = dicts[i];
 +        assert(fontDict.privateDict && fontDict.hasName('Private'),
 +               'There must be an private dictionary.');
 +        var privateDict = fontDict.privateDict;
 +        var privateDictTracker = new CFFOffsetTracker();
 +        var privateDictData = this.compileDict(privateDict, privateDictTracker);
 +
 +        var outputLength = output.length;
 +        privateDictTracker.offset(outputLength);
 +        if (!privateDictData.length) {
 +          // The private dictionary was empty, set the output length to zero to
 +          // ensure the offset length isn't out of bounds in the eyes of the
 +          // sanitizer.
 +          outputLength = 0;
 +        }
 +
 +        trackers[i].setEntryLocation('Private',
 +                                     [privateDictData.length, outputLength],
 +                                     output);
 +        output.add(privateDictData);
 +
 +        if (privateDict.subrsIndex && privateDict.hasName('Subrs')) {
 +          var subrs = this.compileIndex(privateDict.subrsIndex);
 +          privateDictTracker.setEntryLocation('Subrs', [privateDictData.length],
 +                                              output);
 +          output.add(subrs);
 +        }
 +      }
 +    },
 +    compileDict: function CFFCompiler_compileDict(dict, offsetTracker) {
 +      var out = [];
 +      // The dictionary keys must be in a certain order.
 +      var order = dict.order;
 +      for (var i = 0; i < order.length; ++i) {
 +        var key = order[i];
 +        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];
 +
 +        // Remove any empty dict values.
 +        if (values.length === 0)
 +          continue;
 +
 +        for (var j = 0, jj = types.length; j < jj; ++j) {
 +          var type = types[j];
 +          var value = values[j];
 +          switch (type) {
 +            case 'num':
 +            case 'sid':
 +              out = out.concat(this.encodeNumber(value));
 +              break;
 +            case 'offset':
 +              // For offsets we just insert a 32bit integer so we don't have to
 +              // deal with figuring out the length of the offset when it gets
 +              // replaced later on by the compiler.
 +              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))
 +                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)
 +                out = out.concat(this.encodeNumber(values[k]));
 +              break;
 +            default:
 +              error('Unknown data type of ' + type);
 +              break;
 +          }
 +        }
 +        out = out.concat(dict.opcodes[key]);
 +      }
 +      return out;
 +    },
 +    compileStringIndex: function CFFCompiler_compileStringIndex(strings) {
 +      var stringIndex = new CFFIndex();
 +      for (var i = 0, ii = strings.length; i < ii; ++i)
 +        stringIndex.add(stringToArray(strings[i]));
 +      return this.compileIndex(stringIndex);
 +    },
 +    compileGlobalSubrIndex: function CFFCompiler_compileGlobalSubrIndex() {
 +      var globalSubrIndex = this.cff.globalSubrIndex;
 +      this.out.writeByteArray(this.compileIndex(globalSubrIndex));
 +    },
 +    compileCharStrings: function CFFCompiler_compileCharStrings(charStrings) {
 +      return this.compileIndex(charStrings);
 +    },
 +    compileCharset: function CFFCompiler_compileCharset(charset) {
 +      return this.compileTypedArray(charset.raw);
 +    },
 +    compileEncoding: function CFFCompiler_compileEncoding(encoding) {
 +      return this.compileTypedArray(encoding.raw);
 +    },
 +    compileFDSelect: function CFFCompiler_compileFDSelect(fdSelect) {
 +      return this.compileTypedArray(fdSelect);
 +    },
 +    compileTypedArray: function CFFCompiler_compileTypedArray(data) {
 +      var out = [];
 +      for (var i = 0, ii = data.length; i < ii; ++i)
 +        out[i] = data[i];
 +      return out;
 +    },
 +    compileIndex: function CFFCompiler_compileIndex(index, trackers) {
 +      trackers = trackers || [];
 +      var objects = index.objects;
 +      // First 2 bytes contains the number of objects contained into this index
 +      var count = objects.length;
 +
 +      // 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)
 +        return [0, 0, 0];
 +
 +      var data = [(count >> 8) & 0xFF, count & 0xff];
 +
 +      var lastOffset = 1;
 +      for (var i = 0; i < count; ++i)
 +        lastOffset += objects[i].length;
 +
 +      var offsetSize;
 +      if (lastOffset < 0x100)
 +        offsetSize = 1;
 +      else if (lastOffset < 0x10000)
 +        offsetSize = 2;
 +      else if (lastOffset < 0x1000000)
 +        offsetSize = 3;
 +      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++) {
 +        if (offsetSize === 1) {
 +          data.push(relativeOffset & 0xFF);
 +        } else if (offsetSize === 2) {
 +          data.push((relativeOffset >> 8) & 0xFF,
 +                     relativeOffset & 0xFF);
 +        } else if (offsetSize === 3) {
 +          data.push((relativeOffset >> 16) & 0xFF,
 +                    (relativeOffset >> 8) & 0xFF,
 +                     relativeOffset & 0xFF);
 +        } else {
 +          data.push((relativeOffset >>> 24) & 0xFF,
 +                    (relativeOffset >> 16) & 0xFF,
 +                    (relativeOffset >> 8) & 0xFF,
 +                     relativeOffset & 0xFF);
 +        }
 +
 +        if (objects[i])
 +          relativeOffset += objects[i].length;
 +      }
 +      var offset = data.length;
 +
 +      for (var i = 0; i < count; i++) {
 +        // Notify the tracker where the object will be offset in the data.
 +        if (trackers[i])
 +          trackers[i].offset(data.length);
 +        for (var j = 0, jj = objects[i].length; j < jj; j++)
 +          data.push(objects[i][j]);
 +      }
 +      return data;
 +    }
 +  };
 +  return CFFCompiler;
 +})();
 +
 +// Workaround for seac on Windows.
 +(function checkSeacSupport() {
 +  if (/Windows/.test(navigator.userAgent)) {
 +    SEAC_ANALYSIS_ENABLED = true;
 +  }
 +})();
 +
 +// Workaround for Private Use Area characters in Chrome on Windows
 +// http://code.google.com/p/chromium/issues/detail?id=122465
 +// https://github.com/mozilla/pdf.js/issues/1689
 +(function checkChromeWindows() {
 +  if (/Windows.*Chrome/.test(navigator.userAgent)) {
 +    SYMBOLIC_FONT_GLYPH_OFFSET = 0xF100;
 +  }
 +})();
 +
 +
++var FontRendererFactory = (function FontRendererFactoryClosure() {
++  function getLong(data, offset) {
++    return (data[offset] << 24) | (data[offset + 1] << 16) |
++           (data[offset + 2] << 8) | data[offset + 3];
++  }
++
++  function getUshort(data, offset) {
++    return (data[offset] << 8) | data[offset + 1];
++  }
++
++  function parseCmap(data, start, end) {
++    var offset = getUshort(data, start + 2) === 1 ? getLong(data, start + 8) :
++                                                    getLong(data, start + 16);
++    var format = getUshort(data, start + offset);
++    if (format === 4) {
++      var 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) {
++        ranges[i] = {end: getUshort(data, p)};
++      }
++      p += 2;
++      for (var i = 0; i < segCount; i++, p += 2) {
++        ranges[i].start = getUshort(data, p);
++      }
++      for (var i = 0; i < segCount; i++, p += 2) {
++        ranges[i].idDelta = getUshort(data, p);
++      }
++      for (var i = 0; i < segCount; i++, p += 2) {
++        var idOffset = getUshort(data, p);
++        if (idOffset === 0) {
++          continue;
++        }
++        ranges[i].ids = [];
++        for (var j = 0, jj = ranges[i].end - ranges[i].start + 1; j < jj; j++) {
++          ranges[i].ids[j] = getUshort(data, p + idOffset);
++          idOffset += 2;
++        }
++      }
++      return ranges;
++    } else if (format === 12) {
++      var 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++) {
++        ranges.push({
++          start: getLong(data, p),
++          end: getLong(data, p + 4),
++          idDelta: getLong(data, p + 8) - getLong(data, p)
++        });
++        p += 12;
++      }
++      return ranges;
++    }
++    error('not supported cmap: ' + format);
++  }
++
++  function parseCff(data, start, end) {
++    var 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,
++      gsubrs: cff.globalSubrIndex && cff.globalSubrIndex.objects
++    };
++  }
++
++  function parseGlyfTable(glyf, loca, isGlyphLocationsLong) {
++    var itemSize, itemDecode;
++    if (isGlyphLocationsLong) {
++      itemSize = 4;
++      itemDecode = function fontItemDecodeLong(data, offset) {
++        return (data[offset] << 24) | (data[offset + 1] << 16) |
++               (data[offset + 2] << 8) | data[offset + 3];
++      };
++    } else {
++      itemSize = 2;
++      itemDecode = function fontItemDecode(data, offset) {
++        return (data[offset] << 9) | (data[offset + 1] << 1);
++      };
++    }
++    var glyphs = [];
++    var startOffset = itemDecode(loca, 0);
++    for (var j = itemSize; j < loca.length; j += itemSize) {
++      var endOffset = itemDecode(loca, j);
++      glyphs.push(glyf.subarray(startOffset, endOffset));
++      startOffset = endOffset;
++    }
++    return glyphs;
++  }
++
++  function lookupCmap(ranges, unicode) {
++    var code = unicode.charCodeAt(0);
++    var l = 0, r = ranges.length - 1;
++    while (l < r) {
++      var c = (l + r + 1) >> 1;
++      if (code < ranges[c].start) {
++        r = c - 1;
++      } else {
++        l = c;
++      }
++    }
++    if (ranges[l].start <= code && code <= ranges[l].end) {
++      return (ranges[l].idDelta + (ranges[l].ids ?
++        ranges[l].ids[code - ranges[l].start] : code)) & 0xFFFF;
++    }
++    return 0;
++  }
++
++  function compileGlyf(code, js, font) {
++    function moveTo(x, y) {
++      js.push('c.moveTo(' + x + ',' + y + ');');
++    }
++    function lineTo(x, y) {
++      js.push('c.lineTo(' + x + ',' + y + ');');
++    }
++    function quadraticCurveTo(xa, ya, x, y) {
++      js.push('c.quadraticCurveTo(' + xa + ',' + ya + ',' +
++                                   x + ',' + y + ');');
++    }
++
++    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;
++    i += 10;
++    if (numberOfContours < 0) {
++      // composite glyph
++      var x = 0, y = 0;
++      do {
++        var flags = (code[i] << 8) | code[i + 1];
++        var glyphIndex = (code[i + 2] << 8) | code[i + 3];
++        i += 4;
++        var arg1, arg2;
++        if ((flags & 0x01)) {
++          arg1 = ((code[i] << 24) | (code[i + 1] << 16)) >> 16;
++          arg2 = ((code[i + 2] << 24) | (code[i + 3] << 16)) >> 16;
++          i += 4;
++        } else {
++          arg1 = code[i++]; arg2 = code[i++];
++        }
++        if ((flags & 0x02)) {
++           x = arg1;
++           y = arg2;
++        } else {
++           x = 0; y = 0; // TODO "they are points" ?
++        }
++        var scaleX = 1, scaleY = 1, scale01 = 0, scale10 = 0;
++        if ((flags & 0x08)) {
++          scaleX =
++          scaleY = ((code[i] << 24) | (code[i + 1] << 16)) / 1073741824;
++          i += 2;
++        } else if ((flags & 0x40)) {
++          scaleX = ((code[i] << 24) | (code[i + 1] << 16)) / 1073741824;
++          scaleY = ((code[i + 2] << 24) | (code[i + 3] << 16)) / 1073741824;
++          i += 4;
++        } else if ((flags & 0x80)) {
++          scaleX = ((code[i] << 24) | (code[i + 1] << 16)) / 1073741824;
++          scale01 = ((code[i + 2] << 24) | (code[i + 3] << 16)) / 1073741824;
++          scale10 = ((code[i + 4] << 24) | (code[i + 5] << 16)) / 1073741824;
++          scaleY = ((code[i + 6] << 24) | (code[i + 7] << 16)) / 1073741824;
++          i += 8;
++        }
++        var subglyph = font.glyphs[glyphIndex];
++        if (subglyph) {
++          js.push('c.save();');
++          js.push('c.transform(' + scaleX + ',' + scale01 + ',' +
++                  scale10 + ',' + scaleY + ',' + x + ',' + y + ');');
++          compileGlyf(subglyph, js, font);
++          js.push('c.restore();');
++        }
++      } while ((flags & 0x20));
++    } else {
++      // simple glyph
++      var endPtsOfContours = [];
++      for (var j = 0; j < numberOfContours; j++) {
++        endPtsOfContours.push((code[i] << 8) | code[i + 1]);
++        i += 2;
++      }
++      var instructionLength = (code[i] << 8) | code[i + 1];
++      i += 2 + instructionLength; // skipping the instructions
++      var numberOfPoints = endPtsOfContours[endPtsOfContours.length - 1] + 1;
++      var points = [];
++      while (points.length < numberOfPoints) {
++        var flags = code[i++], repeat = 1;
++        if ((flags & 0x08)) {
++          repeat += code[i++];
++        }
++        while (repeat-- > 0) {
++          points.push({flags: flags});
++        }
++      }
++      var x = 0, y = 0;
++      for (var j = 0; j < numberOfPoints; j++) {
++        switch (points[j].flags & 0x12) {
++          case 0x00:
++            x += ((code[i] << 24) | (code[i + 1] << 16)) >> 16;
++            i += 2;
++            break;
++          case 0x02:
++            x -= code[i++];
++            break;
++          case 0x12:
++            x += code[i++];
++            break;
++        }
++        points[j].x = x;
++      }
++      for (var j = 0; j < numberOfPoints; j++) {
++        switch (points[j].flags & 0x24) {
++          case 0x00:
++            y += ((code[i] << 24) | (code[i + 1] << 16)) >> 16;
++            i += 2;
++            break;
++          case 0x04:
++            y -= code[i++];
++            break;
++          case 0x24:
++            y += code[i++];
++            break;
++        }
++        points[j].y = y;
++      }
++
++      var startPoint = 0;
++      for (var 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
++        var contour = points.slice(startPoint, endPoint + 1);
++        if ((contour[0].flags & 1)) {
++          contour.push(contour[0]); // using start point at the contour end
++        } else if ((contour[contour.length - 1].flags & 1)) {
++          // first is off-curve point, trying to use one from the end
++          contour.unshift(contour[contour.length - 1]);
++        } else {
++          // start and end are off-curve points, creating implicit one
++          var p = {
++            flags: 1,
++            x: (contour[0].x + contour[contour.length - 1].x) / 2,
++            y: (contour[0].y + contour[contour.length - 1].y) / 2
++          };
++          contour.unshift(p);
++          contour.push(p);
++        }
++        moveTo(contour[0].x, contour[0].y);
++        for (var 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)){
++            quadraticCurveTo(contour[j].x, contour[j].y,
++                             contour[j + 1].x, contour[j + 1].y);
++            j++;
++          } else {
++            quadraticCurveTo(contour[j].x, contour[j].y,
++              (contour[j].x + contour[j + 1].x) / 2,
++              (contour[j].y + contour[j + 1].y) / 2);
++          }
++        }
++        startPoint = endPoint + 1;
++      }
++    }
++  }
++
++  function compileCharString(code, js, font) {
++    var stack = [];
++    var x = 0, y = 0;
++    var stems = 0;
++
++    function moveTo(x, y) {
++      js.push('c.moveTo(' + x + ',' + y + ');');
++    }
++    function lineTo(x, y) {
++      js.push('c.lineTo(' + x + ',' + y + ');');
++    }
++    function bezierCurveTo(x1, y1, x2, y2, x, y) {
++      js.push('c.bezierCurveTo(' + x1 + ',' + y1 + ',' + x2 + ',' + y2 + ',' +
++                                   x + ',' + y + ');');
++    }
++
++    function parse(code) {
++      var i = 0;
++      while (i < code.length) {
++        var stackClean = false;
++        var v = code[i++];
++        switch (v) {
++          case 1: // hstem
++            stems += stack.length >> 1;
++            stackClean = true;
++            break;
++          case 3: // vstem
++            stems += stack.length >> 1;
++            stackClean = true;
++            break;
++          case 4: // vmoveto
++            y += stack.pop();
++            moveTo(x, y);
++            stackClean = true;
++            break;
++          case 5: // rlineto
++            while (stack.length > 0) {
++              x += stack.shift();
++              y += stack.shift();
++              lineTo(x, y);
++            }
++            break;
++          case 6: // hlineto
++            while (stack.length > 0) {
++              x += stack.shift();
++              lineTo(x, y);
++              if (stack.length === 0) {
++                break;
++              }
++              y += stack.shift();
++              lineTo(x, y);
++            }
++            break;
++          case 7: // vlineto
++            while (stack.length > 0) {
++              y += stack.shift();
++              lineTo(x, y);
++              if (stack.length === 0) {
++                break;
++              }
++              x += stack.shift();
++              lineTo(x, y);
++            }
++            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();
++              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];
++            if (subrCode) {
++              parse(subrCode);
++            }
++            break;
++          case 11: // return
++            return;
++          case 12:
++            v = code[i++];
++            switch (v) {
++              case 34: // flex
++                var xa = x + stack.shift();
++                var 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();
++                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();
++                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();
++                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();
++                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();
++                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();
++                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();
++                x = xb; y = yb;
++                if (Math.abs(x - x0) > Math.abs(y - y0))
++                  x += stack.shift();
++                else
++                  y += stack.shift();
++                bezierCurveTo(xa, ya, xb, yb, x, y);
++                break;
++              default:
++                error('unknown operator: 12 ' + v);
++            }
++            break;
++          case 14: // endchar
++            if (stack.length >= 4) {
++              var achar = stack.pop();
++              var bchar = stack.pop();
++              y = stack.pop();
++              x = stack.pop();
++              js.push('c.save();');
++              js.push('c.translate('+ x + ',' + y + ');');
++              var gid = lookupCmap(font.cmap, String.fromCharCode(
++                font.glyphNameMap[Encodings.StandardEncoding[achar]]));
++              compileCharString(font.glyphs[gid], js, font);
++              js.push('c.restore();');
++
++              gid = lookupCmap(font.cmap, String.fromCharCode(
++                font.glyphNameMap[Encodings.StandardEncoding[bchar]]));
++              compileCharString(font.glyphs[gid], js, font);
++            }
++            return;
++          case 18: // hstemhm
++            stems += stack.length >> 1;
++            stackClean = true;
++            break;
++          case 19: // hintmask
++            stems += stack.length >> 1;
++            i += (stems + 7) >> 3;
++            stackClean = true;
++            break;
++          case 20: // cntrmask
++            stems += stack.length >> 1;
++            i += (stems + 7) >> 3;
++            stackClean = true;
++            break;
++          case 21: // rmoveto
++            y += stack.pop();
++            x += stack.pop();
++            moveTo(x, y);
++            stackClean = true;
++            break;
++          case 22: // hmoveto
++            x += stack.pop();
++            moveTo(x, y);
++            stackClean = true;
++            break;
++          case 23: // vstemhm
++            stems += stack.length >> 1;
++            stackClean = true;
++            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();
++              x = xb + stack.shift(); y = yb + stack.shift();
++              bezierCurveTo(xa, ya, xb, yb, x, y);
++            }
++            x += stack.shift();
++            y += stack.shift();
++            lineTo(x, y);
++            break;
++          case 25: // rlinecurve
++            while (stack.length > 6) {
++              x += stack.shift();
++              y += stack.shift();
++              lineTo(x, y);
++            }
++            var xa = x + stack.shift(), ya = y + stack.shift();
++            var 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 26: // vvcurveto
++            if (stack.length % 2) {
++              x += stack.shift();
++            }
++            while (stack.length > 0) {
++              var xa = x, ya = y + stack.shift();
++              var xb = xa + stack.shift(), yb = ya + stack.shift();
++              x = xb; y = yb + stack.shift();
++              bezierCurveTo(xa, ya, xb, yb, x, y);
++            }
++            break;
++          case 27: // hhcurveto
++            if (stack.length % 2) {
++              y += stack.shift();
++            }
++            while (stack.length > 0) {
++              var xa = x + stack.shift(), ya = y;
++              var xb = xa + stack.shift(), yb = ya + stack.shift();
++              x = xb + stack.shift(); y = yb;
++              bezierCurveTo(xa, ya, xb, yb, x, y);
++            }
++            break;
++          case 28:
++            stack.push(((code[i] << 24) | (code[i + 1] << 16)) >> 16);
++            i += 2;
++            break;
++          case 29: // callgsubr
++            var n = stack.pop() + font.gsubrsBias;
++            var 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();
++              x = xb + stack.shift();
++              y = yb + (stack.length === 1 ? stack.shift() : 0);
++              bezierCurveTo(xa, ya, xb, yb, x, y);
++              if (stack.length === 0) {
++                break;
++              }
++
++              var xa = x + stack.shift(), ya = y;
++              var 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);
++            }
++            break;
++          case 31: // hvcurveto
++            while (stack.length > 0) {
++              var xa = x + stack.shift(), ya = y;
++              var 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);
++              if (stack.length === 0) {
++                break;
++              }
++
++              var xa = x, ya = y + stack.shift();
++              var 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)
++              error('unknown operator: ' + v);
++            if (v < 247)
++              stack.push(v - 139);
++            else if (v < 251)
++              stack.push((v - 247) * 256 + code[i++] + 108);
++            else if (v < 255)
++              stack.push(-(v - 251) * 256 - code[i++] - 108);
++            else {
++              stack.push(((code[i] << 24) | (code[i + 1] << 16) |
++                         (code[i + 2] << 8) | code[i + 3]) / 65536);
++              i += 4;
++            }
++            break;
++        }
++        if (stackClean) {
++          stack.length = 0;
++        }
++      }
++    }
++    parse(code);
++  }
++
++  var noop = '';
++
++  function CompiledFont(fontMatrix) {
++    this.compiledGlyphs = {};
++    this.fontMatrix = fontMatrix;
++  }
++  CompiledFont.prototype = {
++    getPathJs: function (unicode) {
++      var gid = lookupCmap(this.cmap, unicode);
++      var fn = this.compiledGlyphs[gid];
++      if (!fn) {
++        this.compiledGlyphs[gid] = fn = this.compileGlyph(this.glyphs[gid]);
++      }
++      return fn;
++    },
++
++    compileGlyph: function (code) {
++      if (!code || code.length === 0 || code[0] === 14) {
++        return noop;
++      }
++
++      var js = [];
++      js.push('c.save();');
++      js.push('c.transform(' + this.fontMatrix.join(',') + ');');
++      js.push('c.scale(size, -size);');
++
++      this.compileGlyphImpl(code, js);
++
++      js.push('c.restore();');
++
++      return js.join('\n');
++    },
++
++    compileGlyphImpl: function () {
++      error('Children classes should implement this.');
++    },
++
++    hasBuiltPath: function (unicode) {
++      var gid = lookupCmap(this.cmap, unicode);
++      return gid in this.compiledGlyphs;
++    }
++  };
++
++  function TrueTypeCompiled(glyphs, cmap, fontMatrix) {
++    fontMatrix = fontMatrix || [0.000488, 0, 0, 0.000488, 0, 0];
++    CompiledFont.call(this, fontMatrix);
++
++    this.glyphs = glyphs;
++    this.cmap = cmap;
++
++    this.compiledGlyphs = [];
++  }
++
++  Util.inherit(TrueTypeCompiled, CompiledFont, {
++    compileGlyphImpl: function (code, js) {
++      compileGlyf(code, js, this);
++    }
++  });
++
++  function Type2Compiled(cffInfo, cmap, fontMatrix, glyphNameMap) {
++    fontMatrix = fontMatrix || [0.001, 0, 0, 0.001, 0, 0];
++    CompiledFont.call(this, fontMatrix);
++    this.glyphs = cffInfo.glyphs;
++    this.gsubrs = cffInfo.gsubrs || [];
++    this.subrs = cffInfo.subrs || [];
++    this.cmap = cmap;
++    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;
++  }
++
++  Util.inherit(Type2Compiled, CompiledFont, {
++    compileGlyphImpl: function (code, js) {
++      compileCharString(code, js, this);
++    }
++  });
++
++
++  return {
++    create: function FontRendererFactory_create(font) {
++      var data = new Uint8Array(font.data);
++      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 offset = getLong(data, p + 8);
++        var length = getLong(data, p + 12);
++        switch (tag) {
++          case 'cmap':
++            cmap = parseCmap(data, offset, offset + length);
++            break;
++          case 'glyf':
++            glyf = data.subarray(offset, offset + length);
++            break;
++          case 'loca':
++            loca = data.subarray(offset, offset + length);
++            break;
++          case 'head':
++            unitsPerEm = getUshort(data, offset + 18);
++            indexToLocFormat = getUshort(data, offset + 50);
++            break;
++          case 'CFF ':
++            cff = parseCff(data, offset, offset + length);
++            break;
++        }
++      }
++
++      if (glyf) {
++        var fontMatrix = !unitsPerEm ? font.fontMatrix :
++          [1 / unitsPerEm, 0, 0, 1 / unitsPerEm, 0, 0];
++        return new TrueTypeCompiled(
++          parseGlyfTable(glyf, loca, indexToLocFormat), cmap, fontMatrix);
++      } else {
++        return new Type2Compiled(cff, cmap, font.fontMatrix, font.glyphNameMap);
++      }
++    }
++  };
++})();
++
++
++
 +var GlyphsUnicode = {
 +  A: 0x0041,
 +  AE: 0x00C6,
 +  AEacute: 0x01FC,
 +  AEmacron: 0x01E2,
 +  AEsmall: 0xF7E6,
 +  Aacute: 0x00C1,
 +  Aacutesmall: 0xF7E1,
 +  Abreve: 0x0102,
 +  Abreveacute: 0x1EAE,
 +  Abrevecyrillic: 0x04D0,
 +  Abrevedotbelow: 0x1EB6,
 +  Abrevegrave: 0x1EB0,
 +  Abrevehookabove: 0x1EB2,
 +  Abrevetilde: 0x1EB4,
 +  Acaron: 0x01CD,
 +  Acircle: 0x24B6,
 +  Acircumflex: 0x00C2,
 +  Acircumflexacute: 0x1EA4,
 +  Acircumflexdotbelow: 0x1EAC,
 +  Acircumflexgrave: 0x1EA6,
 +  Acircumflexhookabove: 0x1EA8,
 +  Acircumflexsmall: 0xF7E2,
 +  Acircumflextilde: 0x1EAA,
 +  Acute: 0xF6C9,
 +  Acutesmall: 0xF7B4,
 +  Acyrillic: 0x0410,
 +  Adblgrave: 0x0200,
 +  Adieresis: 0x00C4,
 +  Adieresiscyrillic: 0x04D2,
 +  Adieresismacron: 0x01DE,
 +  Adieresissmall: 0xF7E4,
 +  Adotbelow: 0x1EA0,
 +  Adotmacron: 0x01E0,
 +  Agrave: 0x00C0,
 +  Agravesmall: 0xF7E0,
 +  Ahookabove: 0x1EA2,
 +  Aiecyrillic: 0x04D4,
 +  Ainvertedbreve: 0x0202,
 +  Alpha: 0x0391,
 +  Alphatonos: 0x0386,
 +  Amacron: 0x0100,
 +  Amonospace: 0xFF21,
 +  Aogonek: 0x0104,
 +  Aring: 0x00C5,
 +  Aringacute: 0x01FA,
 +  Aringbelow: 0x1E00,
 +  Aringsmall: 0xF7E5,
 +  Asmall: 0xF761,
 +  Atilde: 0x00C3,
 +  Atildesmall: 0xF7E3,
 +  Aybarmenian: 0x0531,
 +  B: 0x0042,
 +  Bcircle: 0x24B7,
 +  Bdotaccent: 0x1E02,
 +  Bdotbelow: 0x1E04,
 +  Becyrillic: 0x0411,
 +  Benarmenian: 0x0532,
 +  Beta: 0x0392,
 +  Bhook: 0x0181,
 +  Blinebelow: 0x1E06,
 +  Bmonospace: 0xFF22,
 +  Brevesmall: 0xF6F4,
 +  Bsmall: 0xF762,
 +  Btopbar: 0x0182,
 +  C: 0x0043,
 +  Caarmenian: 0x053E,
 +  Cacute: 0x0106,
 +  Caron: 0xF6CA,
 +  Caronsmall: 0xF6F5,
 +  Ccaron: 0x010C,
 +  Ccedilla: 0x00C7,
 +  Ccedillaacute: 0x1E08,
 +  Ccedillasmall: 0xF7E7,
 +  Ccircle: 0x24B8,
 +  Ccircumflex: 0x0108,
 +  Cdot: 0x010A,
 +  Cdotaccent: 0x010A,
 +  Cedillasmall: 0xF7B8,
 +  Chaarmenian: 0x0549,
 +  Cheabkhasiancyrillic: 0x04BC,
 +  Checyrillic: 0x0427,
 +  Chedescenderabkhasiancyrillic: 0x04BE,
 +  Chedescendercyrillic: 0x04B6,
 +  Chedieresiscyrillic: 0x04F4,
 +  Cheharmenian: 0x0543,
 +  Chekhakassiancyrillic: 0x04CB,
 +  Cheverticalstrokecyrillic: 0x04B8,
 +  Chi: 0x03A7,
 +  Chook: 0x0187,
 +  Circumflexsmall: 0xF6F6,
 +  Cmonospace: 0xFF23,
 +  Coarmenian: 0x0551,
 +  Csmall: 0xF763,
 +  D: 0x0044,
 +  DZ: 0x01F1,
 +  DZcaron: 0x01C4,
 +  Daarmenian: 0x0534,
 +  Dafrican: 0x0189,
 +  Dcaron: 0x010E,
 +  Dcedilla: 0x1E10,
 +  Dcircle: 0x24B9,
 +  Dcircumflexbelow: 0x1E12,
 +  Dcroat: 0x0110,
 +  Ddotaccent: 0x1E0A,
 +  Ddotbelow: 0x1E0C,
 +  Decyrillic: 0x0414,
 +  Deicoptic: 0x03EE,
 +  Delta: 0x2206,
 +  Deltagreek: 0x0394,
 +  Dhook: 0x018A,
 +  Dieresis: 0xF6CB,
 +  DieresisAcute: 0xF6CC,
 +  DieresisGrave: 0xF6CD,
 +  Dieresissmall: 0xF7A8,
 +  Digammagreek: 0x03DC,
 +  Djecyrillic: 0x0402,
 +  Dlinebelow: 0x1E0E,
 +  Dmonospace: 0xFF24,
 +  Dotaccentsmall: 0xF6F7,
 +  Dslash: 0x0110,
 +  Dsmall: 0xF764,
 +  Dtopbar: 0x018B,
 +  Dz: 0x01F2,
 +  Dzcaron: 0x01C5,
 +  Dzeabkhasiancyrillic: 0x04E0,
 +  Dzecyrillic: 0x0405,
 +  Dzhecyrillic: 0x040F,
 +  E: 0x0045,
 +  Eacute: 0x00C9,
 +  Eacutesmall: 0xF7E9,
 +  Ebreve: 0x0114,
 +  Ecaron: 0x011A,
 +  Ecedillabreve: 0x1E1C,
 +  Echarmenian: 0x0535,
 +  Ecircle: 0x24BA,
 +  Ecircumflex: 0x00CA,
 +  Ecircumflexacute: 0x1EBE,
 +  Ecircumflexbelow: 0x1E18,
 +  Ecircumflexdotbelow: 0x1EC6,
 +  Ecircumflexgrave: 0x1EC0,
 +  Ecircumflexhookabove: 0x1EC2,
 +  Ecircumflexsmall: 0xF7EA,
 +  Ecircumflextilde: 0x1EC4,
 +  Ecyrillic: 0x0404,
 +  Edblgrave: 0x0204,
 +  Edieresis: 0x00CB,
 +  Edieresissmall: 0xF7EB,
 +  Edot: 0x0116,
 +  Edotaccent: 0x0116,
 +  Edotbelow: 0x1EB8,
 +  Efcyrillic: 0x0424,
 +  Egrave: 0x00C8,
 +  Egravesmall: 0xF7E8,
 +  Eharmenian: 0x0537,
 +  Ehookabove: 0x1EBA,
 +  Eightroman: 0x2167,
 +  Einvertedbreve: 0x0206,
 +  Eiotifiedcyrillic: 0x0464,
 +  Elcyrillic: 0x041B,
 +  Elevenroman: 0x216A,
 +  Emacron: 0x0112,
 +  Emacronacute: 0x1E16,
 +  Emacrongrave: 0x1E14,
 +  Emcyrillic: 0x041C,
 +  Emonospace: 0xFF25,
 +  Encyrillic: 0x041D,
 +  Endescendercyrillic: 0x04A2,
 +  Eng: 0x014A,
 +  Enghecyrillic: 0x04A4,
 +  Enhookcyrillic: 0x04C7,
 +  Eogonek: 0x0118,
 +  Eopen: 0x0190,
 +  Epsilon: 0x0395,
 +  Epsilontonos: 0x0388,
 +  Ercyrillic: 0x0420,
 +  Ereversed: 0x018E,
 +  Ereversedcyrillic: 0x042D,
 +  Escyrillic: 0x0421,
 +  Esdescendercyrillic: 0x04AA,
 +  Esh: 0x01A9,
 +  Esmall: 0xF765,
 +  Eta: 0x0397,
 +  Etarmenian: 0x0538,
 +  Etatonos: 0x0389,
 +  Eth: 0x00D0,
 +  Ethsmall: 0xF7F0,
 +  Etilde: 0x1EBC,
 +  Etildebelow: 0x1E1A,
 +  Euro: 0x20AC,
 +  Ezh: 0x01B7,
 +  Ezhcaron: 0x01EE,
 +  Ezhreversed: 0x01B8,
 +  F: 0x0046,
 +  Fcircle: 0x24BB,
 +  Fdotaccent: 0x1E1E,
 +  Feharmenian: 0x0556,
 +  Feicoptic: 0x03E4,
 +  Fhook: 0x0191,
 +  Fitacyrillic: 0x0472,
 +  Fiveroman: 0x2164,
 +  Fmonospace: 0xFF26,
 +  Fourroman: 0x2163,
 +  Fsmall: 0xF766,
 +  G: 0x0047,
 +  GBsquare: 0x3387,
 +  Gacute: 0x01F4,
 +  Gamma: 0x0393,
 +  Gammaafrican: 0x0194,
 +  Gangiacoptic: 0x03EA,
 +  Gbreve: 0x011E,
 +  Gcaron: 0x01E6,
 +  Gcedilla: 0x0122,
 +  Gcircle: 0x24BC,
 +  Gcircumflex: 0x011C,
 +  Gcommaaccent: 0x0122,
 +  Gdot: 0x0120,
 +  Gdotaccent: 0x0120,
 +  Gecyrillic: 0x0413,
 +  Ghadarmenian: 0x0542,
 +  Ghemiddlehookcyrillic: 0x0494,
 +  Ghestrokecyrillic: 0x0492,
 +  Gheupturncyrillic: 0x0490,
 +  Ghook: 0x0193,
 +  Gimarmenian: 0x0533,
 +  Gjecyrillic: 0x0403,
 +  Gmacron: 0x1E20,
 +  Gmonospace: 0xFF27,
 +  Grave: 0xF6CE,
 +  Gravesmall: 0xF760,
 +  Gsmall: 0xF767,
 +  Gsmallhook: 0x029B,
 +  Gstroke: 0x01E4,
 +  H: 0x0048,
 +  H18533: 0x25CF,
 +  H18543: 0x25AA,
 +  H18551: 0x25AB,
 +  H22073: 0x25A1,
 +  HPsquare: 0x33CB,
 +  Haabkhasiancyrillic: 0x04A8,
 +  Hadescendercyrillic: 0x04B2,
 +  Hardsigncyrillic: 0x042A,
 +  Hbar: 0x0126,
 +  Hbrevebelow: 0x1E2A,
 +  Hcedilla: 0x1E28,
 +  Hcircle: 0x24BD,
 +  Hcircumflex: 0x0124,
 +  Hdieresis: 0x1E26,
 +  Hdotaccent: 0x1E22,
 +  Hdotbelow: 0x1E24,
 +  Hmonospace: 0xFF28,
 +  Hoarmenian: 0x0540,
 +  Horicoptic: 0x03E8,
 +  Hsmall: 0xF768,
 +  Hungarumlaut: 0xF6CF,
 +  Hungarumlautsmall: 0xF6F8,
 +  Hzsquare: 0x3390,
 +  I: 0x0049,
 +  IAcyrillic: 0x042F,
 +  IJ: 0x0132,
 +  IUcyrillic: 0x042E,
 +  Iacute: 0x00CD,
 +  Iacutesmall: 0xF7ED,
 +  Ibreve: 0x012C,
 +  Icaron: 0x01CF,
 +  Icircle: 0x24BE,
 +  Icircumflex: 0x00CE,
 +  Icircumflexsmall: 0xF7EE,
 +  Icyrillic: 0x0406,
 +  Idblgrave: 0x0208,
 +  Idieresis: 0x00CF,
 +  Idieresisacute: 0x1E2E,
 +  Idieresiscyrillic: 0x04E4,
 +  Idieresissmall: 0xF7EF,
 +  Idot: 0x0130,
 +  Idotaccent: 0x0130,
 +  Idotbelow: 0x1ECA,
 +  Iebrevecyrillic: 0x04D6,
 +  Iecyrillic: 0x0415,
 +  Ifraktur: 0x2111,
 +  Igrave: 0x00CC,
 +  Igravesmall: 0xF7EC,
 +  Ihookabove: 0x1EC8,
 +  Iicyrillic: 0x0418,
 +  Iinvertedbreve: 0x020A,
 +  Iishortcyrillic: 0x0419,
 +  Imacron: 0x012A,
 +  Imacroncyrillic: 0x04E2,
 +  Imonospace: 0xFF29,
 +  Iniarmenian: 0x053B,
 +  Iocyrillic: 0x0401,
 +  Iogonek: 0x012E,
 +  Iota: 0x0399,
 +  Iotaafrican: 0x0196,
 +  Iotadieresis: 0x03AA,
 +  Iotatonos: 0x038A,
 +  Ismall: 0xF769,
 +  Istroke: 0x0197,
 +  Itilde: 0x0128,
 +  Itildebelow: 0x1E2C,
 +  Izhitsacyrillic: 0x0474,
 +  Izhitsadblgravecyrillic: 0x0476,
 +  J: 0x004A,
 +  Jaarmenian: 0x0541,
 +  Jcircle: 0x24BF,
 +  Jcircumflex: 0x0134,
 +  Jecyrillic: 0x0408,
 +  Jheharmenian: 0x054B,
 +  Jmonospace: 0xFF2A,
 +  Jsmall: 0xF76A,
 +  K: 0x004B,
 +  KBsquare: 0x3385,
 +  KKsquare: 0x33CD,
 +  Kabashkircyrillic: 0x04A0,
 +  Kacute: 0x1E30,
 +  Kacyrillic: 0x041A,
 +  Kadescendercyrillic: 0x049A,
 +  Kahookcyrillic: 0x04C3,
 +  Kappa: 0x039A,
 +  Kastrokecyrillic: 0x049E,
 +  Kaverticalstrokecyrillic: 0x049C,
 +  Kcaron: 0x01E8,
 +  Kcedilla: 0x0136,
 +  Kcircle: 0x24C0,
 +  Kcommaaccent: 0x0136,
 +  Kdotbelow: 0x1E32,
 +  Keharmenian: 0x0554,
 +  Kenarmenian: 0x053F,
 +  Khacyrillic: 0x0425,
 +  Kheicoptic: 0x03E6,
 +  Khook: 0x0198,
 +  Kjecyrillic: 0x040C,
 +  Klinebelow: 0x1E34,
 +  Kmonospace: 0xFF2B,
 +  Koppacyrillic: 0x0480,
 +  Koppagreek: 0x03DE,
 +  Ksicyrillic: 0x046E,
 +  Ksmall: 0xF76B,
 +  L: 0x004C,
 +  LJ: 0x01C7,
 +  LL: 0xF6BF,
 +  Lacute: 0x0139,
 +  Lambda: 0x039B,
 +  Lcaron: 0x013D,
 +  Lcedilla: 0x013B,
 +  Lcircle: 0x24C1,
 +  Lcircumflexbelow: 0x1E3C,
 +  Lcommaaccent: 0x013B,
 +  Ldot: 0x013F,
 +  Ldotaccent: 0x013F,
 +  Ldotbelow: 0x1E36,
 +  Ldotbelowmacron: 0x1E38,
 +  Liwnarmenian: 0x053C,
 +  Lj: 0x01C8,
 +  Ljecyrillic: 0x0409,
 +  Llinebelow: 0x1E3A,
 +  Lmonospace: 0xFF2C,
 +  Lslash: 0x0141,
 +  Lslashsmall: 0xF6F9,
 +  Lsmall: 0xF76C,
 +  M: 0x004D,
 +  MBsquare: 0x3386,
 +  Macron: 0xF6D0,
 +  Macronsmall: 0xF7AF,
 +  Macute: 0x1E3E,
 +  Mcircle: 0x24C2,
 +  Mdotaccent: 0x1E40,
 +  Mdotbelow: 0x1E42,
 +  Menarmenian: 0x0544,
 +  Mmonospace: 0xFF2D,
 +  Msmall: 0xF76D,
 +  Mturned: 0x019C,
 +  Mu: 0x039C,
 +  N: 0x004E,
 +  NJ: 0x01CA,
 +  Nacute: 0x0143,
 +  Ncaron: 0x0147,
 +  Ncedilla: 0x0145,
 +  Ncircle: 0x24C3,
 +  Ncircumflexbelow: 0x1E4A,
 +  Ncommaaccent: 0x0145,
 +  Ndotaccent: 0x1E44,
 +  Ndotbelow: 0x1E46,
 +  Nhookleft: 0x019D,
 +  Nineroman: 0x2168,
 +  Nj: 0x01CB,
 +  Njecyrillic: 0x040A,
 +  Nlinebelow: 0x1E48,
 +  Nmonospace: 0xFF2E,
 +  Nowarmenian: 0x0546,
 +  Nsmall: 0xF76E,
 +  Ntilde: 0x00D1,
 +  Ntildesmall: 0xF7F1,
 +  Nu: 0x039D,
 +  O: 0x004F,
 +  OE: 0x0152,
 +  OEsmall: 0xF6FA,
 +  Oacute: 0x00D3,
 +  Oacutesmall: 0xF7F3,
 +  Obarredcyrillic: 0x04E8,
 +  Obarreddieresiscyrillic: 0x04EA,
 +  Obreve: 0x014E,
 +  Ocaron: 0x01D1,
 +  Ocenteredtilde: 0x019F,
 +  Ocircle: 0x24C4,
 +  Ocircumflex: 0x00D4,
 +  Ocircumflexacute: 0x1ED0,
 +  Ocircumflexdotbelow: 0x1ED8,
 +  Ocircumflexgrave: 0x1ED2,
 +  Ocircumflexhookabove: 0x1ED4,
 +  Ocircumflexsmall: 0xF7F4,
 +  Ocircumflextilde: 0x1ED6,
 +  Ocyrillic: 0x041E,
 +  Odblacute: 0x0150,
 +  Odblgrave: 0x020C,
 +  Odieresis: 0x00D6,
 +  Odieresiscyrillic: 0x04E6,
 +  Odieresissmall: 0xF7F6,
 +  Odotbelow: 0x1ECC,
 +  Ogoneksmall: 0xF6FB,
 +  Ograve: 0x00D2,
 +  Ogravesmall: 0xF7F2,
 +  Oharmenian: 0x0555,
 +  Ohm: 0x2126,
 +  Ohookabove: 0x1ECE,
 +  Ohorn: 0x01A0,
 +  Ohornacute: 0x1EDA,
 +  Ohorndotbelow: 0x1EE2,
 +  Ohorngrave: 0x1EDC,
 +  Ohornhookabove: 0x1EDE,
 +  Ohorntilde: 0x1EE0,
 +  Ohungarumlaut: 0x0150,
 +  Oi: 0x01A2,
 +  Oinvertedbreve: 0x020E,
 +  Omacron: 0x014C,
 +  Omacronacute: 0x1E52,
 +  Omacrongrave: 0x1E50,
 +  Omega: 0x2126,
 +  Omegacyrillic: 0x0460,
 +  Omegagreek: 0x03A9,
 +  Omegaroundcyrillic: 0x047A,
 +  Omegatitlocyrillic: 0x047C,
 +  Omegatonos: 0x038F,
 +  Omicron: 0x039F,
 +  Omicrontonos: 0x038C,
 +  Omonospace: 0xFF2F,
 +  Oneroman: 0x2160,
 +  Oogonek: 0x01EA,
 +  Oogonekmacron: 0x01EC,
 +  Oopen: 0x0186,
 +  Oslash: 0x00D8,
 +  Oslashacute: 0x01FE,
 +  Oslashsmall: 0xF7F8,
 +  Osmall: 0xF76F,
 +  Ostrokeacute: 0x01FE,
 +  Otcyrillic: 0x047E,
 +  Otilde: 0x00D5,
 +  Otildeacute: 0x1E4C,
 +  Otildedieresis: 0x1E4E,
 +  Otildesmall: 0xF7F5,
 +  P: 0x0050,
 +  Pacute: 0x1E54,
 +  Pcircle: 0x24C5,
 +  Pdotaccent: 0x1E56,
 +  Pecyrillic: 0x041F,
 +  Peharmenian: 0x054A,
 +  Pemiddlehookcyrillic: 0x04A6,
 +  Phi: 0x03A6,
 +  Phook: 0x01A4,
 +  Pi: 0x03A0,
 +  Piwrarmenian: 0x0553,
 +  Pmonospace: 0xFF30,
 +  Psi: 0x03A8,
 +  Psicyrillic: 0x0470,
 +  Psmall: 0xF770,
 +  Q: 0x0051,
 +  Qcircle: 0x24C6,
 +  Qmonospace: 0xFF31,
 +  Qsmall: 0xF771,
 +  R: 0x0052,
 +  Raarmenian: 0x054C,
 +  Racute: 0x0154,
 +  Rcaron: 0x0158,
 +  Rcedilla: 0x0156,
 +  Rcircle: 0x24C7,
 +  Rcommaaccent: 0x0156,
 +  Rdblgrave: 0x0210,
 +  Rdotaccent: 0x1E58,
 +  Rdotbelow: 0x1E5A,
 +  Rdotbelowmacron: 0x1E5C,
 +  Reharmenian: 0x0550,
 +  Rfraktur: 0x211C,
 +  Rho: 0x03A1,
 +  Ringsmall: 0xF6FC,
 +  Rinvertedbreve: 0x0212,
 +  Rlinebelow: 0x1E5E,
 +  Rmonospace: 0xFF32,
 +  Rsmall: 0xF772,
 +  Rsmallinverted: 0x0281,
 +  Rsmallinvertedsuperior: 0x02B6,
 +  S: 0x0053,
 +  SF010000: 0x250C,
 +  SF020000: 0x2514,
 +  SF030000: 0x2510,
 +  SF040000: 0x2518,
 +  SF050000: 0x253C,
 +  SF060000: 0x252C,
 +  SF070000: 0x2534,
 +  SF080000: 0x251C,
 +  SF090000: 0x2524,
 +  SF100000: 0x2500,
 +  SF110000: 0x2502,
 +  SF190000: 0x2561,
 +  SF200000: 0x2562,
 +  SF210000: 0x2556,
 +  SF220000: 0x2555,
 +  SF230000: 0x2563,
 +  SF240000: 0x2551,
 +  SF250000: 0x2557,
 +  SF260000: 0x255D,
 +  SF270000: 0x255C,
 +  SF280000: 0x255B,
 +  SF360000: 0x255E,
 +  SF370000: 0x255F,
 +  SF380000: 0x255A,
 +  SF390000: 0x2554,
 +  SF400000: 0x2569,
 +  SF410000: 0x2566,
 +  SF420000: 0x2560,
 +  SF430000: 0x2550,
 +  SF440000: 0x256C,
 +  SF450000: 0x2567,
 +  SF460000: 0x2568,
 +  SF470000: 0x2564,
 +  SF480000: 0x2565,
 +  SF490000: 0x2559,
 +  SF500000: 0x2558,
 +  SF510000: 0x2552,
 +  SF520000: 0x2553,
 +  SF530000: 0x256B,
 +  SF540000: 0x256A,
 +  Sacute: 0x015A,
 +  Sacutedotaccent: 0x1E64,
 +  Sampigreek: 0x03E0,
 +  Scaron: 0x0160,
 +  Scarondotaccent: 0x1E66,
 +  Scaronsmall: 0xF6FD,
 +  Scedilla: 0x015E,
 +  Schwa: 0x018F,
 +  Schwacyrillic: 0x04D8,
 +  Schwadieresiscyrillic: 0x04DA,
 +  Scircle: 0x24C8,
 +  Scircumflex: 0x015C,
 +  Scommaaccent: 0x0218,
 +  Sdotaccent: 0x1E60,
 +  Sdotbelow: 0x1E62,
 +  Sdotbelowdotaccent: 0x1E68,
 +  Seharmenian: 0x054D,
 +  Sevenroman: 0x2166,
 +  Shaarmenian: 0x0547,
 +  Shacyrillic: 0x0428,
 +  Shchacyrillic: 0x0429,
 +  Sheicoptic: 0x03E2,
 +  Shhacyrillic: 0x04BA,
 +  Shimacoptic: 0x03EC,
 +  Sigma: 0x03A3,
 +  Sixroman: 0x2165,
 +  Smonospace: 0xFF33,
 +  Softsigncyrillic: 0x042C,
 +  Ssmall: 0xF773,
 +  Stigmagreek: 0x03DA,
 +  T: 0x0054,
 +  Tau: 0x03A4,
 +  Tbar: 0x0166,
 +  Tcaron: 0x0164,
 +  Tcedilla: 0x0162,
 +  Tcircle: 0x24C9,
 +  Tcircumflexbelow: 0x1E70,
 +  Tcommaaccent: 0x0162,
 +  Tdotaccent: 0x1E6A,
 +  Tdotbelow: 0x1E6C,
 +  Tecyrillic: 0x0422,
 +  Tedescendercyrillic: 0x04AC,
 +  Tenroman: 0x2169,
 +  Tetsecyrillic: 0x04B4,
 +  Theta: 0x0398,
 +  Thook: 0x01AC,
 +  Thorn: 0x00DE,
 +  Thornsmall: 0xF7FE,
 +  Threeroman: 0x2162,
 +  Tildesmall: 0xF6FE,
 +  Tiwnarmenian: 0x054F,
 +  Tlinebelow: 0x1E6E,
 +  Tmonospace: 0xFF34,
 +  Toarmenian: 0x0539,
 +  Tonefive: 0x01BC,
 +  Tonesix: 0x0184,
 +  Tonetwo: 0x01A7,
 +  Tretroflexhook: 0x01AE,
 +  Tsecyrillic: 0x0426,
 +  Tshecyrillic: 0x040B,
 +  Tsmall: 0xF774,
 +  Twelveroman: 0x216B,
 +  Tworoman: 0x2161,
 +  U: 0x0055,
 +  Uacute: 0x00DA,
 +  Uacutesmall: 0xF7FA,
 +  Ubreve: 0x016C,
 +  Ucaron: 0x01D3,
 +  Ucircle: 0x24CA,
 +  Ucircumflex: 0x00DB,
 +  Ucircumflexbelow: 0x1E76,
 +  Ucircumflexsmall: 0xF7FB,
 +  Ucyrillic: 0x0423,
 +  Udblacute: 0x0170,
 +  Udblgrave: 0x0214,
 +  Udieresis: 0x00DC,
 +  Udieresisacute: 0x01D7,
 +  Udieresisbelow: 0x1E72,
 +  Udieresiscaron: 0x01D9,
 +  Udieresiscyrillic: 0x04F0,
 +  Udieresisgrave: 0x01DB,
 +  Udieresismacron: 0x01D5,
 +  Udieresissmall: 0xF7FC,
 +  Udotbelow: 0x1EE4,
 +  Ugrave: 0x00D9,
 +  Ugravesmall: 0xF7F9,
 +  Uhookabove: 0x1EE6,
 +  Uhorn: 0x01AF,
 +  Uhornacute: 0x1EE8,
 +  Uhorndotbelow: 0x1EF0,
 +  Uhorngrave: 0x1EEA,
 +  Uhornhookabove: 0x1EEC,
 +  Uhorntilde: 0x1EEE,
 +  Uhungarumlaut: 0x0170,
 +  Uhungarumlautcyrillic: 0x04F2,
 +  Uinvertedbreve: 0x0216,
 +  Ukcyrillic: 0x0478,
 +  Umacron: 0x016A,
 +  Umacroncyrillic: 0x04EE,
 +  Umacrondieresis: 0x1E7A,
 +  Umonospace: 0xFF35,
 +  Uogonek: 0x0172,
 +  Upsilon: 0x03A5,
 +  Upsilon1: 0x03D2,
 +  Upsilonacutehooksymbolgreek: 0x03D3,
 +  Upsilonafrican: 0x01B1,
 +  Upsilondieresis: 0x03AB,
 +  Upsilondieresishooksymbolgreek: 0x03D4,
 +  Upsilonhooksymbol: 0x03D2,
 +  Upsilontonos: 0x038E,
 +  Uring: 0x016E,
 +  Ushortcyrillic: 0x040E,
 +  Usmall: 0xF775,
 +  Ustraightcyrillic: 0x04AE,
 +  Ustraightstrokecyrillic: 0x04B0,
 +  Utilde: 0x0168,
 +  Utildeacute: 0x1E78,
 +  Utildebelow: 0x1E74,
 +  V: 0x0056,
 +  Vcircle: 0x24CB,
 +  Vdotbelow: 0x1E7E,
 +  Vecyrillic: 0x0412,
 +  Vewarmenian: 0x054E,
 +  Vhook: 0x01B2,
 +  Vmonospace: 0xFF36,
 +  Voarmenian: 0x0548,
 +  Vsmall: 0xF776,
 +  Vtilde: 0x1E7C,
 +  W: 0x0057,
 +  Wacute: 0x1E82,
 +  Wcircle: 0x24CC,
 +  Wcircumflex: 0x0174,
 +  Wdieresis: 0x1E84,
 +  Wdotaccent: 0x1E86,
 +  Wdotbelow: 0x1E88,
 +  Wgrave: 0x1E80,
 +  Wmonospace: 0xFF37,
 +  Wsmall: 0xF777,
 +  X: 0x0058,
 +  Xcircle: 0x24CD,
 +  Xdieresis: 0x1E8C,
 +  Xdotaccent: 0x1E8A,
 +  Xeharmenian: 0x053D,
 +  Xi: 0x039E,
 +  Xmonospace: 0xFF38,
 +  Xsmall: 0xF778,
 +  Y: 0x0059,
 +  Yacute: 0x00DD,
 +  Yacutesmall: 0xF7FD,
 +  Yatcyrillic: 0x0462,
 +  Ycircle: 0x24CE,
 +  Ycircumflex: 0x0176,
 +  Ydieresis: 0x0178,
 +  Ydieresissmall: 0xF7FF,
 +  Ydotaccent: 0x1E8E,
 +  Ydotbelow: 0x1EF4,
 +  Yericyrillic: 0x042B,
 +  Yerudieresiscyrillic: 0x04F8,
 +  Ygrave: 0x1EF2,
 +  Yhook: 0x01B3,
 +  Yhookabove: 0x1EF6,
 +  Yiarmenian: 0x0545,
 +  Yicyrillic: 0x0407,
 +  Yiwnarmenian: 0x0552,
 +  Ymonospace: 0xFF39,
 +  Ysmall: 0xF779,
 +  Ytilde: 0x1EF8,
 +  Yusbigcyrillic: 0x046A,
 +  Yusbigiotifiedcyrillic: 0x046C,
 +  Yuslittlecyrillic: 0x0466,
 +  Yuslittleiotifiedcyrillic: 0x0468,
 +  Z: 0x005A,
 +  Zaarmenian: 0x0536,
 +  Zacute: 0x0179,
 +  Zcaron: 0x017D,
 +  Zcaronsmall: 0xF6FF,
 +  Zcircle: 0x24CF,
 +  Zcircumflex: 0x1E90,
 +  Zdot: 0x017B,
 +  Zdotaccent: 0x017B,
 +  Zdotbelow: 0x1E92,
 +  Zecyrillic: 0x0417,
 +  Zedescendercyrillic: 0x0498,
 +  Zedieresiscyrillic: 0x04DE,
 +  Zeta: 0x0396,
 +  Zhearmenian: 0x053A,
 +  Zhebrevecyrillic: 0x04C1,
 +  Zhecyrillic: 0x0416,
 +  Zhedescendercyrillic: 0x0496,
 +  Zhedieresiscyrillic: 0x04DC,
 +  Zlinebelow: 0x1E94,
 +  Zmonospace: 0xFF3A,
 +  Zsmall: 0xF77A,
 +  Zstroke: 0x01B5,
 +  a: 0x0061,
 +  aabengali: 0x0986,
 +  aacute: 0x00E1,
 +  aadeva: 0x0906,
 +  aagujarati: 0x0A86,
 +  aagurmukhi: 0x0A06,
 +  aamatragurmukhi: 0x0A3E,
 +  aarusquare: 0x3303,
 +  aavowelsignbengali: 0x09BE,
 +  aavowelsigndeva: 0x093E,
 +  aavowelsigngujarati: 0x0ABE,
 +  abbreviationmarkarmenian: 0x055F,
 +  abbreviationsigndeva: 0x0970,
 +  abengali: 0x0985,
 +  abopomofo: 0x311A,
 +  abreve: 0x0103,
 +  abreveacute: 0x1EAF,
 +  abrevecyrillic: 0x04D1,
 +  abrevedotbelow: 0x1EB7,
 +  abrevegrave: 0x1EB1,
 +  abrevehookabove: 0x1EB3,
 +  abrevetilde: 0x1EB5,
 +  acaron: 0x01CE,
 +  acircle: 0x24D0,
 +  acircumflex: 0x00E2,
 +  acircumflexacute: 0x1EA5,
 +  acircumflexdotbelow: 0x1EAD,
 +  acircumflexgrave: 0x1EA7,
 +  acircumflexhookabove: 0x1EA9,
 +  acircumflextilde: 0x1EAB,
 +  acute: 0x00B4,
 +  acutebelowcmb: 0x0317,
 +  acutecmb: 0x0301,
 +  acutecomb: 0x0301,
 +  acutedeva: 0x0954,
 +  acutelowmod: 0x02CF,
 +  acutetonecmb: 0x0341,
 +  acyrillic: 0x0430,
 +  adblgrave: 0x0201,
 +  addakgurmukhi: 0x0A71,
 +  adeva: 0x0905,
 +  adieresis: 0x00E4,
 +  adieresiscyrillic: 0x04D3,
 +  adieresismacron: 0x01DF,
 +  adotbelow: 0x1EA1,
 +  adotmacron: 0x01E1,
 +  ae: 0x00E6,
 +  aeacute: 0x01FD,
 +  aekorean: 0x3150,
 +  aemacron: 0x01E3,
 +  afii00208: 0x2015,
 +  afii08941: 0x20A4,
 +  afii10017: 0x0410,
 +  afii10018: 0x0411,
 +  afii10019: 0x0412,
 +  afii10020: 0x0413,
 +  afii10021: 0x0414,
 +  afii10022: 0x0415,
 +  afii10023: 0x0401,
 +  afii10024: 0x0416,
 +  afii10025: 0x0417,
 +  afii10026: 0x0418,
 +  afii10027: 0x0419,
 +  afii10028: 0x041A,
 +  afii10029: 0x041B,
 +  afii10030: 0x041C,
 +  afii10031: 0x041D,
 +  afii10032: 0x041E,
 +  afii10033: 0x041F,
 +  afii10034: 0x0420,
 +  afii10035: 0x0421,
 +  afii10036: 0x0422,
 +  afii10037: 0x0423,
 +  afii10038: 0x0424,
 +  afii10039: 0x0425,
 +  afii10040: 0x0426,
 +  afii10041: 0x0427,
 +  afii10042: 0x0428,
 +  afii10043: 0x0429,
 +  afii10044: 0x042A,
 +  afii10045: 0x042B,
 +  afii10046: 0x042C,
 +  afii10047: 0x042D,
 +  afii10048: 0x042E,
 +  afii10049: 0x042F,
 +  afii10050: 0x0490,
 +  afii10051: 0x0402,
 +  afii10052: 0x0403,
 +  afii10053: 0x0404,
 +  afii10054: 0x0405,
 +  afii10055: 0x0406,
 +  afii10056: 0x0407,
 +  afii10057: 0x0408,
 +  afii10058: 0x0409,
 +  afii10059: 0x040A,
 +  afii10060: 0x040B,
 +  afii10061: 0x040C,
 +  afii10062: 0x040E,
 +  afii10063: 0xF6C4,
 +  afii10064: 0xF6C5,
 +  afii10065: 0x0430,
 +  afii10066: 0x0431,
 +  afii10067: 0x0432,
 +  afii10068: 0x0433,
 +  afii10069: 0x0434,
 +  afii10070: 0x0435,
 +  afii10071: 0x0451,
 +  afii10072: 0x0436,
 +  afii10073: 0x0437,
 +  afii10074: 0x0438,
 +  afii10075: 0x0439,
 +  afii10076: 0x043A,
 +  afii10077: 0x043B,
 +  afii10078: 0x043C,
 +  afii10079: 0x043D,
 +  afii10080: 0x043E,
 +  afii10081: 0x043F,
 +  afii10082: 0x0440,
 +  afii10083: 0x0441,
 +  afii10084: 0x0442,
 +  afii10085: 0x0443,
 +  afii10086: 0x0444,
 +  afii10087: 0x0445,
 +  afii10088: 0x0446,
 +  afii10089: 0x0447,
 +  afii10090: 0x0448,
 +  afii10091: 0x0449,
 +  afii10092: 0x044A,
 +  afii10093: 0x044B,
 +  afii10094: 0x044C,
 +  afii10095: 0x044D,
 +  afii10096: 0x044E,
 +  afii10097: 0x044F,
 +  afii10098: 0x0491,
 +  afii10099: 0x0452,
 +  afii10100: 0x0453,
 +  afii10101: 0x0454,
 +  afii10102: 0x0455,
 +  afii10103: 0x0456,
 +  afii10104: 0x0457,
 +  afii10105: 0x0458,
 +  afii10106: 0x0459,
 +  afii10107: 0x045A,
 +  afii10108: 0x045B,
 +  afii10109: 0x045C,
 +  afii10110: 0x045E,
 +  afii10145: 0x040F,
 +  afii10146: 0x0462,
 +  afii10147: 0x0472,
 +  afii10148: 0x0474,
 +  afii10192: 0xF6C6,
 +  afii10193: 0x045F,
 +  afii10194: 0x0463,
 +  afii10195: 0x0473,
 +  afii10196: 0x0475,
 +  afii10831: 0xF6C7,
 +  afii10832: 0xF6C8,
 +  afii10846: 0x04D9,
 +  afii299: 0x200E,
 +  afii300: 0x200F,
 +  afii301: 0x200D,
 +  afii57381: 0x066A,
 +  afii57388: 0x060C,
 +  afii57392: 0x0660,
 +  afii57393: 0x0661,
 +  afii57394: 0x0662,
 +  afii57395: 0x0663,
 +  afii57396: 0x0664,
 +  afii57397: 0x0665,
 +  afii57398: 0x0666,
 +  afii57399: 0x0667,
 +  afii57400: 0x0668,
 +  afii57401: 0x0669,
 +  afii57403: 0x061B,
 +  afii57407: 0x061F,
 +  afii57409: 0x0621,
 +  afii57410: 0x0622,
 +  afii57411: 0x0623,
 +  afii57412: 0x0624,
 +  afii57413: 0x0625,
 +  afii57414: 0x0626,
 +  afii57415: 0x0627,
 +  afii57416: 0x0628,
 +  afii57417: 0x0629,
 +  afii57418: 0x062A,
 +  afii57419: 0x062B,
 +  afii57420: 0x062C,
 +  afii57421: 0x062D,
 +  afii57422: 0x062E,
 +  afii57423: 0x062F,
 +  afii57424: 0x0630,
 +  afii57425: 0x0631,
 +  afii57426: 0x0632,
 +  afii57427: 0x0633,
 +  afii57428: 0x0634,
 +  afii57429: 0x0635,
 +  afii57430: 0x0636,
 +  afii57431: 0x0637,
 +  afii57432: 0x0638,
 +  afii57433: 0x0639,
 +  afii57434: 0x063A,
 +  afii57440: 0x0640,
 +  afii57441: 0x0641,
 +  afii57442: 0x0642,
 +  afii57443: 0x0643,
 +  afii57444: 0x0644,
 +  afii57445: 0x0645,
 +  afii57446: 0x0646,
 +  afii57448: 0x0648,
 +  afii57449: 0x0649,
 +  afii57450: 0x064A,
 +  afii57451: 0x064B,
 +  afii57452: 0x064C,
 +  afii57453: 0x064D,
 +  afii57454: 0x064E,
 +  afii57455: 0x064F,
 +  afii57456: 0x0650,
 +  afii57457: 0x0651,
 +  afii57458: 0x0652,
 +  afii57470: 0x0647,
 +  afii57505: 0x06A4,
 +  afii57506: 0x067E,
 +  afii57507: 0x0686,
 +  afii57508: 0x0698,
 +  afii57509: 0x06AF,
 +  afii57511: 0x0679,
 +  afii57512: 0x0688,
 +  afii57513: 0x0691,
 +  afii57514: 0x06BA,
 +  afii57519: 0x06D2,
 +  afii57534: 0x06D5,
 +  afii57636: 0x20AA,
 +  afii57645: 0x05BE,
 +  afii57658: 0x05C3,
 +  afii57664: 0x05D0,
 +  afii57665: 0x05D1,
 +  afii57666: 0x05D2,
 +  afii57667: 0x05D3,
 +  afii57668: 0x05D4,
 +  afii57669: 0x05D5,
 +  afii57670: 0x05D6,
 +  afii57671: 0x05D7,
 +  afii57672: 0x05D8,
 +  afii57673: 0x05D9,
 +  afii57674: 0x05DA,
 +  afii57675: 0x05DB,
 +  afii57676: 0x05DC,
 +  afii57677: 0x05DD,
 +  afii57678: 0x05DE,
 +  afii57679: 0x05DF,
 +  afii57680: 0x05E0,
 +  afii57681: 0x05E1,
 +  afii57682: 0x05E2,
 +  afii57683: 0x05E3,
 +  afii57684: 0x05E4,
 +  afii57685: 0x05E5,
 +  afii57686: 0x05E6,
 +  afii57687: 0x05E7,
 +  afii57688: 0x05E8,
 +  afii57689: 0x05E9,
 +  afii57690: 0x05EA,
 +  afii57694: 0xFB2A,
 +  afii57695: 0xFB2B,
 +  afii57700: 0xFB4B,
 +  afii57705: 0xFB1F,
 +  afii57716: 0x05F0,
 +  afii57717: 0x05F1,
 +  afii57718: 0x05F2,
 +  afii57723: 0xFB35,
 +  afii57793: 0x05B4,
 +  afii57794: 0x05B5,
 +  afii57795: 0x05B6,
 +  afii57796: 0x05BB,
 +  afii57797: 0x05B8,
 +  afii57798: 0x05B7,
 +  afii57799: 0x05B0,
 +  afii57800: 0x05B2,
 +  afii57801: 0x05B1,
 +  afii57802: 0x05B3,
 +  afii57803: 0x05C2,
 +  afii57804: 0x05C1,
 +  afii57806: 0x05B9,
 +  afii57807: 0x05BC,
 +  afii57839: 0x05BD,
 +  afii57841: 0x05BF,
 +  afii57842: 0x05C0,
 +  afii57929: 0x02BC,
 +  afii61248: 0x2105,
 +  afii61289: 0x2113,
 +  afii61352: 0x2116,
 +  afii61573: 0x202C,
 +  afii61574: 0x202D,
 +  afii61575: 0x202E,
 +  afii61664: 0x200C,
 +  afii63167: 0x066D,
 +  afii64937: 0x02BD,
 +  agrave: 0x00E0,
 +  agujarati: 0x0A85,
 +  agurmukhi: 0x0A05,
 +  ahiragana: 0x3042,
 +  ahookabove: 0x1EA3,
 +  aibengali: 0x0990,
 +  aibopomofo: 0x311E,
 +  aideva: 0x0910,
 +  aiecyrillic: 0x04D5,
 +  aigujarati: 0x0A90,
 +  aigurmukhi: 0x0A10,
 +  aimatragurmukhi: 0x0A48,
 +  ainarabic: 0x0639,
 +  ainfinalarabic: 0xFECA,
 +  aininitialarabic: 0xFECB,
 +  ainmedialarabic: 0xFECC,
 +  ainvertedbreve: 0x0203,
 +  aivowelsignbengali: 0x09C8,
 +  aivowelsigndeva: 0x0948,
 +  aivowelsigngujarati: 0x0AC8,
 +  akatakana: 0x30A2,
 +  akatakanahalfwidth: 0xFF71,
 +  akorean: 0x314F,
 +  alef: 0x05D0,
 +  alefarabic: 0x0627,
 +  alefdageshhebrew: 0xFB30,
 +  aleffinalarabic: 0xFE8E,
 +  alefhamzaabovearabic: 0x0623,
 +  alefhamzaabovefinalarabic: 0xFE84,
 +  alefhamzabelowarabic: 0x0625,
 +  alefhamzabelowfinalarabic: 0xFE88,
 +  alefhebrew: 0x05D0,
 +  aleflamedhebrew: 0xFB4F,
 +  alefmaddaabovearabic: 0x0622,
 +  alefmaddaabovefinalarabic: 0xFE82,
 +  alefmaksuraarabic: 0x0649,
 +  alefmaksurafinalarabic: 0xFEF0,
 +  alefmaksurainitialarabic: 0xFEF3,
 +  alefmaksuramedialarabic: 0xFEF4,
 +  alefpatahhebrew: 0xFB2E,
 +  alefqamatshebrew: 0xFB2F,
 +  aleph: 0x2135,
 +  allequal: 0x224C,
 +  alpha: 0x03B1,
 +  alphatonos: 0x03AC,
 +  amacron: 0x0101,
 +  amonospace: 0xFF41,
 +  ampersand: 0x0026,
 +  ampersandmonospace: 0xFF06,
 +  ampersandsmall: 0xF726,
 +  amsquare: 0x33C2,
 +  anbopomofo: 0x3122,
 +  angbopomofo: 0x3124,
 +  angbracketleft: 0x3008, // This glyph is missing from Adobe's original list.
 +  angbracketright: 0x3009, // This glyph is missing from Adobe's original list.
 +  angkhankhuthai: 0x0E5A,
 +  angle: 0x2220,
 +  anglebracketleft: 0x3008,
 +  anglebracketleftvertical: 0xFE3F,
 +  anglebracketright: 0x3009,
 +  anglebracketrightvertical: 0xFE40,
 +  angleleft: 0x2329,
 +  angleright: 0x232A,
 +  angstrom: 0x212B,
 +  anoteleia: 0x0387,
 +  anudattadeva: 0x0952,
 +  anusvarabengali: 0x0982,
 +  anusvaradeva: 0x0902,
 +  anusvaragujarati: 0x0A82,
 +  aogonek: 0x0105,
 +  apaatosquare: 0x3300,
 +  aparen: 0x249C,
 +  apostrophearmenian: 0x055A,
 +  apostrophemod: 0x02BC,
 +  apple: 0xF8FF,
 +  approaches: 0x2250,
 +  approxequal: 0x2248,
 +  approxequalorimage: 0x2252,
 +  approximatelyequal: 0x2245,
 +  araeaekorean: 0x318E,
 +  araeakorean: 0x318D,
 +  arc: 0x2312,
 +  arighthalfring: 0x1E9A,
 +  aring: 0x00E5,
 +  aringacute: 0x01FB,
 +  aringbelow: 0x1E01,
 +  arrowboth: 0x2194,
 +  arrowdashdown: 0x21E3,
 +  arrowdashleft: 0x21E0,
 +  arrowdashright: 0x21E2,
 +  arrowdashup: 0x21E1,
 +  arrowdblboth: 0x21D4,
 +  arrowdbldown: 0x21D3,
 +  arrowdblleft: 0x21D0,
 +  arrowdblright: 0x21D2,
 +  arrowdblup: 0x21D1,
 +  arrowdown: 0x2193,
 +  arrowdownleft: 0x2199,
 +  arrowdownright: 0x2198,
 +  arrowdownwhite: 0x21E9,
 +  arrowheaddownmod: 0x02C5,
 +  arrowheadleftmod: 0x02C2,
 +  arrowheadrightmod: 0x02C3,
 +  arrowheadupmod: 0x02C4,
 +  arrowhorizex: 0xF8E7,
 +  arrowleft: 0x2190,
 +  arrowleftdbl: 0x21D0,
 +  arrowleftdblstroke: 0x21CD,
 +  arrowleftoverright: 0x21C6,
 +  arrowleftwhite: 0x21E6,
 +  arrowright: 0x2192,
 +  arrowrightdblstroke: 0x21CF,
 +  arrowrightheavy: 0x279E,
 +  arrowrightoverleft: 0x21C4,
 +  arrowrightwhite: 0x21E8,
 +  arrowtableft: 0x21E4,
 +  arrowtabright: 0x21E5,
 +  arrowup: 0x2191,
 +  arrowupdn: 0x2195,
 +  arrowupdnbse: 0x21A8,
 +  arrowupdownbase: 0x21A8,
 +  arrowupleft: 0x2196,
 +  arrowupleftofdown: 0x21C5,
 +  arrowupright: 0x2197,
 +  arrowupwhite: 0x21E7,
 +  arrowvertex: 0xF8E6,
 +  asciicircum: 0x005E,
 +  asciicircummonospace: 0xFF3E,
 +  asciitilde: 0x007E,
 +  asciitildemonospace: 0xFF5E,
 +  ascript: 0x0251,
 +  ascriptturned: 0x0252,
 +  asmallhiragana: 0x3041,
 +  asmallkatakana: 0x30A1,
 +  asmallkatakanahalfwidth: 0xFF67,
 +  asterisk: 0x002A,
 +  asteriskaltonearabic: 0x066D,
 +  asteriskarabic: 0x066D,
 +  asteriskmath: 0x2217,
 +  asteriskmonospace: 0xFF0A,
 +  asterisksmall: 0xFE61,
 +  asterism: 0x2042,
 +  asuperior: 0xF6E9,
 +  asymptoticallyequal: 0x2243,
 +  at: 0x0040,
 +  atilde: 0x00E3,
 +  atmonospace: 0xFF20,
 +  atsmall: 0xFE6B,
 +  aturned: 0x0250,
 +  aubengali: 0x0994,
 +  aubopomofo: 0x3120,
 +  audeva: 0x0914,
 +  augujarati: 0x0A94,
 +  augurmukhi: 0x0A14,
 +  aulengthmarkbengali: 0x09D7,
 +  aumatragurmukhi: 0x0A4C,
 +  auvowelsignbengali: 0x09CC,
 +  auvowelsigndeva: 0x094C,
 +  auvowelsigngujarati: 0x0ACC,
 +  avagrahadeva: 0x093D,
 +  aybarmenian: 0x0561,
 +  ayin: 0x05E2,
 +  ayinaltonehebrew: 0xFB20,
 +  ayinhebrew: 0x05E2,
 +  b: 0x0062,
 +  babengali: 0x09AC,
 +  backslash: 0x005C,
 +  backslashmonospace: 0xFF3C,
 +  badeva: 0x092C,
 +  bagujarati: 0x0AAC,
 +  bagurmukhi: 0x0A2C,
 +  bahiragana: 0x3070,
 +  bahtthai: 0x0E3F,
 +  bakatakana: 0x30D0,
 +  bar: 0x007C,
 +  barmonospace: 0xFF5C,
 +  bbopomofo: 0x3105,
 +  bcircle: 0x24D1,
 +  bdotaccent: 0x1E03,
 +  bdotbelow: 0x1E05,
 +  beamedsixteenthnotes: 0x266C,
 +  because: 0x2235,
 +  becyrillic: 0x0431,
 +  beharabic: 0x0628,
 +  behfinalarabic: 0xFE90,
 +  behinitialarabic: 0xFE91,
 +  behiragana: 0x3079,
 +  behmedialarabic: 0xFE92,
 +  behmeeminitialarabic: 0xFC9F,
 +  behmeemisolatedarabic: 0xFC08,
 +  behnoonfinalarabic: 0xFC6D,
 +  bekatakana: 0x30D9,
 +  benarmenian: 0x0562,
 +  bet: 0x05D1,
 +  beta: 0x03B2,
 +  betasymbolgreek: 0x03D0,
 +  betdagesh: 0xFB31,
 +  betdageshhebrew: 0xFB31,
 +  bethebrew: 0x05D1,
 +  betrafehebrew: 0xFB4C,
 +  bhabengali: 0x09AD,
 +  bhadeva: 0x092D,
 +  bhagujarati: 0x0AAD,
 +  bhagurmukhi: 0x0A2D,
 +  bhook: 0x0253,
 +  bihiragana: 0x3073,
 +  bikatakana: 0x30D3,
 +  bilabialclick: 0x0298,
 +  bindigurmukhi: 0x0A02,
 +  birusquare: 0x3331,
 +  blackcircle: 0x25CF,
 +  blackdiamond: 0x25C6,
 +  blackdownpointingtriangle: 0x25BC,
 +  blackleftpointingpointer: 0x25C4,
 +  blackleftpointingtriangle: 0x25C0,
 +  blacklenticularbracketleft: 0x3010,
 +  blacklenticularbracketleftvertical: 0xFE3B,
 +  blacklenticularbracketright: 0x3011,
 +  blacklenticularbracketrightvertical: 0xFE3C,
 +  blacklowerlefttriangle: 0x25E3,
 +  blacklowerrighttriangle: 0x25E2,
 +  blackrectangle: 0x25AC,
 +  blackrightpointingpointer: 0x25BA,
 +  blackrightpointingtriangle: 0x25B6,
 +  blacksmallsquare: 0x25AA,
 +  blacksmilingface: 0x263B,
 +  blacksquare: 0x25A0,
 +  blackstar: 0x2605,
 +  blackupperlefttriangle: 0x25E4,
 +  blackupperrighttriangle: 0x25E5,
 +  blackuppointingsmalltriangle: 0x25B4,
 +  blackuppointingtriangle: 0x25B2,
 +  blank: 0x2423,
 +  blinebelow: 0x1E07,
 +  block: 0x2588,
 +  bmonospace: 0xFF42,
 +  bobaimaithai: 0x0E1A,
 +  bohiragana: 0x307C,
 +  bokatakana: 0x30DC,
 +  bparen: 0x249D,
 +  bqsquare: 0x33C3,
 +  braceex: 0xF8F4,
 +  braceleft: 0x007B,
 +  braceleftbt: 0xF8F3,
 +  braceleftmid: 0xF8F2,
 +  braceleftmonospace: 0xFF5B,
 +  braceleftsmall: 0xFE5B,
 +  bracelefttp: 0xF8F1,
 +  braceleftvertical: 0xFE37,
 +  braceright: 0x007D,
 +  bracerightbt: 0xF8FE,
 +  bracerightmid: 0xF8FD,
 +  bracerightmonospace: 0xFF5D,
 +  bracerightsmall: 0xFE5C,
 +  bracerighttp: 0xF8FC,
 +  bracerightvertical: 0xFE38,
 +  bracketleft: 0x005B,
 +  bracketleftbt: 0xF8F0,
 +  bracketleftex: 0xF8EF,
 +  bracketleftmonospace: 0xFF3B,
 +  bracketlefttp: 0xF8EE,
 +  bracketright: 0x005D,
 +  bracketrightbt: 0xF8FB,
 +  bracketrightex: 0xF8FA,
 +  bracketrightmonospace: 0xFF3D,
 +  bracketrighttp: 0xF8F9,
 +  breve: 0x02D8,
 +  brevebelowcmb: 0x032E,
 +  brevecmb: 0x0306,
 +  breveinvertedbelowcmb: 0x032F,
 +  breveinvertedcmb: 0x0311,
 +  breveinverteddoublecmb: 0x0361,
 +  bridgebelowcmb: 0x032A,
 +  bridgeinvertedbelowcmb: 0x033A,
 +  brokenbar: 0x00A6,
 +  bstroke: 0x0180,
 +  bsuperior: 0xF6EA,
 +  btopbar: 0x0183,
 +  buhiragana: 0x3076,
 +  bukatakana: 0x30D6,
 +  bullet: 0x2022,
 +  bulletinverse: 0x25D8,
 +  bulletoperator: 0x2219,
 +  bullseye: 0x25CE,
 +  c: 0x0063,
 +  caarmenian: 0x056E,
 +  cabengali: 0x099A,
 +  cacute: 0x0107,
 +  cadeva: 0x091A,
 +  cagujarati: 0x0A9A,
 +  cagurmukhi: 0x0A1A,
 +  calsquare: 0x3388,
 +  candrabindubengali: 0x0981,
 +  candrabinducmb: 0x0310,
 +  candrabindudeva: 0x0901,
 +  candrabindugujarati: 0x0A81,
 +  capslock: 0x21EA,
 +  careof: 0x2105,
 +  caron: 0x02C7,
 +  caronbelowcmb: 0x032C,
 +  caroncmb: 0x030C,
 +  carriagereturn: 0x21B5,
 +  cbopomofo: 0x3118,
 +  ccaron: 0x010D,
 +  ccedilla: 0x00E7,
 +  ccedillaacute: 0x1E09,
 +  ccircle: 0x24D2,
 +  ccircumflex: 0x0109,
 +  ccurl: 0x0255,
 +  cdot: 0x010B,
 +  cdotaccent: 0x010B,
 +  cdsquare: 0x33C5,
 +  cedilla: 0x00B8,
 +  cedillacmb: 0x0327,
 +  cent: 0x00A2,
 +  centigrade: 0x2103,
 +  centinferior: 0xF6DF,
 +  centmonospace: 0xFFE0,
 +  centoldstyle: 0xF7A2,
 +  centsuperior: 0xF6E0,
 +  chaarmenian: 0x0579,
 +  chabengali: 0x099B,
 +  chadeva: 0x091B,
 +  chagujarati: 0x0A9B,
 +  chagurmukhi: 0x0A1B,
 +  chbopomofo: 0x3114,
 +  cheabkhasiancyrillic: 0x04BD,
 +  checkmark: 0x2713,
 +  checyrillic: 0x0447,
 +  chedescenderabkhasiancyrillic: 0x04BF,
 +  chedescendercyrillic: 0x04B7,
 +  chedieresiscyrillic: 0x04F5,
 +  cheharmenian: 0x0573,
 +  chekhakassiancyrillic: 0x04CC,
 +  cheverticalstrokecyrillic: 0x04B9,
 +  chi: 0x03C7,
 +  chieuchacirclekorean: 0x3277,
 +  chieuchaparenkorean: 0x3217,
 +  chieuchcirclekorean: 0x3269,
 +  chieuchkorean: 0x314A,
 +  chieuchparenkorean: 0x3209,
 +  chochangthai: 0x0E0A,
 +  chochanthai: 0x0E08,
 +  chochingthai: 0x0E09,
 +  chochoethai: 0x0E0C,
 +  chook: 0x0188,
 +  cieucacirclekorean: 0x3276,
 +  cieucaparenkorean: 0x3216,
 +  cieuccirclekorean: 0x3268,
 +  cieuckorean: 0x3148,
 +  cieucparenkorean: 0x3208,
 +  cieucuparenkorean: 0x321C,
 +  circle: 0x25CB,
 +  circlecopyrt: 0x00A9, // This glyph is missing from Adobe's original list.
 +  circlemultiply: 0x2297,
 +  circleot: 0x2299,
 +  circleplus: 0x2295,
 +  circlepostalmark: 0x3036,
 +  circlewithlefthalfblack: 0x25D0,
 +  circlewithrighthalfblack: 0x25D1,
 +  circumflex: 0x02C6,
 +  circumflexbelowcmb: 0x032D,
 +  circumflexcmb: 0x0302,
 +  clear: 0x2327,
 +  clickalveolar: 0x01C2,
 +  clickdental: 0x01C0,
 +  clicklateral: 0x01C1,
 +  clickretroflex: 0x01C3,
 +  club: 0x2663,
 +  clubsuitblack: 0x2663,
 +  clubsuitwhite: 0x2667,
 +  cmcubedsquare: 0x33A4,
 +  cmonospace: 0xFF43,
 +  cmsquaredsquare: 0x33A0,
 +  coarmenian: 0x0581,
 +  colon: 0x003A,
 +  colonmonetary: 0x20A1,
 +  colonmonospace: 0xFF1A,
 +  colonsign: 0x20A1,
 +  colonsmall: 0xFE55,
 +  colontriangularhalfmod: 0x02D1,
 +  colontriangularmod: 0x02D0,
 +  comma: 0x002C,
 +  commaabovecmb: 0x0313,
 +  commaaboverightcmb: 0x0315,
 +  commaaccent: 0xF6C3,
 +  commaarabic: 0x060C,
 +  commaarmenian: 0x055D,
 +  commainferior: 0xF6E1,
 +  commamonospace: 0xFF0C,
 +  commareversedabovecmb: 0x0314,
 +  commareversedmod: 0x02BD,
 +  commasmall: 0xFE50,
 +  commasuperior: 0xF6E2,
 +  commaturnedabovecmb: 0x0312,
 +  commaturnedmod: 0x02BB,
 +  compass: 0x263C,
 +  congruent: 0x2245,
 +  contourintegral: 0x222E,
 +  control: 0x2303,
 +  controlACK: 0x0006,
 +  controlBEL: 0x0007,
 +  controlBS: 0x0008,
 +  controlCAN: 0x0018,
 +  controlCR: 0x000D,
 +  controlDC1: 0x0011,
 +  controlDC2: 0x0012,
 +  controlDC3: 0x0013,
 +  controlDC4: 0x0014,
 +  controlDEL: 0x007F,
 +  controlDLE: 0x0010,
 +  controlEM: 0x0019,
 +  controlENQ: 0x0005,
 +  controlEOT: 0x0004,
 +  controlESC: 0x001B,
 +  controlETB: 0x0017,
 +  controlETX: 0x0003,
 +  controlFF: 0x000C,
 +  controlFS: 0x001C,
 +  controlGS: 0x001D,
 +  controlHT: 0x0009,
 +  controlLF: 0x000A,
 +  controlNAK: 0x0015,
 +  controlRS: 0x001E,
 +  controlSI: 0x000F,
 +  controlSO: 0x000E,
 +  controlSOT: 0x0002,
 +  controlSTX: 0x0001,
 +  controlSUB: 0x001A,
 +  controlSYN: 0x0016,
 +  controlUS: 0x001F,
 +  controlVT: 0x000B,
 +  copyright: 0x00A9,
 +  copyrightsans: 0xF8E9,
 +  copyrightserif: 0xF6D9,
 +  cornerbracketleft: 0x300C,
 +  cornerbracketlefthalfwidth: 0xFF62,
 +  cornerbracketleftvertical: 0xFE41,
 +  cornerbracketright: 0x300D,
 +  cornerbracketrighthalfwidth: 0xFF63,
 +  cornerbracketrightvertical: 0xFE42,
 +  corporationsquare: 0x337F,
 +  cosquare: 0x33C7,
 +  coverkgsquare: 0x33C6,
 +  cparen: 0x249E,
 +  cruzeiro: 0x20A2,
 +  cstretched: 0x0297,
 +  curlyand: 0x22CF,
 +  curlyor: 0x22CE,
 +  currency: 0x00A4,
 +  cyrBreve: 0xF6D1,
 +  cyrFlex: 0xF6D2,
 +  cyrbreve: 0xF6D4,
 +  cyrflex: 0xF6D5,
 +  d: 0x0064,
 +  daarmenian: 0x0564,
 +  dabengali: 0x09A6,
 +  dadarabic: 0x0636,
 +  dadeva: 0x0926,
 +  dadfinalarabic: 0xFEBE,
 +  dadinitialarabic: 0xFEBF,
 +  dadmedialarabic: 0xFEC0,
 +  dagesh: 0x05BC,
 +  dageshhebrew: 0x05BC,
 +  dagger: 0x2020,
 +  daggerdbl: 0x2021,
 +  dagujarati: 0x0AA6,
 +  dagurmukhi: 0x0A26,
 +  dahiragana: 0x3060,
 +  dakatakana: 0x30C0,
 +  dalarabic: 0x062F,
 +  dalet: 0x05D3,
 +  daletdagesh: 0xFB33,
 +  daletdageshhebrew: 0xFB33,
 +  dalethebrew: 0x05D3,
 +  dalfinalarabic: 0xFEAA,
 +  dammaarabic: 0x064F,
 +  dammalowarabic: 0x064F,
 +  dammatanaltonearabic: 0x064C,
 +  dammatanarabic: 0x064C,
 +  danda: 0x0964,
 +  dargahebrew: 0x05A7,
 +  dargalefthebrew: 0x05A7,
 +  dasiapneumatacyrilliccmb: 0x0485,
 +  dblGrave: 0xF6D3,
 +  dblanglebracketleft: 0x300A,
 +  dblanglebracketleftvertical: 0xFE3D,
 +  dblanglebracketright: 0x300B,
 +  dblanglebracketrightvertical: 0xFE3E,
 +  dblarchinvertedbelowcmb: 0x032B,
 +  dblarrowleft: 0x21D4,
 +  dblarrowright: 0x21D2,
 +  dbldanda: 0x0965,
 +  dblgrave: 0xF6D6,
 +  dblgravecmb: 0x030F,
 +  dblintegral: 0x222C,
 +  dbllowline: 0x2017,
 +  dbllowlinecmb: 0x0333,
 +  dbloverlinecmb: 0x033F,
 +  dblprimemod: 0x02BA,
 +  dblverticalbar: 0x2016,
 +  dblverticallineabovecmb: 0x030E,
 +  dbopomofo: 0x3109,
 +  dbsquare: 0x33C8,
 +  dcaron: 0x010F,
 +  dcedilla: 0x1E11,
 +  dcircle: 0x24D3,
 +  dcircumflexbelow: 0x1E13,
 +  dcroat: 0x0111,
 +  ddabengali: 0x09A1,
 +  ddadeva: 0x0921,
 +  ddagujarati: 0x0AA1,
 +  ddagurmukhi: 0x0A21,
 +  ddalarabic: 0x0688,
 +  ddalfinalarabic: 0xFB89,
 +  dddhadeva: 0x095C,
 +  ddhabengali: 0x09A2,
 +  ddhadeva: 0x0922,
 +  ddhagujarati: 0x0AA2,
 +  ddhagurmukhi: 0x0A22,
 +  ddotaccent: 0x1E0B,
 +  ddotbelow: 0x1E0D,
 +  decimalseparatorarabic: 0x066B,
 +  decimalseparatorpersian: 0x066B,
 +  decyrillic: 0x0434,
 +  degree: 0x00B0,
 +  dehihebrew: 0x05AD,
 +  dehiragana: 0x3067,
 +  deicoptic: 0x03EF,
 +  dekatakana: 0x30C7,
 +  deleteleft: 0x232B,
 +  deleteright: 0x2326,
 +  delta: 0x03B4,
 +  deltaturned: 0x018D,
 +  denominatorminusonenumeratorbengali: 0x09F8,
 +  dezh: 0x02A4,
 +  dhabengali: 0x09A7,
 +  dhadeva: 0x0927,
 +  dhagujarati: 0x0AA7,
 +  dhagurmukhi: 0x0A27,
 +  dhook: 0x0257,
 +  dialytikatonos: 0x0385,
 +  dialytikatonoscmb: 0x0344,
 +  diamond: 0x2666,
 +  diamondsuitwhite: 0x2662,
 +  dieresis: 0x00A8,
 +  dieresisacute: 0xF6D7,
 +  dieresisbelowcmb: 0x0324,
 +  dieresiscmb: 0x0308,
 +  dieresisgrave: 0xF6D8,
 +  dieresistonos: 0x0385,
 +  dihiragana: 0x3062,
 +  dikatakana: 0x30C2,
 +  dittomark: 0x3003,
 +  divide: 0x00F7,
 +  divides: 0x2223,
 +  divisionslash: 0x2215,
 +  djecyrillic: 0x0452,
 +  dkshade: 0x2593,
 +  dlinebelow: 0x1E0F,
 +  dlsquare: 0x3397,
 +  dmacron: 0x0111,
 +  dmonospace: 0xFF44,
 +  dnblock: 0x2584,
 +  dochadathai: 0x0E0E,
 +  dodekthai: 0x0E14,
 +  dohiragana: 0x3069,
 +  dokatakana: 0x30C9,
 +  dollar: 0x0024,
 +  dollarinferior: 0xF6E3,
 +  dollarmonospace: 0xFF04,
 +  dollaroldstyle: 0xF724,
 +  dollarsmall: 0xFE69,
 +  dollarsuperior: 0xF6E4,
 +  dong: 0x20AB,
 +  dorusquare: 0x3326,
 +  dotaccent: 0x02D9,
 +  dotaccentcmb: 0x0307,
 +  dotbelowcmb: 0x0323,
 +  dotbelowcomb: 0x0323,
 +  dotkatakana: 0x30FB,
 +  dotlessi: 0x0131,
 +  dotlessj: 0xF6BE,
 +  dotlessjstrokehook: 0x0284,
 +  dotmath: 0x22C5,
 +  dottedcircle: 0x25CC,
 +  doubleyodpatah: 0xFB1F,
 +  doubleyodpatahhebrew: 0xFB1F,
 +  downtackbelowcmb: 0x031E,
 +  downtackmod: 0x02D5,
 +  dparen: 0x249F,
 +  dsuperior: 0xF6EB,
 +  dtail: 0x0256,
 +  dtopbar: 0x018C,
 +  duhiragana: 0x3065,
 +  dukatakana: 0x30C5,
 +  dz: 0x01F3,
 +  dzaltone: 0x02A3,
 +  dzcaron: 0x01C6,
 +  dzcurl: 0x02A5,
 +  dzeabkhasiancyrillic: 0x04E1,
 +  dzecyrillic: 0x0455,
 +  dzhecyrillic: 0x045F,
 +  e: 0x0065,
 +  eacute: 0x00E9,
 +  earth: 0x2641,
 +  ebengali: 0x098F,
 +  ebopomofo: 0x311C,
 +  ebreve: 0x0115,
 +  ecandradeva: 0x090D,
 +  ecandragujarati: 0x0A8D,
 +  ecandravowelsigndeva: 0x0945,
 +  ecandravowelsigngujarati: 0x0AC5,
 +  ecaron: 0x011B,
 +  ecedillabreve: 0x1E1D,
 +  echarmenian: 0x0565,
 +  echyiwnarmenian: 0x0587,
 +  ecircle: 0x24D4,
 +  ecircumflex: 0x00EA,
 +  ecircumflexacute: 0x1EBF,
 +  ecircumflexbelow: 0x1E19,
 +  ecircumflexdotbelow: 0x1EC7,
 +  ecircumflexgrave: 0x1EC1,
 +  ecircumflexhookabove: 0x1EC3,
 +  ecircumflextilde: 0x1EC5,
 +  ecyrillic: 0x0454,
 +  edblgrave: 0x0205,
 +  edeva: 0x090F,
 +  edieresis: 0x00EB,
 +  edot: 0x0117,
 +  edotaccent: 0x0117,
 +  edotbelow: 0x1EB9,
 +  eegurmukhi: 0x0A0F,
 +  eematragurmukhi: 0x0A47,
 +  efcyrillic: 0x0444,
 +  egrave: 0x00E8,
 +  egujarati: 0x0A8F,
 +  eharmenian: 0x0567,
 +  ehbopomofo: 0x311D,
 +  ehiragana: 0x3048,
 +  ehookabove: 0x1EBB,
 +  eibopomofo: 0x311F,
 +  eight: 0x0038,
 +  eightarabic: 0x0668,
 +  eightbengali: 0x09EE,
 +  eightcircle: 0x2467,
 +  eightcircleinversesansserif: 0x2791,
 +  eightdeva: 0x096E,
 +  eighteencircle: 0x2471,
 +  eighteenparen: 0x2485,
 +  eighteenperiod: 0x2499,
 +  eightgujarati: 0x0AEE,
 +  eightgurmukhi: 0x0A6E,
 +  eighthackarabic: 0x0668,
 +  eighthangzhou: 0x3028,
 +  eighthnotebeamed: 0x266B,
 +  eightideographicparen: 0x3227,
 +  eightinferior: 0x2088,
 +  eightmonospace: 0xFF18,
 +  eightoldstyle: 0xF738,
 +  eightparen: 0x247B,
 +  eightperiod: 0x248F,
 +  eightpersian: 0x06F8,
 +  eightroman: 0x2177,
 +  eightsuperior: 0x2078,
 +  eightthai: 0x0E58,
 +  einvertedbreve: 0x0207,
 +  eiotifiedcyrillic: 0x0465,
 +  ekatakana: 0x30A8,
 +  ekatakanahalfwidth: 0xFF74,
 +  ekonkargurmukhi: 0x0A74,
 +  ekorean: 0x3154,
 +  elcyrillic: 0x043B,
 +  element: 0x2208,
 +  elevencircle: 0x246A,
 +  elevenparen: 0x247E,
 +  elevenperiod: 0x2492,
 +  elevenroman: 0x217A,
 +  ellipsis: 0x2026,
 +  ellipsisvertical: 0x22EE,
 +  emacron: 0x0113,
 +  emacronacute: 0x1E17,
 +  emacrongrave: 0x1E15,
 +  emcyrillic: 0x043C,
 +  emdash: 0x2014,
 +  emdashvertical: 0xFE31,
 +  emonospace: 0xFF45,
 +  emphasismarkarmenian: 0x055B,
 +  emptyset: 0x2205,
 +  enbopomofo: 0x3123,
 +  encyrillic: 0x043D,
 +  endash: 0x2013,
 +  endashvertical: 0xFE32,
 +  endescendercyrillic: 0x04A3,
 +  eng: 0x014B,
 +  engbopomofo: 0x3125,
 +  enghecyrillic: 0x04A5,
 +  enhookcyrillic: 0x04C8,
 +  enspace: 0x2002,
 +  eogonek: 0x0119,
 +  eokorean: 0x3153,
 +  eopen: 0x025B,
 +  eopenclosed: 0x029A,
 +  eopenreversed: 0x025C,
 +  eopenreversedclosed: 0x025E,
 +  eopenreversedhook: 0x025D,
 +  eparen: 0x24A0,
 +  epsilon: 0x03B5,
 +  epsilontonos: 0x03AD,
 +  equal: 0x003D,
 +  equalmonospace: 0xFF1D,
 +  equalsmall: 0xFE66,
 +  equalsuperior: 0x207C,
 +  equivalence: 0x2261,
 +  erbopomofo: 0x3126,
 +  ercyrillic: 0x0440,
 +  ereversed: 0x0258,
 +  ereversedcyrillic: 0x044D,
 +  escyrillic: 0x0441,
 +  esdescendercyrillic: 0x04AB,
 +  esh: 0x0283,
 +  eshcurl: 0x0286,
 +  eshortdeva: 0x090E,
 +  eshortvowelsigndeva: 0x0946,
 +  eshreversedloop: 0x01AA,
 +  eshsquatreversed: 0x0285,
 +  esmallhiragana: 0x3047,
 +  esmallkatakana: 0x30A7,
 +  esmallkatakanahalfwidth: 0xFF6A,
 +  estimated: 0x212E,
 +  esuperior: 0xF6EC,
 +  eta: 0x03B7,
 +  etarmenian: 0x0568,
 +  etatonos: 0x03AE,
 +  eth: 0x00F0,
 +  etilde: 0x1EBD,
 +  etildebelow: 0x1E1B,
 +  etnahtafoukhhebrew: 0x0591,
 +  etnahtafoukhlefthebrew: 0x0591,
 +  etnahtahebrew: 0x0591,
 +  etnahtalefthebrew: 0x0591,
 +  eturned: 0x01DD,
 +  eukorean: 0x3161,
 +  euro: 0x20AC,
 +  evowelsignbengali: 0x09C7,
 +  evowelsigndeva: 0x0947,
 +  evowelsigngujarati: 0x0AC7,
 +  exclam: 0x0021,
 +  exclamarmenian: 0x055C,
 +  exclamdbl: 0x203C,
 +  exclamdown: 0x00A1,
 +  exclamdownsmall: 0xF7A1,
 +  exclammonospace: 0xFF01,
 +  exclamsmall: 0xF721,
 +  existential: 0x2203,
 +  ezh: 0x0292,
 +  ezhcaron: 0x01EF,
 +  ezhcurl: 0x0293,
 +  ezhreversed: 0x01B9,
 +  ezhtail: 0x01BA,
 +  f: 0x0066,
 +  fadeva: 0x095E,
 +  fagurmukhi: 0x0A5E,
 +  fahrenheit: 0x2109,
 +  fathaarabic: 0x064E,
 +  fathalowarabic: 0x064E,
 +  fathatanarabic: 0x064B,
 +  fbopomofo: 0x3108,
 +  fcircle: 0x24D5,
 +  fdotaccent: 0x1E1F,
 +  feharabic: 0x0641,
 +  feharmenian: 0x0586,
 +  fehfinalarabic: 0xFED2,
 +  fehinitialarabic: 0xFED3,
 +  fehmedialarabic: 0xFED4,
 +  feicoptic: 0x03E5,
 +  female: 0x2640,
 +  ff: 0xFB00,
 +  ffi: 0xFB03,
 +  ffl: 0xFB04,
 +  fi: 0xFB01,
 +  fifteencircle: 0x246E,
 +  fifteenparen: 0x2482,
 +  fifteenperiod: 0x2496,
 +  figuredash: 0x2012,
 +  filledbox: 0x25A0,
 +  filledrect: 0x25AC,
 +  finalkaf: 0x05DA,
 +  finalkafdagesh: 0xFB3A,
 +  finalkafdageshhebrew: 0xFB3A,
 +  finalkafhebrew: 0x05DA,
 +  finalmem: 0x05DD,
 +  finalmemhebrew: 0x05DD,
 +  finalnun: 0x05DF,
 +  finalnunhebrew: 0x05DF,
 +  finalpe: 0x05E3,
 +  finalpehebrew: 0x05E3,
 +  finaltsadi: 0x05E5,
 +  finaltsadihebrew: 0x05E5,
 +  firsttonechinese: 0x02C9,
 +  fisheye: 0x25C9,
 +  fitacyrillic: 0x0473,
 +  five: 0x0035,
 +  fivearabic: 0x0665,
 +  fivebengali: 0x09EB,
 +  fivecircle: 0x2464,
 +  fivecircleinversesansserif: 0x278E,
 +  fivedeva: 0x096B,
 +  fiveeighths: 0x215D,
 +  fivegujarati: 0x0AEB,
 +  fivegurmukhi: 0x0A6B,
 +  fivehackarabic: 0x0665,
 +  fivehangzhou: 0x3025,
 +  fiveideographicparen: 0x3224,
 +  fiveinferior: 0x2085,
 +  fivemonospace: 0xFF15,
 +  fiveoldstyle: 0xF735,
 +  fiveparen: 0x2478,
 +  fiveperiod: 0x248C,
 +  fivepersian: 0x06F5,
 +  fiveroman: 0x2174,
 +  fivesuperior: 0x2075,
 +  fivethai: 0x0E55,
 +  fl: 0xFB02,
 +  florin: 0x0192,
 +  fmonospace: 0xFF46,
 +  fmsquare: 0x3399,
 +  fofanthai: 0x0E1F,
 +  fofathai: 0x0E1D,
 +  fongmanthai: 0x0E4F,
 +  forall: 0x2200,
 +  four: 0x0034,
 +  fourarabic: 0x0664,
 +  fourbengali: 0x09EA,
 +  fourcircle: 0x2463,
 +  fourcircleinversesansserif: 0x278D,
 +  fourdeva: 0x096A,
 +  fourgujarati: 0x0AEA,
 +  fourgurmukhi: 0x0A6A,
 +  fourhackarabic: 0x0664,
 +  fourhangzhou: 0x3024,
 +  fourideographicparen: 0x3223,
 +  fourinferior: 0x2084,
 +  fourmonospace: 0xFF14,
 +  fournumeratorbengali: 0x09F7,
 +  fouroldstyle: 0xF734,
 +  fourparen: 0x2477,
 +  fourperiod: 0x248B,
 +  fourpersian: 0x06F4,
 +  fourroman: 0x2173,
 +  foursuperior: 0x2074,
 +  fourteencircle: 0x246D,
 +  fourteenparen: 0x2481,
 +  fourteenperiod: 0x2495,
 +  fourthai: 0x0E54,
 +  fourthtonechinese: 0x02CB,
 +  fparen: 0x24A1,
 +  fraction: 0x2044,
 +  franc: 0x20A3,
 +  g: 0x0067,
 +  gabengali: 0x0997,
 +  gacute: 0x01F5,
 +  gadeva: 0x0917,
 +  gafarabic: 0x06AF,
 +  gaffinalarabic: 0xFB93,
 +  gafinitialarabic: 0xFB94,
 +  gafmedialarabic: 0xFB95,
 +  gagujarati: 0x0A97,
 +  gagurmukhi: 0x0A17,
 +  gahiragana: 0x304C,
 +  gakatakana: 0x30AC,
 +  gamma: 0x03B3,
 +  gammalatinsmall: 0x0263,
 +  gammasuperior: 0x02E0,
 +  gangiacoptic: 0x03EB,
 +  gbopomofo: 0x310D,
 +  gbreve: 0x011F,
 +  gcaron: 0x01E7,
 +  gcedilla: 0x0123,
 +  gcircle: 0x24D6,
 +  gcircumflex: 0x011D,
 +  gcommaaccent: 0x0123,
 +  gdot: 0x0121,
 +  gdotaccent: 0x0121,
 +  gecyrillic: 0x0433,
 +  gehiragana: 0x3052,
 +  gekatakana: 0x30B2,
 +  geometricallyequal: 0x2251,
 +  gereshaccenthebrew: 0x059C,
 +  gereshhebrew: 0x05F3,
 +  gereshmuqdamhebrew: 0x059D,
 +  germandbls: 0x00DF,
 +  gershayimaccenthebrew: 0x059E,
 +  gershayimhebrew: 0x05F4,
 +  getamark: 0x3013,
 +  ghabengali: 0x0998,
 +  ghadarmenian: 0x0572,
 +  ghadeva: 0x0918,
 +  ghagujarati: 0x0A98,
 +  ghagurmukhi: 0x0A18,
 +  ghainarabic: 0x063A,
 +  ghainfinalarabic: 0xFECE,
 +  ghaininitialarabic: 0xFECF,
 +  ghainmedialarabic: 0xFED0,
 +  ghemiddlehookcyrillic: 0x0495,
 +  ghestrokecyrillic: 0x0493,
 +  gheupturncyrillic: 0x0491,
 +  ghhadeva: 0x095A,
 +  ghhagurmukhi: 0x0A5A,
 +  ghook: 0x0260,
 +  ghzsquare: 0x3393,
 +  gihiragana: 0x304E,
 +  gikatakana: 0x30AE,
 +  gimarmenian: 0x0563,
 +  gimel: 0x05D2,
 +  gimeldagesh: 0xFB32,
 +  gimeldageshhebrew: 0xFB32,
 +  gimelhebrew: 0x05D2,
 +  gjecyrillic: 0x0453,
 +  glottalinvertedstroke: 0x01BE,
 +  glottalstop: 0x0294,
 +  glottalstopinverted: 0x0296,
 +  glottalstopmod: 0x02C0,
 +  glottalstopreversed: 0x0295,
 +  glottalstopreversedmod: 0x02C1,
 +  glottalstopreversedsuperior: 0x02E4,
 +  glottalstopstroke: 0x02A1,
 +  glottalstopstrokereversed: 0x02A2,
 +  gmacron: 0x1E21,
 +  gmonospace: 0xFF47,
 +  gohiragana: 0x3054,
 +  gokatakana: 0x30B4,
 +  gparen: 0x24A2,
 +  gpasquare: 0x33AC,
 +  gradient: 0x2207,
 +  grave: 0x0060,
 +  gravebelowcmb: 0x0316,
 +  gravecmb: 0x0300,
 +  gravecomb: 0x0300,
 +  gravedeva: 0x0953,
 +  gravelowmod: 0x02CE,
 +  gravemonospace: 0xFF40,
 +  gravetonecmb: 0x0340,
 +  greater: 0x003E,
 +  greaterequal: 0x2265,
 +  greaterequalorless: 0x22DB,
 +  greatermonospace: 0xFF1E,
 +  greaterorequivalent: 0x2273,
 +  greaterorless: 0x2277,
 +  greateroverequal: 0x2267,
 +  greatersmall: 0xFE65,
 +  gscript: 0x0261,
 +  gstroke: 0x01E5,
 +  guhiragana: 0x3050,
 +  guillemotleft: 0x00AB,
 +  guillemotright: 0x00BB,
 +  guilsinglleft: 0x2039,
 +  guilsinglright: 0x203A,
 +  gukatakana: 0x30B0,
 +  guramusquare: 0x3318,
 +  gysquare: 0x33C9,
 +  h: 0x0068,
 +  haabkhasiancyrillic: 0x04A9,
 +  haaltonearabic: 0x06C1,
 +  habengali: 0x09B9,
 +  hadescendercyrillic: 0x04B3,
 +  hadeva: 0x0939,
 +  hagujarati: 0x0AB9,
 +  hagurmukhi: 0x0A39,
 +  haharabic: 0x062D,
 +  hahfinalarabic: 0xFEA2,
 +  hahinitialarabic: 0xFEA3,
 +  hahiragana: 0x306F,
 +  hahmedialarabic: 0xFEA4,
 +  haitusquare: 0x332A,
 +  hakatakana: 0x30CF,
 +  hakatakanahalfwidth: 0xFF8A,
 +  halantgurmukhi: 0x0A4D,
 +  hamzaarabic: 0x0621,
 +  hamzalowarabic: 0x0621,
 +  hangulfiller: 0x3164,
 +  hardsigncyrillic: 0x044A,
 +  harpoonleftbarbup: 0x21BC,
 +  harpoonrightbarbup: 0x21C0,
 +  hasquare: 0x33CA,
 +  hatafpatah: 0x05B2,
 +  hatafpatah16: 0x05B2,
 +  hatafpatah23: 0x05B2,
 +  hatafpatah2f: 0x05B2,
 +  hatafpatahhebrew: 0x05B2,
 +  hatafpatahnarrowhebrew: 0x05B2,
 +  hatafpatahquarterhebrew: 0x05B2,
 +  hatafpatahwidehebrew: 0x05B2,
 +  hatafqamats: 0x05B3,
 +  hatafqamats1b: 0x05B3,
 +  hatafqamats28: 0x05B3,
 +  hatafqamats34: 0x05B3,
 +  hatafqamatshebrew: 0x05B3,
 +  hatafqamatsnarrowhebrew: 0x05B3,
 +  hatafqamatsquarterhebrew: 0x05B3,
 +  hatafqamatswidehebrew: 0x05B3,
 +  hatafsegol: 0x05B1,
 +  hatafsegol17: 0x05B1,
 +  hatafsegol24: 0x05B1,
 +  hatafsegol30: 0x05B1,
 +  hatafsegolhebrew: 0x05B1,
 +  hatafsegolnarrowhebrew: 0x05B1,
 +  hatafsegolquarterhebrew: 0x05B1,
 +  hatafsegolwidehebrew: 0x05B1,
 +  hbar: 0x0127,
 +  hbopomofo: 0x310F,
 +  hbrevebelow: 0x1E2B,
 +  hcedilla: 0x1E29,
 +  hcircle: 0x24D7,
 +  hcircumflex: 0x0125,
 +  hdieresis: 0x1E27,
 +  hdotaccent: 0x1E23,
 +  hdotbelow: 0x1E25,
 +  he: 0x05D4,
 +  heart: 0x2665,
 +  heartsuitblack: 0x2665,
 +  heartsuitwhite: 0x2661,
 +  hedagesh: 0xFB34,
 +  hedageshhebrew: 0xFB34,
 +  hehaltonearabic: 0x06C1,
 +  heharabic: 0x0647,
 +  hehebrew: 0x05D4,
 +  hehfinalaltonearabic: 0xFBA7,
 +  hehfinalalttwoarabic: 0xFEEA,
 +  hehfinalarabic: 0xFEEA,
 +  hehhamzaabovefinalarabic: 0xFBA5,
 +  hehhamzaaboveisolatedarabic: 0xFBA4,
 +  hehinitialaltonearabic: 0xFBA8,
 +  hehinitialarabic: 0xFEEB,
 +  hehiragana: 0x3078,
 +  hehmedialaltonearabic: 0xFBA9,
 +  hehmedialarabic: 0xFEEC,
 +  heiseierasquare: 0x337B,
 +  hekatakana: 0x30D8,
 +  hekatakanahalfwidth: 0xFF8D,
 +  hekutaarusquare: 0x3336,
 +  henghook: 0x0267,
 +  herutusquare: 0x3339,
 +  het: 0x05D7,
 +  hethebrew: 0x05D7,
 +  hhook: 0x0266,
 +  hhooksuperior: 0x02B1,
 +  hieuhacirclekorean: 0x327B,
 +  hieuhaparenkorean: 0x321B,
 +  hieuhcirclekorean: 0x326D,
 +  hieuhkorean: 0x314E,
 +  hieuhparenkorean: 0x320D,
 +  hihiragana: 0x3072,
 +  hikatakana: 0x30D2,
 +  hikatakanahalfwidth: 0xFF8B,
 +  hiriq: 0x05B4,
 +  hiriq14: 0x05B4,
 +  hiriq21: 0x05B4,
 +  hiriq2d: 0x05B4,
 +  hiriqhebrew: 0x05B4,
 +  hiriqnarrowhebrew: 0x05B4,
 +  hiriqquarterhebrew: 0x05B4,
 +  hiriqwidehebrew: 0x05B4,
 +  hlinebelow: 0x1E96,
 +  hmonospace: 0xFF48,
 +  hoarmenian: 0x0570,
 +  hohipthai: 0x0E2B,
 +  hohiragana: 0x307B,
 +  hokatakana: 0x30DB,
 +  hokatakanahalfwidth: 0xFF8E,
 +  holam: 0x05B9,
 +  holam19: 0x05B9,
 +  holam26: 0x05B9,
 +  holam32: 0x05B9,
 +  holamhebrew: 0x05B9,
 +  holamnarrowhebrew: 0x05B9,
 +  holamquarterhebrew: 0x05B9,
 +  holamwidehebrew: 0x05B9,
 +  honokhukthai: 0x0E2E,
 +  hookabovecomb: 0x0309,
 +  hookcmb: 0x0309,
 +  hookpalatalizedbelowcmb: 0x0321,
 +  hookretroflexbelowcmb: 0x0322,
 +  hoonsquare: 0x3342,
 +  horicoptic: 0x03E9,
 +  horizontalbar: 0x2015,
 +  horncmb: 0x031B,
 +  hotsprings: 0x2668,
 +  house: 0x2302,
 +  hparen: 0x24A3,
 +  hsuperior: 0x02B0,
 +  hturned: 0x0265,
 +  huhiragana: 0x3075,
 +  huiitosquare: 0x3333,
 +  hukatakana: 0x30D5,
 +  hukatakanahalfwidth: 0xFF8C,
 +  hungarumlaut: 0x02DD,
 +  hungarumlautcmb: 0x030B,
 +  hv: 0x0195,
 +  hyphen: 0x002D,
 +  hypheninferior: 0xF6E5,
 +  hyphenmonospace: 0xFF0D,
 +  hyphensmall: 0xFE63,
 +  hyphensuperior: 0xF6E6,
 +  hyphentwo: 0x2010,
 +  i: 0x0069,
 +  iacute: 0x00ED,
 +  iacyrillic: 0x044F,
 +  ibengali: 0x0987,
 +  ibopomofo: 0x3127,
 +  ibreve: 0x012D,
 +  icaron: 0x01D0,
 +  icircle: 0x24D8,
 +  icircumflex: 0x00EE,
 +  icyrillic: 0x0456,
 +  idblgrave: 0x0209,
 +  ideographearthcircle: 0x328F,
 +  ideographfirecircle: 0x328B,
 +  ideographicallianceparen: 0x323F,
 +  ideographiccallparen: 0x323A,
 +  ideographiccentrecircle: 0x32A5,
 +  ideographicclose: 0x3006,
 +  ideographiccomma: 0x3001,
 +  ideographiccommaleft: 0xFF64,
 +  ideographiccongratulationparen: 0x3237,
 +  ideographiccorrectcircle: 0x32A3,
 +  ideographicearthparen: 0x322F,
 +  ideographicenterpriseparen: 0x323D,
 +  ideographicexcellentcircle: 0x329D,
 +  ideographicfestivalparen: 0x3240,
 +  ideographicfinancialcircle: 0x3296,
 +  ideographicfinancialparen: 0x3236,
 +  ideographicfireparen: 0x322B,
 +  ideographichaveparen: 0x3232,
 +  ideographichighcircle: 0x32A4,
 +  ideographiciterationmark: 0x3005,
 +  ideographiclaborcircle: 0x3298,
 +  ideographiclaborparen: 0x3238,
 +  ideographicleftcircle: 0x32A7,
 +  ideographiclowcircle: 0x32A6,
 +  ideographicmedicinecircle: 0x32A9,
 +  ideographicmetalparen: 0x322E,
 +  ideographicmoonparen: 0x322A,
 +  ideographicnameparen: 0x3234,
 +  ideographicperiod: 0x3002,
 +  ideographicprintcircle: 0x329E,
 +  ideographicreachparen: 0x3243,
 +  ideographicrepresentparen: 0x3239,
 +  ideographicresourceparen: 0x323E,
 +  ideographicrightcircle: 0x32A8,
 +  ideographicsecretcircle: 0x3299,
 +  ideographicselfparen: 0x3242,
 +  ideographicsocietyparen: 0x3233,
 +  ideographicspace: 0x3000,
 +  ideographicspecialparen: 0x3235,
 +  ideographicstockparen: 0x3231,
 +  ideographicstudyparen: 0x323B,
 +  ideographicsunparen: 0x3230,
 +  ideographicsuperviseparen: 0x323C,
 +  ideographicwaterparen: 0x322C,
 +  ideographicwoodparen: 0x322D,
 +  ideographiczero: 0x3007,
 +  ideographmetalcircle: 0x328E,
 +  ideographmooncircle: 0x328A,
 +  ideographnamecircle: 0x3294,
 +  ideographsuncircle: 0x3290,
 +  ideographwatercircle: 0x328C,
 +  ideographwoodcircle: 0x328D,
 +  ideva: 0x0907,
 +  idieresis: 0x00EF,
 +  idieresisacute: 0x1E2F,
 +  idieresiscyrillic: 0x04E5,
 +  idotbelow: 0x1ECB,
 +  iebrevecyrillic: 0x04D7,
 +  iecyrillic: 0x0435,
 +  ieungacirclekorean: 0x3275,
 +  ieungaparenkorean: 0x3215,
 +  ieungcirclekorean: 0x3267,
 +  ieungkorean: 0x3147,
 +  ieungparenkorean: 0x3207,
 +  igrave: 0x00EC,
 +  igujarati: 0x0A87,
 +  igurmukhi: 0x0A07,
 +  ihiragana: 0x3044,
 +  ihookabove: 0x1EC9,
 +  iibengali: 0x0988,
 +  iicyrillic: 0x0438,
 +  iideva: 0x0908,
 +  iigujarati: 0x0A88,
 +  iigurmukhi: 0x0A08,
 +  iimatragurmukhi: 0x0A40,
 +  iinvertedbreve: 0x020B,
 +  iishortcyrillic: 0x0439,
 +  iivowelsignbengali: 0x09C0,
 +  iivowelsigndeva: 0x0940,
 +  iivowelsigngujarati: 0x0AC0,
 +  ij: 0x0133,
 +  ikatakana: 0x30A4,
 +  ikatakanahalfwidth: 0xFF72,
 +  ikorean: 0x3163,
 +  ilde: 0x02DC,
 +  iluyhebrew: 0x05AC,
 +  imacron: 0x012B,
 +  imacroncyrillic: 0x04E3,
 +  imageorapproximatelyequal: 0x2253,
 +  imatragurmukhi: 0x0A3F,
 +  imonospace: 0xFF49,
 +  increment: 0x2206,
 +  infinity: 0x221E,
 +  iniarmenian: 0x056B,
 +  integral: 0x222B,
 +  integralbottom: 0x2321,
 +  integralbt: 0x2321,
 +  integralex: 0xF8F5,
 +  integraltop: 0x2320,
 +  integraltp: 0x2320,
 +  intersection: 0x2229,
 +  intisquare: 0x3305,
 +  invbullet: 0x25D8,
 +  invcircle: 0x25D9,
 +  invsmileface: 0x263B,
 +  iocyrillic: 0x0451,
 +  iogonek: 0x012F,
 +  iota: 0x03B9,
 +  iotadieresis: 0x03CA,
 +  iotadieresistonos: 0x0390,
 +  iotalatin: 0x0269,
 +  iotatonos: 0x03AF,
 +  iparen: 0x24A4,
 +  irigurmukhi: 0x0A72,
 +  ismallhiragana: 0x3043,
 +  ismallkatakana: 0x30A3,
 +  ismallkatakanahalfwidth: 0xFF68,
 +  issharbengali: 0x09FA,
 +  istroke: 0x0268,
 +  isuperior: 0xF6ED,
 +  iterationhiragana: 0x309D,
 +  iterationkatakana: 0x30FD,
 +  itilde: 0x0129,
 +  itildebelow: 0x1E2D,
 +  iubopomofo: 0x3129,
 +  iucyrillic: 0x044E,
 +  ivowelsignbengali: 0x09BF,
 +  ivowelsigndeva: 0x093F,
 +  ivowelsigngujarati: 0x0ABF,
 +  izhitsacyrillic: 0x0475,
 +  izhitsadblgravecyrillic: 0x0477,
 +  j: 0x006A,
 +  jaarmenian: 0x0571,
 +  jabengali: 0x099C,
 +  jadeva: 0x091C,
 +  jagujarati: 0x0A9C,
 +  jagurmukhi: 0x0A1C,
 +  jbopomofo: 0x3110,
 +  jcaron: 0x01F0,
 +  jcircle: 0x24D9,
 +  jcircumflex: 0x0135,
 +  jcrossedtail: 0x029D,
 +  jdotlessstroke: 0x025F,
 +  jecyrillic: 0x0458,
 +  jeemarabic: 0x062C,
 +  jeemfinalarabic: 0xFE9E,
 +  jeeminitialarabic: 0xFE9F,
 +  jeemmedialarabic: 0xFEA0,
 +  jeharabic: 0x0698,
 +  jehfinalarabic: 0xFB8B,
 +  jhabengali: 0x099D,
 +  jhadeva: 0x091D,
 +  jhagujarati: 0x0A9D,
 +  jhagurmukhi: 0x0A1D,
 +  jheharmenian: 0x057B,
 +  jis: 0x3004,
 +  jmonospace: 0xFF4A,
 +  jparen: 0x24A5,
 +  jsuperior: 0x02B2,
 +  k: 0x006B,
 +  kabashkircyrillic: 0x04A1,
 +  kabengali: 0x0995,
 +  kacute: 0x1E31,
 +  kacyrillic: 0x043A,
 +  kadescendercyrillic: 0x049B,
 +  kadeva: 0x0915,
 +  kaf: 0x05DB,
 +  kafarabic: 0x0643,
 +  kafdagesh: 0xFB3B,
 +  kafdageshhebrew: 0xFB3B,
 +  kaffinalarabic: 0xFEDA,
 +  kafhebrew: 0x05DB,
 +  kafinitialarabic: 0xFEDB,
 +  kafmedialarabic: 0xFEDC,
 +  kafrafehebrew: 0xFB4D,
 +  kagujarati: 0x0A95,
 +  kagurmukhi: 0x0A15,
 +  kahiragana: 0x304B,
 +  kahookcyrillic: 0x04C4,
 +  kakatakana: 0x30AB,
 +  kakatakanahalfwidth: 0xFF76,
 +  kappa: 0x03BA,
 +  kappasymbolgreek: 0x03F0,
 +  kapyeounmieumkorean: 0x3171,
 +  kapyeounphieuphkorean: 0x3184,
 +  kapyeounpieupkorean: 0x3178,
 +  kapyeounssangpieupkorean: 0x3179,
 +  karoriisquare: 0x330D,
 +  kashidaautoarabic: 0x0640,
 +  kashidaautonosidebearingarabic: 0x0640,
 +  kasmallkatakana: 0x30F5,
 +  kasquare: 0x3384,
 +  kasraarabic: 0x0650,
 +  kasratanarabic: 0x064D,
 +  kastrokecyrillic: 0x049F,
 +  katahiraprolongmarkhalfwidth: 0xFF70,
 +  kaverticalstrokecyrillic: 0x049D,
 +  kbopomofo: 0x310E,
 +  kcalsquare: 0x3389,
 +  kcaron: 0x01E9,
 +  kcedilla: 0x0137,
 +  kcircle: 0x24DA,
 +  kcommaaccent: 0x0137,
 +  kdotbelow: 0x1E33,
 +  keharmenian: 0x0584,
 +  kehiragana: 0x3051,
 +  kekatakana: 0x30B1,
 +  kekatakanahalfwidth: 0xFF79,
 +  kenarmenian: 0x056F,
 +  kesmallkatakana: 0x30F6,
 +  kgreenlandic: 0x0138,
 +  khabengali: 0x0996,
 +  khacyrillic: 0x0445,
 +  khadeva: 0x0916,
 +  khagujarati: 0x0A96,
 +  khagurmukhi: 0x0A16,
 +  khaharabic: 0x062E,
 +  khahfinalarabic: 0xFEA6,
 +  khahinitialarabic: 0xFEA7,
 +  khahmedialarabic: 0xFEA8,
 +  kheicoptic: 0x03E7,
 +  khhadeva: 0x0959,
 +  khhagurmukhi: 0x0A59,
 +  khieukhacirclekorean: 0x3278,
 +  khieukhaparenkorean: 0x3218,
 +  khieukhcirclekorean: 0x326A,
 +  khieukhkorean: 0x314B,
 +  khieukhparenkorean: 0x320A,
 +  khokhaithai: 0x0E02,
 +  khokhonthai: 0x0E05,
 +  khokhuatthai: 0x0E03,
 +  khokhwaithai: 0x0E04,
 +  khomutthai: 0x0E5B,
 +  khook: 0x0199,
 +  khorakhangthai: 0x0E06,
 +  khzsquare: 0x3391,
 +  kihiragana: 0x304D,
 +  kikatakana: 0x30AD,
 +  kikatakanahalfwidth: 0xFF77,
 +  kiroguramusquare: 0x3315,
 +  kiromeetorusquare: 0x3316,
 +  kirosquare: 0x3314,
 +  kiyeokacirclekorean: 0x326E,
 +  kiyeokaparenkorean: 0x320E,
 +  kiyeokcirclekorean: 0x3260,
 +  kiyeokkorean: 0x3131,
 +  kiyeokparenkorean: 0x3200,
 +  kiyeoksioskorean: 0x3133,
 +  kjecyrillic: 0x045C,
 +  klinebelow: 0x1E35,
 +  klsquare: 0x3398,
 +  kmcubedsquare: 0x33A6,
 +  kmonospace: 0xFF4B,
 +  kmsquaredsquare: 0x33A2,
 +  kohiragana: 0x3053,
 +  kohmsquare: 0x33C0,
 +  kokaithai: 0x0E01,
 +  kokatakana: 0x30B3,
 +  kokatakanahalfwidth: 0xFF7A,
 +  kooposquare: 0x331E,
 +  koppacyrillic: 0x0481,
 +  koreanstandardsymbol: 0x327F,
 +  koroniscmb: 0x0343,
 +  kparen: 0x24A6,
 +  kpasquare: 0x33AA,
 +  ksicyrillic: 0x046F,
 +  ktsquare: 0x33CF,
 +  kturned: 0x029E,
 +  kuhiragana: 0x304F,
 +  kukatakana: 0x30AF,
 +  kukatakanahalfwidth: 0xFF78,
 +  kvsquare: 0x33B8,
 +  kwsquare: 0x33BE,
 +  l: 0x006C,
 +  labengali: 0x09B2,
 +  lacute: 0x013A,
 +  ladeva: 0x0932,
 +  lagujarati: 0x0AB2,
 +  lagurmukhi: 0x0A32,
 +  lakkhangyaothai: 0x0E45,
 +  lamaleffinalarabic: 0xFEFC,
 +  lamalefhamzaabovefinalarabic: 0xFEF8,
 +  lamalefhamzaaboveisolatedarabic: 0xFEF7,
 +  lamalefhamzabelowfinalarabic: 0xFEFA,
 +  lamalefhamzabelowisolatedarabic: 0xFEF9,
 +  lamalefisolatedarabic: 0xFEFB,
 +  lamalefmaddaabovefinalarabic: 0xFEF6,
 +  lamalefmaddaaboveisolatedarabic: 0xFEF5,
 +  lamarabic: 0x0644,
 +  lambda: 0x03BB,
 +  lambdastroke: 0x019B,
 +  lamed: 0x05DC,
 +  lameddagesh: 0xFB3C,
 +  lameddageshhebrew: 0xFB3C,
 +  lamedhebrew: 0x05DC,
 +  lamfinalarabic: 0xFEDE,
 +  lamhahinitialarabic: 0xFCCA,
 +  laminitialarabic: 0xFEDF,
 +  lamjeeminitialarabic: 0xFCC9,
 +  lamkhahinitialarabic: 0xFCCB,
 +  lamlamhehisolatedarabic: 0xFDF2,
 +  lammedialarabic: 0xFEE0,
 +  lammeemhahinitialarabic: 0xFD88,
 +  lammeeminitialarabic: 0xFCCC,
 +  largecircle: 0x25EF,
 +  lbar: 0x019A,
 +  lbelt: 0x026C,
 +  lbopomofo: 0x310C,
 +  lcaron: 0x013E,
 +  lcedilla: 0x013C,
 +  lcircle: 0x24DB,
 +  lcircumflexbelow: 0x1E3D,
 +  lcommaaccent: 0x013C,
 +  ldot: 0x0140,
 +  ldotaccent: 0x0140,
 +  ldotbelow: 0x1E37,
 +  ldotbelowmacron: 0x1E39,
 +  leftangleabovecmb: 0x031A,
 +  lefttackbelowcmb: 0x0318,
 +  less: 0x003C,
 +  lessequal: 0x2264,
 +  lessequalorgreater: 0x22DA,
 +  lessmonospace: 0xFF1C,
 +  lessorequivalent: 0x2272,
 +  lessorgreater: 0x2276,
 +  lessoverequal: 0x2266,
 +  lesssmall: 0xFE64,
 +  lezh: 0x026E,
 +  lfblock: 0x258C,
 +  lhookretroflex: 0x026D,
 +  lira: 0x20A4,
 +  liwnarmenian: 0x056C,
 +  lj: 0x01C9,
 +  ljecyrillic: 0x0459,
 +  ll: 0xF6C0,
 +  lladeva: 0x0933,
 +  llagujarati: 0x0AB3,
 +  llinebelow: 0x1E3B,
 +  llladeva: 0x0934,
 +  llvocalicbengali: 0x09E1,
 +  llvocalicdeva: 0x0961,
 +  llvocalicvowelsignbengali: 0x09E3,
 +  llvocalicvowelsigndeva: 0x0963,
 +  lmiddletilde: 0x026B,
 +  lmonospace: 0xFF4C,
 +  lmsquare: 0x33D0,
 +  lochulathai: 0x0E2C,
 +  logicaland: 0x2227,
 +  logicalnot: 0x00AC,
 +  logicalnotreversed: 0x2310,
 +  logicalor: 0x2228,
 +  lolingthai: 0x0E25,
 +  longs: 0x017F,
 +  lowlinecenterline: 0xFE4E,
 +  lowlinecmb: 0x0332,
 +  lowlinedashed: 0xFE4D,
 +  lozenge: 0x25CA,
 +  lparen: 0x24A7,
 +  lslash: 0x0142,
 +  lsquare: 0x2113,
 +  lsuperior: 0xF6EE,
 +  ltshade: 0x2591,
 +  luthai: 0x0E26,
 +  lvocalicbengali: 0x098C,
 +  lvocalicdeva: 0x090C,
 +  lvocalicvowelsignbengali: 0x09E2,
 +  lvocalicvowelsigndeva: 0x0962,
 +  lxsquare: 0x33D3,
 +  m: 0x006D,
 +  mabengali: 0x09AE,
 +  macron: 0x00AF,
 +  macronbelowcmb: 0x0331,
 +  macroncmb: 0x0304,
 +  macronlowmod: 0x02CD,
 +  macronmonospace: 0xFFE3,
 +  macute: 0x1E3F,
 +  madeva: 0x092E,
 +  magujarati: 0x0AAE,
 +  magurmukhi: 0x0A2E,
 +  mahapakhhebrew: 0x05A4,
 +  mahapakhlefthebrew: 0x05A4,
 +  mahiragana: 0x307E,
 +  maichattawalowleftthai: 0xF895,
 +  maichattawalowrightthai: 0xF894,
 +  maichattawathai: 0x0E4B,
 +  maichattawaupperleftthai: 0xF893,
 +  maieklowleftthai: 0xF88C,
 +  maieklowrightthai: 0xF88B,
 +  maiekthai: 0x0E48,
 +  maiekupperleftthai: 0xF88A,
 +  maihanakatleftthai: 0xF884,
 +  maihanakatthai: 0x0E31,
 +  maitaikhuleftthai: 0xF889,
 +  maitaikhuthai: 0x0E47,
 +  maitholowleftthai: 0xF88F,
 +  maitholowrightthai: 0xF88E,
 +  maithothai: 0x0E49,
 +  maithoupperleftthai: 0xF88D,
 +  maitrilowleftthai: 0xF892,
 +  maitrilowrightthai: 0xF891,
 +  maitrithai: 0x0E4A,
 +  maitriupperleftthai: 0xF890,
 +  maiyamokthai: 0x0E46,
 +  makatakana: 0x30DE,
 +  makatakanahalfwidth: 0xFF8F,
 +  male: 0x2642,
 +  mansyonsquare: 0x3347,
 +  maqafhebrew: 0x05BE,
 +  mars: 0x2642,
 +  masoracirclehebrew: 0x05AF,
 +  masquare: 0x3383,
 +  mbopomofo: 0x3107,
 +  mbsquare: 0x33D4,
 +  mcircle: 0x24DC,
 +  mcubedsquare: 0x33A5,
 +  mdotaccent: 0x1E41,
 +  mdotbelow: 0x1E43,
 +  meemarabic: 0x0645,
 +  meemfinalarabic: 0xFEE2,
 +  meeminitialarabic: 0xFEE3,
 +  meemmedialarabic: 0xFEE4,
 +  meemmeeminitialarabic: 0xFCD1,
 +  meemmeemisolatedarabic: 0xFC48,
 +  meetorusquare: 0x334D,
 +  mehiragana: 0x3081,
 +  meizierasquare: 0x337E,
 +  mekatakana: 0x30E1,
 +  mekatakanahalfwidth: 0xFF92,
 +  mem: 0x05DE,
 +  memdagesh: 0xFB3E,
 +  memdageshhebrew: 0xFB3E,
 +  memhebrew: 0x05DE,
 +  menarmenian: 0x0574,
 +  merkhahebrew: 0x05A5,
 +  merkhakefulahebrew: 0x05A6,
 +  merkhakefulalefthebrew: 0x05A6,
 +  merkhalefthebrew: 0x05A5,
 +  mhook: 0x0271,
 +  mhzsquare: 0x3392,
 +  middledotkatakanahalfwidth: 0xFF65,
 +  middot: 0x00B7,
 +  mieumacirclekorean: 0x3272,
 +  mieumaparenkorean: 0x3212,
 +  mieumcirclekorean: 0x3264,
 +  mieumkorean: 0x3141,
 +  mieumpansioskorean: 0x3170,
 +  mieumparenkorean: 0x3204,
 +  mieumpieupkorean: 0x316E,
 +  mieumsioskorean: 0x316F,
 +  mihiragana: 0x307F,
 +  mikatakana: 0x30DF,
 +  mikatakanahalfwidth: 0xFF90,
 +  minus: 0x2212,
 +  minusbelowcmb: 0x0320,
 +  minuscircle: 0x2296,
 +  minusmod: 0x02D7,
 +  minusplus: 0x2213,
 +  minute: 0x2032,
 +  miribaarusquare: 0x334A,
 +  mirisquare: 0x3349,
 +  mlonglegturned: 0x0270,
 +  mlsquare: 0x3396,
 +  mmcubedsquare: 0x33A3,
 +  mmonospace: 0xFF4D,
 +  mmsquaredsquare: 0x339F,
 +  mohiragana: 0x3082,
 +  mohmsquare: 0x33C1,
 +  mokatakana: 0x30E2,
 +  mokatakanahalfwidth: 0xFF93,
 +  molsquare: 0x33D6,
 +  momathai: 0x0E21,
 +  moverssquare: 0x33A7,
 +  moverssquaredsquare: 0x33A8,
 +  mparen: 0x24A8,
 +  mpasquare: 0x33AB,
 +  mssquare: 0x33B3,
 +  msuperior: 0xF6EF,
 +  mturned: 0x026F,
 +  mu: 0x00B5,
 +  mu1: 0x00B5,
 +  muasquare: 0x3382,
 +  muchgreater: 0x226B,
 +  muchless: 0x226A,
 +  mufsquare: 0x338C,
 +  mugreek: 0x03BC,
 +  mugsquare: 0x338D,
 +  muhiragana: 0x3080,
 +  mukatakana: 0x30E0,
 +  mukatakanahalfwidth: 0xFF91,
 +  mulsquare: 0x3395,
 +  multiply: 0x00D7,
 +  mumsquare: 0x339B,
 +  munahhebrew: 0x05A3,
 +  munahlefthebrew: 0x05A3,
 +  musicalnote: 0x266A,
 +  musicalnotedbl: 0x266B,
 +  musicflatsign: 0x266D,
 +  musicsharpsign: 0x266F,
 +  mussquare: 0x33B2,
 +  muvsquare: 0x33B6,
 +  muwsquare: 0x33BC,
 +  mvmegasquare: 0x33B9,
 +  mvsquare: 0x33B7,
 +  mwmegasquare: 0x33BF,
 +  mwsquare: 0x33BD,
 +  n: 0x006E,
 +  nabengali: 0x09A8,
 +  nabla: 0x2207,
 +  nacute: 0x0144,
 +  nadeva: 0x0928,
 +  nagujarati: 0x0AA8,
 +  nagurmukhi: 0x0A28,
 +  nahiragana: 0x306A,
 +  nakatakana: 0x30CA,
 +  nakatakanahalfwidth: 0xFF85,
 +  napostrophe: 0x0149,
 +  nasquare: 0x3381,
 +  nbopomofo: 0x310B,
 +  nbspace: 0x00A0,
 +  ncaron: 0x0148,
 +  ncedilla: 0x0146,
 +  ncircle: 0x24DD,
 +  ncircumflexbelow: 0x1E4B,
 +  ncommaaccent: 0x0146,
 +  ndotaccent: 0x1E45,
 +  ndotbelow: 0x1E47,
 +  nehiragana: 0x306D,
 +  nekatakana: 0x30CD,
 +  nekatakanahalfwidth: 0xFF88,
 +  newsheqelsign: 0x20AA,
 +  nfsquare: 0x338B,
 +  ngabengali: 0x0999,
 +  ngadeva: 0x0919,
 +  ngagujarati: 0x0A99,
 +  ngagurmukhi: 0x0A19,
 +  ngonguthai: 0x0E07,
 +  nhiragana: 0x3093,
 +  nhookleft: 0x0272,
 +  nhookretroflex: 0x0273,
 +  nieunacirclekorean: 0x326F,
 +  nieunaparenkorean: 0x320F,
 +  nieuncieuckorean: 0x3135,
 +  nieuncirclekorean: 0x3261,
 +  nieunhieuhkorean: 0x3136,
 +  nieunkorean: 0x3134,
 +  nieunpansioskorean: 0x3168,
 +  nieunparenkorean: 0x3201,
 +  nieunsioskorean: 0x3167,
 +  nieuntikeutkorean: 0x3166,
 +  nihiragana: 0x306B,
 +  nikatakana: 0x30CB,
 +  nikatakanahalfwidth: 0xFF86,
 +  nikhahitleftthai: 0xF899,
 +  nikhahitthai: 0x0E4D,
 +  nine: 0x0039,
 +  ninearabic: 0x0669,
 +  ninebengali: 0x09EF,
 +  ninecircle: 0x2468,
 +  ninecircleinversesansserif: 0x2792,
 +  ninedeva: 0x096F,
 +  ninegujarati: 0x0AEF,
 +  ninegurmukhi: 0x0A6F,
 +  ninehackarabic: 0x0669,
 +  ninehangzhou: 0x3029,
 +  nineideographicparen: 0x3228,
 +  nineinferior: 0x2089,
 +  ninemonospace: 0xFF19,
 +  nineoldstyle: 0xF739,
 +  nineparen: 0x247C,
 +  nineperiod: 0x2490,
 +  ninepersian: 0x06F9,
 +  nineroman: 0x2178,
 +  ninesuperior: 0x2079,
 +  nineteencircle: 0x2472,
 +  nineteenparen: 0x2486,
 +  nineteenperiod: 0x249A,
 +  ninethai: 0x0E59,
 +  nj: 0x01CC,
 +  njecyrillic: 0x045A,
 +  nkatakana: 0x30F3,
 +  nkatakanahalfwidth: 0xFF9D,
 +  nlegrightlong: 0x019E,
 +  nlinebelow: 0x1E49,
 +  nmonospace: 0xFF4E,
 +  nmsquare: 0x339A,
 +  nnabengali: 0x09A3,
 +  nnadeva: 0x0923,
 +  nnagujarati: 0x0AA3,
 +  nnagurmukhi: 0x0A23,
 +  nnnadeva: 0x0929,
 +  nohiragana: 0x306E,
 +  nokatakana: 0x30CE,
 +  nokatakanahalfwidth: 0xFF89,
 +  nonbreakingspace: 0x00A0,
 +  nonenthai: 0x0E13,
 +  nonuthai: 0x0E19,
 +  noonarabic: 0x0646,
 +  noonfinalarabic: 0xFEE6,
 +  noonghunnaarabic: 0x06BA,
 +  noonghunnafinalarabic: 0xFB9F,
 +  nooninitialarabic: 0xFEE7,
 +  noonjeeminitialarabic: 0xFCD2,
 +  noonjeemisolatedarabic: 0xFC4B,
 +  noonmedialarabic: 0xFEE8,
 +  noonmeeminitialarabic: 0xFCD5,
 +  noonmeemisolatedarabic: 0xFC4E,
 +  noonnoonfinalarabic: 0xFC8D,
 +  notcontains: 0x220C,
 +  notelement: 0x2209,
 +  notelementof: 0x2209,
 +  notequal: 0x2260,
 +  notgreater: 0x226F,
 +  notgreaternorequal: 0x2271,
 +  notgreaternorless: 0x2279,
 +  notidentical: 0x2262,
 +  notless: 0x226E,
 +  notlessnorequal: 0x2270,
 +  notparallel: 0x2226,
 +  notprecedes: 0x2280,
 +  notsubset: 0x2284,
 +  notsucceeds: 0x2281,
 +  notsuperset: 0x2285,
 +  nowarmenian: 0x0576,
 +  nparen: 0x24A9,
 +  nssquare: 0x33B1,
 +  nsuperior: 0x207F,
 +  ntilde: 0x00F1,
 +  nu: 0x03BD,
 +  nuhiragana: 0x306C,
 +  nukatakana: 0x30CC,
 +  nukatakanahalfwidth: 0xFF87,
 +  nuktabengali: 0x09BC,
 +  nuktadeva: 0x093C,
 +  nuktagujarati: 0x0ABC,
 +  nuktagurmukhi: 0x0A3C,
 +  numbersign: 0x0023,
 +  numbersignmonospace: 0xFF03,
 +  numbersignsmall: 0xFE5F,
 +  numeralsigngreek: 0x0374,
 +  numeralsignlowergreek: 0x0375,
 +  numero: 0x2116,
 +  nun: 0x05E0,
 +  nundagesh: 0xFB40,
 +  nundageshhebrew: 0xFB40,
 +  nunhebrew: 0x05E0,
 +  nvsquare: 0x33B5,
 +  nwsquare: 0x33BB,
 +  nyabengali: 0x099E,
 +  nyadeva: 0x091E,
 +  nyagujarati: 0x0A9E,
 +  nyagurmukhi: 0x0A1E,
 +  o: 0x006F,
 +  oacute: 0x00F3,
 +  oangthai: 0x0E2D,
 +  obarred: 0x0275,
 +  obarredcyrillic: 0x04E9,
 +  obarreddieresiscyrillic: 0x04EB,
 +  obengali: 0x0993,
 +  obopomofo: 0x311B,
 +  obreve: 0x014F,
 +  ocandradeva: 0x0911,
 +  ocandragujarati: 0x0A91,
 +  ocandravowelsigndeva: 0x0949,
 +  ocandravowelsigngujarati: 0x0AC9,
 +  ocaron: 0x01D2,
 +  ocircle: 0x24DE,
 +  ocircumflex: 0x00F4,
 +  ocircumflexacute: 0x1ED1,
 +  ocircumflexdotbelow: 0x1ED9,
 +  ocircumflexgrave: 0x1ED3,
 +  ocircumflexhookabove: 0x1ED5,
 +  ocircumflextilde: 0x1ED7,
 +  ocyrillic: 0x043E,
 +  odblacute: 0x0151,
 +  odblgrave: 0x020D,
 +  odeva: 0x0913,
 +  odieresis: 0x00F6,
 +  odieresiscyrillic: 0x04E7,
 +  odotbelow: 0x1ECD,
 +  oe: 0x0153,
 +  oekorean: 0x315A,
 +  ogonek: 0x02DB,
 +  ogonekcmb: 0x0328,
 +  ograve: 0x00F2,
 +  ogujarati: 0x0A93,
 +  oharmenian: 0x0585,
 +  ohiragana: 0x304A,
 +  ohookabove: 0x1ECF,
 +  ohorn: 0x01A1,
 +  ohornacute: 0x1EDB,
 +  ohorndotbelow: 0x1EE3,
 +  ohorngrave: 0x1EDD,
 +  ohornhookabove: 0x1EDF,
 +  ohorntilde: 0x1EE1,
 +  ohungarumlaut: 0x0151,
 +  oi: 0x01A3,
 +  oinvertedbreve: 0x020F,
 +  okatakana: 0x30AA,
 +  okatakanahalfwidth: 0xFF75,
 +  okorean: 0x3157,
 +  olehebrew: 0x05AB,
 +  omacron: 0x014D,
 +  omacronacute: 0x1E53,
 +  omacrongrave: 0x1E51,
 +  omdeva: 0x0950,
 +  omega: 0x03C9,
 +  omega1: 0x03D6,
 +  omegacyrillic: 0x0461,
 +  omegalatinclosed: 0x0277,
 +  omegaroundcyrillic: 0x047B,
 +  omegatitlocyrillic: 0x047D,
 +  omegatonos: 0x03CE,
 +  omgujarati: 0x0AD0,
 +  omicron: 0x03BF,
 +  omicrontonos: 0x03CC,
 +  omonospace: 0xFF4F,
 +  one: 0x0031,
 +  onearabic: 0x0661,
 +  onebengali: 0x09E7,
 +  onecircle: 0x2460,
 +  onecircleinversesansserif: 0x278A,
 +  onedeva: 0x0967,
 +  onedotenleader: 0x2024,
 +  oneeighth: 0x215B,
 +  onefitted: 0xF6DC,
 +  onegujarati: 0x0AE7,
 +  onegurmukhi: 0x0A67,
 +  onehackarabic: 0x0661,
 +  onehalf: 0x00BD,
 +  onehangzhou: 0x3021,
 +  oneideographicparen: 0x3220,
 +  oneinferior: 0x2081,
 +  onemonospace: 0xFF11,
 +  onenumeratorbengali: 0x09F4,
 +  oneoldstyle: 0xF731,
 +  oneparen: 0x2474,
 +  oneperiod: 0x2488,
 +  onepersian: 0x06F1,
 +  onequarter: 0x00BC,
 +  oneroman: 0x2170,
 +  onesuperior: 0x00B9,
 +  onethai: 0x0E51,
 +  onethird: 0x2153,
 +  oogonek: 0x01EB,
 +  oogonekmacron: 0x01ED,
 +  oogurmukhi: 0x0A13,
 +  oomatragurmukhi: 0x0A4B,
 +  oopen: 0x0254,
 +  oparen: 0x24AA,
 +  openbullet: 0x25E6,
 +  option: 0x2325,
 +  ordfeminine: 0x00AA,
 +  ordmasculine: 0x00BA,
 +  orthogonal: 0x221F,
 +  oshortdeva: 0x0912,
 +  oshortvowelsigndeva: 0x094A,
 +  oslash: 0x00F8,
 +  oslashacute: 0x01FF,
 +  osmallhiragana: 0x3049,
 +  osmallkatakana: 0x30A9,
 +  osmallkatakanahalfwidth: 0xFF6B,
 +  ostrokeacute: 0x01FF,
 +  osuperior: 0xF6F0,
 +  otcyrillic: 0x047F,
 +  otilde: 0x00F5,
 +  otildeacute: 0x1E4D,
 +  otildedieresis: 0x1E4F,
 +  oubopomofo: 0x3121,
 +  overline: 0x203E,
 +  overlinecenterline: 0xFE4A,
 +  overlinecmb: 0x0305,
 +  overlinedashed: 0xFE49,
 +  overlinedblwavy: 0xFE4C,
 +  overlinewavy: 0xFE4B,
 +  overscore: 0x00AF,
 +  ovowelsignbengali: 0x09CB,
 +  ovowelsigndeva: 0x094B,
 +  ovowelsigngujarati: 0x0ACB,
 +  p: 0x0070,
 +  paampssquare: 0x3380,
 +  paasentosquare: 0x332B,
 +  pabengali: 0x09AA,
 +  pacute: 0x1E55,
 +  padeva: 0x092A,
 +  pagedown: 0x21DF,
 +  pageup: 0x21DE,
 +  pagujarati: 0x0AAA,
 +  pagurmukhi: 0x0A2A,
 +  pahiragana: 0x3071,
 +  paiyannoithai: 0x0E2F,
 +  pakatakana: 0x30D1,
 +  palatalizationcyrilliccmb: 0x0484,
 +  palochkacyrillic: 0x04C0,
 +  pansioskorean: 0x317F,
 +  paragraph: 0x00B6,
 +  parallel: 0x2225,
 +  parenleft: 0x0028,
 +  parenleftaltonearabic: 0xFD3E,
 +  parenleftbt: 0xF8ED,
 +  parenleftex: 0xF8EC,
 +  parenleftinferior: 0x208D,
 +  parenleftmonospace: 0xFF08,
 +  parenleftsmall: 0xFE59,
 +  parenleftsuperior: 0x207D,
 +  parenlefttp: 0xF8EB,
 +  parenleftvertical: 0xFE35,
 +  parenright: 0x0029,
 +  parenrightaltonearabic: 0xFD3F,
 +  parenrightbt: 0xF8F8,
 +  parenrightex: 0xF8F7,
 +  parenrightinferior: 0x208E,
 +  parenrightmonospace: 0xFF09,
 +  parenrightsmall: 0xFE5A,
 +  parenrightsuperior: 0x207E,
 +  parenrighttp: 0xF8F6,
 +  parenrightvertical: 0xFE36,
 +  partialdiff: 0x2202,
 +  paseqhebrew: 0x05C0,
 +  pashtahebrew: 0x0599,
 +  pasquare: 0x33A9,
 +  patah: 0x05B7,
 +  patah11: 0x05B7,
 +  patah1d: 0x05B7,
 +  patah2a: 0x05B7,
 +  patahhebrew: 0x05B7,
 +  patahnarrowhebrew: 0x05B7,
 +  patahquarterhebrew: 0x05B7,
 +  patahwidehebrew: 0x05B7,
 +  pazerhebrew: 0x05A1,
 +  pbopomofo: 0x3106,
 +  pcircle: 0x24DF,
 +  pdotaccent: 0x1E57,
 +  pe: 0x05E4,
 +  pecyrillic: 0x043F,
 +  pedagesh: 0xFB44,
 +  pedageshhebrew: 0xFB44,
 +  peezisquare: 0x333B,
 +  pefinaldageshhebrew: 0xFB43,
 +  peharabic: 0x067E,
 +  peharmenian: 0x057A,
 +  pehebrew: 0x05E4,
 +  pehfinalarabic: 0xFB57,
 +  pehinitialarabic: 0xFB58,
 +  pehiragana: 0x307A,
 +  pehmedialarabic: 0xFB59,
 +  pekatakana: 0x30DA,
 +  pemiddlehookcyrillic: 0x04A7,
 +  perafehebrew: 0xFB4E,
 +  percent: 0x0025,
 +  percentarabic: 0x066A,
 +  percentmonospace: 0xFF05,
 +  percentsmall: 0xFE6A,
 +  period: 0x002E,
 +  periodarmenian: 0x0589,
 +  periodcentered: 0x00B7,
 +  periodhalfwidth: 0xFF61,
 +  periodinferior: 0xF6E7,
 +  periodmonospace: 0xFF0E,
 +  periodsmall: 0xFE52,
 +  periodsuperior: 0xF6E8,
 +  perispomenigreekcmb: 0x0342,
 +  perpendicular: 0x22A5,
 +  perthousand: 0x2030,
 +  peseta: 0x20A7,
 +  pfsquare: 0x338A,
 +  phabengali: 0x09AB,
 +  phadeva: 0x092B,
 +  phagujarati: 0x0AAB,
 +  phagurmukhi: 0x0A2B,
 +  phi: 0x03C6,
 +  phi1: 0x03D5,
 +  phieuphacirclekorean: 0x327A,
 +  phieuphaparenkorean: 0x321A,
 +  phieuphcirclekorean: 0x326C,
 +  phieuphkorean: 0x314D,
 +  phieuphparenkorean: 0x320C,
 +  philatin: 0x0278,
 +  phinthuthai: 0x0E3A,
 +  phisymbolgreek: 0x03D5,
 +  phook: 0x01A5,
 +  phophanthai: 0x0E1E,
 +  phophungthai: 0x0E1C,
 +  phosamphaothai: 0x0E20,
 +  pi: 0x03C0,
 +  pieupacirclekorean: 0x3273,
 +  pieupaparenkorean: 0x3213,
 +  pieupcieuckorean: 0x3176,
 +  pieupcirclekorean: 0x3265,
 +  pieupkiyeokkorean: 0x3172,
 +  pieupkorean: 0x3142,
 +  pieupparenkorean: 0x3205,
 +  pieupsioskiyeokkorean: 0x3174,
 +  pieupsioskorean: 0x3144,
 +  pieupsiostikeutkorean: 0x3175,
 +  pieupthieuthkorean: 0x3177,
 +  pieuptikeutkorean: 0x3173,
 +  pihiragana: 0x3074,
 +  pikatakana: 0x30D4,
 +  pisymbolgreek: 0x03D6,
 +  piwrarmenian: 0x0583,
 +  plus: 0x002B,
 +  plusbelowcmb: 0x031F,
 +  pluscircle: 0x2295,
 +  plusminus: 0x00B1,
 +  plusmod: 0x02D6,
 +  plusmonospace: 0xFF0B,
 +  plussmall: 0xFE62,
 +  plussuperior: 0x207A,
 +  pmonospace: 0xFF50,
 +  pmsquare: 0x33D8,
 +  pohiragana: 0x307D,
 +  pointingindexdownwhite: 0x261F,
 +  pointingindexleftwhite: 0x261C,
 +  pointingindexrightwhite: 0x261E,
 +  pointingindexupwhite: 0x261D,
 +  pokatakana: 0x30DD,
 +  poplathai: 0x0E1B,
 +  postalmark: 0x3012,
 +  postalmarkface: 0x3020,
 +  pparen: 0x24AB,
 +  precedes: 0x227A,
 +  prescription: 0x211E,
 +  primemod: 0x02B9,
 +  primereversed: 0x2035,
 +  product: 0x220F,
 +  projective: 0x2305,
 +  prolongedkana: 0x30FC,
 +  propellor: 0x2318,
 +  propersubset: 0x2282,
 +  propersuperset: 0x2283,
 +  proportion: 0x2237,
 +  proportional: 0x221D,
 +  psi: 0x03C8,
 +  psicyrillic: 0x0471,
 +  psilipneumatacyrilliccmb: 0x0486,
 +  pssquare: 0x33B0,
 +  puhiragana: 0x3077,
 +  pukatakana: 0x30D7,
 +  pvsquare: 0x33B4,
 +  pwsquare: 0x33BA,
 +  q: 0x0071,
 +  qadeva: 0x0958,
 +  qadmahebrew: 0x05A8,
 +  qafarabic: 0x0642,
 +  qaffinalarabic: 0xFED6,
 +  qafinitialarabic: 0xFED7,
 +  qafmedialarabic: 0xFED8,
 +  qamats: 0x05B8,
 +  qamats10: 0x05B8,
 +  qamats1a: 0x05B8,
 +  qamats1c: 0x05B8,
 +  qamats27: 0x05B8,
 +  qamats29: 0x05B8,
 +  qamats33: 0x05B8,
 +  qamatsde: 0x05B8,
 +  qamatshebrew: 0x05B8,
 +  qamatsnarrowhebrew: 0x05B8,
 +  qamatsqatanhebrew: 0x05B8,
 +  qamatsqatannarrowhebrew: 0x05B8,
 +  qamatsqatanquarterhebrew: 0x05B8,
 +  qamatsqatanwidehebrew: 0x05B8,
 +  qamatsquarterhebrew: 0x05B8,
 +  qamatswidehebrew: 0x05B8,
 +  qarneyparahebrew: 0x059F,
 +  qbopomofo: 0x3111,
 +  qcircle: 0x24E0,
 +  qhook: 0x02A0,
 +  qmonospace: 0xFF51,
 +  qof: 0x05E7,
 +  qofdagesh: 0xFB47,
 +  qofdageshhebrew: 0xFB47,
 +  qofhebrew: 0x05E7,
 +  qparen: 0x24AC,
 +  quarternote: 0x2669,
 +  qubuts: 0x05BB,
 +  qubuts18: 0x05BB,
 +  qubuts25: 0x05BB,
 +  qubuts31: 0x05BB,
 +  qubutshebrew: 0x05BB,
 +  qubutsnarrowhebrew: 0x05BB,
 +  qubutsquarterhebrew: 0x05BB,
 +  qubutswidehebrew: 0x05BB,
 +  question: 0x003F,
 +  questionarabic: 0x061F,
 +  questionarmenian: 0x055E,
 +  questiondown: 0x00BF,
 +  questiondownsmall: 0xF7BF,
 +  questiongreek: 0x037E,
 +  questionmonospace: 0xFF1F,
 +  questionsmall: 0xF73F,
 +  quotedbl: 0x0022,
 +  quotedblbase: 0x201E,
 +  quotedblleft: 0x201C,
 +  quotedblmonospace: 0xFF02,
 +  quotedblprime: 0x301E,
 +  quotedblprimereversed: 0x301D,
 +  quotedblright: 0x201D,
 +  quoteleft: 0x2018,
 +  quoteleftreversed: 0x201B,
 +  quotereversed: 0x201B,
 +  quoteright: 0x2019,
 +  quoterightn: 0x0149,
 +  quotesinglbase: 0x201A,
 +  quotesingle: 0x0027,
 +  quotesinglemonospace: 0xFF07,
 +  r: 0x0072,
 +  raarmenian: 0x057C,
 +  rabengali: 0x09B0,
 +  racute: 0x0155,
 +  radeva: 0x0930,
 +  radical: 0x221A,
 +  radicalex: 0xF8E5,
 +  radoverssquare: 0x33AE,
 +  radoverssquaredsquare: 0x33AF,
 +  radsquare: 0x33AD,
 +  rafe: 0x05BF,
 +  rafehebrew: 0x05BF,
 +  ragujarati: 0x0AB0,
 +  ragurmukhi: 0x0A30,
 +  rahiragana: 0x3089,
 +  rakatakana: 0x30E9,
 +  rakatakanahalfwidth: 0xFF97,
 +  ralowerdiagonalbengali: 0x09F1,
 +  ramiddlediagonalbengali: 0x09F0,
 +  ramshorn: 0x0264,
 +  ratio: 0x2236,
 +  rbopomofo: 0x3116,
 +  rcaron: 0x0159,
 +  rcedilla: 0x0157,
 +  rcircle: 0x24E1,
 +  rcommaaccent: 0x0157,
 +  rdblgrave: 0x0211,
 +  rdotaccent: 0x1E59,
 +  rdotbelow: 0x1E5B,
 +  rdotbelowmacron: 0x1E5D,
 +  referencemark: 0x203B,
 +  reflexsubset: 0x2286,
 +  reflexsuperset: 0x2287,
 +  registered: 0x00AE,
 +  registersans: 0xF8E8,
 +  registerserif: 0xF6DA,
 +  reharabic: 0x0631,
 +  reharmenian: 0x0580,
 +  rehfinalarabic: 0xFEAE,
 +  rehiragana: 0x308C,
 +  rekatakana: 0x30EC,
 +  rekatakanahalfwidth: 0xFF9A,
 +  resh: 0x05E8,
 +  reshdageshhebrew: 0xFB48,
 +  reshhebrew: 0x05E8,
 +  reversedtilde: 0x223D,
 +  reviahebrew: 0x0597,
 +  reviamugrashhebrew: 0x0597,
 +  revlogicalnot: 0x2310,
 +  rfishhook: 0x027E,
 +  rfishhookreversed: 0x027F,
 +  rhabengali: 0x09DD,
 +  rhadeva: 0x095D,
 +  rho: 0x03C1,
 +  rhook: 0x027D,
 +  rhookturned: 0x027B,
 +  rhookturnedsuperior: 0x02B5,
 +  rhosymbolgreek: 0x03F1,
 +  rhotichookmod: 0x02DE,
 +  rieulacirclekorean: 0x3271,
 +  rieulaparenkorean: 0x3211,
 +  rieulcirclekorean: 0x3263,
 +  rieulhieuhkorean: 0x3140,
 +  rieulkiyeokkorean: 0x313A,
 +  rieulkiyeoksioskorean: 0x3169,
 +  rieulkorean: 0x3139,
 +  rieulmieumkorean: 0x313B,
 +  rieulpansioskorean: 0x316C,
 +  rieulparenkorean: 0x3203,
 +  rieulphieuphkorean: 0x313F,
 +  rieulpieupkorean: 0x313C,
 +  rieulpieupsioskorean: 0x316B,
 +  rieulsioskorean: 0x313D,
 +  rieulthieuthkorean: 0x313E,
 +  rieultikeutkorean: 0x316A,
 +  rieulyeorinhieuhkorean: 0x316D,
 +  rightangle: 0x221F,
 +  righttackbelowcmb: 0x0319,
 +  righttriangle: 0x22BF,
 +  rihiragana: 0x308A,
 +  rikatakana: 0x30EA,
 +  rikatakanahalfwidth: 0xFF98,
 +  ring: 0x02DA,
 +  ringbelowcmb: 0x0325,
 +  ringcmb: 0x030A,
 +  ringhalfleft: 0x02BF,
 +  ringhalfleftarmenian: 0x0559,
 +  ringhalfleftbelowcmb: 0x031C,
 +  ringhalfleftcentered: 0x02D3,
 +  ringhalfright: 0x02BE,
 +  ringhalfrightbelowcmb: 0x0339,
 +  ringhalfrightcentered: 0x02D2,
 +  rinvertedbreve: 0x0213,
 +  rittorusquare: 0x3351,
 +  rlinebelow: 0x1E5F,
 +  rlongleg: 0x027C,
 +  rlonglegturned: 0x027A,
 +  rmonospace: 0xFF52,
 +  rohiragana: 0x308D,
 +  rokatakana: 0x30ED,
 +  rokatakanahalfwidth: 0xFF9B,
 +  roruathai: 0x0E23,
 +  rparen: 0x24AD,
 +  rrabengali: 0x09DC,
 +  rradeva: 0x0931,
 +  rragurmukhi: 0x0A5C,
 +  rreharabic: 0x0691,
 +  rrehfinalarabic: 0xFB8D,
 +  rrvocalicbengali: 0x09E0,
 +  rrvocalicdeva: 0x0960,
 +  rrvocalicgujarati: 0x0AE0,
 +  rrvocalicvowelsignbengali: 0x09C4,
 +  rrvocalicvowelsigndeva: 0x0944,
 +  rrvocalicvowelsigngujarati: 0x0AC4,
 +  rsuperior: 0xF6F1,
 +  rtblock: 0x2590,
 +  rturned: 0x0279,
 +  rturnedsuperior: 0x02B4,
 +  ruhiragana: 0x308B,
 +  rukatakana: 0x30EB,
 +  rukatakanahalfwidth: 0xFF99,
 +  rupeemarkbengali: 0x09F2,
 +  rupeesignbengali: 0x09F3,
 +  rupiah: 0xF6DD,
 +  ruthai: 0x0E24,
 +  rvocalicbengali: 0x098B,
 +  rvocalicdeva: 0x090B,
 +  rvocalicgujarati: 0x0A8B,
 +  rvocalicvowelsignbengali: 0x09C3,
 +  rvocalicvowelsigndeva: 0x0943,
 +  rvocalicvowelsigngujarati: 0x0AC3,
 +  s: 0x0073,
 +  sabengali: 0x09B8,
 +  sacute: 0x015B,
 +  sacutedotaccent: 0x1E65,
 +  sadarabic: 0x0635,
 +  sadeva: 0x0938,
 +  sadfinalarabic: 0xFEBA,
 +  sadinitialarabic: 0xFEBB,
 +  sadmedialarabic: 0xFEBC,
 +  sagujarati: 0x0AB8,
 +  sagurmukhi: 0x0A38,
 +  sahiragana: 0x3055,
 +  sakatakana: 0x30B5,
 +  sakatakanahalfwidth: 0xFF7B,
 +  sallallahoualayhewasallamarabic: 0xFDFA,
 +  samekh: 0x05E1,
 +  samekhdagesh: 0xFB41,
 +  samekhdageshhebrew: 0xFB41,
 +  samekhhebrew: 0x05E1,
 +  saraaathai: 0x0E32,
 +  saraaethai: 0x0E41,
 +  saraaimaimalaithai: 0x0E44,
 +  saraaimaimuanthai: 0x0E43,
 +  saraamthai: 0x0E33,
 +  saraathai: 0x0E30,
 +  saraethai: 0x0E40,
 +  saraiileftthai: 0xF886,
 +  saraiithai: 0x0E35,
 +  saraileftthai: 0xF885,
 +  saraithai: 0x0E34,
 +  saraothai: 0x0E42,
 +  saraueeleftthai: 0xF888,
 +  saraueethai: 0x0E37,
 +  saraueleftthai: 0xF887,
 +  sarauethai: 0x0E36,
 +  sarauthai: 0x0E38,
 +  sarauuthai: 0x0E39,
 +  sbopomofo: 0x3119,
 +  scaron: 0x0161,
 +  scarondotaccent: 0x1E67,
 +  scedilla: 0x015F,
 +  schwa: 0x0259,
 +  schwacyrillic: 0x04D9,
 +  schwadieresiscyrillic: 0x04DB,
 +  schwahook: 0x025A,
 +  scircle: 0x24E2,
 +  scircumflex: 0x015D,
 +  scommaaccent: 0x0219,
 +  sdotaccent: 0x1E61,
 +  sdotbelow: 0x1E63,
 +  sdotbelowdotaccent: 0x1E69,
 +  seagullbelowcmb: 0x033C,
 +  second: 0x2033,
 +  secondtonechinese: 0x02CA,
 +  section: 0x00A7,
 +  seenarabic: 0x0633,
 +  seenfinalarabic: 0xFEB2,
 +  seeninitialarabic: 0xFEB3,
 +  seenmedialarabic: 0xFEB4,
 +  segol: 0x05B6,
 +  segol13: 0x05B6,
 +  segol1f: 0x05B6,
 +  segol2c: 0x05B6,
 +  segolhebrew: 0x05B6,
 +  segolnarrowhebrew: 0x05B6,
 +  segolquarterhebrew: 0x05B6,
 +  segoltahebrew: 0x0592,
 +  segolwidehebrew: 0x05B6,
 +  seharmenian: 0x057D,
 +  sehiragana: 0x305B,
 +  sekatakana: 0x30BB,
 +  sekatakanahalfwidth: 0xFF7E,
 +  semicolon: 0x003B,
 +  semicolonarabic: 0x061B,
 +  semicolonmonospace: 0xFF1B,
 +  semicolonsmall: 0xFE54,
 +  semivoicedmarkkana: 0x309C,
 +  semivoicedmarkkanahalfwidth: 0xFF9F,
 +  sentisquare: 0x3322,
 +  sentosquare: 0x3323,
 +  seven: 0x0037,
 +  sevenarabic: 0x0667,
 +  sevenbengali: 0x09ED,
 +  sevencircle: 0x2466,
 +  sevencircleinversesansserif: 0x2790,
 +  sevendeva: 0x096D,
 +  seveneighths: 0x215E,
 +  sevengujarati: 0x0AED,
 +  sevengurmukhi: 0x0A6D,
 +  sevenhackarabic: 0x0667,
 +  sevenhangzhou: 0x3027,
 +  sevenideographicparen: 0x3226,
 +  seveninferior: 0x2087,
 +  sevenmonospace: 0xFF17,
 +  sevenoldstyle: 0xF737,
 +  sevenparen: 0x247A,
 +  sevenperiod: 0x248E,
 +  sevenpersian: 0x06F7,
 +  sevenroman: 0x2176,
 +  sevensuperior: 0x2077,
 +  seventeencircle: 0x2470,
 +  seventeenparen: 0x2484,
 +  seventeenperiod: 0x2498,
 +  seventhai: 0x0E57,
 +  sfthyphen: 0x00AD,
 +  shaarmenian: 0x0577,
 +  shabengali: 0x09B6,
 +  shacyrillic: 0x0448,
 +  shaddaarabic: 0x0651,
 +  shaddadammaarabic: 0xFC61,
 +  shaddadammatanarabic: 0xFC5E,
 +  shaddafathaarabic: 0xFC60,
 +  shaddakasraarabic: 0xFC62,
 +  shaddakasratanarabic: 0xFC5F,
 +  shade: 0x2592,
 +  shadedark: 0x2593,
 +  shadelight: 0x2591,
 +  shademedium: 0x2592,
 +  shadeva: 0x0936,
 +  shagujarati: 0x0AB6,
 +  shagurmukhi: 0x0A36,
 +  shalshelethebrew: 0x0593,
 +  shbopomofo: 0x3115,
 +  shchacyrillic: 0x0449,
 +  sheenarabic: 0x0634,
 +  sheenfinalarabic: 0xFEB6,
 +  sheeninitialarabic: 0xFEB7,
 +  sheenmedialarabic: 0xFEB8,
 +  sheicoptic: 0x03E3,
 +  sheqel: 0x20AA,
 +  sheqelhebrew: 0x20AA,
 +  sheva: 0x05B0,
 +  sheva115: 0x05B0,
 +  sheva15: 0x05B0,
 +  sheva22: 0x05B0,
 +  sheva2e: 0x05B0,
 +  shevahebrew: 0x05B0,
 +  shevanarrowhebrew: 0x05B0,
 +  shevaquarterhebrew: 0x05B0,
 +  shevawidehebrew: 0x05B0,
 +  shhacyrillic: 0x04BB,
 +  shimacoptic: 0x03ED,
 +  shin: 0x05E9,
 +  shindagesh: 0xFB49,
 +  shindageshhebrew: 0xFB49,
 +  shindageshshindot: 0xFB2C,
 +  shindageshshindothebrew: 0xFB2C,
 +  shindageshsindot: 0xFB2D,
 +  shindageshsindothebrew: 0xFB2D,
 +  shindothebrew: 0x05C1,
 +  shinhebrew: 0x05E9,
 +  shinshindot: 0xFB2A,
 +  shinshindothebrew: 0xFB2A,
 +  shinsindot: 0xFB2B,
 +  shinsindothebrew: 0xFB2B,
 +  shook: 0x0282,
 +  sigma: 0x03C3,
 +  sigma1: 0x03C2,
 +  sigmafinal: 0x03C2,
 +  sigmalunatesymbolgreek: 0x03F2,
 +  sihiragana: 0x3057,
 +  sikatakana: 0x30B7,
 +  sikatakanahalfwidth: 0xFF7C,
 +  siluqhebrew: 0x05BD,
 +  siluqlefthebrew: 0x05BD,
 +  similar: 0x223C,
 +  sindothebrew: 0x05C2,
 +  siosacirclekorean: 0x3274,
 +  siosaparenkorean: 0x3214,
 +  sioscieuckorean: 0x317E,
 +  sioscirclekorean: 0x3266,
 +  sioskiyeokkorean: 0x317A,
 +  sioskorean: 0x3145,
 +  siosnieunkorean: 0x317B,
 +  siosparenkorean: 0x3206,
 +  siospieupkorean: 0x317D,
 +  siostikeutkorean: 0x317C,
 +  six: 0x0036,
 +  sixarabic: 0x0666,
 +  sixbengali: 0x09EC,
 +  sixcircle: 0x2465,
 +  sixcircleinversesansserif: 0x278F,
 +  sixdeva: 0x096C,
 +  sixgujarati: 0x0AEC,
 +  sixgurmukhi: 0x0A6C,
 +  sixhackarabic: 0x0666,
 +  sixhangzhou: 0x3026,
 +  sixideographicparen: 0x3225,
 +  sixinferior: 0x2086,
 +  sixmonospace: 0xFF16,
 +  sixoldstyle: 0xF736,
 +  sixparen: 0x2479,
 +  sixperiod: 0x248D,
 +  sixpersian: 0x06F6,
 +  sixroman: 0x2175,
 +  sixsuperior: 0x2076,
 +  sixteencircle: 0x246F,
 +  sixteencurrencydenominatorbengali: 0x09F9,
 +  sixteenparen: 0x2483,
 +  sixteenperiod: 0x2497,
 +  sixthai: 0x0E56,
 +  slash: 0x002F,
 +  slashmonospace: 0xFF0F,
 +  slong: 0x017F,
 +  slongdotaccent: 0x1E9B,
 +  smileface: 0x263A,
 +  smonospace: 0xFF53,
 +  sofpasuqhebrew: 0x05C3,
 +  softhyphen: 0x00AD,
 +  softsigncyrillic: 0x044C,
 +  sohiragana: 0x305D,
 +  sokatakana: 0x30BD,
 +  sokatakanahalfwidth: 0xFF7F,
 +  soliduslongoverlaycmb: 0x0338,
 +  solidusshortoverlaycmb: 0x0337,
 +  sorusithai: 0x0E29,
 +  sosalathai: 0x0E28,
 +  sosothai: 0x0E0B,
 +  sosuathai: 0x0E2A,
 +  space: 0x0020,
 +  spacehackarabic: 0x0020,
 +  spade: 0x2660,
 +  spadesuitblack: 0x2660,
 +  spadesuitwhite: 0x2664,
 +  sparen: 0x24AE,
 +  squarebelowcmb: 0x033B,
 +  squarecc: 0x33C4,
 +  squarecm: 0x339D,
 +  squarediagonalcrosshatchfill: 0x25A9,
 +  squarehorizontalfill: 0x25A4,
 +  squarekg: 0x338F,
 +  squarekm: 0x339E,
 +  squarekmcapital: 0x33CE,
 +  squareln: 0x33D1,
 +  squarelog: 0x33D2,
 +  squaremg: 0x338E,
 +  squaremil: 0x33D5,
 +  squaremm: 0x339C,
 +  squaremsquared: 0x33A1,
 +  squareorthogonalcrosshatchfill: 0x25A6,
 +  squareupperlefttolowerrightfill: 0x25A7,
 +  squareupperrighttolowerleftfill: 0x25A8,
 +  squareverticalfill: 0x25A5,
 +  squarewhitewithsmallblack: 0x25A3,
 +  srsquare: 0x33DB,
 +  ssabengali: 0x09B7,
 +  ssadeva: 0x0937,
 +  ssagujarati: 0x0AB7,
 +  ssangcieuckorean: 0x3149,
 +  ssanghieuhkorean: 0x3185,
 +  ssangieungkorean: 0x3180,
 +  ssangkiyeokkorean: 0x3132,
 +  ssangnieunkorean: 0x3165,
 +  ssangpieupkorean: 0x3143,
 +  ssangsioskorean: 0x3146,
 +  ssangtikeutkorean: 0x3138,
 +  ssuperior: 0xF6F2,
 +  sterling: 0x00A3,
 +  sterlingmonospace: 0xFFE1,
 +  strokelongoverlaycmb: 0x0336,
 +  strokeshortoverlaycmb: 0x0335,
 +  subset: 0x2282,
 +  subsetnotequal: 0x228A,
 +  subsetorequal: 0x2286,
 +  succeeds: 0x227B,
 +  suchthat: 0x220B,
 +  suhiragana: 0x3059,
 +  sukatakana: 0x30B9,
 +  sukatakanahalfwidth: 0xFF7D,
 +  sukunarabic: 0x0652,
 +  summation: 0x2211,
 +  sun: 0x263C,
 +  superset: 0x2283,
 +  supersetnotequal: 0x228B,
 +  supersetorequal: 0x2287,
 +  svsquare: 0x33DC,
 +  syouwaerasquare: 0x337C,
 +  t: 0x0074,
 +  tabengali: 0x09A4,
 +  tackdown: 0x22A4,
 +  tackleft: 0x22A3,
 +  tadeva: 0x0924,
 +  tagujarati: 0x0AA4,
 +  tagurmukhi: 0x0A24,
 +  taharabic: 0x0637,
 +  tahfinalarabic: 0xFEC2,
 +  tahinitialarabic: 0xFEC3,
 +  tahiragana: 0x305F,
 +  tahmedialarabic: 0xFEC4,
 +  taisyouerasquare: 0x337D,
 +  takatakana: 0x30BF,
 +  takatakanahalfwidth: 0xFF80,
 +  tatweelarabic: 0x0640,
 +  tau: 0x03C4,
 +  tav: 0x05EA,
 +  tavdages: 0xFB4A,
 +  tavdagesh: 0xFB4A,
 +  tavdageshhebrew: 0xFB4A,
 +  tavhebrew: 0x05EA,
 +  tbar: 0x0167,
 +  tbopomofo: 0x310A,
 +  tcaron: 0x0165,
 +  tccurl: 0x02A8,
 +  tcedilla: 0x0163,
 +  tcheharabic: 0x0686,
 +  tchehfinalarabic: 0xFB7B,
 +  tchehinitialarabic: 0xFB7C,
 +  tchehmedialarabic: 0xFB7D,
 +  tcircle: 0x24E3,
 +  tcircumflexbelow: 0x1E71,
 +  tcommaaccent: 0x0163,
 +  tdieresis: 0x1E97,
 +  tdotaccent: 0x1E6B,
 +  tdotbelow: 0x1E6D,
 +  tecyrillic: 0x0442,
 +  tedescendercyrillic: 0x04AD,
 +  teharabic: 0x062A,
 +  tehfinalarabic: 0xFE96,
 +  tehhahinitialarabic: 0xFCA2,
 +  tehhahisolatedarabic: 0xFC0C,
 +  tehinitialarabic: 0xFE97,
 +  tehiragana: 0x3066,
 +  tehjeeminitialarabic: 0xFCA1,
 +  tehjeemisolatedarabic: 0xFC0B,
 +  tehmarbutaarabic: 0x0629,
 +  tehmarbutafinalarabic: 0xFE94,
 +  tehmedialarabic: 0xFE98,
 +  tehmeeminitialarabic: 0xFCA4,
 +  tehmeemisolatedarabic: 0xFC0E,
 +  tehnoonfinalarabic: 0xFC73,
 +  tekatakana: 0x30C6,
 +  tekatakanahalfwidth: 0xFF83,
 +  telephone: 0x2121,
 +  telephoneblack: 0x260E,
 +  telishagedolahebrew: 0x05A0,
 +  telishaqetanahebrew: 0x05A9,
 +  tencircle: 0x2469,
 +  tenideographicparen: 0x3229,
 +  tenparen: 0x247D,
 +  tenperiod: 0x2491,
 +  tenroman: 0x2179,
 +  tesh: 0x02A7,
 +  tet: 0x05D8,
 +  tetdagesh: 0xFB38,
 +  tetdageshhebrew: 0xFB38,
 +  tethebrew: 0x05D8,
 +  tetsecyrillic: 0x04B5,
 +  tevirhebrew: 0x059B,
 +  tevirlefthebrew: 0x059B,
 +  thabengali: 0x09A5,
 +  thadeva: 0x0925,
 +  thagujarati: 0x0AA5,
 +  thagurmukhi: 0x0A25,
 +  thalarabic: 0x0630,
 +  thalfinalarabic: 0xFEAC,
 +  thanthakhatlowleftthai: 0xF898,
 +  thanthakhatlowrightthai: 0xF897,
 +  thanthakhatthai: 0x0E4C,
 +  thanthakhatupperleftthai: 0xF896,
 +  theharabic: 0x062B,
 +  thehfinalarabic: 0xFE9A,
 +  thehinitialarabic: 0xFE9B,
 +  thehmedialarabic: 0xFE9C,
 +  thereexists: 0x2203,
 +  therefore: 0x2234,
 +  theta: 0x03B8,
 +  theta1: 0x03D1,
 +  thetasymbolgreek: 0x03D1,
 +  thieuthacirclekorean: 0x3279,
 +  thieuthaparenkorean: 0x3219,
 +  thieuthcirclekorean: 0x326B,
 +  thieuthkorean: 0x314C,
 +  thieuthparenkorean: 0x320B,
 +  thirteencircle: 0x246C,
 +  thirteenparen: 0x2480,
 +  thirteenperiod: 0x2494,
 +  thonangmonthothai: 0x0E11,
 +  thook: 0x01AD,
 +  thophuthaothai: 0x0E12,
 +  thorn: 0x00FE,
 +  thothahanthai: 0x0E17,
 +  thothanthai: 0x0E10,
 +  thothongthai: 0x0E18,
 +  thothungthai: 0x0E16,
 +  thousandcyrillic: 0x0482,
 +  thousandsseparatorarabic: 0x066C,
 +  thousandsseparatorpersian: 0x066C,
 +  three: 0x0033,
 +  threearabic: 0x0663,
 +  threebengali: 0x09E9,
 +  threecircle: 0x2462,
 +  threecircleinversesansserif: 0x278C,
 +  threedeva: 0x0969,
 +  threeeighths: 0x215C,
 +  threegujarati: 0x0AE9,
 +  threegurmukhi: 0x0A69,
 +  threehackarabic: 0x0663,
 +  threehangzhou: 0x3023,
 +  threeideographicparen: 0x3222,
 +  threeinferior: 0x2083,
 +  threemonospace: 0xFF13,
 +  threenumeratorbengali: 0x09F6,
 +  threeoldstyle: 0xF733,
 +  threeparen: 0x2476,
 +  threeperiod: 0x248A,
 +  threepersian: 0x06F3,
 +  threequarters: 0x00BE,
 +  threequartersemdash: 0xF6DE,
 +  threeroman: 0x2172,
 +  threesuperior: 0x00B3,
 +  threethai: 0x0E53,
 +  thzsquare: 0x3394,
 +  tihiragana: 0x3061,
 +  tikatakana: 0x30C1,
 +  tikatakanahalfwidth: 0xFF81,
 +  tikeutacirclekorean: 0x3270,
 +  tikeutaparenkorean: 0x3210,
 +  tikeutcirclekorean: 0x3262,
 +  tikeutkorean: 0x3137,
 +  tikeutparenkorean: 0x3202,
 +  tilde: 0x02DC,
 +  tildebelowcmb: 0x0330,
 +  tildecmb: 0x0303,
 +  tildecomb: 0x0303,
 +  tildedoublecmb: 0x0360,
 +  tildeoperator: 0x223C,
 +  tildeoverlaycmb: 0x0334,
 +  tildeverticalcmb: 0x033E,
 +  timescircle: 0x2297,
 +  tipehahebrew: 0x0596,
 +  tipehalefthebrew: 0x0596,
 +  tippigurmukhi: 0x0A70,
 +  titlocyrilliccmb: 0x0483,
 +  tiwnarmenian: 0x057F,
 +  tlinebelow: 0x1E6F,
 +  tmonospace: 0xFF54,
 +  toarmenian: 0x0569,
 +  tohiragana: 0x3068,
 +  tokatakana: 0x30C8,
 +  tokatakanahalfwidth: 0xFF84,
 +  tonebarextrahighmod: 0x02E5,
 +  tonebarextralowmod: 0x02E9,
 +  tonebarhighmod: 0x02E6,
 +  tonebarlowmod: 0x02E8,
 +  tonebarmidmod: 0x02E7,
 +  tonefive: 0x01BD,
 +  tonesix: 0x0185,
 +  tonetwo: 0x01A8,
 +  tonos: 0x0384,
 +  tonsquare: 0x3327,
 +  topatakthai: 0x0E0F,
 +  tortoiseshellbracketleft: 0x3014,
 +  tortoiseshellbracketleftsmall: 0xFE5D,
 +  tortoiseshellbracketleftvertical: 0xFE39,
 +  tortoiseshellbracketright: 0x3015,
 +  tortoiseshellbracketrightsmall: 0xFE5E,
 +  tortoiseshellbracketrightvertical: 0xFE3A,
 +  totaothai: 0x0E15,
 +  tpalatalhook: 0x01AB,
 +  tparen: 0x24AF,
 +  trademark: 0x2122,
 +  trademarksans: 0xF8EA,
 +  trademarkserif: 0xF6DB,
 +  tretroflexhook: 0x0288,
 +  triagdn: 0x25BC,
 +  triaglf: 0x25C4,
 +  triagrt: 0x25BA,
 +  triagup: 0x25B2,
 +  ts: 0x02A6,
 +  tsadi: 0x05E6,
 +  tsadidagesh: 0xFB46,
 +  tsadidageshhebrew: 0xFB46,
 +  tsadihebrew: 0x05E6,
 +  tsecyrillic: 0x0446,
 +  tsere: 0x05B5,
 +  tsere12: 0x05B5,
 +  tsere1e: 0x05B5,
 +  tsere2b: 0x05B5,
 +  tserehebrew: 0x05B5,
 +  tserenarrowhebrew: 0x05B5,
 +  tserequarterhebrew: 0x05B5,
 +  tserewidehebrew: 0x05B5,
 +  tshecyrillic: 0x045B,
 +  tsuperior: 0xF6F3,
 +  ttabengali: 0x099F,
 +  ttadeva: 0x091F,
 +  ttagujarati: 0x0A9F,
 +  ttagurmukhi: 0x0A1F,
 +  tteharabic: 0x0679,
 +  ttehfinalarabic: 0xFB67,
 +  ttehinitialarabic: 0xFB68,
 +  ttehmedialarabic: 0xFB69,
 +  tthabengali: 0x09A0,
 +  tthadeva: 0x0920,
 +  tthagujarati: 0x0AA0,
 +  tthagurmukhi: 0x0A20,
 +  tturned: 0x0287,
 +  tuhiragana: 0x3064,
 +  tukatakana: 0x30C4,
 +  tukatakanahalfwidth: 0xFF82,
 +  tusmallhiragana: 0x3063,
 +  tusmallkatakana: 0x30C3,
 +  tusmallkatakanahalfwidth: 0xFF6F,
 +  twelvecircle: 0x246B,
 +  twelveparen: 0x247F,
 +  twelveperiod: 0x2493,
 +  twelveroman: 0x217B,
 +  twentycircle: 0x2473,
 +  twentyhangzhou: 0x5344,
 +  twentyparen: 0x2487,
 +  twentyperiod: 0x249B,
 +  two: 0x0032,
 +  twoarabic: 0x0662,
 +  twobengali: 0x09E8,
 +  twocircle: 0x2461,
 +  twocircleinversesansserif: 0x278B,
 +  twodeva: 0x0968,
 +  twodotenleader: 0x2025,
 +  twodotleader: 0x2025,
 +  twodotleadervertical: 0xFE30,
 +  twogujarati: 0x0AE8,
 +  twogurmukhi: 0x0A68,
 +  twohackarabic: 0x0662,
 +  twohangzhou: 0x3022,
 +  twoideographicparen: 0x3221,
 +  twoinferior: 0x2082,
 +  twomonospace: 0xFF12,
 +  twonumeratorbengali: 0x09F5,
 +  twooldstyle: 0xF732,
 +  twoparen: 0x2475,
 +  twoperiod: 0x2489,
 +  twopersian: 0x06F2,
 +  tworoman: 0x2171,
 +  twostroke: 0x01BB,
 +  twosuperior: 0x00B2,
 +  twothai: 0x0E52,
 +  twothirds: 0x2154,
 +  u: 0x0075,
 +  uacute: 0x00FA,
 +  ubar: 0x0289,
 +  ubengali: 0x0989,
 +  ubopomofo: 0x3128,
 +  ubreve: 0x016D,
 +  ucaron: 0x01D4,
 +  ucircle: 0x24E4,
 +  ucircumflex: 0x00FB,
 +  ucircumflexbelow: 0x1E77,
 +  ucyrillic: 0x0443,
 +  udattadeva: 0x0951,
 +  udblacute: 0x0171,
 +  udblgrave: 0x0215,
 +  udeva: 0x0909,
 +  udieresis: 0x00FC,
 +  udieresisacute: 0x01D8,
 +  udieresisbelow: 0x1E73,
 +  udieresiscaron: 0x01DA,
 +  udieresiscyrillic: 0x04F1,
 +  udieresisgrave: 0x01DC,
 +  udieresismacron: 0x01D6,
 +  udotbelow: 0x1EE5,
 +  ugrave: 0x00F9,
 +  ugujarati: 0x0A89,
 +  ugurmukhi: 0x0A09,
 +  uhiragana: 0x3046,
 +  uhookabove: 0x1EE7,
 +  uhorn: 0x01B0,
 +  uhornacute: 0x1EE9,
 +  uhorndotbelow: 0x1EF1,
 +  uhorngrave: 0x1EEB,
 +  uhornhookabove: 0x1EED,
 +  uhorntilde: 0x1EEF,
 +  uhungarumlaut: 0x0171,
 +  uhungarumlautcyrillic: 0x04F3,
 +  uinvertedbreve: 0x0217,
 +  ukatakana: 0x30A6,
 +  ukatakanahalfwidth: 0xFF73,
 +  ukcyrillic: 0x0479,
 +  ukorean: 0x315C,
 +  umacron: 0x016B,
 +  umacroncyrillic: 0x04EF,
 +  umacrondieresis: 0x1E7B,
 +  umatragurmukhi: 0x0A41,
 +  umonospace: 0xFF55,
 +  underscore: 0x005F,
 +  underscoredbl: 0x2017,
 +  underscoremonospace: 0xFF3F,
 +  underscorevertical: 0xFE33,
 +  underscorewavy: 0xFE4F,
 +  union: 0x222A,
 +  universal: 0x2200,
 +  uogonek: 0x0173,
 +  uparen: 0x24B0,
 +  upblock: 0x2580,
 +  upperdothebrew: 0x05C4,
 +  upsilon: 0x03C5,
 +  upsilondieresis: 0x03CB,
 +  upsilondieresistonos: 0x03B0,
 +  upsilonlatin: 0x028A,
 +  upsilontonos: 0x03CD,
 +  uptackbelowcmb: 0x031D,
 +  uptackmod: 0x02D4,
 +  uragurmukhi: 0x0A73,
 +  uring: 0x016F,
 +  ushortcyrillic: 0x045E,
 +  usmallhiragana: 0x3045,
 +  usmallkatakana: 0x30A5,
 +  usmallkatakanahalfwidth: 0xFF69,
 +  ustraightcyrillic: 0x04AF,
 +  ustraightstrokecyrillic: 0x04B1,
 +  utilde: 0x0169,
 +  utildeacute: 0x1E79,
 +  utildebelow: 0x1E75,
 +  uubengali: 0x098A,
 +  uudeva: 0x090A,
 +  uugujarati: 0x0A8A,
 +  uugurmukhi: 0x0A0A,
 +  uumatragurmukhi: 0x0A42,
 +  uuvowelsignbengali: 0x09C2,
 +  uuvowelsigndeva: 0x0942,
 +  uuvowelsigngujarati: 0x0AC2,
 +  uvowelsignbengali: 0x09C1,
 +  uvowelsigndeva: 0x0941,
 +  uvowelsigngujarati: 0x0AC1,
 +  v: 0x0076,
 +  vadeva: 0x0935,
 +  vagujarati: 0x0AB5,
 +  vagurmukhi: 0x0A35,
 +  vakatakana: 0x30F7,
 +  vav: 0x05D5,
 +  vavdagesh: 0xFB35,
 +  vavdagesh65: 0xFB35,
 +  vavdageshhebrew: 0xFB35,
 +  vavhebrew: 0x05D5,
 +  vavholam: 0xFB4B,
 +  vavholamhebrew: 0xFB4B,
 +  vavvavhebrew: 0x05F0,
 +  vavyodhebrew: 0x05F1,
 +  vcircle: 0x24E5,
 +  vdotbelow: 0x1E7F,
 +  vecyrillic: 0x0432,
 +  veharabic: 0x06A4,
 +  vehfinalarabic: 0xFB6B,
 +  vehinitialarabic: 0xFB6C,
 +  vehmedialarabic: 0xFB6D,
 +  vekatakana: 0x30F9,
 +  venus: 0x2640,
 +  verticalbar: 0x007C,
 +  verticallineabovecmb: 0x030D,
 +  verticallinebelowcmb: 0x0329,
 +  verticallinelowmod: 0x02CC,
 +  verticallinemod: 0x02C8,
 +  vewarmenian: 0x057E,
 +  vhook: 0x028B,
 +  vikatakana: 0x30F8,
 +  viramabengali: 0x09CD,
 +  viramadeva: 0x094D,
 +  viramagujarati: 0x0ACD,
 +  visargabengali: 0x0983,
 +  visargadeva: 0x0903,
 +  visargagujarati: 0x0A83,
 +  vmonospace: 0xFF56,
 +  voarmenian: 0x0578,
 +  voicediterationhiragana: 0x309E,
 +  voicediterationkatakana: 0x30FE,
 +  voicedmarkkana: 0x309B,
 +  voicedmarkkanahalfwidth: 0xFF9E,
 +  vokatakana: 0x30FA,
 +  vparen: 0x24B1,
 +  vtilde: 0x1E7D,
 +  vturned: 0x028C,
 +  vuhiragana: 0x3094,
 +  vukatakana: 0x30F4,
 +  w: 0x0077,
 +  wacute: 0x1E83,
 +  waekorean: 0x3159,
 +  wahiragana: 0x308F,
 +  wakatakana: 0x30EF,
 +  wakatakanahalfwidth: 0xFF9C,
 +  wakorean: 0x3158,
 +  wasmallhiragana: 0x308E,
 +  wasmallkatakana: 0x30EE,
 +  wattosquare: 0x3357,
 +  wavedash: 0x301C,
 +  wavyunderscorevertical: 0xFE34,
 +  wawarabic: 0x0648,
 +  wawfinalarabic: 0xFEEE,
 +  wawhamzaabovearabic: 0x0624,
 +  wawhamzaabovefinalarabic: 0xFE86,
 +  wbsquare: 0x33DD,
 +  wcircle: 0x24E6,
 +  wcircumflex: 0x0175,
 +  wdieresis: 0x1E85,
 +  wdotaccent: 0x1E87,
 +  wdotbelow: 0x1E89,
 +  wehiragana: 0x3091,
 +  weierstrass: 0x2118,
 +  wekatakana: 0x30F1,
 +  wekorean: 0x315E,
 +  weokorean: 0x315D,
 +  wgrave: 0x1E81,
 +  whitebullet: 0x25E6,
 +  whitecircle: 0x25CB,
 +  whitecircleinverse: 0x25D9,
 +  whitecornerbracketleft: 0x300E,
 +  whitecornerbracketleftvertical: 0xFE43,
 +  whitecornerbracketright: 0x300F,
 +  whitecornerbracketrightvertical: 0xFE44,
 +  whitediamond: 0x25C7,
 +  whitediamondcontainingblacksmalldiamond: 0x25C8,
 +  whitedownpointingsmalltriangle: 0x25BF,
 +  whitedownpointingtriangle: 0x25BD,
 +  whiteleftpointingsmalltriangle: 0x25C3,
 +  whiteleftpointingtriangle: 0x25C1,
 +  whitelenticularbracketleft: 0x3016,
 +  whitelenticularbracketright: 0x3017,
 +  whiterightpointingsmalltriangle: 0x25B9,
 +  whiterightpointingtriangle: 0x25B7,
 +  whitesmallsquare: 0x25AB,
 +  whitesmilingface: 0x263A,
 +  whitesquare: 0x25A1,
 +  whitestar: 0x2606,
 +  whitetelephone: 0x260F,
 +  whitetortoiseshellbracketleft: 0x3018,
 +  whitetortoiseshellbracketright: 0x3019,
 +  whiteuppointingsmalltriangle: 0x25B5,
 +  whiteuppointingtriangle: 0x25B3,
 +  wihiragana: 0x3090,
 +  wikatakana: 0x30F0,
 +  wikorean: 0x315F,
 +  wmonospace: 0xFF57,
 +  wohiragana: 0x3092,
 +  wokatakana: 0x30F2,
 +  wokatakanahalfwidth: 0xFF66,
 +  won: 0x20A9,
 +  wonmonospace: 0xFFE6,
 +  wowaenthai: 0x0E27,
 +  wparen: 0x24B2,
 +  wring: 0x1E98,
 +  wsuperior: 0x02B7,
 +  wturned: 0x028D,
 +  wynn: 0x01BF,
 +  x: 0x0078,
 +  xabovecmb: 0x033D,
 +  xbopomofo: 0x3112,
 +  xcircle: 0x24E7,
 +  xdieresis: 0x1E8D,
 +  xdotaccent: 0x1E8B,
 +  xeharmenian: 0x056D,
 +  xi: 0x03BE,
 +  xmonospace: 0xFF58,
 +  xparen: 0x24B3,
 +  xsuperior: 0x02E3,
 +  y: 0x0079,
 +  yaadosquare: 0x334E,
 +  yabengali: 0x09AF,
 +  yacute: 0x00FD,
 +  yadeva: 0x092F,
 +  yaekorean: 0x3152,
 +  yagujarati: 0x0AAF,
 +  yagurmukhi: 0x0A2F,
 +  yahiragana: 0x3084,
 +  yakatakana: 0x30E4,
 +  yakatakanahalfwidth: 0xFF94,
 +  yakorean: 0x3151,
 +  yamakkanthai: 0x0E4E,
 +  yasmallhiragana: 0x3083,
 +  yasmallkatakana: 0x30E3,
 +  yasmallkatakanahalfwidth: 0xFF6C,
 +  yatcyrillic: 0x0463,
 +  ycircle: 0x24E8,
 +  ycircumflex: 0x0177,
 +  ydieresis: 0x00FF,
 +  ydotaccent: 0x1E8F,
 +  ydotbelow: 0x1EF5,
 +  yeharabic: 0x064A,
 +  yehbarreearabic: 0x06D2,
 +  yehbarreefinalarabic: 0xFBAF,
 +  yehfinalarabic: 0xFEF2,
 +  yehhamzaabovearabic: 0x0626,
 +  yehhamzaabovefinalarabic: 0xFE8A,
 +  yehhamzaaboveinitialarabic: 0xFE8B,
 +  yehhamzaabovemedialarabic: 0xFE8C,
 +  yehinitialarabic: 0xFEF3,
 +  yehmedialarabic: 0xFEF4,
 +  yehmeeminitialarabic: 0xFCDD,
 +  yehmeemisolatedarabic: 0xFC58,
 +  yehnoonfinalarabic: 0xFC94,
 +  yehthreedotsbelowarabic: 0x06D1,
 +  yekorean: 0x3156,
 +  yen: 0x00A5,
 +  yenmonospace: 0xFFE5,
 +  yeokorean: 0x3155,
 +  yeorinhieuhkorean: 0x3186,
 +  yerahbenyomohebrew: 0x05AA,
 +  yerahbenyomolefthebrew: 0x05AA,
 +  yericyrillic: 0x044B,
 +  yerudieresiscyrillic: 0x04F9,
 +  yesieungkorean: 0x3181,
 +  yesieungpansioskorean: 0x3183,
 +  yesieungsioskorean: 0x3182,
 +  yetivhebrew: 0x059A,
 +  ygrave: 0x1EF3,
 +  yhook: 0x01B4,
 +  yhookabove: 0x1EF7,
 +  yiarmenian: 0x0575,
 +  yicyrillic: 0x0457,
 +  yikorean: 0x3162,
 +  yinyang: 0x262F,
 +  yiwnarmenian: 0x0582,
 +  ymonospace: 0xFF59,
 +  yod: 0x05D9,
 +  yoddagesh: 0xFB39,
 +  yoddageshhebrew: 0xFB39,
 +  yodhebrew: 0x05D9,
 +  yodyodhebrew: 0x05F2,
 +  yodyodpatahhebrew: 0xFB1F,
 +  yohiragana: 0x3088,
 +  yoikorean: 0x3189,
 +  yokatakana: 0x30E8,
 +  yokatakanahalfwidth: 0xFF96,
 +  yokorean: 0x315B,
 +  yosmallhiragana: 0x3087,
 +  yosmallkatakana: 0x30E7,
 +  yosmallkatakanahalfwidth: 0xFF6E,
 +  yotgreek: 0x03F3,
 +  yoyaekorean: 0x3188,
 +  yoyakorean: 0x3187,
 +  yoyakthai: 0x0E22,
 +  yoyingthai: 0x0E0D,
 +  yparen: 0x24B4,
 +  ypogegrammeni: 0x037A,
 +  ypogegrammenigreekcmb: 0x0345,
 +  yr: 0x01A6,
 +  yring: 0x1E99,
 +  ysuperior: 0x02B8,
 +  ytilde: 0x1EF9,
 +  yturned: 0x028E,
 +  yuhiragana: 0x3086,
 +  yuikorean: 0x318C,
 +  yukatakana: 0x30E6,
 +  yukatakanahalfwidth: 0xFF95,
 +  yukorean: 0x3160,
 +  yusbigcyrillic: 0x046B,
 +  yusbigiotifiedcyrillic: 0x046D,
 +  yuslittlecyrillic: 0x0467,
 +  yuslittleiotifiedcyrillic: 0x0469,
 +  yusmallhiragana: 0x3085,
 +  yusmallkatakana: 0x30E5,
 +  yusmallkatakanahalfwidth: 0xFF6D,
 +  yuyekorean: 0x318B,
 +  yuyeokorean: 0x318A,
 +  yyabengali: 0x09DF,
 +  yyadeva: 0x095F,
 +  z: 0x007A,
 +  zaarmenian: 0x0566,
 +  zacute: 0x017A,
 +  zadeva: 0x095B,
 +  zagurmukhi: 0x0A5B,
 +  zaharabic: 0x0638,
 +  zahfinalarabic: 0xFEC6,
 +  zahinitialarabic: 0xFEC7,
 +  zahiragana: 0x3056,
 +  zahmedialarabic: 0xFEC8,
 +  zainarabic: 0x0632,
 +  zainfinalarabic: 0xFEB0,
 +  zakatakana: 0x30B6,
 +  zaqefgadolhebrew: 0x0595,
 +  zaqefqatanhebrew: 0x0594,
 +  zarqahebrew: 0x0598,
 +  zayin: 0x05D6,
 +  zayindagesh: 0xFB36,
 +  zayindageshhebrew: 0xFB36,
 +  zayinhebrew: 0x05D6,
 +  zbopomofo: 0x3117,
 +  zcaron: 0x017E,
 +  zcircle: 0x24E9,
 +  zcircumflex: 0x1E91,
 +  zcurl: 0x0291,
 +  zdot: 0x017C,
 +  zdotaccent: 0x017C,
 +  zdotbelow: 0x1E93,
 +  zecyrillic: 0x0437,
 +  zedescendercyrillic: 0x0499,
 +  zedieresiscyrillic: 0x04DF,
 +  zehiragana: 0x305C,
 +  zekatakana: 0x30BC,
 +  zero: 0x0030,
 +  zeroarabic: 0x0660,
 +  zerobengali: 0x09E6,
 +  zerodeva: 0x0966,
 +  zerogujarati: 0x0AE6,
 +  zerogurmukhi: 0x0A66,
 +  zerohackarabic: 0x0660,
 +  zeroinferior: 0x2080,
 +  zeromonospace: 0xFF10,
 +  zerooldstyle: 0xF730,
 +  zeropersian: 0x06F0,
 +  zerosuperior: 0x2070,
 +  zerothai: 0x0E50,
 +  zerowidthjoiner: 0xFEFF,
 +  zerowidthnonjoiner: 0x200C,
 +  zerowidthspace: 0x200B,
 +  zeta: 0x03B6,
 +  zhbopomofo: 0x3113,
 +  zhearmenian: 0x056A,
 +  zhebrevecyrillic: 0x04C2,
 +  zhecyrillic: 0x0436,
 +  zhedescendercyrillic: 0x0497,
 +  zhedieresiscyrillic: 0x04DD,
 +  zihiragana: 0x3058,
 +  zikatakana: 0x30B8,
 +  zinorhebrew: 0x05AE,
 +  zlinebelow: 0x1E95,
 +  zmonospace: 0xFF5A,
 +  zohiragana: 0x305E,
 +  zokatakana: 0x30BE,
 +  zparen: 0x24B5,
 +  zretroflexhook: 0x0290,
 +  zstroke: 0x01B6,
 +  zuhiragana: 0x305A,
 +  zukatakana: 0x30BA,
 +  '.notdef': 0x0000
 +};
 +
 +
 +
 +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) {
 +    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 data = message.data;
 +        var stream = new Stream(data, 0, data.length, image.dict);
 +        promise.resolve(stream);
 +      });
 +    } else {
 +      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.
 +   */
 +  function decodeAndClamp(value, addend, coefficient, max) {
 +    value = addend + value * coefficient;
 +    // Clamp the value to the range
 +    return value < 0 ? 0 : value > max ? max : value;
 +  }
-   function PDFImage(xref, res, image, inline, smask, mask) {
++  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.
-       TODO('get params from actual stream');
++      warn('get params from actual stream');
 +      // var bits = ...
 +      // var colorspace = ...
 +    }
 +    // 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;
++    this.matte = dict.get('Matte') || false;
 +
 +    var bitsPerComponent = image.bitsPerComponent;
 +    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;
 +
 +    if (!this.imageMask) {
 +      var colorSpace = dict.get('ColorSpace', 'CS');
 +      if (!colorSpace) {
-         TODO('JPX images (which don"t require color spaces');
-         colorSpace = new Name('DeviceRGB');
++        warn('JPX images (which don"t require color spaces');
++        colorSpace = Name.get('DeviceRGB');
 +      }
 +      this.colorSpace = ColorSpace.parse(colorSpace, xref, res);
 +      this.numComps = this.colorSpace.numComps;
 +    }
 +
 +    this.decode = dict.get('Decode', 'D');
 +    this.needsDecode = false;
-     if (this.decode && this.colorSpace &&
-         !this.colorSpace.isDefaultDecode(this.decode)) {
++    if (this.decode &&
++        ((this.colorSpace && !this.colorSpace.isDefaultDecode(this.decode)) ||
++         (isMask && !ColorSpace.isDefaultDecode(this.decode, 1)))) {
 +      this.needsDecode = true;
 +      // Do some preprocessing to avoid more math.
 +      var max = (1 << bitsPerComponent) - 1;
 +      this.decodeCoefficients = [];
 +      this.decodeAddends = [];
 +      for (var i = 0, j = 0; i < this.decode.length; i += 2, ++j) {
 +        var dmin = this.decode[i];
 +        var dmax = this.decode[i + 1];
 +        this.decodeCoefficients[j] = dmax - dmin;
 +        this.decodeAddends[j] = max * dmin;
 +      }
 +    }
 +
 +    if (smask) {
 +      this.smask = new PDFImage(xref, res, smask, false);
 +    } else if (mask) {
 +      if (isStream(mask)) {
-         this.mask = new PDFImage(xref, res, mask, false);
++        this.mask = new PDFImage(xref, res, mask, false, null, null, true);
 +      } else {
 +        // Color key mask (just an array).
 +        this.mask = mask;
 +      }
 +    }
 +  }
 +  /**
 +   * Handles processing of image data and calls the callback with an argument
 +   * of a PDFImage when the image is ready to be used.
 +   */
 +  PDFImage.buildImage = function PDFImage_buildImage(callback, handler, xref,
 +                                                     res, image, inline) {
-     var imageDataPromise = new Promise();
-     var smaskPromise = new Promise();
-     var maskPromise = new Promise();
++    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 smask = image.dict.get('SMask');
 +    var mask = image.dict.get('Mask');
 +
 +    if (smask) {
 +      handleImageData(handler, xref, res, smask, smaskPromise);
 +      maskPromise.resolve(null);
 +    } else {
 +      smaskPromise.resolve(null);
 +      if (mask) {
 +        if (isStream(mask)) {
 +          handleImageData(handler, xref, res, mask, maskPromise);
 +        } else if (isArray(mask)) {
 +          maskPromise.resolve(mask);
 +        } else {
 +          warn('Unsupported mask format.');
 +          maskPromise.resolve(null);
 +        }
 +      } else {
 +        maskPromise.resolve(null);
 +      }
 +    }
 +  };
 +
 +  /**
 +   * 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.
 +   * @param {Number} components Number of color components, 1 or 3 is supported.
 +   * @param {Number} w1 Original width.
 +   * @param {Number} h1 Original height.
 +   * @param {Number} w2 New width.
 +   * @param {Number} h2 New height.
 +   * @return {TypedArray} Resized image data.
 +   */
 +  PDFImage.resize = function PDFImage_resize(pixels, bpc, components,
 +                                             w1, h1, w2, h2) {
 +    var length = w2 * h2 * components;
 +    var temp = 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];
 +        }
 +      }
 +    }
 +    return temp;
 +  };
 +
++  PDFImage.createMask = function PDFImage_createMask(imgArray, width, height,
++                                                     inverseDecode) {
++    // Copy imgArray into a typed array (inverting if necessary) so it can be
++    // transferred to the main thread.
++    var length = ((width + 7) >> 3) * height;
++    var data = new Uint8Array(length);
++    if (inverseDecode) {
++      for (var i = 0; i < length; i++) {
++        data[i] = ~imgArray[i];
++      }
++    } else {
++      for (var i = 0; i < length; i++) {
++        data[i] = imgArray[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);
 +    },
 +    get drawHeight() {
 +      if (!this.smask)
 +        return this.height;
 +      return Math.max(this.height, this.smask.height);
 +    },
-     getComponents: function PDFImage_getComponents(buffer) {
++    decodeBuffer: function PDFImage_decodeBuffer(buffer) {
 +      var bpc = this.bpc;
-       var needsDecode = this.needsDecode;
 +      var decodeMap = this.decode;
++      var numComps = this.numComps;
++
++      var decodeAddends, decodeCoefficients;
++      var decodeAddends = this.decodeAddends;
++      var decodeCoefficients = this.decodeCoefficients;
++      var max = (1 << bpc) - 1;
++
++      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++) {
++          buffer[i] = +!(buffer[i]);
++        }
++        return;
++      }
++      var index = 0;
++      for (var 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);
++          index++;
++        }
++      }
++    },
++    getComponents: function PDFImage_getComponents(buffer) {
++      var bpc = this.bpc;
 +
 +      // This image doesn't require any extra work.
-       if (bpc == 8 && !needsDecode)
++      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 rowComps = width * numComps;
-       var decodeAddends, decodeCoefficients;
-       if (needsDecode) {
-         decodeAddends = this.decodeAddends;
-         decodeCoefficients = this.decodeCoefficients;
-       }
++
 +      var max = (1 << bpc) - 1;
 +
-       if (bpc == 8) {
-         // Optimization for reading 8 bpc images that have a decode.
-         for (var i = 0, ii = length; i < ii; ++i) {
-           var compIndex = i % numComps;
-           var value = buffer[i];
-           value = decodeAndClamp(value, decodeAddends[compIndex],
-                           decodeCoefficients[compIndex], max);
-           output[i] = value;
-         }
-       } else if (bpc == 1) {
++      if (bpc === 1) {
 +        // Optimization for reading 1 bpc images.
-         var valueZero = 0, valueOne = 1;
-         if (decodeMap) {
-           valueZero = decodeMap[0] ? 1 : 0;
-           valueOne = decodeMap[1] ? 1 : 0;
-         }
-         var mask = 0;
-         var buf = 0;
++        var i = 0, buf, 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) ? valueZero : valueOne;
 +        }
 +      } else {
 +        // The general case that handles all other bpc values.
 +        var bits = 0, buf = 0;
 +        for (var i = 0, ii = length; i < ii; ++i) {
 +          if (i % rowComps === 0) {
 +            buf = 0;
 +            bits = 0;
 +          }
 +
 +          while (bits < bpc) {
 +            buf = (buf << 8) | buffer[bufferPos++];
 +            bits += 8;
 +          }
 +
 +          var remainingBits = bits - bpc;
 +          var value = buf >> remainingBits;
-           if (needsDecode) {
-             var compIndex = i % numComps;
-             value = decodeAndClamp(value, decodeAddends[compIndex],
-                             decodeCoefficients[compIndex], max);
-           }
-           output[i] = 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;
 +
 +      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);
++        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);
++          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 (var 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) {
 +            var opacity = 0;
 +            var imageOffset = i * numComps;
 +            for (var j = 0; j < numComps; ++j) {
 +              var color = image[imageOffset + j];
 +              var maskOffset = j * 2;
 +              if (color < mask[maskOffset] || color > mask[maskOffset + 1]) {
 +                opacity = 255;
 +                break;
 +              }
 +            }
-             buf[i] = opacity;
++            alphaBuf[i] = opacity;
 +          }
 +        } else {
 +          error('Unknown mask format.');
 +        }
++      }
++
++      if (alphaBuf) {
++        for (var i = 0, j = 3, ii = width * actualHeight; i < ii; ++i, j += 4) {
++          rgbaBuf[j] = alphaBuf[i];
++        }
 +      } else {
-         buf = new Uint8Array(width * height);
-         for (var i = 0, ii = width * height; i < ii; ++i)
-           buf[i] = 255;
-       }
-       return buf;
-     },
-     applyStencilMask: function PDFImage_applyStencilMask(buffer,
-                                                          inverseDecode) {
-       var width = this.width, height = this.height;
-       var bitStrideLength = (width + 7) >> 3;
-       var imgArray = this.getImageBytes(bitStrideLength * height);
-       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] = 0;
-           }
-           bufferPos += 4;
-           mask >>= 1;
++        // No mask.
++        for (var i = 0, j = 3, ii = width * actualHeight; i < ii; ++i, j += 4) {
++          rgbaBuf[j] = 255;
 +        }
 +      }
 +    },
-     fillRgbaBuffer: function PDFImage_fillRgbaBuffer(buffer, width, height) {
++    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 length = width * height * 4;
++      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
++          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]);
++      }
++    },
++    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);
 +
-       // 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) {
++          kind = ImageKind.RGB_24BPP;
++        }
++        if (kind && !this.smask && !this.mask && !this.needsDecode &&
++            drawWidth === originalWidth && drawHeight === originalHeight) {
++          imgData.kind = kind;
++
++          // 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;
++          }
++          return imgData;
++        }
++      }
++
++      // imgArray can be incomplete (e.g. after CCITT fax encoding).
 +      var actualHeight = 0 | (imgArray.length / rowBytes *
-                          height / originalHeight);
- 
-       var comps = this.colorSpace.createRgbBuffer(this.getComponents(imgArray),
-         0, originalWidth * originalHeight, bpc);
-       if (originalWidth != width || originalHeight != height)
-         comps = PDFImage.resize(comps, this.bpc, 3, originalWidth,
-                                 originalHeight, width, height);
-       var compsPos = 0;
-       var opacity = this.getOpacity(width, height, imgArray);
-       var opacityPos = 0;
-       var length = width * actualHeight * 4;
++                         drawHeight / originalHeight);
 +
-       for (var i = 0; i < length; i += 4) {
-         buffer[i] = comps[compsPos++];
-         buffer[i + 1] = comps[compsPos++];
-         buffer[i + 2] = comps[compsPos++];
-         buffer[i + 3] = opacity[opacityPos++];
++      var comps = this.getComponents(imgArray);
++
++      // 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);
++      }
++      this.colorSpace.fillRgb(imgData.data, originalWidth, originalHeight,
++                              drawWidth, drawHeight, actualHeight, bpc, comps,
++                              alpha01);
++      if (maybeUndoPreblend) {
++        this.undoPreblend(imgData.data, drawWidth, actualHeight);
++      }
++
++      return imgData;
 +    },
 +    fillGrayBuffer: function PDFImage_fillGrayBuffer(buffer) {
 +      var numComps = this.numComps;
 +      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;
 +      var rowBytes = (width * numComps * bpc + 7) >> 3;
 +      var imgArray = this.getImageBytes(height * rowBytes);
 +
 +      var comps = this.getComponents(imgArray);
++
++      if (bpc === 1) {
++        // inline decoding (= inversion) for 1 bpc images
++        var length = width * height;
++        if (this.needsDecode) {
++          // invert and scale to {0, 255} 
++          for (var i = 0; i < length; ++i) {
++            buffer[i] = (comps[i] - 1) & 255;
++          }
++        } else {
++          // scale to {0, 255}
++          for (var i = 0; i < length; ++i) {
++            buffer[i] = (-comps[i]) & 255;
++          }
++        }
++        return;
++      }
++
++      if (this.needsDecode) {
++        this.decodeBuffer(comps);
++      }
 +      var 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 (var 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) {
 +      this.image.reset();
 +      return this.image.getBytes(length);
 +    }
 +  };
 +  return PDFImage;
 +})();
 +
- function loadJpegStream(id, imageData, objs) {
-   var img = new Image();
-   img.onload = (function loadJpegStream_onloadClosure() {
-     objs.resolve(id, img);
-   });
-   img.src = 'data:image/jpeg;base64,' + window.btoa(imageData);
- }
- 
- 
 +
 +// The Metrics object contains glyph widths (in glyph space units).
 +// As per PDF spec, for most fonts (Type 3 being an exception) a glyph
 +// space unit corresponds to 1/1000th of text space unit.
 +var Metrics = {
 +  'Courier': 600,
 +  'Courier-Bold': 600,
 +  'Courier-BoldOblique': 600,
 +  'Courier-Oblique': 600,
 +  'Helvetica' : {
 +    'space': 278,
 +    'exclam': 278,
 +    'quotedbl': 355,
 +    'numbersign': 556,
 +    'dollar': 556,
 +    'percent': 889,
 +    'ampersand': 667,
 +    'quoteright': 222,
 +    'parenleft': 333,
 +    'parenright': 333,
 +    'asterisk': 389,
 +    'plus': 584,
 +    'comma': 278,
 +    'hyphen': 333,
 +    'period': 278,
 +    'slash': 278,
 +    'zero': 556,
 +    'one': 556,
 +    'two': 556,
 +    'three': 556,
 +    'four': 556,
 +    'five': 556,
 +    'six': 556,
 +    'seven': 556,
 +    'eight': 556,
 +    'nine': 556,
 +    'colon': 278,
 +    'semicolon': 278,
 +    'less': 584,
 +    'equal': 584,
 +    'greater': 584,
 +    'question': 556,
 +    'at': 1015,
 +    'A': 667,
 +    'B': 667,
 +    'C': 722,
 +    'D': 722,
 +    'E': 667,
 +    'F': 611,
 +    'G': 778,
 +    'H': 722,
 +    'I': 278,
 +    'J': 500,
 +    'K': 667,
 +    'L': 556,
 +    'M': 833,
 +    'N': 722,
 +    'O': 778,
 +    'P': 667,
 +    'Q': 778,
 +    'R': 722,
 +    'S': 667,
 +    'T': 611,
 +    'U': 722,
 +    'V': 667,
 +    'W': 944,
 +    'X': 667,
 +    'Y': 667,
 +    'Z': 611,
 +    'bracketleft': 278,
 +    'backslash': 278,
 +    'bracketright': 278,
 +    'asciicircum': 469,
 +    'underscore': 556,
 +    'quoteleft': 222,
 +    'a': 556,
 +    'b': 556,
 +    'c': 500,
 +    'd': 556,
 +    'e': 556,
 +    'f': 278,
 +    'g': 556,
 +    'h': 556,
 +    'i': 222,
 +    'j': 222,
 +    'k': 500,
 +    'l': 222,
 +    'm': 833,
 +    'n': 556,
 +    'o': 556,
 +    'p': 556,
 +    'q': 556,
 +    'r': 333,
 +    's': 500,
 +    't': 278,
 +    'u': 556,
 +    'v': 500,
 +    'w': 722,
 +    'x': 500,
 +    'y': 500,
 +    'z': 500,
 +    'braceleft': 334,
 +    'bar': 260,
 +    'braceright': 334,
 +    'asciitilde': 584,
 +    'exclamdown': 333,
 +    'cent': 556,
 +    'sterling': 556,
 +    'fraction': 167,
 +    'yen': 556,
 +    'florin': 556,
 +    'section': 556,
 +    'currency': 556,
 +    'quotesingle': 191,
 +    'quotedblleft': 333,
 +    'guillemotleft': 556,
 +    'guilsinglleft': 333,
 +    'guilsinglright': 333,
 +    'fi': 500,
 +    'fl': 500,
 +    'endash': 556,
 +    'dagger': 556,
 +    'daggerdbl': 556,
 +    'periodcentered': 278,
 +    'paragraph': 537,
 +    'bullet': 350,
 +    'quotesinglbase': 222,
 +    'quotedblbase': 333,
 +    'quotedblright': 333,
 +    'guillemotright': 556,
 +    'ellipsis': 1000,
 +    'perthousand': 1000,
 +    'questiondown': 611,
 +    'grave': 333,
 +    'acute': 333,
 +    'circumflex': 333,
 +    'tilde': 333,
 +    'macron': 333,
 +    'breve': 333,
 +    'dotaccent': 333,
 +    'dieresis': 333,
 +    'ring': 333,
 +    'cedilla': 333,
 +    'hungarumlaut': 333,
 +    'ogonek': 333,
 +    'caron': 333,
 +    'emdash': 1000,
 +    'AE': 1000,
 +    'ordfeminine': 370,
 +    'Lslash': 556,
 +    'Oslash': 778,
 +    'OE': 1000,
 +    'ordmasculine': 365,
 +    'ae': 889,
 +    'dotlessi': 278,
 +    'lslash': 222,
 +    'oslash': 611,
 +    'oe': 944,
 +    'germandbls': 611,
 +    'Idieresis': 278,
 +    'eacute': 556,
 +    'abreve': 556,
 +    'uhungarumlaut': 556,
 +    'ecaron': 556,
 +    'Ydieresis': 667,
 +    'divide': 584,
 +    'Yacute': 667,
 +    'Acircumflex': 667,
 +    'aacute': 556,
 +    'Ucircumflex': 722,
 +    'yacute': 500,
 +    'scommaaccent': 500,
 +    'ecircumflex': 556,
 +    'Uring': 722,
 +    'Udieresis': 722,
 +    'aogonek': 556,
 +    'Uacute': 722,
 +    'uogonek': 556,
 +    'Edieresis': 667,
 +    'Dcroat': 722,
 +    'commaaccent': 250,
 +    'copyright': 737,
 +    'Emacron': 667,
 +    'ccaron': 500,
 +    'aring': 556,
 +    'Ncommaaccent': 722,
 +    'lacute': 222,
 +    'agrave': 556,
 +    'Tcommaaccent': 611,
 +    'Cacute': 722,
 +    'atilde': 556,
 +    'Edotaccent': 667,
 +    'scaron': 500,
 +    'scedilla': 500,
 +    'iacute': 278,
 +    'lozenge': 471,
 +    'Rcaron': 722,
 +    'Gcommaaccent': 778,
 +    'ucircumflex': 556,
 +    'acircumflex': 556,
 +    'Amacron': 667,
 +    'rcaron': 333,
 +    'ccedilla': 500,
 +    'Zdotaccent': 611,
 +    'Thorn': 667,
 +    'Omacron': 778,
 +    'Racute': 722,
 +    'Sacute': 667,
 +    'dcaron': 643,
 +    'Umacron': 722,
 +    'uring': 556,
 +    'threesuperior': 333,
 +    'Ograve': 778,
 +    'Agrave': 667,
 +    'Abreve': 667,
 +    'multiply': 584,
 +    'uacute': 556,
 +    'Tcaron': 611,
 +    'partialdiff': 476,
 +    'ydieresis': 500,
 +    'Nacute': 722,
 +    'icircumflex': 278,
 +    'Ecircumflex': 667,
 +    'adieresis': 556,
 +    'edieresis': 556,
 +    'cacute': 500,
 +    'nacute': 556,
 +    'umacron': 556,
 +    'Ncaron': 722,
 +    'Iacute': 278,
 +    'plusminus': 584,
 +    'brokenbar': 260,
 +    'registered': 737,
 +    'Gbreve': 778,
 +    'Idotaccent': 278,
 +    'summation': 600,
 +    'Egrave': 667,
 +    'racute': 333,
 +    'omacron': 556,
 +    'Zacute': 611,
 +    'Zcaron': 611,
 +    'greaterequal': 549,
 +    'Eth': 722,
 +    'Ccedilla': 722,
 +    'lcommaaccent': 222,
 +    'tcaron': 317,
 +    'eogonek': 556,
 +    'Uogonek': 722,
 +    'Aacute': 667,
 +    'Adieresis': 667,
 +    'egrave': 556,
 +    'zacute': 500,
 +    'iogonek': 222,
 +    'Oacute': 778,
 +    'oacute': 556,
 +    'amacron': 556,
 +    'sacute': 500,
 +    'idieresis': 278,
 +    'Ocircumflex': 778,
 +    'Ugrave': 722,
 +    'Delta': 612,
 +    'thorn': 556,
 +    'twosuperior': 333,
 +    'Odieresis': 778,
 +    'mu': 556,
 +    'igrave': 278,
 +    'ohungarumlaut': 556,
 +    'Eogonek': 667,
 +    'dcroat': 556,
 +    'threequarters': 834,
 +    'Scedilla': 667,
 +    'lcaron': 299,
 +    'Kcommaaccent': 667,
 +    'Lacute': 556,
 +    'trademark': 1000,
 +    'edotaccent': 556,
 +    'Igrave': 278,
 +    'Imacron': 278,
 +    'Lcaron': 556,
 +    'onehalf': 834,
 +    'lessequal': 549,
 +    'ocircumflex': 556,
 +    'ntilde': 556,
 +    'Uhungarumlaut': 722,
 +    'Eacute': 667,
 +    'emacron': 556,
 +    'gbreve': 556,
 +    'onequarter': 834,
 +    'Scaron': 667,
 +    'Scommaaccent': 667,
 +    'Ohungarumlaut': 778,
 +    'degree': 400,
 +    'ograve': 556,
 +    'Ccaron': 722,
 +    'ugrave': 556,
 +    'radical': 453,
 +    'Dcaron': 722,
 +    'rcommaaccent': 333,
 +    'Ntilde': 722,
 +    'otilde': 556,
 +    'Rcommaaccent': 722,
 +    'Lcommaaccent': 556,
 +    'Atilde': 667,
 +    'Aogonek': 667,
 +    'Aring': 667,
 +    'Otilde': 778,
 +    'zdotaccent': 500,
 +    'Ecaron': 667,
 +    'Iogonek': 278,
 +    'kcommaaccent': 500,
 +    'minus': 584,
 +    'Icircumflex': 278,
 +    'ncaron': 556,
 +    'tcommaaccent': 278,
 +    'logicalnot': 584,
 +    'odieresis': 556,
 +    'udieresis': 556,
 +    'notequal': 549,
 +    'gcommaaccent': 556,
 +    'eth': 556,
 +    'zcaron': 500,
 +    'ncommaaccent': 556,
 +    'onesuperior': 333,
 +    'imacron': 278,
 +    'Euro': 556
 +  },
 +  'Helvetica-Bold': {
 +    'space': 278,
 +    'exclam': 333,
 +    'quotedbl': 474,
 +    'numbersign': 556,
 +    'dollar': 556,
 +    'percent': 889,
 +    'ampersand': 722,
 +    'quoteright': 278,
 +    'parenleft': 333,
 +    'parenright': 333,
 +    'asterisk': 389,
 +    'plus': 584,
 +    'comma': 278,
 +    'hyphen': 333,
 +    'period': 278,
 +    'slash': 278,
 +    'zero': 556,
 +    'one': 556,
 +    'two': 556,
 +    'three': 556,
 +    'four': 556,
 +    'five': 556,
 +    'six': 556,
 +    'seven': 556,
 +    'eight': 556,
 +    'nine': 556,
 +    'colon': 333,
 +    'semicolon': 333,
 +    'less': 584,
 +    'equal': 584,
 +    'greater': 584,
 +    'question': 611,
 +    'at': 975,
 +    'A': 722,
 +    'B': 722,
 +    'C': 722,
 +    'D': 722,
 +    'E': 667,
 +    'F': 611,
 +    'G': 778,
 +    'H': 722,
 +    'I': 278,
 +    'J': 556,
 +    'K': 722,
 +    'L': 611,
 +    'M': 833,
 +    'N': 722,
 +    'O': 778,
 +    'P': 667,
 +    'Q': 778,
 +    'R': 722,
 +    'S': 667,
 +    'T': 611,
 +    'U': 722,
 +    'V': 667,
 +    'W': 944,
 +    'X': 667,
 +    'Y': 667,
 +    'Z': 611,
 +    'bracketleft': 333,
 +    'backslash': 278,
 +    'bracketright': 333,
 +    'asciicircum': 584,
 +    'underscore': 556,
 +    'quoteleft': 278,
 +    'a': 556,
 +    'b': 611,
 +    'c': 556,
 +    'd': 611,
 +    'e': 556,
 +    'f': 333,
 +    'g': 611,
 +    'h': 611,
 +    'i': 278,
 +    'j': 278,
 +    'k': 556,
 +    'l': 278,
 +    'm': 889,
 +    'n': 611,
 +    'o': 611,
 +    'p': 611,
 +    'q': 611,
 +    'r': 389,
 +    's': 556,
 +    't': 333,
 +    'u': 611,
 +    'v': 556,
 +    'w': 778,
 +    'x': 556,
 +    'y': 556,
 +    'z': 500,
 +    'braceleft': 389,
 +    'bar': 280,
 +    'braceright': 389,
 +    'asciitilde': 584,
 +    'exclamdown': 333,
 +    'cent': 556,
 +    'sterling': 556,
 +    'fraction': 167,
 +    'yen': 556,
 +    'florin': 556,
 +    'section': 556,
 +    'currency': 556,
 +    'quotesingle': 238,
 +    'quotedblleft': 500,
 +    'guillemotleft': 556,
 +    'guilsinglleft': 333,
 +    'guilsinglright': 333,
 +    'fi': 611,
 +    'fl': 611,
 +    'endash': 556,
 +    'dagger': 556,
 +    'daggerdbl': 556,
 +    'periodcentered': 278,
 +    'paragraph': 556,
 +    'bullet': 350,
 +    'quotesinglbase': 278,
 +    'quotedblbase': 500,
 +    'quotedblright': 500,
 +    'guillemotright': 556,
 +    'ellipsis': 1000,
 +    'perthousand': 1000,
 +    'questiondown': 611,
 +    'grave': 333,
 +    'acute': 333,
 +    'circumflex': 333,
 +    'tilde': 333,
 +    'macron': 333,
 +    'breve': 333,
 +    'dotaccent': 333,
 +    'dieresis': 333,
 +    'ring': 333,
 +    'cedilla': 333,
 +    'hungarumlaut': 333,
 +    'ogonek': 333,
 +    'caron': 333,
 +    'emdash': 1000,
 +    'AE': 1000,
 +    'ordfeminine': 370,
 +    'Lslash': 611,
 +    'Oslash': 778,
 +    'OE': 1000,
 +    'ordmasculine': 365,
 +    'ae': 889,
 +    'dotlessi': 278,
 +    'lslash': 278,
 +    'oslash': 611,
 +    'oe': 944,
 +    'germandbls': 611,
 +    'Idieresis': 278,
 +    'eacute': 556,
 +    'abreve': 556,
 +    'uhungarumlaut': 611,
 +    'ecaron': 556,
 +    'Ydieresis': 667,
 +    'divide': 584,
 +    'Yacute': 667,
 +    'Acircumflex': 722,
 +    'aacute': 556,
 +    'Ucircumflex': 722,
 +    'yacute': 556,
 +    'scommaaccent': 556,
 +    'ecircumflex': 556,
 +    'Uring': 722,
 +    'Udieresis': 722,
 +    'aogonek': 556,
 +    'Uacute': 722,
 +    'uogonek': 611,
 +    'Edieresis': 667,
 +    'Dcroat': 722,
 +    'commaaccent': 250,
 +    'copyright': 737,
 +    'Emacron': 667,
 +    'ccaron': 556,
 +    'aring': 556,
 +    'Ncommaaccent': 722,
 +    'lacute': 278,
 +    'agrave': 556,
 +    'Tcommaaccent': 611,
 +    'Cacute': 722,
 +    'atilde': 556,
 +    'Edotaccent': 667,
 +    'scaron': 556,
 +    'scedilla': 556,
 +    'iacute': 278,
 +    'lozenge': 494,
 +    'Rcaron': 722,
 +    'Gcommaaccent': 778,
 +    'ucircumflex': 611,
 +    'acircumflex': 556,
 +    'Amacron': 722,
 +    'rcaron': 389,
 +    'ccedilla': 556,
 +    'Zdotaccent': 611,
 +    'Thorn': 667,
 +    'Omacron': 778,
 +    'Racute': 722,
 +    'Sacute': 667,
 +    'dcaron': 743,
 +    'Umacron': 722,
 +    'uring': 611,
 +    'threesuperior': 333,
 +    'Ograve': 778,
 +    'Agrave': 722,
 +    'Abreve': 722,
 +    'multiply': 584,
 +    'uacute': 611,
 +    'Tcaron': 611,
 +    'partialdiff': 494,
 +    'ydieresis': 556,
 +    'Nacute': 722,
 +    'icircumflex': 278,
 +    'Ecircumflex': 667,
 +    'adieresis': 556,
 +    'edieresis': 556,
 +    'cacute': 556,
 +    'nacute': 611,
 +    'umacron': 611,
 +    'Ncaron': 722,
 +    'Iacute': 278,
 +    'plusminus': 584,
 +    'brokenbar': 280,
 +    'registered': 737,
 +    'Gbreve': 778,
 +    'Idotaccent': 278,
 +    'summation': 600,
 +    'Egrave': 667,
 +    'racute': 389,
 +    'omacron': 611,
 +    'Zacute': 611,
 +    'Zcaron': 611,
 +    'greaterequal': 549,
 +    'Eth': 722,
 +    'Ccedilla': 722,
 +    'lcommaaccent': 278,
 +    'tcaron': 389,
 +    'eogonek': 556,
 +    'Uogonek': 722,
 +    'Aacute': 722,
 +    'Adieresis': 722,
 +    'egrave': 556,
 +    'zacute': 500,
 +    'iogonek': 278,
 +    'Oacute': 778,
 +    'oacute': 611,
 +    'amacron': 556,
 +    'sacute': 556,
 +    'idieresis': 278,
 +    'Ocircumflex': 778,
 +    'Ugrave': 722,
 +    'Delta': 612,
 +    'thorn': 611,
 +    'twosuperior': 333,
 +    'Odieresis': 778,
 +    'mu': 611,
 +    'igrave': 278,
 +    'ohungarumlaut': 611,
 +    'Eogonek': 667,
 +    'dcroat': 611,
 +    'threequarters': 834,
 +    'Scedilla': 667,
 +    'lcaron': 400,
 +    'Kcommaaccent': 722,
 +    'Lacute': 611,
 +    'trademark': 1000,
 +    'edotaccent': 556,
 +    'Igrave': 278,
 +    'Imacron': 278,
 +    'Lcaron': 611,
 +    'onehalf': 834,
 +    'lessequal': 549,
 +    'ocircumflex': 611,
 +    'ntilde': 611,
 +    'Uhungarumlaut': 722,
 +    'Eacute': 667,
 +    'emacron': 556,
 +    'gbreve': 611,
 +    'onequarter': 834,
 +    'Scaron': 667,
 +    'Scommaaccent': 667,
 +    'Ohungarumlaut': 778,
 +    'degree': 400,
 +    'ograve': 611,
 +    'Ccaron': 722,
 +    'ugrave': 611,
 +    'radical': 549,
 +    'Dcaron': 722,
 +    'rcommaaccent': 389,
 +    'Ntilde': 722,
 +    'otilde': 611,
 +    'Rcommaaccent': 722,
 +    'Lcommaaccent': 611,
 +    'Atilde': 722,
 +    'Aogonek': 722,
 +    'Aring': 722,
 +    'Otilde': 778,
 +    'zdotaccent': 500,
 +    'Ecaron': 667,
 +    'Iogonek': 278,
 +    'kcommaaccent': 556,
 +    'minus': 584,
 +    'Icircumflex': 278,
 +    'ncaron': 611,
 +    'tcommaaccent': 333,
 +    'logicalnot': 584,
 +    'odieresis': 611,
 +    'udieresis': 611,
 +    'notequal': 549,
 +    'gcommaaccent': 611,
 +    'eth': 611,
 +    'zcaron': 500,
 +    'ncommaaccent': 611,
 +    'onesuperior': 333,
 +    'imacron': 278,
 +    'Euro': 556
 +  },
 +  'Helvetica-BoldOblique': {
 +    'space': 278,
 +    'exclam': 333,
 +    'quotedbl': 474,
 +    'numbersign': 556,
 +    'dollar': 556,
 +    'percent': 889,
 +    'ampersand': 722,
 +    'quoteright': 278,
 +    'parenleft': 333,
 +    'parenright': 333,
 +    'asterisk': 389,
 +    'plus': 584,
 +    'comma': 278,
 +    'hyphen': 333,
 +    'period': 278,
 +    'slash': 278,
 +    'zero': 556,
 +    'one': 556,
 +    'two': 556,
 +    'three': 556,
 +    'four': 556,
 +    'five': 556,
 +    'six': 556,
 +    'seven': 556,
 +    'eight': 556,
 +    'nine': 556,
 +    'colon': 333,
 +    'semicolon': 333,
 +    'less': 584,
 +    'equal': 584,
 +    'greater': 584,
 +    'question': 611,
 +    'at': 975,
 +    'A': 722,
 +    'B': 722,
 +    'C': 722,
 +    'D': 722,
 +    'E': 667,
 +    'F': 611,
 +    'G': 778,
 +    'H': 722,
 +    'I': 278,
 +    'J': 556,
 +    'K': 722,
 +    'L': 611,
 +    'M': 833,
 +    'N': 722,
 +    'O': 778,
 +    'P': 667,
 +    'Q': 778,
 +    'R': 722,
 +    'S': 667,
 +    'T': 611,
 +    'U': 722,
 +    'V': 667,
 +    'W': 944,
 +    'X': 667,
 +    'Y': 667,
 +    'Z': 611,
 +    'bracketleft': 333,
 +    'backslash': 278,
 +    'bracketright': 333,
 +    'asciicircum': 584,
 +    'underscore': 556,
 +    'quoteleft': 278,
 +    'a': 556,
 +    'b': 611,
 +    'c': 556,
 +    'd': 611,
 +    'e': 556,
 +    'f': 333,
 +    'g': 611,
 +    'h': 611,
 +    'i': 278,
 +    'j': 278,
 +    'k': 556,
 +    'l': 278,
 +    'm': 889,
 +    'n': 611,
 +    'o': 611,
 +    'p': 611,
 +    'q': 611,
 +    'r': 389,
 +    's': 556,
 +    't': 333,
 +    'u': 611,
 +    'v': 556,
 +    'w': 778,
 +    'x': 556,
 +    'y': 556,
 +    'z': 500,
 +    'braceleft': 389,
 +    'bar': 280,
 +    'braceright': 389,
 +    'asciitilde': 584,
 +    'exclamdown': 333,
 +    'cent': 556,
 +    'sterling': 556,
 +    'fraction': 167,
 +    'yen': 556,
 +    'florin': 556,
 +    'section': 556,
 +    'currency': 556,
 +    'quotesingle': 238,
 +    'quotedblleft': 500,
 +    'guillemotleft': 556,
 +    'guilsinglleft': 333,
 +    'guilsinglright': 333,
 +    'fi': 611,
 +    'fl': 611,
 +    'endash': 556,
 +    'dagger': 556,
 +    'daggerdbl': 556,
 +    'periodcentered': 278,
 +    'paragraph': 556,
 +    'bullet': 350,
 +    'quotesinglbase': 278,
 +    'quotedblbase': 500,
 +    'quotedblright': 500,
 +    'guillemotright': 556,
 +    'ellipsis': 1000,
 +    'perthousand': 1000,
 +    'questiondown': 611,
 +    'grave': 333,
 +    'acute': 333,
 +    'circumflex': 333,
 +    'tilde': 333,
 +    'macron': 333,
 +    'breve': 333,
 +    'dotaccent': 333,
 +    'dieresis': 333,
 +    'ring': 333,
 +    'cedilla': 333,
 +    'hungarumlaut': 333,
 +    'ogonek': 333,
 +    'caron': 333,
 +    'emdash': 1000,
 +    'AE': 1000,
 +    'ordfeminine': 370,
 +    'Lslash': 611,
 +    'Oslash': 778,
 +    'OE': 1000,
 +    'ordmasculine': 365,
 +    'ae': 889,
 +    'dotlessi': 278,
 +    'lslash': 278,
 +    'oslash': 611,
 +    'oe': 944,
 +    'germandbls': 611,
 +    'Idieresis': 278,
 +    'eacute': 556,
 +    'abreve': 556,
 +    'uhungarumlaut': 611,
 +    'ecaron': 556,
 +    'Ydieresis': 667,
 +    'divide': 584,
 +    'Yacute': 667,
 +    'Acircumflex': 722,
 +    'aacute': 556,
 +    'Ucircumflex': 722,
 +    'yacute': 556,
 +    'scommaaccent': 556,
 +    'ecircumflex': 556,
 +    'Uring': 722,
 +    'Udieresis': 722,
 +    'aogonek': 556,
 +    'Uacute': 722,
 +    'uogonek': 611,
 +    'Edieresis': 667,
 +    'Dcroat': 722,
 +    'commaaccent': 250,
 +    'copyright': 737,
 +    'Emacron': 667,
 +    'ccaron': 556,
 +    'aring': 556,
 +    'Ncommaaccent': 722,
 +    'lacute': 278,
 +    'agrave': 556,
 +    'Tcommaaccent': 611,
 +    'Cacute': 722,
 +    'atilde': 556,
 +    'Edotaccent': 667,
 +    'scaron': 556,
 +    'scedilla': 556,
 +    'iacute': 278,
 +    'lozenge': 494,
 +    'Rcaron': 722,
 +    'Gcommaaccent': 778,
 +    'ucircumflex': 611,
 +    'acircumflex': 556,
 +    'Amacron': 722,
 +    'rcaron': 389,
 +    'ccedilla': 556,
 +    'Zdotaccent': 611,
 +    'Thorn': 667,
 +    'Omacron': 778,
 +    'Racute': 722,
 +    'Sacute': 667,
 +    'dcaron': 743,
 +    'Umacron': 722,
 +    'uring': 611,
 +    'threesuperior': 333,
 +    'Ograve': 778,
 +    'Agrave': 722,
 +    'Abreve': 722,
 +    'multiply': 584,
 +    'uacute': 611,
 +    'Tcaron': 611,
 +    'partialdiff': 494,
 +    'ydieresis': 556,
 +    'Nacute': 722,
 +    'icircumflex': 278,
 +    'Ecircumflex': 667,
 +    'adieresis': 556,
 +    'edieresis': 556,
 +    'cacute': 556,
 +    'nacute': 611,
 +    'umacron': 611,
 +    'Ncaron': 722,
 +    'Iacute': 278,
 +    'plusminus': 584,
 +    'brokenbar': 280,
 +    'registered': 737,
 +    'Gbreve': 778,
 +    'Idotaccent': 278,
 +    'summation': 600,
 +    'Egrave': 667,
 +    'racute': 389,
 +    'omacron': 611,
 +    'Zacute': 611,
 +    'Zcaron': 611,
 +    'greaterequal': 549,
 +    'Eth': 722,
 +    'Ccedilla': 722,
 +    'lcommaaccent': 278,
 +    'tcaron': 389,
 +    'eogonek': 556,
 +    'Uogonek': 722,
 +    'Aacute': 722,
 +    'Adieresis': 722,
 +    'egrave': 556,
 +    'zacute': 500,
 +    'iogonek': 278,
 +    'Oacute': 778,
 +    'oacute': 611,
 +    'amacron': 556,
 +    'sacute': 556,
 +    'idieresis': 278,
 +    'Ocircumflex': 778,
 +    'Ugrave': 722,
 +    'Delta': 612,
 +    'thorn': 611,
 +    'twosuperior': 333,
 +    'Odieresis': 778,
 +    'mu': 611,
 +    'igrave': 278,
 +    'ohungarumlaut': 611,
 +    'Eogonek': 667,
 +    'dcroat': 611,
 +    'threequarters': 834,
 +    'Scedilla': 667,
 +    'lcaron': 400,
 +    'Kcommaaccent': 722,
 +    'Lacute': 611,
 +    'trademark': 1000,
 +    'edotaccent': 556,
 +    'Igrave': 278,
 +    'Imacron': 278,
 +    'Lcaron': 611,
 +    'onehalf': 834,
 +    'lessequal': 549,
 +    'ocircumflex': 611,
 +    'ntilde': 611,
 +    'Uhungarumlaut': 722,
 +    'Eacute': 667,
 +    'emacron': 556,
 +    'gbreve': 611,
 +    'onequarter': 834,
 +    'Scaron': 667,
 +    'Scommaaccent': 667,
 +    'Ohungarumlaut': 778,
 +    'degree': 400,
 +    'ograve': 611,
 +    'Ccaron': 722,
 +    'ugrave': 611,
 +    'radical': 549,
 +    'Dcaron': 722,
 +    'rcommaaccent': 389,
 +    'Ntilde': 722,
 +    'otilde': 611,
 +    'Rcommaaccent': 722,
 +    'Lcommaaccent': 611,
 +    'Atilde': 722,
 +    'Aogonek': 722,
 +    'Aring': 722,
 +    'Otilde': 778,
 +    'zdotaccent': 500,
 +    'Ecaron': 667,
 +    'Iogonek': 278,
 +    'kcommaaccent': 556,
 +    'minus': 584,
 +    'Icircumflex': 278,
 +    'ncaron': 611,
 +    'tcommaaccent': 333,
 +    'logicalnot': 584,
 +    'odieresis': 611,
 +    'udieresis': 611,
 +    'notequal': 549,
 +    'gcommaaccent': 611,
 +    'eth': 611,
 +    'zcaron': 500,
 +    'ncommaaccent': 611,
 +    'onesuperior': 333,
 +    'imacron': 278,
 +    'Euro': 556
 +  },
 +  'Helvetica-Oblique' : {
 +    'space': 278,
 +    'exclam': 278,
 +    'quotedbl': 355,
 +    'numbersign': 556,
 +    'dollar': 556,
 +    'percent': 889,
 +    'ampersand': 667,
 +    'quoteright': 222,
 +    'parenleft': 333,
 +    'parenright': 333,
 +    'asterisk': 389,
 +    'plus': 584,
 +    'comma': 278,
 +    'hyphen': 333,
 +    'period': 278,
 +    'slash': 278,
 +    'zero': 556,
 +    'one': 556,
 +    'two': 556,
 +    'three': 556,
 +    'four': 556,
 +    'five': 556,
 +    'six': 556,
 +    'seven': 556,
 +    'eight': 556,
 +    'nine': 556,
 +    'colon': 278,
 +    'semicolon': 278,
 +    'less': 584,
 +    'equal': 584,
 +    'greater': 584,
 +    'question': 556,
 +    'at': 1015,
 +    'A': 667,
 +    'B': 667,
 +    'C': 722,
 +    'D': 722,
 +    'E': 667,
 +    'F': 611,
 +    'G': 778,
 +    'H': 722,
 +    'I': 278,
 +    'J': 500,
 +    'K': 667,
 +    'L': 556,
 +    'M': 833,
 +    'N': 722,
 +    'O': 778,
 +    'P': 667,
 +    'Q': 778,
 +    'R': 722,
 +    'S': 667,
 +    'T': 611,
 +    'U': 722,
 +    'V': 667,
 +    'W': 944,
 +    'X': 667,
 +    'Y': 667,
 +    'Z': 611,
 +    'bracketleft': 278,
 +    'backslash': 278,
 +    'bracketright': 278,
 +    'asciicircum': 469,
 +    'underscore': 556,
 +    'quoteleft': 222,
 +    'a': 556,
 +    'b': 556,
 +    'c': 500,
 +    'd': 556,
 +    'e': 556,
 +    'f': 278,
 +    'g': 556,
 +    'h': 556,
 +    'i': 222,
 +    'j': 222,
 +    'k': 500,
 +    'l': 222,
 +    'm': 833,
 +    'n': 556,
 +    'o': 556,
 +    'p': 556,
 +    'q': 556,
 +    'r': 333,
 +    's': 500,
 +    't': 278,
 +    'u': 556,
 +    'v': 500,
 +    'w': 722,
 +    'x': 500,
 +    'y': 500,
 +    'z': 500,
 +    'braceleft': 334,
 +    'bar': 260,
 +    'braceright': 334,
 +    'asciitilde': 584,
 +    'exclamdown': 333,
 +    'cent': 556,
 +    'sterling': 556,
 +    'fraction': 167,
 +    'yen': 556,
 +    'florin': 556,
 +    'section': 556,
 +    'currency': 556,
 +    'quotesingle': 191,
 +    'quotedblleft': 333,
 +    'guillemotleft': 556,
 +    'guilsinglleft': 333,
 +    'guilsinglright': 333,
 +    'fi': 500,
 +    'fl': 500,
 +    'endash': 556,
 +    'dagger': 556,
 +    'daggerdbl': 556,
 +    'periodcentered': 278,
 +    'paragraph': 537,
 +    'bullet': 350,
 +    'quotesinglbase': 222,
 +    'quotedblbase': 333,
 +    'quotedblright': 333,
 +    'guillemotright': 556,
 +    'ellipsis': 1000,
 +    'perthousand': 1000,
 +    'questiondown': 611,
 +    'grave': 333,
 +    'acute': 333,
 +    'circumflex': 333,
 +    'tilde': 333,
 +    'macron': 333,
 +    'breve': 333,
 +    'dotaccent': 333,
 +    'dieresis': 333,
 +    'ring': 333,
 +    'cedilla': 333,
 +    'hungarumlaut': 333,
 +    'ogonek': 333,
 +    'caron': 333,
 +    'emdash': 1000,
 +    'AE': 1000,
 +    'ordfeminine': 370,
 +    'Lslash': 556,
 +    'Oslash': 778,
 +    'OE': 1000,
 +    'ordmasculine': 365,
 +    'ae': 889,
 +    'dotlessi': 278,
 +    'lslash': 222,
 +    'oslash': 611,
 +    'oe': 944,
 +    'germandbls': 611,
 +    'Idieresis': 278,
 +    'eacute': 556,
 +    'abreve': 556,
 +    'uhungarumlaut': 556,
 +    'ecaron': 556,
 +    'Ydieresis': 667,
 +    'divide': 584,
 +    'Yacute': 667,
 +    'Acircumflex': 667,
 +    'aacute': 556,
 +    'Ucircumflex': 722,
 +    'yacute': 500,
 +    'scommaaccent': 500,
 +    'ecircumflex': 556,
 +    'Uring': 722,
 +    'Udieresis': 722,
 +    'aogonek': 556,
 +    'Uacute': 722,
 +    'uogonek': 556,
 +    'Edieresis': 667,
 +    'Dcroat': 722,
 +    'commaaccent': 250,
 +    'copyright': 737,
 +    'Emacron': 667,
 +    'ccaron': 500,
 +    'aring': 556,
 +    'Ncommaaccent': 722,
 +    'lacute': 222,
 +    'agrave': 556,
 +    'Tcommaaccent': 611,
 +    'Cacute': 722,
 +    'atilde': 556,
 +    'Edotaccent': 667,
 +    'scaron': 500,
 +    'scedilla': 500,
 +    'iacute': 278,
 +    'lozenge': 471,
 +    'Rcaron': 722,
 +    'Gcommaaccent': 778,
 +    'ucircumflex': 556,
 +    'acircumflex': 556,
 +    'Amacron': 667,
 +    'rcaron': 333,
 +    'ccedilla': 500,
 +    'Zdotaccent': 611,
 +    'Thorn': 667,
 +    'Omacron': 778,
 +    'Racute': 722,
 +    'Sacute': 667,
 +    'dcaron': 643,
 +    'Umacron': 722,
 +    'uring': 556,
 +    'threesuperior': 333,
 +    'Ograve': 778,
 +    'Agrave': 667,
 +    'Abreve': 667,
 +    'multiply': 584,
 +    'uacute': 556,
 +    'Tcaron': 611,
 +    'partialdiff': 476,
 +    'ydieresis': 500,
 +    'Nacute': 722,
 +    'icircumflex': 278,
 +    'Ecircumflex': 667,
 +    'adieresis': 556,
 +    'edieresis': 556,
 +    'cacute': 500,
 +    'nacute': 556,
 +    'umacron': 556,
 +    'Ncaron': 722,
 +    'Iacute': 278,
 +    'plusminus': 584,
 +    'brokenbar': 260,
 +    'registered': 737,
 +    'Gbreve': 778,
 +    'Idotaccent': 278,
 +    'summation': 600,
 +    'Egrave': 667,
 +    'racute': 333,
 +    'omacron': 556,
 +    'Zacute': 611,
 +    'Zcaron': 611,
 +    'greaterequal': 549,
 +    'Eth': 722,
 +    'Ccedilla': 722,
 +    'lcommaaccent': 222,
 +    'tcaron': 317,
 +    'eogonek': 556,
 +    'Uogonek': 722,
 +    'Aacute': 667,
 +    'Adieresis': 667,
 +    'egrave': 556,
 +    'zacute': 500,
 +    'iogonek': 222,
 +    'Oacute': 778,
 +    'oacute': 556,
 +    'amacron': 556,
 +    'sacute': 500,
 +    'idieresis': 278,
 +    'Ocircumflex': 778,
 +    'Ugrave': 722,
 +    'Delta': 612,
 +    'thorn': 556,
 +    'twosuperior': 333,
 +    'Odieresis': 778,
 +    'mu': 556,
 +    'igrave': 278,
 +    'ohungarumlaut': 556,
 +    'Eogonek': 667,
 +    'dcroat': 556,
 +    'threequarters': 834,
 +    'Scedilla': 667,
 +    'lcaron': 299,
 +    'Kcommaaccent': 667,
 +    'Lacute': 556,
 +    'trademark': 1000,
 +    'edotaccent': 556,
 +    'Igrave': 278,
 +    'Imacron': 278,
 +    'Lcaron': 556,
 +    'onehalf': 834,
 +    'lessequal': 549,
 +    'ocircumflex': 556,
 +    'ntilde': 556,
 +    'Uhungarumlaut': 722,
 +    'Eacute': 667,
 +    'emacron': 556,
 +    'gbreve': 556,
 +    'onequarter': 834,
 +    'Scaron': 667,
 +    'Scommaaccent': 667,
 +    'Ohungarumlaut': 778,
 +    'degree': 400,
 +    'ograve': 556,
 +    'Ccaron': 722,
 +    'ugrave': 556,
 +    'radical': 453,
 +    'Dcaron': 722,
 +    'rcommaaccent': 333,
 +    'Ntilde': 722,
 +    'otilde': 556,
 +    'Rcommaaccent': 722,
 +    'Lcommaaccent': 556,
 +    'Atilde': 667,
 +    'Aogonek': 667,
 +    'Aring': 667,
 +    'Otilde': 778,
 +    'zdotaccent': 500,
 +    'Ecaron': 667,
 +    'Iogonek': 278,
 +    'kcommaaccent': 500,
 +    'minus': 584,
 +    'Icircumflex': 278,
 +    'ncaron': 556,
 +    'tcommaaccent': 278,
 +    'logicalnot': 584,
 +    'odieresis': 556,
 +    'udieresis': 556,
 +    'notequal': 549,
 +    'gcommaaccent': 556,
 +    'eth': 556,
 +    'zcaron': 500,
 +    'ncommaaccent': 556,
 +    'onesuperior': 333,
 +    'imacron': 278,
 +    'Euro': 556
 +  },
 +  'Symbol': {
 +    'space': 250,
 +    'exclam': 333,
 +    'universal': 713,
 +    'numbersign': 500,
 +    'existential': 549,
 +    'percent': 833,
 +    'ampersand': 778,
 +    'suchthat': 439,
 +    'parenleft': 333,
 +    'parenright': 333,
 +    'asteriskmath': 500,
 +    'plus': 549,
 +    'comma': 250,
 +    'minus': 549,
 +    'period': 250,
 +    'slash': 278,
 +    'zero': 500,
 +    'one': 500,
 +    'two': 500,
 +    'three': 500,
 +    'four': 500,
 +    'five': 500,
 +    'six': 500,
 +    'seven': 500,
 +    'eight': 500,
 +    'nine': 500,
 +    'colon': 278,
 +    'semicolon': 278,
 +    'less': 549,
 +    'equal': 549,
 +    'greater': 549,
 +    'question': 444,
 +    'congruent': 549,
 +    'Alpha': 722,
 +    'Beta': 667,
 +    'Chi': 722,
 +    'Delta': 612,
 +    'Epsilon': 611,
 +    'Phi': 763,
 +    'Gamma': 603,
 +    'Eta': 722,
 +    'Iota': 333,
 +    'theta1': 631,
 +    'Kappa': 722,
 +    'Lambda': 686,
 +    'Mu': 889,
 +    'Nu': 722,
 +    'Omicron': 722,
 +    'Pi': 768,
 +    'Theta': 741,
 +    'Rho': 556,
 +    'Sigma': 592,
 +    'Tau': 611,
 +    'Upsilon': 690,
 +    'sigma1': 439,
 +    'Omega': 768,
 +    'Xi': 645,
 +    'Psi': 795,
 +    'Zeta': 611,
 +    'bracketleft': 333,
 +    'therefore': 863,
 +    'bracketright': 333,
 +    'perpendicular': 658,
 +    'underscore': 500,
 +    'radicalex': 500,
 +    'alpha': 631,
 +    'beta': 549,
 +    'chi': 549,
 +    'delta': 494,
 +    'epsilon': 439,
 +    'phi': 521,
 +    'gamma': 411,
 +    'eta': 603,
 +    'iota': 329,
 +    'phi1': 603,
 +    'kappa': 549,
 +    'lambda': 549,
 +    'mu': 576,
 +    'nu': 521,
 +    'omicron': 549,
 +    'pi': 549,
 +    'theta': 521,
 +    'rho': 549,
 +    'sigma': 603,
 +    'tau': 439,
 +    'upsilon': 576,
 +    'omega1': 713,
 +    'omega': 686,
 +    'xi': 493,
 +    'psi': 686,
 +    'zeta': 494,
 +    'braceleft': 480,
 +    'bar': 200,
 +    'braceright': 480,
 +    'similar': 549,
 +    'Euro': 750,
 +    'Upsilon1': 620,
 +    'minute': 247,
 +    'lessequal': 549,
 +    'fraction': 167,
 +    'infinity': 713,
 +    'florin': 500,
 +    'club': 753,
 +    'diamond': 753,
 +    'heart': 753,
 +    'spade': 753,
 +    'arrowboth': 1042,
 +    'arrowleft': 987,
 +    'arrowup': 603,
 +    'arrowright': 987,
 +    'arrowdown': 603,
 +    'degree': 400,
 +    'plusminus': 549,
 +    'second': 411,
 +    'greaterequal': 549,
 +    'multiply': 549,
 +    'proportional': 713,
 +    'partialdiff': 494,
 +    'bullet': 460,
 +    'divide': 549,
 +    'notequal': 549,
 +    'equivalence': 549,
 +    'approxequal': 549,
 +    'ellipsis': 1000,
 +    'arrowvertex': 603,
 +    'arrowhorizex': 1000,
 +    'carriagereturn': 658,
 +    'aleph': 823,
 +    'Ifraktur': 686,
 +    'Rfraktur': 795,
 +    'weierstrass': 987,
 +    'circlemultiply': 768,
 +    'circleplus': 768,
 +    'emptyset': 823,
 +    'intersection': 768,
 +    'union': 768,
 +    'propersuperset': 713,
 +    'reflexsuperset': 713,
 +    'notsubset': 713,
 +    'propersubset': 713,
 +    'reflexsubset': 713,
 +    'element': 713,
 +    'notelement': 713,
 +    'angle': 768,
 +    'gradient': 713,
 +    'registerserif': 790,
 +    'copyrightserif': 790,
 +    'trademarkserif': 890,
 +    'product': 823,
 +    'radical': 549,
 +    'dotmath': 250,
 +    'logicalnot': 713,
 +    'logicaland': 603,
 +    'logicalor': 603,
 +    'arrowdblboth': 1042,
 +    'arrowdblleft': 987,
 +    'arrowdblup': 603,
 +    'arrowdblright': 987,
 +    'arrowdbldown': 603,
 +    'lozenge': 494,
 +    'angleleft': 329,
 +    'registersans': 790,
 +    'copyrightsans': 790,
 +    'trademarksans': 786,
 +    'summation': 713,
 +    'parenlefttp': 384,
 +    'parenleftex': 384,
 +    'parenleftbt': 384,
 +    'bracketlefttp': 384,
 +    'bracketleftex': 384,
 +    'bracketleftbt': 384,
 +    'bracelefttp': 494,
 +    'braceleftmid': 494,
 +    'braceleftbt': 494,
 +    'braceex': 494,
 +    'angleright': 329,
 +    'integral': 274,
 +    'integraltp': 686,
 +    'integralex': 686,
 +    'integralbt': 686,
 +    'parenrighttp': 384,
 +    'parenrightex': 384,
 +    'parenrightbt': 384,
 +    'bracketrighttp': 384,
 +    'bracketrightex': 384,
 +    'bracketrightbt': 384,
 +    'bracerighttp': 494,
 +    'bracerightmid': 494,
 +    'bracerightbt': 494,
 +    'apple': 790
 +  },
 +  'Times-Roman': {
 +    'space': 250,
 +    'exclam': 333,
 +    'quotedbl': 408,
 +    'numbersign': 500,
 +    'dollar': 500,
 +    'percent': 833,
 +    'ampersand': 778,
 +    'quoteright': 333,
 +    'parenleft': 333,
 +    'parenright': 333,
 +    'asterisk': 500,
 +    'plus': 564,
 +    'comma': 250,
 +    'hyphen': 333,
 +    'period': 250,
 +    'slash': 278,
 +    'zero': 500,
 +    'one': 500,
 +    'two': 500,
 +    'three': 500,
 +    'four': 500,
 +    'five': 500,
 +    'six': 500,
 +    'seven': 500,
 +    'eight': 500,
 +    'nine': 500,
 +    'colon': 278,
 +    'semicolon': 278,
 +    'less': 564,
 +    'equal': 564,
 +    'greater': 564,
 +    'question': 444,
 +    'at': 921,
 +    'A': 722,
 +    'B': 667,
 +    'C': 667,
 +    'D': 722,
 +    'E': 611,
 +    'F': 556,
 +    'G': 722,
 +    'H': 722,
 +    'I': 333,
 +    'J': 389,
 +    'K': 722,
 +    'L': 611,
 +    'M': 889,
 +    'N': 722,
 +    'O': 722,
 +    'P': 556,
 +    'Q': 722,
 +    'R': 667,
 +    'S': 556,
 +    'T': 611,
 +    'U': 722,
 +    'V': 722,
 +    'W': 944,
 +    'X': 722,
 +    'Y': 722,
 +    'Z': 611,
 +    'bracketleft': 333,
 +    'backslash': 278,
 +    'bracketright': 333,
 +    'asciicircum': 469,
 +    'underscore': 500,
 +    'quoteleft': 333,
 +    'a': 444,
 +    'b': 500,
 +    'c': 444,
 +    'd': 500,
 +    'e': 444,
 +    'f': 333,
 +    'g': 500,
 +    'h': 500,
 +    'i': 278,
 +    'j': 278,
 +    'k': 500,
 +    'l': 278,
 +    'm': 778,
 +    'n': 500,
 +    'o': 500,
 +    'p': 500,
 +    'q': 500,
 +    'r': 333,
 +    's': 389,
 +    't': 278,
 +    'u': 500,
 +    'v': 500,
 +    'w': 722,
 +    'x': 500,
 +    'y': 500,
 +    'z': 444,
 +    'braceleft': 480,
 +    'bar': 200,
 +    'braceright': 480,
 +    'asciitilde': 541,
 +    'exclamdown': 333,
 +    'cent': 500,
 +    'sterling': 500,
 +    'fraction': 167,
 +    'yen': 500,
 +    'florin': 500,
 +    'section': 500,
 +    'currency': 500,
 +    'quotesingle': 180,
 +    'quotedblleft': 444,
 +    'guillemotleft': 500,
 +    'guilsinglleft': 333,
 +    'guilsinglright': 333,
 +    'fi': 556,
 +    'fl': 556,
 +    'endash': 500,
 +    'dagger': 500,
 +    'daggerdbl': 500,
 +    'periodcentered': 250,
 +    'paragraph': 453,
 +    'bullet': 350,
 +    'quotesinglbase': 333,
 +    'quotedblbase': 444,
 +    'quotedblright': 444,
 +    'guillemotright': 500,
 +    'ellipsis': 1000,
 +    'perthousand': 1000,
 +    'questiondown': 444,
 +    'grave': 333,
 +    'acute': 333,
 +    'circumflex': 333,
 +    'tilde': 333,
 +    'macron': 333,
 +    'breve': 333,
 +    'dotaccent': 333,
 +    'dieresis': 333,
 +    'ring': 333,
 +    'cedilla': 333,
 +    'hungarumlaut': 333,
 +    'ogonek': 333,
 +    'caron': 333,
 +    'emdash': 1000,
 +    'AE': 889,
 +    'ordfeminine': 276,
 +    'Lslash': 611,
 +    'Oslash': 722,
 +    'OE': 889,
 +    'ordmasculine': 310,
 +    'ae': 667,
 +    'dotlessi': 278,
 +    'lslash': 278,
 +    'oslash': 500,
 +    'oe': 722,
 +    'germandbls': 500,
 +    'Idieresis': 333,
 +    'eacute': 444,
 +    'abreve': 444,
 +    'uhungarumlaut': 500,
 +    'ecaron': 444,
 +    'Ydieresis': 722,
 +    'divide': 564,
 +    'Yacute': 722,
 +    'Acircumflex': 722,
 +    'aacute': 444,
 +    'Ucircumflex': 722,
 +    'yacute': 500,
 +    'scommaaccent': 389,
 +    'ecircumflex': 444,
 +    'Uring': 722,
 +    'Udieresis': 722,
 +    'aogonek': 444,
 +    'Uacute': 722,
 +    'uogonek': 500,
 +    'Edieresis': 611,
 +    'Dcroat': 722,
 +    'commaaccent': 250,
 +    'copyright': 760,
 +    'Emacron': 611,
 +    'ccaron': 444,
 +    'aring': 444,
 +    'Ncommaaccent': 722,
 +    'lacute': 278,
 +    'agrave': 444,
 +    'Tcommaaccent': 611,
 +    'Cacute': 667,
 +    'atilde': 444,
 +    'Edotaccent': 611,
 +    'scaron': 389,
 +    'scedilla': 389,
 +    'iacute': 278,
 +    'lozenge': 471,
 +    'Rcaron': 667,
 +    'Gcommaaccent': 722,
 +    'ucircumflex': 500,
 +    'acircumflex': 444,
 +    'Amacron': 722,
 +    'rcaron': 333,
 +    'ccedilla': 444,
 +    'Zdotaccent': 611,
 +    'Thorn': 556,
 +    'Omacron': 722,
 +    'Racute': 667,
 +    'Sacute': 556,
 +    'dcaron': 588,
 +    'Umacron': 722,
 +    'uring': 500,
 +    'threesuperior': 300,
 +    'Ograve': 722,
 +    'Agrave': 722,
 +    'Abreve': 722,
 +    'multiply': 564,
 +    'uacute': 500,
 +    'Tcaron': 611,
 +    'partialdiff': 476,
 +    'ydieresis': 500,
 +    'Nacute': 722,
 +    'icircumflex': 278,
 +    'Ecircumflex': 611,
 +    'adieresis': 444,
 +    'edieresis': 444,
 +    'cacute': 444,
 +    'nacute': 500,
 +    'umacron': 500,
 +    'Ncaron': 722,
 +    'Iacute': 333,
 +    'plusminus': 564,
 +    'brokenbar': 200,
 +    'registered': 760,
 +    'Gbreve': 722,
 +    'Idotaccent': 333,
 +    'summation': 600,
 +    'Egrave': 611,
 +    'racute': 333,
 +    'omacron': 500,
 +    'Zacute': 611,
 +    'Zcaron': 611,
 +    'greaterequal': 549,
 +    'Eth': 722,
 +    'Ccedilla': 667,
 +    'lcommaaccent': 278,
 +    'tcaron': 326,
 +    'eogonek': 444,
 +    'Uogonek': 722,
 +    'Aacute': 722,
 +    'Adieresis': 722,
 +    'egrave': 444,
 +    'zacute': 444,
 +    'iogonek': 278,
 +    'Oacute': 722,
 +    'oacute': 500,
 +    'amacron': 444,
 +    'sacute': 389,
 +    'idieresis': 278,
 +    'Ocircumflex': 722,
 +    'Ugrave': 722,
 +    'Delta': 612,
 +    'thorn': 500,
 +    'twosuperior': 300,
 +    'Odieresis': 722,
 +    'mu': 500,
 +    'igrave': 278,
 +    'ohungarumlaut': 500,
 +    'Eogonek': 611,
 +    'dcroat': 500,
 +    'threequarters': 750,
 +    'Scedilla': 556,
 +    'lcaron': 344,
 +    'Kcommaaccent': 722,
 +    'Lacute': 611,
 +    'trademark': 980,
 +    'edotaccent': 444,
 +    'Igrave': 333,
 +    'Imacron': 333,
 +    'Lcaron': 611,
 +    'onehalf': 750,
 +    'lessequal': 549,
 +    'ocircumflex': 500,
 +    'ntilde': 500,
 +    'Uhungarumlaut': 722,
 +    'Eacute': 611,
 +    'emacron': 444,
 +    'gbreve': 500,
 +    'onequarter': 750,
 +    'Scaron': 556,
 +    'Scommaaccent': 556,
 +    'Ohungarumlaut': 722,
 +    'degree': 400,
 +    'ograve': 500,
 +    'Ccaron': 667,
 +    'ugrave': 500,
 +    'radical': 453,
 +    'Dcaron': 722,
 +    'rcommaaccent': 333,
 +    'Ntilde': 722,
 +    'otilde': 500,
 +    'Rcommaaccent': 667,
 +    'Lcommaaccent': 611,
 +    'Atilde': 722,
 +    'Aogonek': 722,
 +    'Aring': 722,
 +    'Otilde': 722,
 +    'zdotaccent': 444,
 +    'Ecaron': 611,
 +    'Iogonek': 333,
 +    'kcommaaccent': 500,
 +    'minus': 564,
 +    'Icircumflex': 333,
 +    'ncaron': 500,
 +    'tcommaaccent': 278,
 +    'logicalnot': 564,
 +    'odieresis': 500,
 +    'udieresis': 500,
 +    'notequal': 549,
 +    'gcommaaccent': 500,
 +    'eth': 500,
 +    'zcaron': 444,
 +    'ncommaaccent': 500,
 +    'onesuperior': 300,
 +    'imacron': 278,
 +    'Euro': 500
 +  },
 +  'Times-Bold': {
 +    'space': 250,
 +    'exclam': 333,
 +    'quotedbl': 555,
 +    'numbersign': 500,
 +    'dollar': 500,
 +    'percent': 1000,
 +    'ampersand': 833,
 +    'quoteright': 333,
 +    'parenleft': 333,
 +    'parenright': 333,
 +    'asterisk': 500,
 +    'plus': 570,
 +    'comma': 250,
 +    'hyphen': 333,
 +    'period': 250,
 +    'slash': 278,
 +    'zero': 500,
 +    'one': 500,
 +    'two': 500,
 +    'three': 500,
 +    'four': 500,
 +    'five': 500,
 +    'six': 500,
 +    'seven': 500,
 +    'eight': 500,
 +    'nine': 500,
 +    'colon': 333,
 +    'semicolon': 333,
 +    'less': 570,
 +    'equal': 570,
 +    'greater': 570,
 +    'question': 500,
 +    'at': 930,
 +    'A': 722,
 +    'B': 667,
 +    'C': 722,
 +    'D': 722,
 +    'E': 667,
 +    'F': 611,
 +    'G': 778,
 +    'H': 778,
 +    'I': 389,
 +    'J': 500,
 +    'K': 778,
 +    'L': 667,
 +    'M': 944,
 +    'N': 722,
 +    'O': 778,
 +    'P': 611,
 +    'Q': 778,
 +    'R': 722,
 +    'S': 556,
 +    'T': 667,
 +    'U': 722,
 +    'V': 722,
 +    'W': 1000,
 +    'X': 722,
 +    'Y': 722,
 +    'Z': 667,
 +    'bracketleft': 333,
 +    'backslash': 278,
 +    'bracketright': 333,
 +    'asciicircum': 581,
 +    'underscore': 500,
 +    'quoteleft': 333,
 +    'a': 500,
 +    'b': 556,
 +    'c': 444,
 +    'd': 556,
 +    'e': 444,
 +    'f': 333,
 +    'g': 500,
 +    'h': 556,
 +    'i': 278,
 +    'j': 333,
 +    'k': 556,
 +    'l': 278,
 +    'm': 833,
 +    'n': 556,
 +    'o': 500,
 +    'p': 556,
 +    'q': 556,
 +    'r': 444,
 +    's': 389,
 +    't': 333,
 +    'u': 556,
 +    'v': 500,
 +    'w': 722,
 +    'x': 500,
 +    'y': 500,
 +    'z': 444,
 +    'braceleft': 394,
 +    'bar': 220,
 +    'braceright': 394,
 +    'asciitilde': 520,
 +    'exclamdown': 333,
 +    'cent': 500,
 +    'sterling': 500,
 +    'fraction': 167,
 +    'yen': 500,
 +    'florin': 500,
 +    'section': 500,
 +    'currency': 500,
 +    'quotesingle': 278,
 +    'quotedblleft': 500,
 +    'guillemotleft': 500,
 +    'guilsinglleft': 333,
 +    'guilsinglright': 333,
 +    'fi': 556,
 +    'fl': 556,
 +    'endash': 500,
 +    'dagger': 500,
 +    'daggerdbl': 500,
 +    'periodcentered': 250,
 +    'paragraph': 540,
 +    'bullet': 350,
 +    'quotesinglbase': 333,
 +    'quotedblbase': 500,
 +    'quotedblright': 500,
 +    'guillemotright': 500,
 +    'ellipsis': 1000,
 +    'perthousand': 1000,
 +    'questiondown': 500,
 +    'grave': 333,
 +    'acute': 333,
 +    'circumflex': 333,
 +    'tilde': 333,
 +    'macron': 333,
 +    'breve': 333,
 +    'dotaccent': 333,
 +    'dieresis': 333,
 +    'ring': 333,
 +    'cedilla': 333,
 +    'hungarumlaut': 333,
 +    'ogonek': 333,
 +    'caron': 333,
 +    'emdash': 1000,
 +    'AE': 1000,
 +    'ordfeminine': 300,
 +    'Lslash': 667,
 +    'Oslash': 778,
 +    'OE': 1000,
 +    'ordmasculine': 330,
 +    'ae': 722,
 +    'dotlessi': 278,
 +    'lslash': 278,
 +    'oslash': 500,
 +    'oe': 722,
 +    'germandbls': 556,
 +    'Idieresis': 389,
 +    'eacute': 444,
 +    'abreve': 500,
 +    'uhungarumlaut': 556,
 +    'ecaron': 444,
 +    'Ydieresis': 722,
 +    'divide': 570,
 +    'Yacute': 722,
 +    'Acircumflex': 722,
 +    'aacute': 500,
 +    'Ucircumflex': 722,
 +    'yacute': 500,
 +    'scommaaccent': 389,
 +    'ecircumflex': 444,
 +    'Uring': 722,
 +    'Udieresis': 722,
 +    'aogonek': 500,
 +    'Uacute': 722,
 +    'uogonek': 556,
 +    'Edieresis': 667,
 +    'Dcroat': 722,
 +    'commaaccent': 250,
 +    'copyright': 747,
 +    'Emacron': 667,
 +    'ccaron': 444,
 +    'aring': 500,
 +    'Ncommaaccent': 722,
 +    'lacute': 278,
 +    'agrave': 500,
 +    'Tcommaaccent': 667,
 +    'Cacute': 722,
 +    'atilde': 500,
 +    'Edotaccent': 667,
 +    'scaron': 389,
 +    'scedilla': 389,
 +    'iacute': 278,
 +    'lozenge': 494,
 +    'Rcaron': 722,
 +    'Gcommaaccent': 778,
 +    'ucircumflex': 556,
 +    'acircumflex': 500,
 +    'Amacron': 722,
 +    'rcaron': 444,
 +    'ccedilla': 444,
 +    'Zdotaccent': 667,
 +    'Thorn': 611,
 +    'Omacron': 778,
 +    'Racute': 722,
 +    'Sacute': 556,
 +    'dcaron': 672,
 +    'Umacron': 722,
 +    'uring': 556,
 +    'threesuperior': 300,
 +    'Ograve': 778,
 +    'Agrave': 722,
 +    'Abreve': 722,
 +    'multiply': 570,
 +    'uacute': 556,
 +    'Tcaron': 667,
 +    'partialdiff': 494,
 +    'ydieresis': 500,
 +    'Nacute': 722,
 +    'icircumflex': 278,
 +    'Ecircumflex': 667,
 +    'adieresis': 500,
 +    'edieresis': 444,
 +    'cacute': 444,
 +    'nacute': 556,
 +    'umacron': 556,
 +    'Ncaron': 722,
 +    'Iacute': 389,
 +    'plusminus': 570,
 +    'brokenbar': 220,
 +    'registered': 747,
 +    'Gbreve': 778,
 +    'Idotaccent': 389,
 +    'summation': 600,
 +    'Egrave': 667,
 +    'racute': 444,
 +    'omacron': 500,
 +    'Zacute': 667,
 +    'Zcaron': 667,
 +    'greaterequal': 549,
 +    'Eth': 722,
 +    'Ccedilla': 722,
 +    'lcommaaccent': 278,
 +    'tcaron': 416,
 +    'eogonek': 444,
 +    'Uogonek': 722,
 +    'Aacute': 722,
 +    'Adieresis': 722,
 +    'egrave': 444,
 +    'zacute': 444,
 +    'iogonek': 278,
 +    'Oacute': 778,
 +    'oacute': 500,
 +    'amacron': 500,
 +    'sacute': 389,
 +    'idieresis': 278,
 +    'Ocircumflex': 778,
 +    'Ugrave': 722,
 +    'Delta': 612,
 +    'thorn': 556,
 +    'twosuperior': 300,
 +    'Odieresis': 778,
 +    'mu': 556,
 +    'igrave': 278,
 +    'ohungarumlaut': 500,
 +    'Eogonek': 667,
 +    'dcroat': 556,
 +    'threequarters': 750,
 +    'Scedilla': 556,
 +    'lcaron': 394,
 +    'Kcommaaccent': 778,
 +    'Lacute': 667,
 +    'trademark': 1000,
 +    'edotaccent': 444,
 +    'Igrave': 389,
 +    'Imacron': 389,
 +    'Lcaron': 667,
 +    'onehalf': 750,
 +    'lessequal': 549,
 +    'ocircumflex': 500,
 +    'ntilde': 556,
 +    'Uhungarumlaut': 722,
 +    'Eacute': 667,
 +    'emacron': 444,
 +    'gbreve': 500,
 +    'onequarter': 750,
 +    'Scaron': 556,
 +    'Scommaaccent': 556,
 +    'Ohungarumlaut': 778,
 +    'degree': 400,
 +    'ograve': 500,
 +    'Ccaron': 722,
 +    'ugrave': 556,
 +    'radical': 549,
 +    'Dcaron': 722,
 +    'rcommaaccent': 444,
 +    'Ntilde': 722,
 +    'otilde': 500,
 +    'Rcommaaccent': 722,
 +    'Lcommaaccent': 667,
 +    'Atilde': 722,
 +    'Aogonek': 722,
 +    'Aring': 722,
 +    'Otilde': 778,
 +    'zdotaccent': 444,
 +    'Ecaron': 667,
 +    'Iogonek': 389,
 +    'kcommaaccent': 556,
 +    'minus': 570,
 +    'Icircumflex': 389,
 +    'ncaron': 556,
 +    'tcommaaccent': 333,
 +    'logicalnot': 570,
 +    'odieresis': 500,
 +    'udieresis': 556,
 +    'notequal': 549,
 +    'gcommaaccent': 500,
 +    'eth': 500,
 +    'zcaron': 444,
 +    'ncommaaccent': 556,
 +    'onesuperior': 300,
 +    'imacron': 278,
 +    'Euro': 500
 +  },
 +  'Times-BoldItalic': {
 +    'space': 250,
 +    'exclam': 389,
 +    'quotedbl': 555,
 +    'numbersign': 500,
 +    'dollar': 500,
 +    'percent': 833,
 +    'ampersand': 778,
 +    'quoteright': 333,
 +    'parenleft': 333,
 +    'parenright': 333,
 +    'asterisk': 500,
 +    'plus': 570,
 +    'comma': 250,
 +    'hyphen': 333,
 +    'period': 250,
 +    'slash': 278,
 +    'zero': 500,
 +    'one': 500,
 +    'two': 500,
 +    'three': 500,
 +    'four': 500,
 +    'five': 500,
 +    'six': 500,
 +    'seven': 500,
 +    'eight': 500,
 +    'nine': 500,
 +    'colon': 333,
 +    'semicolon': 333,
 +    'less': 570,
 +    'equal': 570,
 +    'greater': 570,
 +    'question': 500,
 +    'at': 832,
 +    'A': 667,
 +    'B': 667,
 +    'C': 667,
 +    'D': 722,
 +    'E': 667,
 +    'F': 667,
 +    'G': 722,
 +    'H': 778,
 +    'I': 389,
 +    'J': 500,
 +    'K': 667,
 +    'L': 611,
 +    'M': 889,
 +    'N': 722,
 +    'O': 722,
 +    'P': 611,
 +    'Q': 722,
 +    'R': 667,
 +    'S': 556,
 +    'T': 611,
 +    'U': 722,
 +    'V': 667,
 +    'W': 889,
 +    'X': 667,
 +    'Y': 611,
 +    'Z': 611,
 +    'bracketleft': 333,
 +    'backslash': 278,
 +    'bracketright': 333,
 +    'asciicircum': 570,
 +    'underscore': 500,
 +    'quoteleft': 333,
 +    'a': 500,
 +    'b': 500,
 +    'c': 444,
 +    'd': 500,
 +    'e': 444,
 +    'f': 333,
 +    'g': 500,
 +    'h': 556,
 +    'i': 278,
 +    'j': 278,
 +    'k': 500,
 +    'l': 278,
 +    'm': 778,
 +    'n': 556,
 +    'o': 500,
 +    'p': 500,
 +    'q': 500,
 +    'r': 389,
 +    's': 389,
 +    't': 278,
 +    'u': 556,
 +    'v': 444,
 +    'w': 667,
 +    'x': 500,
 +    'y': 444,
 +    'z': 389,
 +    'braceleft': 348,
 +    'bar': 220,
 +    'braceright': 348,
 +    'asciitilde': 570,
 +    'exclamdown': 389,
 +    'cent': 500,
 +    'sterling': 500,
 +    'fraction': 167,
 +    'yen': 500,
 +    'florin': 500,
 +    'section': 500,
 +    'currency': 500,
 +    'quotesingle': 278,
 +    'quotedblleft': 500,
 +    'guillemotleft': 500,
 +    'guilsinglleft': 333,
 +    'guilsinglright': 333,
 +    'fi': 556,
 +    'fl': 556,
 +    'endash': 500,
 +    'dagger': 500,
 +    'daggerdbl': 500,
 +    'periodcentered': 250,
 +    'paragraph': 500,
 +    'bullet': 350,
 +    'quotesinglbase': 333,
 +    'quotedblbase': 500,
 +    'quotedblright': 500,
 +    'guillemotright': 500,
 +    'ellipsis': 1000,
 +    'perthousand': 1000,
 +    'questiondown': 500,
 +    'grave': 333,
 +    'acute': 333,
 +    'circumflex': 333,
 +    'tilde': 333,
 +    'macron': 333,
 +    'breve': 333,
 +    'dotaccent': 333,
 +    'dieresis': 333,
 +    'ring': 333,
 +    'cedilla': 333,
 +    'hungarumlaut': 333,
 +    'ogonek': 333,
 +    'caron': 333,
 +    'emdash': 1000,
 +    'AE': 944,
 +    'ordfeminine': 266,
 +    'Lslash': 611,
 +    'Oslash': 722,
 +    'OE': 944,
 +    'ordmasculine': 300,
 +    'ae': 722,
 +    'dotlessi': 278,
 +    'lslash': 278,
 +    'oslash': 500,
 +    'oe': 722,
 +    'germandbls': 500,
 +    'Idieresis': 389,
 +    'eacute': 444,
 +    'abreve': 500,
 +    'uhungarumlaut': 556,
 +    'ecaron': 444,
 +    'Ydieresis': 611,
 +    'divide': 570,
 +    'Yacute': 611,
 +    'Acircumflex': 667,
 +    'aacute': 500,
 +    'Ucircumflex': 722,
 +    'yacute': 444,
 +    'scommaaccent': 389,
 +    'ecircumflex': 444,
 +    'Uring': 722,
 +    'Udieresis': 722,
 +    'aogonek': 500,
 +    'Uacute': 722,
 +    'uogonek': 556,
 +    'Edieresis': 667,
 +    'Dcroat': 722,
 +    'commaaccent': 250,
 +    'copyright': 747,
 +    'Emacron': 667,
 +    'ccaron': 444,
 +    'aring': 500,
 +    'Ncommaaccent': 722,
 +    'lacute': 278,
 +    'agrave': 500,
 +    'Tcommaaccent': 611,
 +    'Cacute': 667,
 +    'atilde': 500,
 +    'Edotaccent': 667,
 +    'scaron': 389,
 +    'scedilla': 389,
 +    'iacute': 278,
 +    'lozenge': 494,
 +    'Rcaron': 667,
 +    'Gcommaaccent': 722,
 +    'ucircumflex': 556,
 +    'acircumflex': 500,
 +    'Amacron': 667,
 +    'rcaron': 389,
 +    'ccedilla': 444,
 +    'Zdotaccent': 611,
 +    'Thorn': 611,
 +    'Omacron': 722,
 +    'Racute': 667,
 +    'Sacute': 556,
 +    'dcaron': 608,
 +    'Umacron': 722,
 +    'uring': 556,
 +    'threesuperior': 300,
 +    'Ograve': 722,
 +    'Agrave': 667,
 +    'Abreve': 667,
 +    'multiply': 570,
 +    'uacute': 556,
 +    'Tcaron': 611,
 +    'partialdiff': 494,
 +    'ydieresis': 444,
 +    'Nacute': 722,
 +    'icircumflex': 278,
 +    'Ecircumflex': 667,
 +    'adieresis': 500,
 +    'edieresis': 444,
 +    'cacute': 444,
 +    'nacute': 556,
 +    'umacron': 556,
 +    'Ncaron': 722,
 +    'Iacute': 389,
 +    'plusminus': 570,
 +    'brokenbar': 220,
 +    'registered': 747,
 +    'Gbreve': 722,
 +    'Idotaccent': 389,
 +    'summation': 600,
 +    'Egrave': 667,
 +    'racute': 389,
 +    'omacron': 500,
 +    'Zacute': 611,
 +    'Zcaron': 611,
 +    'greaterequal': 549,
 +    'Eth': 722,
 +    'Ccedilla': 667,
 +    'lcommaaccent': 278,
 +    'tcaron': 366,
 +    'eogonek': 444,
 +    'Uogonek': 722,
 +    'Aacute': 667,
 +    'Adieresis': 667,
 +    'egrave': 444,
 +    'zacute': 389,
 +    'iogonek': 278,
 +    'Oacute': 722,
 +    'oacute': 500,
 +    'amacron': 500,
 +    'sacute': 389,
 +    'idieresis': 278,
 +    'Ocircumflex': 722,
 +    'Ugrave': 722,
 +    'Delta': 612,
 +    'thorn': 500,
 +    'twosuperior': 300,
 +    'Odieresis': 722,
 +    'mu': 576,
 +    'igrave': 278,
 +    'ohungarumlaut': 500,
 +    'Eogonek': 667,
 +    'dcroat': 500,
 +    'threequarters': 750,
 +    'Scedilla': 556,
 +    'lcaron': 382,
 +    'Kcommaaccent': 667,
 +    'Lacute': 611,
 +    'trademark': 1000,
 +    'edotaccent': 444,
 +    'Igrave': 389,
 +    'Imacron': 389,
 +    'Lcaron': 611,
 +    'onehalf': 750,
 +    'lessequal': 549,
 +    'ocircumflex': 500,
 +    'ntilde': 556,
 +    'Uhungarumlaut': 722,
 +    'Eacute': 667,
 +    'emacron': 444,
 +    'gbreve': 500,
 +    'onequarter': 750,
 +    'Scaron': 556,
 +    'Scommaaccent': 556,
 +    'Ohungarumlaut': 722,
 +    'degree': 400,
 +    'ograve': 500,
 +    'Ccaron': 667,
 +    'ugrave': 556,
 +    'radical': 549,
 +    'Dcaron': 722,
 +    'rcommaaccent': 389,
 +    'Ntilde': 722,
 +    'otilde': 500,
 +    'Rcommaaccent': 667,
 +    'Lcommaaccent': 611,
 +    'Atilde': 667,
 +    'Aogonek': 667,
 +    'Aring': 667,
 +    'Otilde': 722,
 +    'zdotaccent': 389,
 +    'Ecaron': 667,
 +    'Iogonek': 389,
 +    'kcommaaccent': 500,
 +    'minus': 606,
 +    'Icircumflex': 389,
 +    'ncaron': 556,
 +    'tcommaaccent': 278,
 +    'logicalnot': 606,
 +    'odieresis': 500,
 +    'udieresis': 556,
 +    'notequal': 549,
 +    'gcommaaccent': 500,
 +    'eth': 500,
 +    'zcaron': 389,
 +    'ncommaaccent': 556,
 +    'onesuperior': 300,
 +    'imacron': 278,
 +    'Euro': 500
 +  },
 +  'Times-Italic': {
 +    'space': 250,
 +    'exclam': 333,
 +    'quotedbl': 420,
 +    'numbersign': 500,
 +    'dollar': 500,
 +    'percent': 833,
 +    'ampersand': 778,
 +    'quoteright': 333,
 +    'parenleft': 333,
 +    'parenright': 333,
 +    'asterisk': 500,
 +    'plus': 675,
 +    'comma': 250,
 +    'hyphen': 333,
 +    'period': 250,
 +    'slash': 278,
 +    'zero': 500,
 +    'one': 500,
 +    'two': 500,
 +    'three': 500,
 +    'four': 500,
 +    'five': 500,
 +    'six': 500,
 +    'seven': 500,
 +    'eight': 500,
 +    'nine': 500,
 +    'colon': 333,
 +    'semicolon': 333,
 +    'less': 675,
 +    'equal': 675,
 +    'greater': 675,
 +    'question': 500,
 +    'at': 920,
 +    'A': 611,
 +    'B': 611,
 +    'C': 667,
 +    'D': 722,
 +    'E': 611,
 +    'F': 611,
 +    'G': 722,
 +    'H': 722,
 +    'I': 333,
 +    'J': 444,
 +    'K': 667,
 +    'L': 556,
 +    'M': 833,
 +    'N': 667,
 +    'O': 722,
 +    'P': 611,
 +    'Q': 722,
 +    'R': 611,
 +    'S': 500,
 +    'T': 556,
 +    'U': 722,
 +    'V': 611,
 +    'W': 833,
 +    'X': 611,
 +    'Y': 556,
 +    'Z': 556,
 +    'bracketleft': 389,
 +    'backslash': 278,
 +    'bracketright': 389,
 +    'asciicircum': 422,
 +    'underscore': 500,
 +    'quoteleft': 333,
 +    'a': 500,
 +    'b': 500,
 +    'c': 444,
 +    'd': 500,
 +    'e': 444,
 +    'f': 278,
 +    'g': 500,
 +    'h': 500,
 +    'i': 278,
 +    'j': 278,
 +    'k': 444,
 +    'l': 278,
 +    'm': 722,
 +    'n': 500,
 +    'o': 500,
 +    'p': 500,
 +    'q': 500,
 +    'r': 389,
 +    's': 389,
 +    't': 278,
 +    'u': 500,
 +    'v': 444,
 +    'w': 667,
 +    'x': 444,
 +    'y': 444,
 +    'z': 389,
 +    'braceleft': 400,
 +    'bar': 275,
 +    'braceright': 400,
 +    'asciitilde': 541,
 +    'exclamdown': 389,
 +    'cent': 500,
 +    'sterling': 500,
 +    'fraction': 167,
 +    'yen': 500,
 +    'florin': 500,
 +    'section': 500,
 +    'currency': 500,
 +    'quotesingle': 214,
 +    'quotedblleft': 556,
 +    'guillemotleft': 500,
 +    'guilsinglleft': 333,
 +    'guilsinglright': 333,
 +    'fi': 500,
 +    'fl': 500,
 +    'endash': 500,
 +    'dagger': 500,
 +    'daggerdbl': 500,
 +    'periodcentered': 250,
 +    'paragraph': 523,
 +    'bullet': 350,
 +    'quotesinglbase': 333,
 +    'quotedblbase': 556,
 +    'quotedblright': 556,
 +    'guillemotright': 500,
 +    'ellipsis': 889,
 +    'perthousand': 1000,
 +    'questiondown': 500,
 +    'grave': 333,
 +    'acute': 333,
 +    'circumflex': 333,
 +    'tilde': 333,
 +    'macron': 333,
 +    'breve': 333,
 +    'dotaccent': 333,
 +    'dieresis': 333,
 +    'ring': 333,
 +    'cedilla': 333,
 +    'hungarumlaut': 333,
 +    'ogonek': 333,
 +    'caron': 333,
 +    'emdash': 889,
 +    'AE': 889,
 +    'ordfeminine': 276,
 +    'Lslash': 556,
 +    'Oslash': 722,
 +    'OE': 944,
 +    'ordmasculine': 310,
 +    'ae': 667,
 +    'dotlessi': 278,
 +    'lslash': 278,
 +    'oslash': 500,
 +    'oe': 667,
 +    'germandbls': 500,
 +    'Idieresis': 333,
 +    'eacute': 444,
 +    'abreve': 500,
 +    'uhungarumlaut': 500,
 +    'ecaron': 444,
 +    'Ydieresis': 556,
 +    'divide': 675,
 +    'Yacute': 556,
 +    'Acircumflex': 611,
 +    'aacute': 500,
 +    'Ucircumflex': 722,
 +    'yacute': 444,
 +    'scommaaccent': 389,
 +    'ecircumflex': 444,
 +    'Uring': 722,
 +    'Udieresis': 722,
 +    'aogonek': 500,
 +    'Uacute': 722,
 +    'uogonek': 500,
 +    'Edieresis': 611,
 +    'Dcroat': 722,
 +    'commaaccent': 250,
 +    'copyright': 760,
 +    'Emacron': 611,
 +    'ccaron': 444,
 +    'aring': 500,
 +    'Ncommaaccent': 667,
 +    'lacute': 278,
 +    'agrave': 500,
 +    'Tcommaaccent': 556,
 +    'Cacute': 667,
 +    'atilde': 500,
 +    'Edotaccent': 611,
 +    'scaron': 389,
 +    'scedilla': 389,
 +    'iacute': 278,
 +    'lozenge': 471,
 +    'Rcaron': 611,
 +    'Gcommaaccent': 722,
 +    'ucircumflex': 500,
 +    'acircumflex': 500,
 +    'Amacron': 611,
 +    'rcaron': 389,
 +    'ccedilla': 444,
 +    'Zdotaccent': 556,
 +    'Thorn': 611,
 +    'Omacron': 722,
 +    'Racute': 611,
 +    'Sacute': 500,
 +    'dcaron': 544,
 +    'Umacron': 722,
 +    'uring': 500,
 +    'threesuperior': 300,
 +    'Ograve': 722,
 +    'Agrave': 611,
 +    'Abreve': 611,
 +    'multiply': 675,
 +    'uacute': 500,
 +    'Tcaron': 556,
 +    'partialdiff': 476,
 +    'ydieresis': 444,
 +    'Nacute': 667,
 +    'icircumflex': 278,
 +    'Ecircumflex': 611,
 +    'adieresis': 500,
 +    'edieresis': 444,
 +    'cacute': 444,
 +    'nacute': 500,
 +    'umacron': 500,
 +    'Ncaron': 667,
 +    'Iacute': 333,
 +    'plusminus': 675,
 +    'brokenbar': 275,
 +    'registered': 760,
 +    'Gbreve': 722,
 +    'Idotaccent': 333,
 +    'summation': 600,
 +    'Egrave': 611,
 +    'racute': 389,
 +    'omacron': 500,
 +    'Zacute': 556,
 +    'Zcaron': 556,
 +    'greaterequal': 549,
 +    'Eth': 722,
 +    'Ccedilla': 667,
 +    'lcommaaccent': 278,
 +    'tcaron': 300,
 +    'eogonek': 444,
 +    'Uogonek': 722,
 +    'Aacute': 611,
 +    'Adieresis': 611,
 +    'egrave': 444,
 +    'zacute': 389,
 +    'iogonek': 278,
 +    'Oacute': 722,
 +    'oacute': 500,
 +    'amacron': 500,
 +    'sacute': 389,
 +    'idieresis': 278,
 +    'Ocircumflex': 722,
 +    'Ugrave': 722,
 +    'Delta': 612,
 +    'thorn': 500,
 +    'twosuperior': 300,
 +    'Odieresis': 722,
 +    'mu': 500,
 +    'igrave': 278,
 +    'ohungarumlaut': 500,
 +    'Eogonek': 611,
 +    'dcroat': 500,
 +    'threequarters': 750,
 +    'Scedilla': 500,
 +    'lcaron': 300,
 +    'Kcommaaccent': 667,
 +    'Lacute': 556,
 +    'trademark': 980,
 +    'edotaccent': 444,
 +    'Igrave': 333,
 +    'Imacron': 333,
 +    'Lcaron': 611,
 +    'onehalf': 750,
 +    'lessequal': 549,
 +    'ocircumflex': 500,
 +    'ntilde': 500,
 +    'Uhungarumlaut': 722,
 +    'Eacute': 611,
 +    'emacron': 444,
 +    'gbreve': 500,
 +    'onequarter': 750,
 +    'Scaron': 500,
 +    'Scommaaccent': 500,
 +    'Ohungarumlaut': 722,
 +    'degree': 400,
 +    'ograve': 500,
 +    'Ccaron': 667,
 +    'ugrave': 500,
 +    'radical': 453,
 +    'Dcaron': 722,
 +    'rcommaaccent': 389,
 +    'Ntilde': 667,
 +    'otilde': 500,
 +    'Rcommaaccent': 611,
 +    'Lcommaaccent': 556,
 +    'Atilde': 611,
 +    'Aogonek': 611,
 +    'Aring': 611,
 +    'Otilde': 722,
 +    'zdotaccent': 389,
 +    'Ecaron': 611,
 +    'Iogonek': 333,
 +    'kcommaaccent': 444,
 +    'minus': 675,
 +    'Icircumflex': 333,
 +    'ncaron': 500,
 +    'tcommaaccent': 278,
 +    'logicalnot': 675,
 +    'odieresis': 500,
 +    'udieresis': 500,
 +    'notequal': 549,
 +    'gcommaaccent': 500,
 +    'eth': 500,
 +    'zcaron': 389,
 +    'ncommaaccent': 500,
 +    'onesuperior': 300,
 +    'imacron': 278,
 +    'Euro': 500
 +  },
 +  'ZapfDingbats': {
 +    'space': 278,
 +    'a1': 974,
 +    'a2': 961,
 +    'a202': 974,
 +    'a3': 980,
 +    'a4': 719,
 +    'a5': 789,
 +    'a119': 790,
 +    'a118': 791,
 +    'a117': 690,
 +    'a11': 960,
 +    'a12': 939,
 +    'a13': 549,
 +    'a14': 855,
 +    'a15': 911,
 +    'a16': 933,
 +    'a105': 911,
 +    'a17': 945,
 +    'a18': 974,
 +    'a19': 755,
 +    'a20': 846,
 +    'a21': 762,
 +    'a22': 761,
 +    'a23': 571,
 +    'a24': 677,
 +    'a25': 763,
 +    'a26': 760,
 +    'a27': 759,
 +    'a28': 754,
 +    'a6': 494,
 +    'a7': 552,
 +    'a8': 537,
 +    'a9': 577,
 +    'a10': 692,
 +    'a29': 786,
 +    'a30': 788,
 +    'a31': 788,
 +    'a32': 790,
 +    'a33': 793,
 +    'a34': 794,
 +    'a35': 816,
 +    'a36': 823,
 +    'a37': 789,
 +    'a38': 841,
 +    'a39': 823,
 +    'a40': 833,
 +    'a41': 816,
 +    'a42': 831,
 +    'a43': 923,
 +    'a44': 744,
 +    'a45': 723,
 +    'a46': 749,
 +    'a47': 790,
 +    'a48': 792,
 +    'a49': 695,
 +    'a50': 776,
 +    'a51': 768,
 +    'a52': 792,
 +    'a53': 759,
 +    'a54': 707,
 +    'a55': 708,
 +    'a56': 682,
 +    'a57': 701,
 +    'a58': 826,
 +    'a59': 815,
 +    'a60': 789,
 +    'a61': 789,
 +    'a62': 707,
 +    'a63': 687,
 +    'a64': 696,
 +    'a65': 689,
 +    'a66': 786,
 +    'a67': 787,
 +    'a68': 713,
 +    'a69': 791,
 +    'a70': 785,
 +    'a71': 791,
 +    'a72': 873,
 +    'a73': 761,
 +    'a74': 762,
 +    'a203': 762,
 +    'a75': 759,
 +    'a204': 759,
 +    'a76': 892,
 +    'a77': 892,
 +    'a78': 788,
 +    'a79': 784,
 +    'a81': 438,
 +    'a82': 138,
 +    'a83': 277,
 +    'a84': 415,
 +    'a97': 392,
 +    'a98': 392,
 +    'a99': 668,
 +    'a100': 668,
 +    'a89': 390,
 +    'a90': 390,
 +    'a93': 317,
 +    'a94': 317,
 +    'a91': 276,
 +    'a92': 276,
 +    'a205': 509,
 +    'a85': 509,
 +    'a206': 410,
 +    'a86': 410,
 +    'a87': 234,
 +    'a88': 234,
 +    'a95': 334,
 +    'a96': 334,
 +    'a101': 732,
 +    'a102': 544,
 +    'a103': 544,
 +    'a104': 910,
 +    'a106': 667,
 +    'a107': 760,
 +    'a108': 760,
 +    'a112': 776,
 +    'a111': 595,
 +    'a110': 694,
 +    'a109': 626,
 +    'a120': 788,
 +    'a121': 788,
 +    'a122': 788,
 +    'a123': 788,
 +    'a124': 788,
 +    'a125': 788,
 +    'a126': 788,
 +    'a127': 788,
 +    'a128': 788,
 +    'a129': 788,
 +    'a130': 788,
 +    'a131': 788,
 +    'a132': 788,
 +    'a133': 788,
 +    'a134': 788,
 +    'a135': 788,
 +    'a136': 788,
 +    'a137': 788,
 +    'a138': 788,
 +    'a139': 788,
 +    'a140': 788,
 +    'a141': 788,
 +    'a142': 788,
 +    'a143': 788,
 +    'a144': 788,
 +    'a145': 788,
 +    'a146': 788,
 +    'a147': 788,
 +    'a148': 788,
 +    'a149': 788,
 +    'a150': 788,
 +    'a151': 788,
 +    'a152': 788,
 +    'a153': 788,
 +    'a154': 788,
 +    'a155': 788,
 +    'a156': 788,
 +    'a157': 788,
 +    'a158': 788,
 +    'a159': 788,
 +    'a160': 894,
 +    'a161': 838,
 +    'a163': 1016,
 +    'a164': 458,
 +    'a196': 748,
 +    'a165': 924,
 +    'a192': 748,
 +    'a166': 918,
 +    'a167': 927,
 +    'a168': 928,
 +    'a169': 928,
 +    'a170': 834,
 +    'a171': 873,
 +    'a172': 828,
 +    'a173': 924,
 +    'a162': 924,
 +    'a174': 917,
 +    'a175': 930,
 +    'a176': 931,
 +    'a177': 463,
 +    'a178': 883,
 +    'a179': 836,
 +    'a193': 836,
 +    'a180': 867,
 +    'a199': 867,
 +    'a181': 696,
 +    'a200': 696,
 +    'a182': 874,
 +    'a201': 874,
 +    'a183': 760,
 +    'a184': 946,
 +    'a197': 771,
 +    'a185': 865,
 +    'a194': 771,
 +    'a198': 888,
 +    'a186': 967,
 +    'a195': 888,
 +    'a187': 831,
 +    'a188': 873,
 +    'a189': 927,
 +    'a190': 970,
 +    'a191': 918
 +  }
 +};
 +
 +
 +
 +var EOF = {};
 +
 +function isEOF(v) {
 +  return v == EOF;
 +}
 +
 +var Parser = (function ParserClosure() {
 +  function Parser(lexer, allowStreams, xref) {
 +    this.lexer = lexer;
 +    this.allowStreams = allowStreams;
 +    this.xref = xref;
 +    this.refill();
 +  }
 +
 +  Parser.prototype = {
 +    refill: function Parser_refill() {
 +      this.buf1 = this.lexer.getObj();
 +      this.buf2 = this.lexer.getObj();
 +    },
 +    shift: function Parser_shift() {
 +      if (isCmd(this.buf2, 'ID')) {
 +        this.buf1 = this.buf2;
 +        this.buf2 = null;
-         // skip byte after ID
-         this.lexer.skip();
 +      } else {
 +        this.buf1 = this.buf2;
 +        this.buf2 = this.lexer.getObj();
 +      }
 +    },
 +    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))
-             error('Dictionary key must be a name object');
++          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');
 +
 +        // 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;
 +      }
 +      if (isInt(this.buf1)) { // indirect reference or integer
 +        var num = this.buf1;
 +        this.shift();
 +        if (isInt(this.buf1) && isCmd(this.buf2, 'R')) {
 +          var ref = new Ref(num, this.buf1);
 +          this.shift();
 +          this.shift();
 +          return ref;
 +        }
 +        return num;
 +      }
 +      if (isString(this.buf1)) { // string
 +        var str = this.buf1;
 +        this.shift();
 +        if (cipherTransform)
 +          str = cipherTransform.decryptString(str);
 +        return str;
 +      }
 +
 +      // simple object
 +      var obj = this.buf1;
 +      this.shift();
 +      return obj;
 +    },
 +    makeInlineImage: function Parser_makeInlineImage(cipherTransform) {
 +      var lexer = this.lexer;
 +      var stream = lexer.stream;
 +
 +      // parse dictionary
 +      var dict = new Dict();
 +      while (!isCmd(this.buf1, 'ID') && !isEOF(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))
 +          break;
 +        dict.set(key, this.getObj(cipherTransform));
 +      }
 +
 +      // parse image stream
 +      var startPos = stream.pos;
 +
 +      // searching for the /EI\s/
-       var state = 0, ch;
-       while (state != 4 &&
-              (ch = stream.getByte()) !== null && ch !== undefined) {
-         switch (ch) {
++      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++) {
++              ch = followingBytes[i];
++              if (ch !== 0x0A && ch !== 0x0D && (ch < 0x20 || ch > 0x7F)) {
++                // not a LF, CR, SPACE or any visible ASCII character
++                state = 0;
++                break; // some binary stuff found, resetting the state
++              }
++            }
 +            state = state === 3 ? 4 : 0;
 +            break;
 +          case 0x45:
 +            state = 2;
 +            break;
 +          case 0x49:
 +            state = state === 2 ? 3 : 0;
 +            break;
 +          default:
 +            state = 0;
 +            break;
 +        }
 +      }
 +
 +      var length = (stream.pos - 4) - startPos;
 +      var imageStream = stream.makeSubStream(startPos, length, dict);
 +      if (cipherTransform)
 +        imageStream = cipherTransform.createStream(imageStream);
 +      imageStream = this.filter(imageStream, dict, length);
-       imageStream.parameters = dict;
++      imageStream.dict = dict;
 +
 +      this.buf2 = Cmd.get('EI');
 +      this.shift();
 +
 +      return imageStream;
 +    },
 +    fetchIfRef: function Parser_fetchIfRef(obj) {
 +      // not relying on the xref.fetchIfRef -- xref might not be set
 +      return isRef(obj) ? this.xref.fetch(obj) : obj;
 +    },
 +    makeStream: function Parser_makeStream(dict, cipherTransform) {
 +      var lexer = this.lexer;
 +      var stream = lexer.stream;
 +
 +      // get stream start position
 +      lexer.skipToNextLine();
-       var pos = stream.pos;
++      var pos = stream.pos - 1;
 +
 +      // get length
 +      var length = this.fetchIfRef(dict.get('Length'));
-       if (!isInt(length))
-         error('Bad ' + length + ' attribute in stream');
++      if (!isInt(length)) {
++        info('Bad ' + length + ' attribute in stream');
++        length = 0;
++      }
 +
 +      // skip over the stream data
 +      stream.pos = pos + length;
++      lexer.nextChar();
++
 +      this.shift(); // '>>'
 +      this.shift(); // 'stream'
-       if (!isCmd(this.buf1, 'endstream'))
-         error('Missing endstream');
-       this.shift();
++      if (!isCmd(this.buf1, 'endstream')) {
++        // bad stream length, scanning for endstream
++        stream.pos = pos;
++        var SCAN_BLOCK_SIZE = 2048;
++        var ENDSTREAM_SIGNATURE_LENGTH = 9;
++        var ENDSTREAM_SIGNATURE = [0x65, 0x6E, 0x64, 0x73, 0x74, 0x72, 0x65,
++                                   0x61, 0x6D];
++        var skipped = 0, found = false;
++        while (stream.pos < stream.end) {
++          var scanBytes = stream.peekBytes(SCAN_BLOCK_SIZE);
++          var scanLength = scanBytes.length - ENDSTREAM_SIGNATURE_LENGTH;
++          var found = false, i, j;
++          for (i = 0, j = 0; i < scanLength; i++) {
++            var b = scanBytes[i];
++            if (b !== ENDSTREAM_SIGNATURE[j]) {
++              i -= j;
++              j = 0;
++            } else {
++              j++;
++              if (j >= ENDSTREAM_SIGNATURE_LENGTH) {
++                i++;
++                found = true;
++                break;
++              }
++            }
++          }
++          if (found) {
++            skipped += i - ENDSTREAM_SIGNATURE_LENGTH;
++            stream.pos += i - ENDSTREAM_SIGNATURE_LENGTH;
++            break;
++          }
++          skipped += scanLength;
++          stream.pos += scanLength;
++        }
++        if (!found) {
++          error('Missing endstream');
++        }
++        length = skipped;
++
++        lexer.nextChar();
++        this.shift();
++        this.shift();
++      }
++      this.shift(); // 'endstream'
 +
 +      stream = stream.makeSubStream(pos, length, dict);
 +      if (cipherTransform)
 +        stream = cipherTransform.createStream(stream);
 +      stream = this.filter(stream, dict, length);
-       stream.parameters = dict;
++      stream.dict = dict;
 +      return stream;
 +    },
 +    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))
 +        return this.makeFilter(stream, filter.name, length, params);
 +      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))
 +            error('Bad filter name: ' + filter);
 +
 +          params = null;
 +          if (isArray(paramsArray) && (i in paramsArray))
 +            params = paramsArray[i];
 +          stream = this.makeFilter(stream, filter.name, length, params);
 +          // after the first stream the length variable is invalid
 +          length = null;
 +        }
 +      }
 +      return stream;
 +    },
 +    makeFilter: function Parser_makeFilter(stream, name, length, params) {
 +      if (stream.dict.get('Length') === 0) {
 +        return new NullStream(stream);
 +      }
 +      if (name == 'FlateDecode' || name == 'Fl') {
 +        if (params) {
 +          return new PredictorStream(new FlateStream(stream), 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);
 +        }
 +        return new LZWStream(stream, earlyChange);
 +      }
 +      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;
 +    }
 +  };
 +
 +  return Parser;
 +})();
 +
 +var Lexer = (function LexerClosure() {
 +  function Lexer(stream, knownCommands) {
 +    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:
 +    // if there a command that is a prefix of the other valid command or
 +    // literal (e.g. 'f' and 'false') the following prefixes must be included,
 +    // 'fa', 'fal', 'fals'. The prefixes are not needed, if the command has no
 +    // other commands or literals as a prefix. The knowCommands is optional.
 +    this.knownCommands = knownCommands;
 +  }
 +
 +  Lexer.isSpace = function Lexer_isSpace(ch) {
-     return ch == ' ' || ch == '\t' || ch == '\x0d' || ch == '\x0a';
++    // 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
 +  // '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
 +  ];
 +
 +  function toHexDigit(ch) {
-     if (ch >= '0' && ch <= '9')
-       return ch.charCodeAt(0) - 48;
-     ch = ch.toUpperCase();
-     if (ch >= 'A' && ch <= 'F')
-       return ch.charCodeAt(0) - 55;
++    if (ch >= 0x30 && ch <= 0x39) { // '0'-'9'
++      return ch & 0x0F;
++    }
++    if ((ch >= 0x41 && ch <= 0x46) || (ch >= 0x61 && ch <= 0x66)) {
++      // 'A'-'F', 'a'-'f'
++      return (ch & 0x0F) + 9;
++    }
 +    return -1;
 +  }
 +
 +  Lexer.prototype = {
-     getNumber: function Lexer_getNumber(ch) {
-       var floating = false;
-       var str = ch;
-       var stream = this.stream;
-       while ((ch = stream.lookChar())) {
-         if (ch == '.' && !floating) {
-           str += ch;
-           floating = true;
-         } else if (ch == '-') {
++    nextChar: function Lexer_nextChar() {
++      return (this.currentChar = this.stream.getByte());
++    },
++    peekChar: function Lexer_peekChar() {
++      return this.stream.peekBytes(1)[0];
++    },
++    getNumber: function Lexer_getNumber() {
++      var ch = this.currentChar;
++      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 (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 >= '0' && ch <= '9') {
-           str += ch;
-         } else if (ch == 'e' || ch == 'E') {
-           floating = true;
++        } else if (ch === 0x45 || ch === 0x65) { // 'E', 'e'
++          // 'E' can be either a scientific notation or the beginning of a new
++          // operator
++          var hasE = true;
++          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;
 +        }
-         stream.skip();
 +      }
-       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 stream = this.stream;
-       var ch;
-       do {
-         ch = stream.getChar();
-         switch (ch) {
-           case null:
-           case undefined:
++      var strBuf = this.strBuf;
++      strBuf.length = 0;
++
++      var ch = this.nextChar();
++      while (true) {
++        var charBuffered = false;
++        switch (ch | 0) {
++          case -1:
 +            warn('Unterminated string');
 +            done = true;
 +            break;
-           case '(':
++          case 0x28: // '('
 +            ++numParen;
-             str += ch;
++            strBuf.push('(');
 +            break;
-           case ')':
++          case 0x29: // ')'
 +            if (--numParen === 0) {
++              this.nextChar(); // consume strings ')'
 +              done = true;
 +            } else {
-               str += ch;
++              strBuf.push(')');
 +            }
 +            break;
-           case '\\':
-             ch = stream.getChar();
++          case 0x5C: // '\\'
++            ch = this.nextChar();
 +            switch (ch) {
-               case null:
-               case undefined:
++              case -1:
 +                warn('Unterminated string');
 +                done = true;
 +                break;
-               case 'n':
-                 str += '\n';
++              case 0x6E: // 'n'
++                strBuf.push('\n');
 +                break;
-               case 'r':
-                 str += '\r';
++              case 0x72: // 'r'
++                strBuf.push('\r');
 +                break;
-               case 't':
-                 str += '\t';
++              case 0x74: // 't'
++                strBuf.push('\t');
 +                break;
-               case 'b':
-                 str += '\b';
++              case 0x62: // 'b'
++                strBuf.push('\b');
 +                break;
-               case 'f':
-                 str += '\f';
++              case 0x66: // 'f'
++                strBuf.push('\f');
 +                break;
-               case '\\':
-               case '(':
-               case ')':
-                 str += ch;
++              case 0x5C: // '\'
++              case 0x28: // '('
++              case 0x29: // ')'
++                strBuf.push(String.fromCharCode(ch));
 +                break;
-               case '0': case '1': case '2': case '3':
-               case '4': case '5': case '6': case '7':
-                 var x = ch - '0';
-                 ch = stream.lookChar();
-                 if (ch >= '0' && ch <= '7') {
-                   stream.skip();
-                   x = (x << 3) + (ch - '0');
-                   ch = stream.lookChar();
-                   if (ch >= '0' && ch <= '7') {
-                     stream.skip();
-                     x = (x << 3) + (ch - '0');
++              case 0x30: case 0x31: case 0x32: case 0x33: // '0'-'3'
++              case 0x34: case 0x35: case 0x36: case 0x37: // '4'-'7'
++                var x = ch & 0x0F;
++                ch = this.nextChar();
++                charBuffered = true;
++                if (ch >= 0x30 && ch <= 0x37) { // '0'-'7'
++                  x = (x << 3) + (ch & 0x0F);
++                  ch = this.nextChar();
++                  if (ch >= 0x30 && ch <= 0x37) {  // '0'-'7'
++                    charBuffered = false;
++                    x = (x << 3) + (ch & 0x0F);
 +                  }
 +                }
 +
-                 str += String.fromCharCode(x);
-                 break;
-               case '\r':
-                 ch = stream.lookChar();
-                 if (ch == '\n')
-                   stream.skip();
++                strBuf.push(String.fromCharCode(x));
 +                break;
-               case '\n':
++              case 0x0A: case 0x0D: // LF, CR
 +                break;
 +              default:
-                 str += ch;
++                strBuf.push(String.fromCharCode(ch));
 +                break;
 +            }
 +            break;
 +          default:
-             str += ch;
++            strBuf.push(String.fromCharCode(ch));
 +            break;
 +        }
-       } while (!done);
-       return str;
++        if (done) {
++          break;
++        }
++        if (!charBuffered) {
++          ch = this.nextChar();
++        }
++      }
++      return strBuf.join('');
 +    },
-     getName: function Lexer_getName(ch) {
-       var str = '';
-       var stream = this.stream;
-       while (!!(ch = stream.lookChar()) && !specialChars[ch.charCodeAt(0)]) {
-         stream.skip();
-         if (ch == '#') {
-           ch = stream.lookChar();
++    getName: function Lexer_getName() {
++      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) {
-             stream.skip();
-             var x2 = toHexDigit(stream.getChar());
++            var x2 = toHexDigit(this.nextChar());
 +            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 += ch;
++            strBuf.push('#', String.fromCharCode(ch));
 +          }
 +        } else {
-           str += 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);
-       return new Name(str);
++              strBuf.length);
++      }
++      return Name.get(strBuf.join(''));
 +    },
-     getHexString: function Lexer_getHexString(ch) {
-       var str = '';
-       var stream = this.stream;
++    getHexString: function Lexer_getHexString() {
++      var strBuf = this.strBuf;
++      strBuf.length = 0;
++      var ch = this.currentChar;
 +      var isFirstHex = true;
 +      var firstDigit;
 +      var secondDigit;
 +      while (true) {
-         ch = stream.getChar();
-         if (!ch) {
++        if (ch < 0) {
 +          warn('Unterminated hex string');
 +          break;
-         } else if (ch === '>') {
++        } else if (ch === 0x3E) { // '>'
++          this.nextChar();
 +          break;
-         } else if (specialChars[ch.charCodeAt(0)] === 1) {
++        } else if (specialChars[ch] === 1) {
++          ch = this.nextChar();
 +          continue;
 +        } else {
 +          if (isFirstHex) {
 +            firstDigit = toHexDigit(ch);
 +            if (firstDigit === -1) {
 +              warn('Ignoring invalid character "' + ch + '" in hex string');
++              ch = this.nextChar();
 +              continue;
 +            }
 +          } else {
 +            secondDigit = toHexDigit(ch);
 +            if (secondDigit === -1) {
 +              warn('Ignoring invalid character "' + ch + '" in hex string');
++              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
 +      var comment = false;
-       var stream = this.stream;
-       var ch;
++      var ch = this.currentChar;
 +      while (true) {
-         if (!(ch = stream.getChar()))
++        if (ch < 0) {
 +          return EOF;
++        }
 +        if (comment) {
-           if (ch == '\r' || ch == '\n')
++          if (ch === 0x0A || ch == 0x0D) // LF, CR
 +            comment = false;
-         } else if (ch == '%') {
++        } else if (ch === 0x25) { // '%'
 +          comment = true;
-         } else if (specialChars[ch.charCodeAt(0)] != 1) {
++        } else if (specialChars[ch] !== 1) {
 +          break;
 +        }
++        ch = this.nextChar();
 +      }
 +
 +      // start reading token
-       switch (ch) {
-         case '0': case '1': case '2': case '3': case '4':
-         case '5': case '6': case '7': case '8': case '9':
-         case '+': case '-': case '.':
-           return this.getNumber(ch);
-         case '(':
++      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 this.getNumber();
++        case 0x28: // '('
 +          return this.getString();
-         case '/':
-           return this.getName(ch);
++        case 0x2F: // '/'
++          return this.getName();
 +        // array punctuation
-         case '[':
-         case ']':
-           return Cmd.get(ch);
++        case 0x5B: // '['
++          this.nextChar();
++          return Cmd.get('[');
++        case 0x5D: // ']'
++          this.nextChar();
++          return Cmd.get(']');
 +        // hex string or dict punctuation
-         case '<':
-           ch = stream.lookChar();
-           if (ch == '<') {
++        case 0x3C: // '<'
++          ch = this.nextChar();
++          if (ch === 0x3C) {
 +            // dict punctuation
-             stream.skip();
++            this.nextChar();
 +            return Cmd.get('<<');
 +          }
-           return this.getHexString(ch);
++          return this.getHexString();
 +        // dict punctuation
-         case '>':
-           ch = stream.lookChar();
-           if (ch == '>') {
-             stream.skip();
++        case 0x3E: // '>'
++          ch = this.nextChar();
++          if (ch === 0x3E) {
++            this.nextChar();
 +            return Cmd.get('>>');
 +          }
-           return Cmd.get(ch);
-         case '{':
-         case '}':
-           return Cmd.get(ch);
-         // fall through
-         case ')':
++          return Cmd.get('>');
++        case 0x7B: // '{'
++          this.nextChar();
++          return Cmd.get('{');
++        case 0x7D: // '}'
++          this.nextChar();
++          return Cmd.get('}');
++        case 0x29: // ')'
 +          error('Illegal character: ' + ch);
++          break;
 +      }
 +
 +      // command
-       var str = ch;
++      var str = String.fromCharCode(ch);
 +      var knownCommands = this.knownCommands;
 +      var knownCommandFound = knownCommands && (str in knownCommands);
-       while (!!(ch = stream.lookChar()) && !specialChars[ch.charCodeAt(0)]) {
++      while ((ch = this.nextChar()) >= 0 && !specialChars[ch]) {
 +        // stop if known command is found and next character does not make
 +        // the str a command
-         if (knownCommandFound && !((str + ch) in knownCommands))
++        var possibleCommand = str + String.fromCharCode(ch);
++        if (knownCommandFound && !(possibleCommand in knownCommands)) {
 +          break;
-         stream.skip();
++        }
 +        if (str.length == 128)
 +          error('Command token too long: ' + str.length);
-         str += ch;
++        str = possibleCommand;
 +        knownCommandFound = knownCommands && (str in knownCommands);
 +      }
 +      if (str == 'true')
 +        return true;
 +      if (str == 'false')
 +        return false;
 +      if (str == 'null')
 +        return null;
 +      return Cmd.get(str);
 +    },
 +    skipToNextLine: function Lexer_skipToNextLine() {
 +      var stream = this.stream;
-       while (true) {
-         var ch = stream.getChar();
-         if (!ch || ch == '\n')
-           return;
-         if (ch == '\r') {
-           if ((ch = stream.lookChar()) == '\n')
-             stream.skip();
-           return;
++      var ch = this.currentChar;
++      while (ch >= 0) {
++        if (ch === 0x0D) { // CR
++          ch = this.nextChar();
++          if (ch === 0x0A) { // LF
++            this.nextChar();
++          }
++          break;
++        } else if (ch === 0x0A) { // LF
++          this.nextChar();
++          break;
 +        }
++        ch = this.nextChar();
 +      }
-     },
-     skip: function Lexer_skip() {
-       this.stream.skip();
 +    }
 +  };
 +
 +  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) {
 +        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;
 +      }
 +      error('Hints table in linearization table is invalid: ' + index);
 +    },
 +    get length() {
 +      if (!isDict(this.linDict))
 +        return 0;
 +      return this.getInt('L');
 +    },
 +    get hintsOffset() {
 +      return this.getHint(0);
 +    },
 +    get hintsLength() {
 +      return this.getHint(1);
 +    },
 +    get hintsOffset2() {
 +      return this.getHint(2);
 +    },
 +    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');
 +    }
 +  };
 +
 +  return Linearization;
 +})();
 +
 +
 +
- var PatternType = {
-   AXIAL: 2,
-   RADIAL: 3
- };
- 
- var Pattern = (function PatternClosure() {
-   // Constructor should define this.getPattern
-   function Pattern() {
-     error('should not call Pattern constructor');
++var PostScriptParser = (function PostScriptParserClosure() {
++  function PostScriptParser(lexer) {
++    this.lexer = lexer;
++    this.operators = [];
++    this.token = null;
++    this.prev = null;
 +  }
- 
-   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:
-         TODO('Unsupported shading type: ' + type);
-         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));
++  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;
 +      }
-       fn = function radialAxialColorFunction(arg) {
-         var out = [];
-         for (var i = 0, ii = fnArray.length; i < ii; i++) {
-           out.push(fnArray[i](arg)[0]);
++      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;
 +        }
-         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);
++    },
++    parseCondition: function PostScriptParser_parseCondition() {
++      // Add two place holders that will be updated later
++      var conditionLocation = this.operators.length;
++      this.operators.push(null, null);
 +
-         for (var i = 0, ii = colorStops.length; i < ii; ++i) {
-           var c = colorStops[i];
-           grad.addColorStop(c[0], c[1]);
-         }
-         return grad;
-       }
-     };
-   };
++      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';
 +
-   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];
++        this.operators[conditionLocation] = endOfTrue;
++        this.operators[conditionLocation + 1] = 'jz';
 +      } else {
-         error('getPattern type unknown: ' + type);
-       }
- 
-       var matrix = this.matrix;
-       if (matrix) {
-         p0 = Util.applyTransform(p0, matrix);
-         p1 = Util.applyTransform(p1, matrix);
++        error('PS Function: error parsing conditional.');
 +      }
- 
-       return ['RadialAxial', type, this.colorStops, p0, p1, r0, r1];
 +    }
 +  };
- 
-   return RadialAxial;
++  return PostScriptParser;
 +})();
 +
- Shadings.Dummy = (function DummyClosure() {
-   function Dummy() {
-     this.type = 'Pattern';
++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;
 +  }
 +
-   Dummy.fromIR = function Dummy_fromIR() {
-     return {
-       type: 'Pattern',
-       getPattern: function Dummy_fromIR_getPattern() {
-         return 'hotpink';
-       }
-     };
-   };
++  var opCache = {};
 +
-   Dummy.prototype = {
-     getIR: function Dummy_getIR() {
-       return ['Dummy'];
-     }
-   };
-   return Dummy;
- })();
++  PostScriptToken.getOperator = function PostScriptToken_getOperator(op) {
++    var opValue = opCache[op];
++    if (opValue)
++      return opValue;
 +
- var TilingPattern = (function TilingPatternClosure() {
-   var PaintType = {
-     COLORED: 1,
-     UNCOLORED: 2
++    return opCache[op] = new PostScriptToken(PostScriptTokenTypes.OPERATOR, op);
 +  };
-   var MAX_PATTERN_SIZE = 4096;
- 
-   function TilingPattern(IR, color, ctx, objs, commonObjs) {
-     var operatorList = IR[2];
-     this.matrix = IR[3] || [1, 0, 0, 1, 0, 0];
-     var bbox = IR[4];
-     var xstep = IR[5];
-     var ystep = IR[6];
-     var paintType = IR[7];
-     var tilingType = IR[8];
- 
-     TODO('TilingType: ' + tilingType);
- 
-     this.curMatrix = ctx.mozCurrentTransform;
-     this.ctx = ctx;
-     this.type = 'Pattern';
- 
-     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.curMatrix);
-     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 = createScratchCanvas(width, height);
- 
-     // set the new canvas element context as the graphics context
-     var tmpCtx = tmpCanvas.getContext('2d');
-     var graphics = new CanvasGraphics(tmpCtx, commonObjs, objs);
- 
-     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);
++  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;
++})();
 +
-     this.canvas = tmpCanvas;
++var PostScriptLexer = (function PostScriptLexerClosure() {
++  function PostScriptLexer(stream) {
++    this.stream = stream;
++    this.nextChar();
 +  }
- 
-   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 = {
-     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]);
++  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;
 +
-     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();
-       }
-     },
++      // skip comments
++      while (true) {
++        if (ch < 0) {
++          return EOF;
++        }
 +
-     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 = new DeviceRgbCS().getRgb(color, 0);
-           var cssColor = Util.makeCssRgb(rgbColor);
-           context.fillStyle = cssColor;
-           context.strokeStyle = cssColor;
++        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:
-           error('Unsupported paint type: ' + paintType);
++          return PostScriptToken.getOperator(str);
 +      }
 +    },
- 
-     getPattern: function TilingPattern_getPattern() {
-       var matrix = this.matrix;
-       var curMatrix = this.curMatrix;
-       var ctx = this.ctx;
- 
-       ctx.setTransform.apply(ctx, curMatrix);
-       ctx.transform.apply(ctx, matrix);
-       this.scaleToContext();
- 
-       return ctx.createPattern(this.canvas, 'repeat');
++    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 TilingPattern;
++  return PostScriptLexer;
 +})();
 +
 +
- 
 +var Stream = (function StreamClosure() {
 +  function Stream(arrayBuffer, start, length, dict) {
 +    this.bytes = arrayBuffer instanceof Uint8Array ? arrayBuffer :
 +      new Uint8Array(arrayBuffer);
 +    this.start = start || 0;
 +    this.pos = this.start;
 +    this.end = (start + length) || this.bytes.length;
 +    this.dict = dict;
 +  }
 +
 +  // required methods for a stream. if a particular stream does not
 +  // implement these, an error should be thrown
 +  Stream.prototype = {
 +    get length() {
 +      return this.end - this.start;
 +    },
 +    getByte: function Stream_getByte() {
 +      if (this.pos >= this.end)
-         return null;
++        return -1;
 +      return this.bytes[this.pos++];
 +    },
 +    // returns subarray of original buffer
 +    // should only be read
 +    getBytes: function Stream_getBytes(length) {
 +      var bytes = this.bytes;
 +      var pos = this.pos;
 +      var strEnd = this.end;
 +
 +      if (!length)
 +        return bytes.subarray(pos, strEnd);
 +
 +      var end = pos + length;
 +      if (end > strEnd)
 +        end = strEnd;
 +
 +      this.pos = end;
 +      return bytes.subarray(pos, end);
 +    },
-     lookChar: function Stream_lookChar() {
-       if (this.pos >= this.end)
-         return null;
-       return String.fromCharCode(this.bytes[this.pos]);
-     },
-     getChar: function Stream_getChar() {
-       if (this.pos >= this.end)
-         return null;
-       return String.fromCharCode(this.bytes[this.pos++]);
++    peekBytes: function Stream_peekBytes(length) {
++      var bytes = this.getBytes(length);
++      this.pos -= bytes.length;
++      return bytes;
 +    },
 +    skip: function Stream_skip(n) {
 +      if (!n)
 +        n = 1;
 +      this.pos += n;
 +    },
 +    reset: function Stream_reset() {
 +      this.pos = this.start;
 +    },
 +    moveStart: function Stream_moveStart() {
 +      this.start = this.pos;
 +    },
 +    makeSubStream: function Stream_makeSubStream(start, length, dict) {
 +      return new Stream(this.bytes.buffer, start, length, dict);
 +    },
 +    isStream: true
 +  };
 +
 +  return Stream;
 +})();
 +
 +var StringStream = (function StringStreamClosure() {
 +  function StringStream(str) {
 +    var length = str.length;
 +    var bytes = new Uint8Array(length);
 +    for (var n = 0; n < length; ++n)
 +      bytes[n] = str.charCodeAt(n);
 +    Stream.call(this, bytes);
 +  }
 +
 +  StringStream.prototype = Stream.prototype;
 +
 +  return StringStream;
 +})();
 +
 +// super class for the decoding streams
 +var DecodeStream = (function DecodeStreamClosure() {
 +  function DecodeStream() {
 +    this.pos = 0;
 +    this.bufferLength = 0;
 +    this.eof = false;
 +    this.buffer = null;
 +  }
 +
 +  DecodeStream.prototype = {
 +    ensureBuffer: function DecodeStream_ensureBuffer(requested) {
 +      var buffer = this.buffer;
-       var current = buffer ? buffer.byteLength : 0;
-       if (requested < current)
-         return buffer;
++      var current;
++      if (buffer) {
++        current = buffer.byteLength;
++        if (requested <= current) {
++          return buffer;
++        }
++      } else {
++        current = 0;
++      }
 +      var size = 512;
-       while (size < requested)
-         size <<= 1;
++      while (size < requested) {
++        size *= 2;
++      }
 +      var buffer2 = new Uint8Array(size);
-       for (var i = 0; i < current; ++i)
++      for (var i = 0; i < current; ++i) {
 +        buffer2[i] = buffer[i];
++      }
 +      return (this.buffer = buffer2);
 +    },
 +    getByte: function DecodeStream_getByte() {
 +      var pos = this.pos;
 +      while (this.bufferLength <= pos) {
 +        if (this.eof)
-           return null;
++          return -1;
 +        this.readBlock();
 +      }
 +      return this.buffer[this.pos++];
 +    },
 +    getBytes: function DecodeStream_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 {
 +        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);
 +    },
-     lookChar: function DecodeStream_lookChar() {
-       var pos = this.pos;
-       while (this.bufferLength <= pos) {
-         if (this.eof)
-           return null;
-         this.readBlock();
-       }
-       return String.fromCharCode(this.buffer[this.pos]);
-     },
-     getChar: function DecodeStream_getChar() {
-       var pos = this.pos;
-       while (this.bufferLength <= pos) {
-         if (this.eof)
-           return null;
-         this.readBlock();
-       }
-       return String.fromCharCode(this.buffer[this.pos++]);
++    peekBytes: function DecodeStream_peekBytes(length) {
++      var bytes = this.getBytes(length);
++      this.pos -= bytes.length;
++      return bytes;
 +    },
 +    makeSubStream: function DecodeStream_makeSubStream(start, length, dict) {
 +      var end = start + length;
 +      while (this.bufferLength <= end && !this.eof)
 +        this.readBlock();
 +      return new Stream(this.buffer, start, length, dict);
 +    },
-     skip: function DecodeStream_skip(n) {
++    skip: function Stream_skip(n) {
 +      if (!n)
 +        n = 1;
 +      this.pos += n;
 +    },
 +    reset: function DecodeStream_reset() {
 +      this.pos = 0;
++    },
++    getBaseStreams: function DecodeStream_getBaseStreams() {
++      if (this.str && this.str.getBaseStreams) {
++        return this.str.getBaseStreams();
++      }
++      return [];
 +    }
 +  };
 +
 +  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);
 +  }
 +
 +  StreamsSequenceStream.prototype = Object.create(DecodeStream.prototype);
 +
 +  StreamsSequenceStream.prototype.readBlock =
 +    function streamSequenceStreamReadBlock() {
 +
 +    var streams = this.streams;
 +    if (streams.length === 0) {
 +      this.eof = true;
 +      return;
 +    }
 +    var stream = streams.shift();
 +    var chunk = stream.getBytes();
 +    var bufferLength = this.bufferLength;
 +    var newLength = bufferLength + chunk.length;
 +    var buffer = this.ensureBuffer(newLength);
 +    buffer.set(chunk, bufferLength);
 +    this.bufferLength = newLength;
 +  };
 +
++  StreamsSequenceStream.prototype.getBaseStreams =
++    function StreamsSequenceStream_getBaseStreams() {
++
++    var baseStreams = [];
++    for (var i = 0, ii = this.streams.length; i < ii; i++) {
++      var stream = this.streams[i];
++      if (stream.getBaseStreams) {
++        Util.concatenateToArray(baseStreams, stream.getBaseStreams());
++      }
++    }
++    return baseStreams;
++  };
++
 +  return StreamsSequenceStream;
 +})();
 +
 +var FlateStream = (function FlateStreamClosure() {
 +  var codeLenCodeMap = new Uint32Array([
 +    16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
 +  ]);
 +
 +  var lengthDecode = new Uint32Array([
 +    0x00003, 0x00004, 0x00005, 0x00006, 0x00007, 0x00008, 0x00009, 0x0000a,
 +    0x1000b, 0x1000d, 0x1000f, 0x10011, 0x20013, 0x20017, 0x2001b, 0x2001f,
 +    0x30023, 0x3002b, 0x30033, 0x3003b, 0x40043, 0x40053, 0x40063, 0x40073,
 +    0x50083, 0x500a3, 0x500c3, 0x500e3, 0x00102, 0x00102, 0x00102
 +  ]);
 +
 +  var distDecode = new Uint32Array([
 +    0x00001, 0x00002, 0x00003, 0x00004, 0x10005, 0x10007, 0x20009, 0x2000d,
 +    0x30011, 0x30019, 0x40021, 0x40031, 0x50041, 0x50061, 0x60081, 0x600c1,
 +    0x70101, 0x70181, 0x80201, 0x80301, 0x90401, 0x90601, 0xa0801, 0xa0c01,
 +    0xb1001, 0xb1801, 0xc2001, 0xc3001, 0xd4001, 0xd6001
 +  ]);
 +
 +  var fixedLitCodeTab = [new Uint32Array([
 +    0x70100, 0x80050, 0x80010, 0x80118, 0x70110, 0x80070, 0x80030, 0x900c0,
 +    0x70108, 0x80060, 0x80020, 0x900a0, 0x80000, 0x80080, 0x80040, 0x900e0,
 +    0x70104, 0x80058, 0x80018, 0x90090, 0x70114, 0x80078, 0x80038, 0x900d0,
 +    0x7010c, 0x80068, 0x80028, 0x900b0, 0x80008, 0x80088, 0x80048, 0x900f0,
 +    0x70102, 0x80054, 0x80014, 0x8011c, 0x70112, 0x80074, 0x80034, 0x900c8,
 +    0x7010a, 0x80064, 0x80024, 0x900a8, 0x80004, 0x80084, 0x80044, 0x900e8,
 +    0x70106, 0x8005c, 0x8001c, 0x90098, 0x70116, 0x8007c, 0x8003c, 0x900d8,
 +    0x7010e, 0x8006c, 0x8002c, 0x900b8, 0x8000c, 0x8008c, 0x8004c, 0x900f8,
 +    0x70101, 0x80052, 0x80012, 0x8011a, 0x70111, 0x80072, 0x80032, 0x900c4,
 +    0x70109, 0x80062, 0x80022, 0x900a4, 0x80002, 0x80082, 0x80042, 0x900e4,
 +    0x70105, 0x8005a, 0x8001a, 0x90094, 0x70115, 0x8007a, 0x8003a, 0x900d4,
 +    0x7010d, 0x8006a, 0x8002a, 0x900b4, 0x8000a, 0x8008a, 0x8004a, 0x900f4,
 +    0x70103, 0x80056, 0x80016, 0x8011e, 0x70113, 0x80076, 0x80036, 0x900cc,
 +    0x7010b, 0x80066, 0x80026, 0x900ac, 0x80006, 0x80086, 0x80046, 0x900ec,
 +    0x70107, 0x8005e, 0x8001e, 0x9009c, 0x70117, 0x8007e, 0x8003e, 0x900dc,
 +    0x7010f, 0x8006e, 0x8002e, 0x900bc, 0x8000e, 0x8008e, 0x8004e, 0x900fc,
 +    0x70100, 0x80051, 0x80011, 0x80119, 0x70110, 0x80071, 0x80031, 0x900c2,
 +    0x70108, 0x80061, 0x80021, 0x900a2, 0x80001, 0x80081, 0x80041, 0x900e2,
 +    0x70104, 0x80059, 0x80019, 0x90092, 0x70114, 0x80079, 0x80039, 0x900d2,
 +    0x7010c, 0x80069, 0x80029, 0x900b2, 0x80009, 0x80089, 0x80049, 0x900f2,
 +    0x70102, 0x80055, 0x80015, 0x8011d, 0x70112, 0x80075, 0x80035, 0x900ca,
 +    0x7010a, 0x80065, 0x80025, 0x900aa, 0x80005, 0x80085, 0x80045, 0x900ea,
 +    0x70106, 0x8005d, 0x8001d, 0x9009a, 0x70116, 0x8007d, 0x8003d, 0x900da,
 +    0x7010e, 0x8006d, 0x8002d, 0x900ba, 0x8000d, 0x8008d, 0x8004d, 0x900fa,
 +    0x70101, 0x80053, 0x80013, 0x8011b, 0x70111, 0x80073, 0x80033, 0x900c6,
 +    0x70109, 0x80063, 0x80023, 0x900a6, 0x80003, 0x80083, 0x80043, 0x900e6,
 +    0x70105, 0x8005b, 0x8001b, 0x90096, 0x70115, 0x8007b, 0x8003b, 0x900d6,
 +    0x7010d, 0x8006b, 0x8002b, 0x900b6, 0x8000b, 0x8008b, 0x8004b, 0x900f6,
 +    0x70103, 0x80057, 0x80017, 0x8011f, 0x70113, 0x80077, 0x80037, 0x900ce,
 +    0x7010b, 0x80067, 0x80027, 0x900ae, 0x80007, 0x80087, 0x80047, 0x900ee,
 +    0x70107, 0x8005f, 0x8001f, 0x9009e, 0x70117, 0x8007f, 0x8003f, 0x900de,
 +    0x7010f, 0x8006f, 0x8002f, 0x900be, 0x8000f, 0x8008f, 0x8004f, 0x900fe,
 +    0x70100, 0x80050, 0x80010, 0x80118, 0x70110, 0x80070, 0x80030, 0x900c1,
 +    0x70108, 0x80060, 0x80020, 0x900a1, 0x80000, 0x80080, 0x80040, 0x900e1,
 +    0x70104, 0x80058, 0x80018, 0x90091, 0x70114, 0x80078, 0x80038, 0x900d1,
 +    0x7010c, 0x80068, 0x80028, 0x900b1, 0x80008, 0x80088, 0x80048, 0x900f1,
 +    0x70102, 0x80054, 0x80014, 0x8011c, 0x70112, 0x80074, 0x80034, 0x900c9,
 +    0x7010a, 0x80064, 0x80024, 0x900a9, 0x80004, 0x80084, 0x80044, 0x900e9,
 +    0x70106, 0x8005c, 0x8001c, 0x90099, 0x70116, 0x8007c, 0x8003c, 0x900d9,
 +    0x7010e, 0x8006c, 0x8002c, 0x900b9, 0x8000c, 0x8008c, 0x8004c, 0x900f9,
 +    0x70101, 0x80052, 0x80012, 0x8011a, 0x70111, 0x80072, 0x80032, 0x900c5,
 +    0x70109, 0x80062, 0x80022, 0x900a5, 0x80002, 0x80082, 0x80042, 0x900e5,
 +    0x70105, 0x8005a, 0x8001a, 0x90095, 0x70115, 0x8007a, 0x8003a, 0x900d5,
 +    0x7010d, 0x8006a, 0x8002a, 0x900b5, 0x8000a, 0x8008a, 0x8004a, 0x900f5,
 +    0x70103, 0x80056, 0x80016, 0x8011e, 0x70113, 0x80076, 0x80036, 0x900cd,
 +    0x7010b, 0x80066, 0x80026, 0x900ad, 0x80006, 0x80086, 0x80046, 0x900ed,
 +    0x70107, 0x8005e, 0x8001e, 0x9009d, 0x70117, 0x8007e, 0x8003e, 0x900dd,
 +    0x7010f, 0x8006e, 0x8002e, 0x900bd, 0x8000e, 0x8008e, 0x8004e, 0x900fd,
 +    0x70100, 0x80051, 0x80011, 0x80119, 0x70110, 0x80071, 0x80031, 0x900c3,
 +    0x70108, 0x80061, 0x80021, 0x900a3, 0x80001, 0x80081, 0x80041, 0x900e3,
 +    0x70104, 0x80059, 0x80019, 0x90093, 0x70114, 0x80079, 0x80039, 0x900d3,
 +    0x7010c, 0x80069, 0x80029, 0x900b3, 0x80009, 0x80089, 0x80049, 0x900f3,
 +    0x70102, 0x80055, 0x80015, 0x8011d, 0x70112, 0x80075, 0x80035, 0x900cb,
 +    0x7010a, 0x80065, 0x80025, 0x900ab, 0x80005, 0x80085, 0x80045, 0x900eb,
 +    0x70106, 0x8005d, 0x8001d, 0x9009b, 0x70116, 0x8007d, 0x8003d, 0x900db,
 +    0x7010e, 0x8006d, 0x8002d, 0x900bb, 0x8000d, 0x8008d, 0x8004d, 0x900fb,
 +    0x70101, 0x80053, 0x80013, 0x8011b, 0x70111, 0x80073, 0x80033, 0x900c7,
 +    0x70109, 0x80063, 0x80023, 0x900a7, 0x80003, 0x80083, 0x80043, 0x900e7,
 +    0x70105, 0x8005b, 0x8001b, 0x90097, 0x70115, 0x8007b, 0x8003b, 0x900d7,
 +    0x7010d, 0x8006b, 0x8002b, 0x900b7, 0x8000b, 0x8008b, 0x8004b, 0x900f7,
 +    0x70103, 0x80057, 0x80017, 0x8011f, 0x70113, 0x80077, 0x80037, 0x900cf,
 +    0x7010b, 0x80067, 0x80027, 0x900af, 0x80007, 0x80087, 0x80047, 0x900ef,
 +    0x70107, 0x8005f, 0x8001f, 0x9009f, 0x70117, 0x8007f, 0x8003f, 0x900df,
 +    0x7010f, 0x8006f, 0x8002f, 0x900bf, 0x8000f, 0x8008f, 0x8004f, 0x900ff
 +  ]), 9];
 +
 +  var fixedDistCodeTab = [new Uint32Array([
 +    0x50000, 0x50010, 0x50008, 0x50018, 0x50004, 0x50014, 0x5000c, 0x5001c,
 +    0x50002, 0x50012, 0x5000a, 0x5001a, 0x50006, 0x50016, 0x5000e, 0x00000,
 +    0x50001, 0x50011, 0x50009, 0x50019, 0x50005, 0x50015, 0x5000d, 0x5001d,
 +    0x50003, 0x50013, 0x5000b, 0x5001b, 0x50007, 0x50017, 0x5000f, 0x00000
 +  ]), 5];
 +
 +  function FlateStream(stream) {
 +    var bytes = stream.getBytes();
 +    var bytesPos = 0;
 +
 +    this.dict = stream.dict;
 +    var cmf = bytes[bytesPos++];
 +    var flg = bytes[bytesPos++];
 +    if (cmf == -1 || flg == -1)
 +      error('Invalid header in flate stream: ' + cmf + ', ' + flg);
 +    if ((cmf & 0x0f) != 0x08)
 +      error('Unknown compression method in flate stream: ' + cmf + ', ' + flg);
 +    if ((((cmf << 8) + flg) % 31) !== 0)
 +      error('Bad FCHECK in flate stream: ' + cmf + ', ' + flg);
 +    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);
 +  }
 +
 +  FlateStream.prototype = Object.create(DecodeStream.prototype);
 +
 +  FlateStream.prototype.getBits = function FlateStream_getBits(bits) {
 +    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')
 +        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 codes = table[0];
 +    var maxLen = table[1];
 +    var codeSize = this.codeSize;
 +    var codeBuf = this.codeBuf;
 +    var bytes = this.bytes;
 +    var bytesPos = this.bytesPos;
 +
 +    while (codeSize < maxLen) {
 +      var b;
 +      if (typeof (b = bytes[bytesPos++]) == 'undefined')
 +        error('Bad encoding in flate stream');
 +      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)
 +      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) {
 +    var n = lengths.length;
 +
 +    // find max code length
 +    var maxLen = 0;
 +    for (var i = 0; i < n; ++i) {
 +      if (lengths[i] > maxLen)
 +        maxLen = lengths[i];
 +    }
 +
 +    // build the table
 +    var size = 1 << maxLen;
 +    var codes = new Uint32Array(size);
 +    for (var len = 1, code = 0, skip = 2;
 +         len <= maxLen;
 +         ++len, code <<= 1, skip <<= 1) {
 +      for (var val = 0; val < n; ++val) {
 +        if (lengths[val] == len) {
 +          // bit-reverse the code
 +          var code2 = 0;
 +          var t = code;
 +          for (var i = 0; i < len; ++i) {
 +            code2 = (code2 << 1) | (t & 1);
 +            t >>= 1;
 +          }
 +
 +          // fill the table entries
 +          for (var i = code2; i < size; i += skip)
 +            codes[i] = (len << 16) | val;
 +
 +          ++code;
 +        }
 +      }
 +    }
 +
 +    return [codes, maxLen];
 +  };
 +
 +  FlateStream.prototype.readBlock = function FlateStream_readBlock() {
 +    // read block header
 +    var hdr = this.getBits(3);
 +    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')
 +        error('Bad block header in flate stream');
 +      var blockLen = b;
 +      if (typeof (b = bytes[bytesPos++]) == 'undefined')
 +        error('Bad block header in flate stream');
 +      blockLen |= (b << 8);
 +      if (typeof (b = bytes[bytesPos++]) == 'undefined')
 +        error('Bad block header in flate stream');
 +      var check = b;
 +      if (typeof (b = bytes[bytesPos++]) == 'undefined')
 +        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');
++      }
 +
 +      this.codeBuf = 0;
 +      this.codeSize = 0;
 +
 +      var bufferLength = this.bufferLength;
 +      var buffer = this.ensureBuffer(bufferLength + blockLen);
 +      var end = bufferLength + blockLen;
 +      this.bufferLength = end;
-       for (var n = bufferLength; n < end; ++n) {
-         if (typeof (b = bytes[bytesPos++]) == 'undefined') {
++      if (blockLen === 0) {
++        if (typeof bytes[bytesPos] == 'undefined') {
 +          this.eof = true;
-           break;
 +        }
-         buffer[n] = b;
++      } else {
++        for (var n = bufferLength; n < end; ++n) {
++          if (typeof (b = bytes[bytesPos++]) == 'undefined') {
++            this.eof = true;
++            break;
++          }
++          buffer[n] = b;
++        }
 +      }
 +      this.bytesPos = bytesPos;
 +      return;
 +    }
 +
 +    var litCodeTable;
 +    var distCodeTable;
 +    if (hdr == 1) { // compressed block, fixed codes
 +      litCodeTable = fixedLitCodeTab;
 +      distCodeTable = fixedDistCodeTab;
 +    } 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;
 +
 +      // build the code lengths code table
 +      var codeLenCodeLengths = new Uint8Array(codeLenCodeMap.length);
 +
 +      for (var 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;
 +      var codes = numLitCodes + numDistCodes;
 +      var codeLengths = new Uint8Array(codes);
 +      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);
 +        } else {
 +          codeLengths[i++] = len = code;
 +          continue;
 +        }
 +
 +        var repeatLength = this.getBits(bitsLength) + bitsOffset;
 +        while (repeatLength-- > 0)
 +          codeLengths[i++] = what;
 +      }
 +
 +      litCodeTable =
 +        this.generateHuffmanTable(codeLengths.subarray(0, numLitCodes));
 +      distCodeTable =
 +        this.generateHuffmanTable(codeLengths.subarray(numLitCodes, codes));
 +    } else {
 +      error('Unknown block type in flate stream');
 +    }
 +
 +    var buffer = this.buffer;
 +    var limit = buffer ? buffer.length : 0;
 +    var pos = this.bufferLength;
 +    while (true) {
 +      var code1 = this.getCode(litCodeTable);
 +      if (code1 < 256) {
 +        if (pos + 1 >= limit) {
 +          buffer = this.ensureBuffer(pos + 1);
 +          limit = buffer.length;
 +        }
 +        buffer[pos++] = code1;
 +        continue;
 +      }
 +      if (code1 == 256) {
 +        this.bufferLength = pos;
 +        return;
 +      }
 +      code1 -= 257;
 +      code1 = lengthDecode[code1];
 +      var code2 = code1 >> 16;
 +      if (code2 > 0)
 +        code2 = this.getBits(code2);
 +      var len = (code1 & 0xffff) + code2;
 +      code1 = this.getCode(distCodeTable);
 +      code1 = distDecode[code1];
 +      code2 = code1 >> 16;
 +      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)
 +        buffer[pos] = buffer[pos - dist];
 +    }
 +  };
 +
 +  return FlateStream;
 +})();
 +
 +var PredictorStream = (function PredictorStreamClosure() {
-   function PredictorStream(stream, params) {
++  function PredictorStream(str, params) {
 +    var predictor = this.predictor = params.get('Predictor') || 1;
 +
 +    if (predictor <= 1)
-       return stream; // no prediction
++      return str; // no prediction
 +    if (predictor !== 2 && (predictor < 10 || predictor > 15))
 +      error('Unsupported predictor: ' + predictor);
 +
 +    if (predictor === 2)
 +      this.readBlock = this.readBlockTiff;
 +    else
 +      this.readBlock = this.readBlockPng;
 +
-     this.stream = stream;
-     this.dict = stream.dict;
++    this.str = str;
++    this.dict = str.dict;
 +
 +    var colors = this.colors = params.get('Colors') || 1;
 +    var bits = this.bits = params.get('BitsPerComponent') || 8;
 +    var columns = this.columns = params.get('Columns') || 1;
 +
 +    this.pixBytes = (colors * bits + 7) >> 3;
 +    this.rowBytes = (columns * colors * bits + 7) >> 3;
 +
 +    DecodeStream.call(this);
 +    return this;
 +  }
 +
 +  PredictorStream.prototype = Object.create(DecodeStream.prototype);
 +
 +  PredictorStream.prototype.readBlockTiff =
 +    function predictorStreamReadBlockTiff() {
 +    var rowBytes = this.rowBytes;
 +
 +    var bufferLength = this.bufferLength;
 +    var buffer = this.ensureBuffer(bufferLength + rowBytes);
 +
 +    var bits = this.bits;
 +    var colors = this.colors;
 +
-     var rawBytes = this.stream.getBytes(rowBytes);
++    var rawBytes = this.str.getBytes(rowBytes);
++    this.eof = !rawBytes.length;
++    if (this.eof) {
++      return;
++    }
 +
 +    var inbuf = 0, outbuf = 0;
 +    var inbits = 0, outbits = 0;
 +    var pos = bufferLength;
 +
 +    if (bits === 1) {
 +      for (var i = 0; i < rowBytes; ++i) {
 +        var c = rawBytes[i];
 +        inbuf = (inbuf << 8) | c;
 +        // bitwise addition is exclusive or
 +        // first shift inbuf and then add
 +        buffer[pos++] = (c ^ (inbuf >> colors)) & 0xFF;
 +        // truncate inbuf (assumes colors < 16)
 +        inbuf &= 0xFFFF;
 +      }
 +    } else if (bits === 8) {
 +      for (var i = 0; i < colors; ++i)
 +        buffer[pos++] = rawBytes[i];
 +      for (; i < rowBytes; ++i) {
 +        buffer[pos] = buffer[pos - colors] + rawBytes[i];
 +        pos++;
 +      }
 +    } else {
 +      var compArray = new Uint8Array(colors + 1);
 +      var bitMask = (1 << bits) - 1;
 +      var j = 0, k = bufferLength;
 +      var columns = this.columns;
 +      for (var i = 0; i < columns; ++i) {
 +        for (var kk = 0; kk < colors; ++kk) {
 +          if (inbits < bits) {
 +            inbuf = (inbuf << 8) | (rawBytes[j++] & 0xFF);
 +            inbits += 8;
 +          }
 +          compArray[kk] = (compArray[kk] +
 +                           (inbuf >> (inbits - bits))) & bitMask;
 +          inbits -= bits;
 +          outbuf = (outbuf << bits) | compArray[kk];
 +          outbits += bits;
 +          if (outbits >= 8) {
 +            buffer[k++] = (outbuf >> (outbits - 8)) & 0xFF;
 +            outbits -= 8;
 +          }
 +        }
 +      }
 +      if (outbits > 0) {
 +        buffer[k++] = (outbuf << (8 - outbits)) +
 +        (inbuf & ((1 << (8 - outbits)) - 1));
 +      }
 +    }
 +    this.bufferLength += rowBytes;
 +  };
 +
 +  PredictorStream.prototype.readBlockPng =
 +    function predictorStreamReadBlockPng() {
 +
 +    var rowBytes = this.rowBytes;
 +    var pixBytes = this.pixBytes;
 +
-     var predictor = this.stream.getByte();
-     var rawBytes = this.stream.getBytes(rowBytes);
++    var predictor = this.str.getByte();
++    var rawBytes = this.str.getBytes(rowBytes);
++    this.eof = !rawBytes.length;
++    if (this.eof) {
++      return;
++    }
 +
 +    var bufferLength = this.bufferLength;
 +    var buffer = this.ensureBuffer(bufferLength + rowBytes);
 +
 +    var prevRow = buffer.subarray(bufferLength - rowBytes, bufferLength);
 +    if (prevRow.length === 0)
 +      prevRow = new Uint8Array(rowBytes);
 +
 +    var j = bufferLength;
 +    switch (predictor) {
 +      case 0:
 +        for (var i = 0; i < rowBytes; ++i)
 +          buffer[j++] = rawBytes[i];
 +        break;
 +      case 1:
 +        for (var 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)
 +          buffer[j++] = (prevRow[i] + rawBytes[i]) & 0xFF;
 +        break;
 +      case 3:
 +        for (var 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;
 +          j++;
 +        }
 +        break;
 +      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];
 +          buffer[j++] = up + c;
 +        }
 +        for (; i < rowBytes; ++i) {
 +          var 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)
 +            pa = -pa;
 +          var pb = p - up;
 +          if (pb < 0)
 +            pb = -pb;
 +          var pc = p - upLeft;
 +          if (pc < 0)
 +            pc = -pc;
 +
 +          var c = rawBytes[i];
 +          if (pa <= pb && pa <= pc)
 +            buffer[j++] = left + c;
 +          else if (pb <= pc)
 +            buffer[j++] = up + c;
 +          else
 +            buffer[j++] = upLeft + c;
 +        }
 +        break;
 +      default:
 +        error('Unsupported predictor: ' + predictor);
 +    }
 +    this.bufferLength += rowBytes;
 +  };
 +
 +  return PredictorStream;
 +})();
 +
 +/**
 + * Depending on the type of JPEG a JpegStream is handled in different ways. For
 + * JPEG's that are supported natively such as DeviceGray and DeviceRGB the image
 + * data is stored and then loaded by the browser.  For unsupported JPEG's we use
 + * a library to decode these images and the stream behaves like all the other
 + * DecodeStreams.
 + */
 +var JpegStream = (function JpegStreamClosure() {
-   function isAdobeImage(bytes) {
-     var maxBytesScanned = Math.max(bytes.length - 16, 1024);
-     // Looking for APP14, 'Adobe'
-     for (var i = 0; i < maxBytesScanned; ++i) {
-       if (bytes[i] == 0xFF && bytes[i + 1] == 0xEE &&
-           bytes[i + 2] === 0x00 && bytes[i + 3] == 0x0E &&
-           bytes[i + 4] == 0x41 && bytes[i + 5] == 0x64 &&
-           bytes[i + 6] == 0x6F && bytes[i + 7] == 0x62 &&
-           bytes[i + 8] == 0x65 && bytes[i + 9] === 0x00)
-           return true;
-       // scanning until frame tag
-       if (bytes[i] == 0xFF && bytes[i + 1] == 0xC0)
-         break;
-     }
-     return false;
-   }
- 
-   function fixAdobeImage(bytes) {
-     // Inserting 'EMBED' marker after JPEG signature
-     var embedMarker = new Uint8Array([0xFF, 0xEC, 0, 8, 0x45, 0x4D, 0x42, 0x45,
-                                       0x44, 0]);
-     var newBytes = new Uint8Array(bytes.length + embedMarker.length);
-     newBytes.set(bytes, embedMarker.length);
-     // copy JPEG header
-     newBytes[0] = bytes[0];
-     newBytes[1] = bytes[1];
-     newBytes.set(embedMarker, 2);
-     return newBytes;
-   }
- 
 +  function JpegStream(bytes, dict, xref) {
 +    // TODO: per poppler, some images may have 'junk' before that
 +    // need to be removed
 +    this.dict = dict;
- 
-     this.isAdobeImage = false;
-     this.colorTransform = dict.get('ColorTransform') || -1;
- 
-     if (isAdobeImage(bytes)) {
-       this.isAdobeImage = true;
-       bytes = fixAdobeImage(bytes);
-     }
- 
 +    this.bytes = bytes;
 +
 +    DecodeStream.call(this);
 +  }
 +
 +  JpegStream.prototype = Object.create(DecodeStream.prototype);
 +
 +  JpegStream.prototype.ensureBuffer = function JpegStream_ensureBuffer(req) {
 +    if (this.bufferLength)
 +      return;
 +    try {
 +      var jpegImage = new JpegImage();
 +      if (this.colorTransform != -1)
 +        jpegImage.colorTransform = this.colorTransform;
 +      jpegImage.parse(this.bytes);
 +      var width = jpegImage.width;
 +      var height = jpegImage.height;
 +      var data = jpegImage.getData(width, height);
 +      this.buffer = data;
 +      this.bufferLength = data.length;
++      this.eof = true;
 +    } catch (e) {
 +      error('JPEG error: ' + e);
 +    }
 +  };
 +  JpegStream.prototype.getIR = function JpegStream_getIR() {
-     return bytesToString(this.bytes);
-   };
-   JpegStream.prototype.getChar = function JpegStream_getChar() {
-     error('internal error: getChar is not valid on JpegStream');
++    return PDFJS.createObjectURL(this.bytes, 'image/jpeg');
 +  };
 +  /**
 +   * Checks if the image can be decoded and displayed by the browser without any
 +   * further processing such as color space conversions.
 +   */
 +  JpegStream.prototype.isNativelySupported =
 +    function JpegStream_isNativelySupported(xref, res) {
 +    var cs = ColorSpace.parse(this.dict.get('ColorSpace', 'CS'), xref, res);
-     // when bug 674619 lands, let's check if browser can do
-     // normal cmyk and then we won't need to decode in JS
-     if (cs.name === 'DeviceGray' || cs.name === 'DeviceRGB')
-       return true;
-     if (cs.name === 'DeviceCMYK' && !this.isAdobeImage &&
-         this.colorTransform < 1)
-       return true;
-     return false;
++    return cs.name === 'DeviceGray' || cs.name === 'DeviceRGB';
 +  };
 +  /**
 +   * Checks if the image can be decoded by the browser.
 +   */
 +  JpegStream.prototype.isNativelyDecodable =
 +    function JpegStream_isNativelyDecodable(xref, res) {
 +    var cs = ColorSpace.parse(this.dict.get('ColorSpace', 'CS'), xref, res);
 +    var numComps = cs.numComps;
-     if (numComps == 1 || numComps == 3)
-       return true;
- 
-     return false;
++    return numComps == 1 || numComps == 3;
 +  };
 +
 +  return JpegStream;
 +})();
 +
 +/**
 + * For JPEG 2000's we use a library to decode these images and
 + * the stream behaves like all the other DecodeStreams.
 + */
 +var JpxStream = (function JpxStreamClosure() {
 +  function JpxStream(bytes, dict) {
 +    this.dict = dict;
 +    this.bytes = bytes;
 +
 +    DecodeStream.call(this);
 +  }
 +
 +  JpxStream.prototype = Object.create(DecodeStream.prototype);
 +
 +  JpxStream.prototype.ensureBuffer = function JpxStream_ensureBuffer(req) {
 +    if (this.bufferLength)
 +      return;
 +
 +    var jpxImage = new JpxImage();
 +    jpxImage.parse(this.bytes);
 +
 +    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 data = new Uint8Array(width * height * componentsCount);
 +
 +    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 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;
 +      }
 +    }
 +
 +    this.buffer = data;
 +    this.bufferLength = data.length;
-   };
-   JpxStream.prototype.getChar = function JpxStream_getChar() {
-     error('internal error: getChar is not valid on JpxStream');
++    this.eof = true;
 +  };
 +
 +  return JpxStream;
 +})();
 +
 +/**
 + * For JBIG2's we use a library to decode these images and
 + * the stream behaves like all the other DecodeStreams.
 + */
 +var Jbig2Stream = (function Jbig2StreamClosure() {
 +  function Jbig2Stream(bytes, dict) {
 +    this.dict = dict;
 +    this.bytes = bytes;
 +
 +    DecodeStream.call(this);
 +  }
 +
 +  Jbig2Stream.prototype = Object.create(DecodeStream.prototype);
 +
 +  Jbig2Stream.prototype.ensureBuffer = function Jbig2Stream_ensureBuffer(req) {
 +    if (this.bufferLength)
 +      return;
 +
 +    var jbig2Image = new Jbig2Image();
 +
 +    var chunks = [], decodeParams = this.dict.get('DecodeParms');
++
++    // According to the PDF specification, DecodeParms can be either
++    // a dictionary, or an array whose elements are dictionaries.
++    if (isArray(decodeParams)) {
++      if (decodeParams.length > 1) {
++        warn('JBIG2 - \'DecodeParms\' array with multiple elements ' +
++             'not supported.');
++      }
++      decodeParams = decodeParams[0];
++    }
 +    if (decodeParams && decodeParams.has('JBIG2Globals')) {
 +      var globalsStream = decodeParams.get('JBIG2Globals');
 +      var globals = globalsStream.getBytes();
 +      chunks.push({data: globals, start: 0, end: globals.length});
 +    }
 +    chunks.push({data: this.bytes, start: 0, end: this.bytes.length});
 +    var data = jbig2Image.parseChunks(chunks);
 +    var dataLength = data.length;
 +
 +    // JBIG2 had black as 1 and white as 0, inverting the colors
 +    for (var i = 0; i < dataLength; i++)
 +      data[i] ^= 0xFF;
 +
 +    this.buffer = data;
 +    this.bufferLength = dataLength;
-   };
-   Jbig2Stream.prototype.getChar = function Jbig2Stream_getChar() {
-     error('internal error: getChar is not valid on Jbig2Stream');
++    this.eof = true;
 +  };
 +
 +  return Jbig2Stream;
 +})();
 +
 +var DecryptStream = (function DecryptStreamClosure() {
 +  function DecryptStream(str, decrypt) {
 +    this.str = str;
 +    this.dict = str.dict;
 +    this.decrypt = decrypt;
++    this.nextChunk = null;
++    this.initialized = false;
 +
 +    DecodeStream.call(this);
 +  }
 +
 +  var chunkSize = 512;
 +
 +  DecryptStream.prototype = Object.create(DecodeStream.prototype);
 +
 +  DecryptStream.prototype.readBlock = function DecryptStream_readBlock() {
-     var chunk = this.str.getBytes(chunkSize);
++    var chunk;
++    if (this.initialized) {
++      chunk = this.nextChunk;
++    } else {
++      chunk = this.str.getBytes(chunkSize);
++      this.initialized = true;
++    }
 +    if (!chunk || chunk.length === 0) {
 +      this.eof = true;
 +      return;
 +    }
++    this.nextChunk = this.str.getBytes(chunkSize);
++    var hasMoreData = this.nextChunk && this.nextChunk.length > 0;
++
 +    var decrypt = this.decrypt;
-     chunk = decrypt(chunk);
++    chunk = decrypt(chunk, !hasMoreData);
 +
 +    var bufferLength = this.bufferLength;
 +    var i, n = chunk.length;
 +    var buffer = this.ensureBuffer(bufferLength + n);
 +    for (i = 0; i < n; i++)
 +      buffer[bufferLength++] = chunk[i];
 +    this.bufferLength = bufferLength;
 +  };
 +
 +  return DecryptStream;
 +})();
 +
 +var Ascii85Stream = (function Ascii85StreamClosure() {
 +  function Ascii85Stream(str) {
 +    this.str = str;
 +    this.dict = str.dict;
 +    this.input = new Uint8Array(5);
 +
 +    DecodeStream.call(this);
 +  }
 +
 +  Ascii85Stream.prototype = Object.create(DecodeStream.prototype);
 +
 +  Ascii85Stream.prototype.readBlock = function Ascii85Stream_readBlock() {
-     var tildaCode = '~'.charCodeAt(0);
-     var zCode = 'z'.charCodeAt(0);
++    var TILDA_CHAR = 0x7E; // '~'
++    var Z_LOWER_CHAR = 0x7A; // 'z'
++    var EOF = -1;
++
 +    var str = this.str;
 +
 +    var c = str.getByte();
-     while (Lexer.isSpace(String.fromCharCode(c)))
++    while (Lexer.isSpace(c)) {
 +      c = str.getByte();
++    }
 +
-     if (!c || c === tildaCode) {
++    if (c === EOF || c === TILDA_CHAR) {
 +      this.eof = true;
 +      return;
 +    }
 +
 +    var bufferLength = this.bufferLength, buffer;
 +
 +    // special code for z
-     if (c == zCode) {
++    if (c == Z_LOWER_CHAR) {
 +      buffer = this.ensureBuffer(bufferLength + 4);
 +      for (var 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) {
 +        c = str.getByte();
-         while (Lexer.isSpace(String.fromCharCode(c)))
++        while (Lexer.isSpace(c)) {
 +          c = str.getByte();
++        }
 +
 +        input[i] = c;
 +
-         if (!c || c == tildaCode)
++        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)
 +          input[i] = 0x21 + 84;
 +        this.eof = true;
 +      }
 +      var t = 0;
 +      for (var i = 0; i < 5; ++i)
 +        t = t * 85 + (input[i] - 0x21);
 +
 +      for (var i = 3; i >= 0; --i) {
 +        buffer[bufferLength + i] = t & 0xFF;
 +        t >>= 8;
 +      }
 +    }
 +  };
 +
 +  return Ascii85Stream;
 +})();
 +
 +var AsciiHexStream = (function AsciiHexStreamClosure() {
 +  function AsciiHexStream(str) {
 +    this.str = str;
 +    this.dict = str.dict;
 +
++    this.firstDigit = -1;
++
 +    DecodeStream.call(this);
 +  }
 +
-   var hexvalueMap = {
-       9: -1, // \t
-       32: -1, // space
-       48: 0,
-       49: 1,
-       50: 2,
-       51: 3,
-       52: 4,
-       53: 5,
-       54: 6,
-       55: 7,
-       56: 8,
-       57: 9,
-       65: 10,
-       66: 11,
-       67: 12,
-       68: 13,
-       69: 14,
-       70: 15,
-       97: 10,
-       98: 11,
-       99: 12,
-       100: 13,
-       101: 14,
-       102: 15
-   };
- 
 +  AsciiHexStream.prototype = Object.create(DecodeStream.prototype);
 +
 +  AsciiHexStream.prototype.readBlock = function AsciiHexStream_readBlock() {
-     var gtCode = '>'.charCodeAt(0), bytes = this.str.getBytes(), c, n,
-         decodeLength, buffer, bufferLength, i, length;
++    var UPSTREAM_BLOCK_SIZE = 8000;
++    var bytes = this.str.getBytes(UPSTREAM_BLOCK_SIZE);
++    if (!bytes.length) {
++      this.eof = true;
++      return;
++    }
 +
-     decodeLength = (bytes.length + 1) >> 1;
-     buffer = this.ensureBuffer(this.bufferLength + decodeLength);
-     bufferLength = this.bufferLength;
++    var maxDecodeLength = (bytes.length + 1) >> 1;
++    var buffer = this.ensureBuffer(this.bufferLength + maxDecodeLength);
++    var bufferLength = this.bufferLength;
 +
-     for (i = 0, length = bytes.length; i < length; i++) {
-       c = hexvalueMap[bytes[i]];
-       while (c == -1 && (i + 1) < length) {
-         c = hexvalueMap[bytes[++i]];
++    var firstDigit = this.firstDigit;
++    for (var i = 0, ii = bytes.length; i < ii; i++) {
++      var ch = bytes[i], digit;
++      if (ch >= 0x30 && ch <= 0x39) { // '0'-'9'
++        digit = ch & 0x0F;
++      } else if ((ch >= 0x41 && ch <= 0x46) || (ch >= 0x61 && ch <= 0x66)) {
++        // 'A'-'Z', 'a'-'z'
++        digit = (ch & 0x0F) + 9;
++      } else if (ch === 0x3E) { // '>'
++        this.eof = true;
++        break;
++      } else { // probably whitespace
++        continue; // ignoring
 +      }
- 
-       if ((i + 1) < length && (bytes[i + 1] !== gtCode)) {
-         n = hexvalueMap[bytes[++i]];
-         buffer[bufferLength++] = c * 16 + n;
++      if (firstDigit < 0) {
++        firstDigit = digit;
 +      } else {
-         // EOD marker at an odd number, behave as if a 0 followed the last
-         // digit.
-         if (bytes[i] !== gtCode) {
-           buffer[bufferLength++] = c * 16;
-         }
++        buffer[bufferLength++] = (firstDigit << 4) | digit;
++        firstDigit = -1;
 +      }
 +    }
- 
++    if (firstDigit >= 0 && this.eof) {
++      // incomplete byte
++      buffer[bufferLength++] = (firstDigit << 4);
++      firstDigit = -1;
++    }
++    this.firstDigit = firstDigit;
 +    this.bufferLength = bufferLength;
-     this.eof = true;
 +  };
 +
 +  return AsciiHexStream;
 +})();
 +
 +var RunLengthStream = (function RunLengthStreamClosure() {
 +  function RunLengthStream(str) {
 +    this.str = str;
 +    this.dict = str.dict;
 +
 +    DecodeStream.call(this);
 +  }
 +
 +  RunLengthStream.prototype = Object.create(DecodeStream.prototype);
 +
 +  RunLengthStream.prototype.readBlock = function RunLengthStream_readBlock() {
 +    // The repeatHeader has following format. The first byte defines type of run
 +    // and amount of bytes to repeat/copy: n = 0 through 127 - copy next n bytes
 +    // (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) {
 +      this.eof = true;
 +      return;
 +    }
 +
 +    var bufferLength = this.bufferLength;
 +    var n = repeatHeader[0];
 +    if (n < 128) {
 +      // copy n bytes
 +      var buffer = this.ensureBuffer(bufferLength + n + 1);
 +      buffer[bufferLength++] = repeatHeader[1];
 +      if (n > 0) {
 +        var source = this.str.getBytes(n);
 +        buffer.set(source, bufferLength);
 +        bufferLength += n;
 +      }
 +    } else {
 +      n = 257 - n;
 +      var b = repeatHeader[1];
 +      var buffer = this.ensureBuffer(bufferLength + n + 1);
 +      for (var i = 0; i < n; i++)
 +        buffer[bufferLength++] = b;
 +    }
 +    this.bufferLength = bufferLength;
 +  };
 +
 +  return RunLengthStream;
 +})();
 +
 +var CCITTFaxStream = (function CCITTFaxStreamClosure() {
 +
 +  var ccittEOL = -2;
 +  var twoDimPass = 0;
 +  var twoDimHoriz = 1;
 +  var twoDimVert0 = 2;
 +  var twoDimVertR1 = 3;
 +  var twoDimVertL1 = 4;
 +  var twoDimVertR2 = 5;
 +  var twoDimVertL2 = 6;
 +  var twoDimVertR3 = 7;
 +  var twoDimVertL3 = 8;
 +
 +  var twoDimTable = [
 +    [-1, -1], [-1, -1],                   // 000000x
 +    [7, twoDimVertL3],                    // 0000010
 +    [7, twoDimVertR3],                    // 0000011
 +    [6, twoDimVertL2], [6, twoDimVertL2], // 000010x
 +    [6, twoDimVertR2], [6, twoDimVertR2], // 000011x
 +    [4, twoDimPass], [4, twoDimPass],     // 0001xxx
 +    [4, twoDimPass], [4, twoDimPass],
 +    [4, twoDimPass], [4, twoDimPass],
 +    [4, twoDimPass], [4, twoDimPass],
 +    [3, twoDimHoriz], [3, twoDimHoriz],   // 001xxxx
 +    [3, twoDimHoriz], [3, twoDimHoriz],
 +    [3, twoDimHoriz], [3, twoDimHoriz],
 +    [3, twoDimHoriz], [3, twoDimHoriz],
 +    [3, twoDimHoriz], [3, twoDimHoriz],
 +    [3, twoDimHoriz], [3, twoDimHoriz],
 +    [3, twoDimHoriz], [3, twoDimHoriz],
 +    [3, twoDimHoriz], [3, twoDimHoriz],
 +    [3, twoDimVertL1], [3, twoDimVertL1], // 010xxxx
 +    [3, twoDimVertL1], [3, twoDimVertL1],
 +    [3, twoDimVertL1], [3, twoDimVertL1],
 +    [3, twoDimVertL1], [3, twoDimVertL1],
 +    [3, twoDimVertL1], [3, twoDimVertL1],
 +    [3, twoDimVertL1], [3, twoDimVertL1],
 +    [3, twoDimVertL1], [3, twoDimVertL1],
 +    [3, twoDimVertL1], [3, twoDimVertL1],
 +    [3, twoDimVertR1], [3, twoDimVertR1], // 011xxxx
 +    [3, twoDimVertR1], [3, twoDimVertR1],
 +    [3, twoDimVertR1], [3, twoDimVertR1],
 +    [3, twoDimVertR1], [3, twoDimVertR1],
 +    [3, twoDimVertR1], [3, twoDimVertR1],
 +    [3, twoDimVertR1], [3, twoDimVertR1],
 +    [3, twoDimVertR1], [3, twoDimVertR1],
 +    [3, twoDimVertR1], [3, twoDimVertR1],
 +    [1, twoDimVert0], [1, twoDimVert0],   // 1xxxxxx
 +    [1, twoDimVert0], [1, twoDimVert0],
 +    [1, twoDimVert0], [1, twoDimVert0],
 +    [1, twoDimVert0], [1, twoDimVert0],
 +    [1, twoDimVert0], [1, twoDimVert0],
 +    [1, twoDimVert0], [1, twoDimVert0],
 +    [1, twoDimVert0], [1, twoDimVert0],
 +    [1, twoDimVert0], [1, twoDimVert0],
 +    [1, twoDimVert0], [1, twoDimVert0],
 +    [1, twoDimVert0], [1, twoDimVert0],
 +    [1, twoDimVert0], [1, twoDimVert0],
 +    [1, twoDimVert0], [1, twoDimVert0],
 +    [1, twoDimVert0], [1, twoDimVert0],
 +    [1, twoDimVert0], [1, twoDimVert0],
 +    [1, twoDimVert0], [1, twoDimVert0],
 +    [1, twoDimVert0], [1, twoDimVert0],
 +    [1, twoDimVert0], [1, twoDimVert0],
 +    [1, twoDimVert0], [1, twoDimVert0],
 +    [1, twoDimVert0], [1, twoDimVert0],
 +    [1, twoDimVert0], [1, twoDimVert0],
 +    [1, twoDimVert0], [1, twoDimVert0],
 +    [1, twoDimVert0], [1, twoDimVert0],
 +    [1, twoDimVert0], [1, twoDimVert0],
 +    [1, twoDimVert0], [1, twoDimVert0],
 +    [1, twoDimVert0], [1, twoDimVert0],
 +    [1, twoDimVert0], [1, twoDimVert0],
 +    [1, twoDimVert0], [1, twoDimVert0],
 +    [1, twoDimVert0], [1, twoDimVert0],
 +    [1, twoDimVert0], [1, twoDimVert0],
 +    [1, twoDimVert0], [1, twoDimVert0],
 +    [1, twoDimVert0], [1, twoDimVert0],
 +    [1, twoDimVert0], [1, twoDimVert0]
 +  ];
 +
 +  var whiteTable1 = [
 +    [-1, -1],                               // 00000
 +    [12, ccittEOL],                         // 00001
 +    [-1, -1], [-1, -1],                     // 0001x
 +    [-1, -1], [-1, -1], [-1, -1], [-1, -1], // 001xx
 +    [-1, -1], [-1, -1], [-1, -1], [-1, -1], // 010xx
 +    [-1, -1], [-1, -1], [-1, -1], [-1, -1], // 011xx
 +    [11, 1792], [11, 1792],                 // 1000x
 +    [12, 1984],                             // 10010
 +    [12, 2048],                             // 10011
 +    [12, 2112],                             // 10100
 +    [12, 2176],                             // 10101
 +    [12, 2240],                             // 10110
 +    [12, 2304],                             // 10111
 +    [11, 1856], [11, 1856],                 // 1100x
 +    [11, 1920], [11, 1920],                 // 1101x
 +    [12, 2368],                             // 11100
 +    [12, 2432],                             // 11101
 +    [12, 2496],                             // 11110
 +    [12, 2560]                              // 11111
 +  ];
 +
 +  var whiteTable2 = [
 +    [-1, -1], [-1, -1], [-1, -1], [-1, -1],     // 0000000xx
 +    [8, 29], [8, 29],                           // 00000010x
 +    [8, 30], [8, 30],                           // 00000011x
 +    [8, 45], [8, 45],                           // 00000100x
 +    [8, 46], [8, 46],                           // 00000101x
 +    [7, 22], [7, 22], [7, 22], [7, 22],         // 0000011xx
 +    [7, 23], [7, 23], [7, 23], [7, 23],         // 0000100xx
 +    [8, 47], [8, 47],                           // 00001010x
 +    [8, 48], [8, 48],                           // 00001011x
 +    [6, 13], [6, 13], [6, 13], [6, 13],         // 000011xxx
 +    [6, 13], [6, 13], [6, 13], [6, 13],
 +    [7, 20], [7, 20], [7, 20], [7, 20],         // 0001000xx
 +    [8, 33], [8, 33],                           // 00010010x
 +    [8, 34], [8, 34],                           // 00010011x
 +    [8, 35], [8, 35],                           // 00010100x
 +    [8, 36], [8, 36],                           // 00010101x
 +    [8, 37], [8, 37],                           // 00010110x
 +    [8, 38], [8, 38],                           // 00010111x
 +    [7, 19], [7, 19], [7, 19], [7, 19],         // 0001100xx
 +    [8, 31], [8, 31],                           // 00011010x
 +    [8, 32], [8, 32],                           // 00011011x
 +    [6, 1], [6, 1], [6, 1], [6, 1],             // 000111xxx
 +    [6, 1], [6, 1], [6, 1], [6, 1],
 +    [6, 12], [6, 12], [6, 12], [6, 12],         // 001000xxx
 +    [6, 12], [6, 12], [6, 12], [6, 12],
 +    [8, 53], [8, 53],                           // 00100100x
 +    [8, 54], [8, 54],                           // 00100101x
 +    [7, 26], [7, 26], [7, 26], [7, 26],         // 0010011xx
 +    [8, 39], [8, 39],                           // 00101000x
 +    [8, 40], [8, 40],                           // 00101001x
 +    [8, 41], [8, 41],                           // 00101010x
 +    [8, 42], [8, 42],                           // 00101011x
 +    [8, 43], [8, 43],                           // 00101100x
 +    [8, 44], [8, 44],                           // 00101101x
 +    [7, 21], [7, 21], [7, 21], [7, 21],         // 0010111xx
 +    [7, 28], [7, 28], [7, 28], [7, 28],         // 0011000xx
 +    [8, 61], [8, 61],                           // 00110010x
 +    [8, 62], [8, 62],                           // 00110011x
 +    [8, 63], [8, 63],                           // 00110100x
 +    [8, 0], [8, 0],                             // 00110101x
 +    [8, 320], [8, 320],                         // 00110110x
 +    [8, 384], [8, 384],                         // 00110111x
 +    [5, 10], [5, 10], [5, 10], [5, 10],         // 00111xxxx
 +    [5, 10], [5, 10], [5, 10], [5, 10],
 +    [5, 10], [5, 10], [5, 10], [5, 10],
 +    [5, 10], [5, 10], [5, 10], [5, 10],
 +    [5, 11], [5, 11], [5, 11], [5, 11],         // 01000xxxx
 +    [5, 11], [5, 11], [5, 11], [5, 11],
 +    [5, 11], [5, 11], [5, 11], [5, 11],
 +    [5, 11], [5, 11], [5, 11], [5, 11],
 +    [7, 27], [7, 27], [7, 27], [7, 27],         // 0100100xx
 +    [8, 59], [8, 59],                           // 01001010x
 +    [8, 60], [8, 60],                           // 01001011x
 +    [9, 1472],                                  // 010011000
 +    [9, 1536],                                  // 010011001
 +    [9, 1600],                                  // 010011010
 +    [9, 1728],                                  // 010011011
 +    [7, 18], [7, 18], [7, 18], [7, 18],         // 0100111xx
 +    [7, 24], [7, 24], [7, 24], [7, 24],         // 0101000xx
 +    [8, 49], [8, 49],                           // 01010010x
 +    [8, 50], [8, 50],                           // 01010011x
 +    [8, 51], [8, 51],                           // 01010100x
 +    [8, 52], [8, 52],                           // 01010101x
 +    [7, 25], [7, 25], [7, 25], [7, 25],         // 0101011xx
 +    [8, 55], [8, 55],                           // 01011000x
 +    [8, 56], [8, 56],                           // 01011001x
 +    [8, 57], [8, 57],                           // 01011010x
 +    [8, 58], [8, 58],                           // 01011011x
 +    [6, 192], [6, 192], [6, 192], [6, 192],     // 010111xxx
 +    [6, 192], [6, 192], [6, 192], [6, 192],
 +    [6, 1664], [6, 1664], [6, 1664], [6, 1664], // 011000xxx
 +    [6, 1664], [6, 1664], [6, 1664], [6, 1664],
 +    [8, 448], [8, 448],                         // 01100100x
 +    [8, 512], [8, 512],                         // 01100101x
 +    [9, 704],                                   // 011001100
 +    [9, 768],                                   // 011001101
 +    [8, 640], [8, 640],                         // 01100111x
 +    [8, 576], [8, 576],                         // 01101000x
 +    [9, 832],                                   // 011010010
 +    [9, 896],                                   // 011010011
 +    [9, 960],                                   // 011010100
 +    [9, 1024],                                  // 011010101
 +    [9, 1088],                                  // 011010110
 +    [9, 1152],                                  // 011010111
 +    [9, 1216],                                  // 011011000
 +    [9, 1280],                                  // 011011001
 +    [9, 1344],                                  // 011011010
 +    [9, 1408],                                  // 011011011
 +    [7, 256], [7, 256], [7, 256], [7, 256],     // 0110111xx
 +    [4, 2], [4, 2], [4, 2], [4, 2],             // 0111xxxxx
 +    [4, 2], [4, 2], [4, 2], [4, 2],
 +    [4, 2], [4, 2], [4, 2], [4, 2],
 +    [4, 2], [4, 2], [4, 2], [4, 2],
 +    [4, 2], [4, 2], [4, 2], [4, 2],
 +    [4, 2], [4, 2], [4, 2], [4, 2],
 +    [4, 2], [4, 2], [4, 2], [4, 2],
 +    [4, 2], [4, 2], [4, 2], [4, 2],
 +    [4, 3], [4, 3], [4, 3], [4, 3],             // 1000xxxxx
 +    [4, 3], [4, 3], [4, 3], [4, 3],
 +    [4, 3], [4, 3], [4, 3], [4, 3],
 +    [4, 3], [4, 3], [4, 3], [4, 3],
 +    [4, 3], [4, 3], [4, 3], [4, 3],
 +    [4, 3], [4, 3], [4, 3], [4, 3],
 +    [4, 3], [4, 3], [4, 3], [4, 3],
 +    [4, 3], [4, 3], [4, 3], [4, 3],
 +    [5, 128], [5, 128], [5, 128], [5, 128],     // 10010xxxx
 +    [5, 128], [5, 128], [5, 128], [5, 128],
 +    [5, 128], [5, 128], [5, 128], [5, 128],
 +    [5, 128], [5, 128], [5, 128], [5, 128],
 +    [5, 8], [5, 8], [5, 8], [5, 8],             // 10011xxxx
 +    [5, 8], [5, 8], [5, 8], [5, 8],
 +    [5, 8], [5, 8], [5, 8], [5, 8],
 +    [5, 8], [5, 8], [5, 8], [5, 8],
 +    [5, 9], [5, 9], [5, 9], [5, 9],             // 10100xxxx
 +    [5, 9], [5, 9], [5, 9], [5, 9],
 +    [5, 9], [5, 9], [5, 9], [5, 9],
 +    [5, 9], [5, 9], [5, 9], [5, 9],
 +    [6, 16], [6, 16], [6, 16], [6, 16],         // 101010xxx
 +    [6, 16], [6, 16], [6, 16], [6, 16],
 +    [6, 17], [6, 17], [6, 17], [6, 17],         // 101011xxx
 +    [6, 17], [6, 17], [6, 17], [6, 17],
 +    [4, 4], [4, 4], [4, 4], [4, 4],             // 1011xxxxx
 +    [4, 4], [4, 4], [4, 4], [4, 4],
 +    [4, 4], [4, 4], [4, 4], [4, 4],
 +    [4, 4], [4, 4], [4, 4], [4, 4],
 +    [4, 4], [4, 4], [4, 4], [4, 4],
 +    [4, 4], [4, 4], [4, 4], [4, 4],
 +    [4, 4], [4, 4], [4, 4], [4, 4],
 +    [4, 4], [4, 4], [4, 4], [4, 4],
 +    [4, 5], [4, 5], [4, 5], [4, 5],             // 1100xxxxx
 +    [4, 5], [4, 5], [4, 5], [4, 5],
 +    [4, 5], [4, 5], [4, 5], [4, 5],
 +    [4, 5], [4, 5], [4, 5], [4, 5],
 +    [4, 5], [4, 5], [4, 5], [4, 5],
 +    [4, 5], [4, 5], [4, 5], [4, 5],
 +    [4, 5], [4, 5], [4, 5], [4, 5],
 +    [4, 5], [4, 5], [4, 5], [4, 5],
 +    [6, 14], [6, 14], [6, 14], [6, 14],         // 110100xxx
 +    [6, 14], [6, 14], [6, 14], [6, 14],
 +    [6, 15], [6, 15], [6, 15], [6, 15],         // 110101xxx
 +    [6, 15], [6, 15], [6, 15], [6, 15],
 +    [5, 64], [5, 64], [5, 64], [5, 64],         // 11011xxxx
 +    [5, 64], [5, 64], [5, 64], [5, 64],
 +    [5, 64], [5, 64], [5, 64], [5, 64],
 +    [5, 64], [5, 64], [5, 64], [5, 64],
 +    [4, 6], [4, 6], [4, 6], [4, 6],             // 1110xxxxx
 +    [4, 6], [4, 6], [4, 6], [4, 6],
 +    [4, 6], [4, 6], [4, 6], [4, 6],
 +    [4, 6], [4, 6], [4, 6], [4, 6],
 +    [4, 6], [4, 6], [4, 6], [4, 6],
 +    [4, 6], [4, 6], [4, 6], [4, 6],
 +    [4, 6], [4, 6], [4, 6], [4, 6],
 +    [4, 6], [4, 6], [4, 6], [4, 6],
 +    [4, 7], [4, 7], [4, 7], [4, 7],             // 1111xxxxx
 +    [4, 7], [4, 7], [4, 7], [4, 7],
 +    [4, 7], [4, 7], [4, 7], [4, 7],
 +    [4, 7], [4, 7], [4, 7], [4, 7],
 +    [4, 7], [4, 7], [4, 7], [4, 7],
 +    [4, 7], [4, 7], [4, 7], [4, 7],
 +    [4, 7], [4, 7], [4, 7], [4, 7],
 +    [4, 7], [4, 7], [4, 7], [4, 7]
 +  ];
 +
 +  var blackTable1 = [
 +    [-1, -1], [-1, -1],                             // 000000000000x
 +    [12, ccittEOL], [12, ccittEOL],                 // 000000000001x
 +    [-1, -1], [-1, -1], [-1, -1], [-1, -1],         // 00000000001xx
 +    [-1, -1], [-1, -1], [-1, -1], [-1, -1],         // 00000000010xx
 +    [-1, -1], [-1, -1], [-1, -1], [-1, -1],         // 00000000011xx
 +    [-1, -1], [-1, -1], [-1, -1], [-1, -1],         // 00000000100xx
 +    [-1, -1], [-1, -1], [-1, -1], [-1, -1],         // 00000000101xx
 +    [-1, -1], [-1, -1], [-1, -1], [-1, -1],         // 00000000110xx
 +    [-1, -1], [-1, -1], [-1, -1], [-1, -1],         // 00000000111xx
 +    [11, 1792], [11, 1792], [11, 1792], [11, 1792], // 00000001000xx
 +    [12, 1984], [12, 1984],                         // 000000010010x
 +    [12, 2048], [12, 2048],                         // 000000010011x
 +    [12, 2112], [12, 2112],                         // 000000010100x
 +    [12, 2176], [12, 2176],                         // 000000010101x
 +    [12, 2240], [12, 2240],                         // 000000010110x
 +    [12, 2304], [12, 2304],                         // 000000010111x
 +    [11, 1856], [11, 1856], [11, 1856], [11, 1856], // 00000001100xx
 +    [11, 1920], [11, 1920], [11, 1920], [11, 1920], // 00000001101xx
 +    [12, 2368], [12, 2368],                         // 000000011100x
 +    [12, 2432], [12, 2432],                         // 000000011101x
 +    [12, 2496], [12, 2496],                         // 000000011110x
 +    [12, 2560], [12, 2560],                         // 000000011111x
 +    [10, 18], [10, 18], [10, 18], [10, 18],         // 0000001000xxx
 +    [10, 18], [10, 18], [10, 18], [10, 18],
 +    [12, 52], [12, 52],                             // 000000100100x
 +    [13, 640],                                      // 0000001001010
 +    [13, 704],                                      // 0000001001011
 +    [13, 768],                                      // 0000001001100
 +    [13, 832],                                      // 0000001001101
 +    [12, 55], [12, 55],                             // 000000100111x
 +    [12, 56], [12, 56],                             // 000000101000x
 +    [13, 1280],                                     // 0000001010010
 +    [13, 1344],                                     // 0000001010011
 +    [13, 1408],                                     // 0000001010100
 +    [13, 1472],                                     // 0000001010101
 +    [12, 59], [12, 59],                             // 000000101011x
 +    [12, 60], [12, 60],                             // 000000101100x
 +    [13, 1536],                                     // 0000001011010
 +    [13, 1600],                                     // 0000001011011
 +    [11, 24], [11, 24], [11, 24], [11, 24],         // 00000010111xx
 +    [11, 25], [11, 25], [11, 25], [11, 25],         // 00000011000xx
 +    [13, 1664],                                     // 0000001100100
 +    [13, 1728],                                     // 0000001100101
 +    [12, 320], [12, 320],                           // 000000110011x
 +    [12, 384], [12, 384],                           // 000000110100x
 +    [12, 448], [12, 448],                           // 000000110101x
 +    [13, 512],                                      // 0000001101100
 +    [13, 576],                                      // 0000001101101
 +    [12, 53], [12, 53],                             // 000000110111x
 +    [12, 54], [12, 54],                             // 000000111000x
 +    [13, 896],                                      // 0000001110010
 +    [13, 960],                                      // 0000001110011
 +    [13, 1024],                                     // 0000001110100
 +    [13, 1088],                                     // 0000001110101
 +    [13, 1152],                                     // 0000001110110
 +    [13, 1216],                                     // 0000001110111
 +    [10, 64], [10, 64], [10, 64], [10, 64],         // 0000001111xxx
 +    [10, 64], [10, 64], [10, 64], [10, 64]
 +  ];
 +
 +  var blackTable2 = [
 +    [8, 13], [8, 13], [8, 13], [8, 13],     // 00000100xxxx
 +    [8, 13], [8, 13], [8, 13], [8, 13],
 +    [8, 13], [8, 13], [8, 13], [8, 13],
 +    [8, 13], [8, 13], [8, 13], [8, 13],
 +    [11, 23], [11, 23],                     // 00000101000x
 +    [12, 50],                               // 000001010010
 +    [12, 51],                               // 000001010011
 +    [12, 44],                               // 000001010100
 +    [12, 45],                               // 000001010101
 +    [12, 46],                               // 000001010110
 +    [12, 47],                               // 000001010111
 +    [12, 57],                               // 000001011000
 +    [12, 58],                               // 000001011001
 +    [12, 61],                               // 000001011010
 +    [12, 256],                              // 000001011011
 +    [10, 16], [10, 16], [10, 16], [10, 16], // 0000010111xx
 +    [10, 17], [10, 17], [10, 17], [10, 17], // 0000011000xx
 +    [12, 48],                               // 000001100100
 +    [12, 49],                               // 000001100101
 +    [12, 62],                               // 000001100110
 +    [12, 63],                               // 000001100111
 +    [12, 30],                               // 000001101000
 +    [12, 31],                               // 000001101001
 +    [12, 32],                               // 000001101010
 +    [12, 33],                               // 000001101011
 +    [12, 40],                               // 000001101100
 +    [12, 41],                               // 000001101101
 +    [11, 22], [11, 22],                     // 00000110111x
 +    [8, 14], [8, 14], [8, 14], [8, 14],     // 00000111xxxx
 +    [8, 14], [8, 14], [8, 14], [8, 14],
 +    [8, 14], [8, 14], [8, 14], [8, 14],
 +    [8, 14], [8, 14], [8, 14], [8, 14],
 +    [7, 10], [7, 10], [7, 10], [7, 10],     // 0000100xxxxx
 +    [7, 10], [7, 10], [7, 10], [7, 10],
 +    [7, 10], [7, 10], [7, 10], [7, 10],
 +    [7, 10], [7, 10], [7, 10], [7, 10],
 +    [7, 10], [7, 10], [7, 10], [7, 10],
 +    [7, 10], [7, 10], [7, 10], [7, 10],
 +    [7, 10], [7, 10], [7, 10], [7, 10],
 +    [7, 10], [7, 10], [7, 10], [7, 10],
 +    [7, 11], [7, 11], [7, 11], [7, 11],     // 0000101xxxxx
 +    [7, 11], [7, 11], [7, 11], [7, 11],
 +    [7, 11], [7, 11], [7, 11], [7, 11],
 +    [7, 11], [7, 11], [7, 11], [7, 11],
 +    [7, 11], [7, 11], [7, 11], [7, 11],
 +    [7, 11], [7, 11], [7, 11], [7, 11],
 +    [7, 11], [7, 11], [7, 11], [7, 11],
 +    [7, 11], [7, 11], [7, 11], [7, 11],
 +    [9, 15], [9, 15], [9, 15], [9, 15],     // 000011000xxx
 +    [9, 15], [9, 15], [9, 15], [9, 15],
 +    [12, 128],                              // 000011001000
 +    [12, 192],                              // 000011001001
 +    [12, 26],                               // 000011001010
 +    [12, 27],                               // 000011001011
 +    [12, 28],                               // 000011001100
 +    [12, 29],                               // 000011001101
 +    [11, 19], [11, 19],                     // 00001100111x
 +    [11, 20], [11, 20],                     // 00001101000x
 +    [12, 34],                               // 000011010010
 +    [12, 35],                               // 000011010011
 +    [12, 36],                               // 000011010100
 +    [12, 37],                               // 000011010101
 +    [12, 38],                               // 000011010110
 +    [12, 39],                               // 000011010111
 +    [11, 21], [11, 21],                     // 00001101100x
 +    [12, 42],                               // 000011011010
 +    [12, 43],                               // 000011011011
 +    [10, 0], [10, 0], [10, 0], [10, 0],     // 0000110111xx
 +    [7, 12], [7, 12], [7, 12], [7, 12],     // 0000111xxxxx
 +    [7, 12], [7, 12], [7, 12], [7, 12],
 +    [7, 12], [7, 12], [7, 12], [7, 12],
 +    [7, 12], [7, 12], [7, 12], [7, 12],
 +    [7, 12], [7, 12], [7, 12], [7, 12],
 +    [7, 12], [7, 12], [7, 12], [7, 12],
 +    [7, 12], [7, 12], [7, 12], [7, 12],
 +    [7, 12], [7, 12], [7, 12], [7, 12]
 +  ];
 +
 +  var blackTable3 = [
 +    [-1, -1], [-1, -1], [-1, -1], [-1, -1], // 0000xx
 +    [6, 9],                                 // 000100
 +    [6, 8],                                 // 000101
 +    [5, 7], [5, 7],                         // 00011x
 +    [4, 6], [4, 6], [4, 6], [4, 6],         // 0010xx
 +    [4, 5], [4, 5], [4, 5], [4, 5],         // 0011xx
 +    [3, 1], [3, 1], [3, 1], [3, 1],         // 010xxx
 +    [3, 1], [3, 1], [3, 1], [3, 1],
 +    [3, 4], [3, 4], [3, 4], [3, 4],         // 011xxx
 +    [3, 4], [3, 4], [3, 4], [3, 4],
 +    [2, 3], [2, 3], [2, 3], [2, 3],         // 10xxxx
 +    [2, 3], [2, 3], [2, 3], [2, 3],
 +    [2, 3], [2, 3], [2, 3], [2, 3],
 +    [2, 3], [2, 3], [2, 3], [2, 3],
 +    [2, 2], [2, 2], [2, 2], [2, 2],         // 11xxxx
 +    [2, 2], [2, 2], [2, 2], [2, 2],
 +    [2, 2], [2, 2], [2, 2], [2, 2],
 +    [2, 2], [2, 2], [2, 2], [2, 2]
 +  ];
 +
 +  function CCITTFaxStream(str, params) {
 +    this.str = str;
 +    this.dict = str.dict;
 +
 +    params = params || new Dict();
 +
 +    this.encoding = params.get('K') || 0;
 +    this.eoline = params.get('EndOfLine') || false;
 +    this.byteAlign = params.get('EncodedByteAlign') || false;
 +    this.columns = params.get('Columns') || 1728;
 +    this.rows = params.get('Rows') || 0;
 +    var eoblock = params.get('EndOfBlock');
 +    if (eoblock === null || eoblock === undefined)
 +      eoblock = true;
 +    this.eoblock = eoblock;
 +    this.black = params.get('BlackIs1') || false;
 +
 +    this.codingLine = new Uint32Array(this.columns + 1);
 +    this.refLine = new Uint32Array(this.columns + 2);
 +
 +    this.codingLine[0] = this.columns;
 +    this.codingPos = 0;
 +
 +    this.row = 0;
 +    this.nextLine2D = this.encoding < 0;
 +    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) {
 +      this.eatBits(12);
 +    }
 +    if (this.encoding > 0) {
 +      this.nextLine2D = !this.lookBits(1);
 +      this.eatBits(1);
 +    }
 +
 +    DecodeStream.call(this);
 +  }
 +
 +  CCITTFaxStream.prototype = Object.create(DecodeStream.prototype);
 +
 +  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) {
 +    var codingLine = this.codingLine;
 +    var codingPos = this.codingPos;
 +
 +    if (a1 > codingLine[codingPos]) {
 +      if (a1 > this.columns) {
 +        info('row is wrong length');
 +        this.err = true;
 +        a1 = this.columns;
 +      }
 +      if ((codingPos & 1) ^ blackPixels) {
 +        ++codingPos;
 +      }
 +
 +      codingLine[codingPos] = a1;
 +    }
 +    this.codingPos = codingPos;
 +  };
 +
 +  CCITTFaxStream.prototype.addPixelsNeg =
 +    function ccittFaxStreamAddPixelsNeg(a1, blackPixels) {
 +    var codingLine = this.codingLine;
 +    var codingPos = this.codingPos;
 +
 +    if (a1 > codingLine[codingPos]) {
 +      if (a1 > this.columns) {
 +        info('row is wrong length');
 +        this.err = true;
 +        a1 = this.columns;
 +      }
 +      if ((codingPos & 1) ^ blackPixels)
 +        ++codingPos;
 +
 +      codingLine[codingPos] = a1;
 +    } else if (a1 < codingLine[codingPos]) {
 +      if (a1 < 0) {
 +        info('invalid code');
 +        this.err = true;
 +        a1 = 0;
 +      }
 +      while (codingPos > 0 && a1 < codingLine[codingPos - 1])
 +        --codingPos;
 +      codingLine[codingPos] = a1;
 +    }
 +
 +    this.codingPos = codingPos;
 +  };
 +
 +  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;
 +
 +    if (this.outputBits === 0) {
 +      if (this.eof)
 +        return null;
 +
 +      this.err = false;
 +
 +      var code1, code2, code3;
 +      if (this.nextLine2D) {
 +        for (var i = 0; codingLine[i] < columns; ++i)
 +          refLine[i] = codingLine[i];
 +
 +        refLine[i++] = columns;
 +        refLine[i] = columns;
 +        codingLine[0] = 0;
 +        this.codingPos = 0;
 +        refPos = 0;
 +        blackPixels = 0;
 +
 +        while (codingLine[this.codingPos] < columns) {
 +          code1 = this.getTwoDimCode();
 +          switch (code1) {
 +            case twoDimPass:
 +              this.addPixels(refLine[refPos + 1], blackPixels);
 +              if (refLine[refPos + 1] < columns)
 +                refPos += 2;
 +              break;
 +            case twoDimHoriz:
 +              code1 = code2 = 0;
 +              if (blackPixels) {
 +                do {
 +                  code1 += (code3 = this.getBlackCode());
 +                } while (code3 >= 64);
 +                do {
 +                  code2 += (code3 = this.getWhiteCode());
 +                } while (code3 >= 64);
 +              } else {
 +                do {
 +                  code1 += (code3 = this.getWhiteCode());
 +                } while (code3 >= 64);
 +                do {
 +                  code2 += (code3 = this.getBlackCode());
 +                } while (code3 >= 64);
 +              }
 +              this.addPixels(codingLine[this.codingPos] +
 +                             code1, blackPixels);
 +              if (codingLine[this.codingPos] < columns) {
 +                this.addPixels(codingLine[this.codingPos] + code2,
 +                               blackPixels ^ 1);
 +              }
 +              while (refLine[refPos] <= codingLine[this.codingPos] &&
 +                     refLine[refPos] < columns) {
 +                refPos += 2;
 +              }
 +              break;
 +            case twoDimVertR3:
 +              this.addPixels(refLine[refPos] + 3, blackPixels);
 +              blackPixels ^= 1;
 +              if (codingLine[this.codingPos] < columns) {
 +                ++refPos;
 +                while (refLine[refPos] <= codingLine[this.codingPos] &&
 +                       refLine[refPos] < columns)
 +                  refPos += 2;
 +              }
 +              break;
 +            case twoDimVertR2:
 +              this.addPixels(refLine[refPos] + 2, blackPixels);
 +              blackPixels ^= 1;
 +              if (codingLine[this.codingPos] < columns) {
 +                ++refPos;
 +                while (refLine[refPos] <= codingLine[this.codingPos] &&
 +                       refLine[refPos] < columns) {
 +                  refPos += 2;
 +                }
 +              }
 +              break;
 +            case twoDimVertR1:
 +              this.addPixels(refLine[refPos] + 1, blackPixels);
 +              blackPixels ^= 1;
 +              if (codingLine[this.codingPos] < columns) {
 +                ++refPos;
 +                while (refLine[refPos] <= codingLine[this.codingPos] &&
 +                       refLine[refPos] < columns)
 +                  refPos += 2;
 +              }
 +              break;
 +            case twoDimVert0:
 +              this.addPixels(refLine[refPos], blackPixels);
 +              blackPixels ^= 1;
 +              if (codingLine[this.codingPos] < columns) {
 +                ++refPos;
 +                while (refLine[refPos] <= codingLine[this.codingPos] &&
 +                       refLine[refPos] < columns)
 +                  refPos += 2;
 +              }
 +              break;
 +            case twoDimVertL3:
 +              this.addPixelsNeg(refLine[refPos] - 3, blackPixels);
 +              blackPixels ^= 1;
 +              if (codingLine[this.codingPos] < columns) {
 +                if (refPos > 0)
 +                  --refPos;
 +                else
 +                  ++refPos;
 +                while (refLine[refPos] <= codingLine[this.codingPos] &&
 +                       refLine[refPos] < columns)
 +                  refPos += 2;
 +              }
 +              break;
 +            case twoDimVertL2:
 +              this.addPixelsNeg(refLine[refPos] - 2, blackPixels);
 +              blackPixels ^= 1;
 +              if (codingLine[this.codingPos] < columns) {
 +                if (refPos > 0)
 +                  --refPos;
 +                else
 +                  ++refPos;
 +                while (refLine[refPos] <= codingLine[this.codingPos] &&
 +                       refLine[refPos] < columns)
 +                  refPos += 2;
 +              }
 +              break;
 +            case twoDimVertL1:
 +              this.addPixelsNeg(refLine[refPos] - 1, blackPixels);
 +              blackPixels ^= 1;
 +              if (codingLine[this.codingPos] < columns) {
 +                if (refPos > 0)
 +                  --refPos;
 +                else
 +                  ++refPos;
 +
 +                while (refLine[refPos] <= codingLine[this.codingPos] &&
 +                       refLine[refPos] < columns)
 +                  refPos += 2;
 +              }
 +              break;
 +            case EOF:
 +              this.addPixels(columns, 0);
 +              this.eof = true;
 +              break;
 +            default:
 +              info('bad 2d code');
 +              this.addPixels(columns, 0);
 +              this.err = true;
 +          }
 +        }
 +      } else {
 +        codingLine[0] = 0;
 +        this.codingPos = 0;
 +        blackPixels = 0;
 +        while (codingLine[this.codingPos] < columns) {
 +          code1 = 0;
 +          if (blackPixels) {
 +            do {
 +              code1 += (code3 = this.getBlackCode());
 +            } while (code3 >= 64);
 +          } else {
 +            do {
 +              code1 += (code3 = this.getWhiteCode());
 +            } while (code3 >= 64);
 +          }
 +          this.addPixels(codingLine[this.codingPos] + code1, blackPixels);
 +          blackPixels ^= 1;
 +        }
 +      }
 +
 +      if (this.byteAlign)
 +        this.inputBits &= ~7;
 +
 +      var gotEOL = false;
 +
 +      if (!this.eoblock && this.row == this.rows - 1) {
 +        this.eof = true;
 +      } else {
 +        code1 = this.lookBits(12);
 +        while (code1 === 0) {
 +          this.eatBits(1);
 +          code1 = this.lookBits(12);
 +        }
 +        if (code1 == 1) {
 +          this.eatBits(12);
 +          gotEOL = true;
 +        } else if (code1 == EOF) {
 +          this.eof = true;
 +        }
 +      }
 +
 +      if (!this.eof && this.encoding > 0) {
 +        this.nextLine2D = !this.lookBits(1);
 +        this.eatBits(1);
 +      }
 +
 +      if (this.eoblock && gotEOL) {
 +        code1 = this.lookBits(12);
 +        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) {
 +              code1 = this.lookBits(12);
 +              if (code1 != 1)
 +                info('bad rtc code: ' + code1);
 +              this.eatBits(12);
 +              if (this.encoding > 0) {
 +                this.lookBits(1);
 +                this.eatBits(1);
 +              }
 +            }
 +          }
 +          this.eof = true;
 +        }
 +      } else if (this.err && this.eoline) {
 +        while (true) {
 +          code1 = this.lookBits(13);
 +          if (code1 == EOF) {
 +            this.eof = true;
 +            return null;
 +          }
 +          if ((code1 >> 1) == 1) {
 +            break;
 +          }
 +          this.eatBits(1);
 +        }
 +        this.eatBits(12);
 +        if (this.encoding > 0) {
 +          this.eatBits(1);
 +          this.nextLine2D = !(code1 & 1);
 +        }
 +      }
 +
 +      if (codingLine[0] > 0)
 +        this.outputBits = codingLine[this.codingPos = 0];
 +      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++;
 +        this.outputBits = (codingLine[this.codingPos] -
 +                           codingLine[this.codingPos - 1]);
 +      }
 +    } else {
 +      var bits = 8;
-       this.buf = 0;
++      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;
 +          if (codingLine[this.codingPos] < columns) {
 +            this.codingPos++;
 +            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.
 +  // The start and end parameters set the boundaries for searching the table.
 +  // The limit parameter is optional. Function returns an array with three
 +  // values. The first array element indicates whether a valid code is being
 +  // 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) {
 +
 +    var limitValue = limit || 0;
 +    for (var i = start; i <= end; ++i) {
 +      var code = this.lookBits(i);
 +      if (code == EOF)
 +        return [true, 1, false];
 +      if (i < end)
 +        code <<= end - i;
 +      if (!limitValue || code >= limitValue) {
 +        var p = table[code - limitValue];
 +        if (p[0] == i) {
 +          this.eatBits(i);
 +          return [true, p[1], true];
 +        }
 +      }
 +    }
 +    return [false, 0, false];
 +  };
 +
 +  CCITTFaxStream.prototype.getTwoDimCode =
 +    function ccittFaxStreamGetTwoDimCode() {
 +
 +    var code = 0;
 +    var p;
 +    if (this.eoblock) {
 +      code = this.lookBits(7);
 +      p = twoDimTable[code];
 +      if (p && p[0] > 0) {
 +        this.eatBits(p[0]);
 +        return p[1];
 +      }
 +    } else {
 +      var result = this.findTableCode(1, 7, twoDimTable);
 +      if (result[0] && result[2])
 +        return result[1];
 +    }
 +    info('Bad two dim code');
 +    return EOF;
 +  };
 +
 +  CCITTFaxStream.prototype.getWhiteCode =
 +    function ccittFaxStreamGetWhiteCode() {
 +
 +    var code = 0;
 +    var p;
 +    var n;
 +    if (this.eoblock) {
 +      code = this.lookBits(12);
 +      if (code == EOF)
 +        return 1;
 +
 +      if ((code >> 5) === 0)
 +        p = whiteTable1[code];
 +      else
 +        p = whiteTable2[code >> 3];
 +
 +      if (p[0] > 0) {
 +        this.eatBits(p[0]);
 +        return p[1];
 +      }
 +    } else {
 +      var result = this.findTableCode(1, 9, whiteTable2);
 +      if (result[0])
 +        return result[1];
 +
 +      result = this.findTableCode(11, 12, whiteTable1);
 +      if (result[0])
 +        return result[1];
 +    }
 +    info('bad white code');
 +    this.eatBits(1);
 +    return 1;
 +  };
 +
 +  CCITTFaxStream.prototype.getBlackCode =
 +    function ccittFaxStreamGetBlackCode() {
 +
 +    var code, p;
 +    if (this.eoblock) {
 +      code = this.lookBits(13);
 +      if (code == EOF)
 +        return 1;
 +      if ((code >> 7) === 0)
 +        p = blackTable1[code];
 +      else if ((code >> 9) === 0 && (code >> 7) !== 0)
 +        p = blackTable2[(code >> 1) - 64];
 +      else
 +        p = blackTable3[code >> 7];
 +
 +      if (p[0] > 0) {
 +        this.eatBits(p[0]);
 +        return p[1];
 +      }
 +    } else {
 +      var result = this.findTableCode(2, 6, blackTable3);
 +      if (result[0])
 +        return result[1];
 +
 +      result = this.findTableCode(7, 12, blackTable2, 64);
 +      if (result[0])
 +        return result[1];
 +
 +      result = this.findTableCode(10, 13, blackTable1);
 +      if (result[0])
 +        return result[1];
 +    }
 +    info('bad black code');
 +    this.eatBits(1);
 +    return 1;
 +  };
 +
 +  CCITTFaxStream.prototype.lookBits = function CCITTFaxStream_lookBits(n) {
 +    var c;
 +    while (this.inputBits < n) {
-       if ((c = this.str.getByte()) === null || c === undefined) {
++      if ((c = this.str.getByte()) === -1) {
 +        if (this.inputBits === 0)
 +          return EOF;
 +        return ((this.inputBuf << (n - this.inputBits)) &
 +                (0xFFFF >> (16 - n)));
 +      }
 +      this.inputBuf = (this.inputBuf << 8) + c;
 +      this.inputBits += 8;
 +    }
 +    return (this.inputBuf >> (this.inputBits - n)) & (0xFFFF >> (16 - n));
 +  };
 +
 +  CCITTFaxStream.prototype.eatBits = function CCITTFaxStream_eatBits(n) {
 +    if ((this.inputBits -= n) < 0)
 +      this.inputBits = 0;
 +  };
 +
 +  return CCITTFaxStream;
 +})();
 +
 +var LZWStream = (function LZWStreamClosure() {
 +  function LZWStream(str, earlyChange) {
 +    this.str = str;
 +    this.dict = str.dict;
 +    this.cachedData = 0;
 +    this.bitsCached = 0;
 +
 +    var maxLzwDictionarySize = 4096;
 +    var lzwState = {
 +      earlyChange: earlyChange,
 +      codeLength: 9,
 +      nextCode: 258,
 +      dictionaryValues: new Uint8Array(maxLzwDictionarySize),
 +      dictionaryLengths: new Uint16Array(maxLzwDictionarySize),
 +      dictionaryPrevCodes: new Uint16Array(maxLzwDictionarySize),
 +      currentSequence: new Uint8Array(maxLzwDictionarySize),
 +      currentSequenceLength: 0
 +    };
 +    for (var i = 0; i < 256; ++i) {
 +      lzwState.dictionaryValues[i] = i;
 +      lzwState.dictionaryLengths[i] = 1;
 +    }
 +    this.lzwState = lzwState;
 +
 +    DecodeStream.call(this);
 +  }
 +
 +  LZWStream.prototype = Object.create(DecodeStream.prototype);
 +
 +  LZWStream.prototype.readBits = function LZWStream_readBits(n) {
 +    var bitsCached = this.bitsCached;
 +    var cachedData = this.cachedData;
 +    while (bitsCached < n) {
 +      var c = this.str.getByte();
-       if (c === null || c === undefined) {
++      if (c === -1) {
 +        this.eof = true;
 +        return null;
 +      }
 +      cachedData = (cachedData << 8) | c;
 +      bitsCached += 8;
 +    }
 +    this.bitsCached = (bitsCached -= n);
 +    this.cachedData = cachedData;
 +    this.lastCode = null;
 +    return (cachedData >>> bitsCached) & ((1 << n) - 1);
 +  };
 +
 +  LZWStream.prototype.readBlock = function LZWStream_readBlock() {
 +    var blockSize = 512;
 +    var estimatedDecodedSize = blockSize * 2, decodedSizeDelta = blockSize;
 +    var i, j, q;
 +
 +    var lzwState = this.lzwState;
 +    if (!lzwState)
 +      return; // eof was found
 +
 +    var earlyChange = lzwState.earlyChange;
 +    var nextCode = lzwState.nextCode;
 +    var dictionaryValues = lzwState.dictionaryValues;
 +    var dictionaryLengths = lzwState.dictionaryLengths;
 +    var dictionaryPrevCodes = lzwState.dictionaryPrevCodes;
 +    var codeLength = lzwState.codeLength;
 +    var prevCode = lzwState.prevCode;
 +    var currentSequence = lzwState.currentSequence;
 +    var currentSequenceLength = lzwState.currentSequenceLength;
 +
 +    var decodedLength = 0;
 +    var currentBufferLength = this.bufferLength;
 +    var buffer = this.ensureBuffer(this.bufferLength + estimatedDecodedSize);
 +
 +    for (i = 0; i < blockSize; i++) {
 +      var code = this.readBits(codeLength);
 +      var hasPrev = currentSequenceLength > 0;
 +      if (code < 256) {
 +        currentSequence[0] = code;
 +        currentSequenceLength = 1;
 +      } else if (code >= 258) {
 +        if (code < nextCode) {
 +          currentSequenceLength = dictionaryLengths[code];
 +          for (j = currentSequenceLength - 1, q = code; j >= 0; j--) {
 +            currentSequence[j] = dictionaryValues[q];
 +            q = dictionaryPrevCodes[q];
 +          }
 +        } else {
 +          currentSequence[currentSequenceLength++] = currentSequence[0];
 +        }
 +      } else if (code == 256) {
 +        codeLength = 9;
 +        nextCode = 258;
 +        currentSequenceLength = 0;
 +        continue;
 +      } else {
 +        this.eof = true;
 +        delete this.lzwState;
 +        break;
 +      }
 +
 +      if (hasPrev) {
 +        dictionaryPrevCodes[nextCode] = prevCode;
 +        dictionaryLengths[nextCode] = dictionaryLengths[prevCode] + 1;
 +        dictionaryValues[nextCode] = currentSequence[0];
 +        nextCode++;
 +        codeLength = (nextCode + earlyChange) & (nextCode + earlyChange - 1) ?
 +          codeLength : Math.min(Math.log(nextCode + earlyChange) /
 +          0.6931471805599453 + 1, 12) | 0;
 +      }
 +      prevCode = code;
 +
 +      decodedLength += currentSequenceLength;
 +      if (estimatedDecodedSize < decodedLength) {
 +        do {
 +          estimatedDecodedSize += decodedSizeDelta;
 +        } while (estimatedDecodedSize < decodedLength);
 +        buffer = this.ensureBuffer(this.bufferLength + estimatedDecodedSize);
 +      }
 +      for (j = 0; j < currentSequenceLength; j++)
 +        buffer[currentBufferLength++] = currentSequence[j];
 +    }
 +    lzwState.nextCode = nextCode;
 +    lzwState.codeLength = codeLength;
 +    lzwState.prevCode = prevCode;
 +    lzwState.currentSequenceLength = currentSequenceLength;
 +
 +    this.bufferLength = currentBufferLength;
 +  };
 +
 +  return LZWStream;
 +})();
 +
 +var NullStream = (function NullStreamClosure() {
 +  function NullStream() {
 +    Stream.call(this, new Uint8Array(0));
 +  }
 +
 +  NullStream.prototype = Stream.prototype;
 +
 +  return NullStream;
 +})();
 +
 +
- function MessageHandler(name, comObj) {
-   this.name = name;
-   this.comObj = comObj;
-   this.callbackIndex = 1;
-   var callbacks = this.callbacks = {};
-   var ah = this.actionHandler = {};
++var WorkerMessageHandler = PDFJS.WorkerMessageHandler = {
++  setup: function wphSetup(handler) {
++    var pdfManager;
++
++    function loadDocument(recoveryMode) {
++      var loadDocumentPromise = new LegacyPromise();
++
++      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 encryptedPromise = pdfManager.ensureXRef('encrypt');
++        var javaScriptPromise = pdfManager.ensureCatalog('javaScript');
++        Promise.all([numPagesPromise, fingerprintPromise, outlinePromise,
++          infoPromise, metadataPromise, encryptedPromise,
++          javaScriptPromise]).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]
++          };
++          loadDocumentPromise.resolve(doc);
++        },
++        parseFailure);
++      };
 +
-   ah['console_log'] = [function ahConsoleLog(data) {
-     log.apply(null, 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['_warn'] = [function ah_Warn(data) {
-     warn(data);
-   }];
++      var parseFailure = function parseFailure(e) {
++        loadDocumentPromise.reject(e);
++      };
 +
-   comObj.onmessage = function messageHandlerComObjOnMessage(event) {
-     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);
-       } else {
-         error('Cannot resolve callback ' + callbackId);
-       }
-     } else if (data.action in ah) {
-       var action = ah[data.action];
-       if (data.callbackId) {
-         var promise = new Promise();
-         promise.then(function(resolvedData) {
-           comObj.postMessage({
-             isReply: true,
-             callbackId: data.callbackId,
-             data: resolvedData
-           });
-         });
-         action[0].call(action[1], data.data, promise);
-       } else {
-         action[0].call(action[1], data.data);
-       }
-     } else {
-       error('Unkown action from worker: ' + data.action);
-     }
-   };
- }
++      pdfManager.ensureModel('checkHeader', []).then(function() {
++        pdfManager.ensureModel('parseStartXRef', []).then(function() {
++          pdfManager.ensureModel('parse', [recoveryMode]).then(
++              parseSuccess, parseFailure);
++        }, parseFailure);
++      }, parseFailure);
 +
- MessageHandler.prototype = {
-   on: function messageHandlerOn(actionName, handler, scope) {
-     var ah = this.actionHandler;
-     if (ah[actionName]) {
-       error('There is already an actionName called "' + actionName + '"');
-     }
-     ah[actionName] = [handler, scope];
-   },
-   /**
-    * 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.
-    */
-   send: function messageHandlerSend(actionName, data, callback) {
-     var message = {
-       action: actionName,
-       data: data
-     };
-     if (callback) {
-       var callbackId = this.callbackIndex++;
-       this.callbacks[callbackId] = callback;
-       message.callbackId = callbackId;
++      return loadDocumentPromise;
 +    }
-     this.comObj.postMessage(message);
-   }
- };
 +
- var WorkerMessageHandler = {
-   setup: function wphSetup(handler) {
-     var pdfModel = null;
++    function getPdfManager(data) {
++      var pdfManagerPromise = new LegacyPromise();
 +
-     function loadDocument(pdfData, pdfModelSource) {
-       // Create only the model of the PDFDoc, which is enough for
-       // processing the content of the pdf.
-       var pdfPassword = pdfModelSource.password;
-       try {
-         pdfModel = new PDFDocument(new Stream(pdfData), pdfPassword);
-       } catch (e) {
-         if (e instanceof PasswordException) {
-           if (e.code === 'needpassword') {
-             handler.send('NeedPassword', {
-               exception: e
-             });
-           } else if (e.code === 'incorrectpassword') {
-             handler.send('IncorrectPassword', {
-               exception: e
-             });
++      var source = data.source;
++      var disableRange = data.disableRange;
++      if (source.data) {
++        try {
++          pdfManager = new LocalPdfManager(source.data, source.password);
++          pdfManagerPromise.resolve();
++        } catch (ex) {
++          pdfManagerPromise.reject(ex);
++        }
++        return pdfManagerPromise;
++      } else if (source.chunkedViewerLoading) {
++        try {
++          pdfManager = new NetworkPdfManager(source, handler);
++          pdfManagerPromise.resolve();
++        } catch (ex) {
++          pdfManagerPromise.reject(ex);
++        }
++        return pdfManagerPromise;
++      }
++
++      var networkManager = new NetworkManager(source.url, {
++        httpHeaders: source.httpHeaders,
++        withCredentials: source.withCredentials
++      });
++      var fullRequestXhrId = networkManager.requestFull({
++        onHeadersReceived: function onHeadersReceived() {
++          if (disableRange) {
++            return;
 +          }
 +
-           return;
-         } else if (e instanceof InvalidPDFException) {
-           handler.send('InvalidPDF', {
-             exception: e
-           });
++          var fullRequestXhr = networkManager.getRequestXhr(fullRequestXhrId);
++          if (fullRequestXhr.getResponseHeader('Accept-Ranges') !== 'bytes') {
++            return;
++          }
 +
-           return;
-         } else if (e instanceof MissingPDFException) {
-           handler.send('MissingPDF', {
-             exception: e
-           });
++          var contentEncoding =
++            fullRequestXhr.getResponseHeader('Content-Encoding') || 'identity';
++          if (contentEncoding !== 'identity') {
++            return;
++          }
 +
-           return;
-         } else {
-           handler.send('UnknownError', {
-             exception: new UnknownErrorException(e.message, e.toString())
-           });
++          var length = fullRequestXhr.getResponseHeader('Content-Length');
++          length = parseInt(length, 10);
++          if (!isInt(length)) {
++            return;
++          }
++          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;
++          }
 +
-           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);
++
++          try {
++            pdfManager = new NetworkPdfManager(source, handler);
++            pdfManagerPromise.resolve(pdfManager);
++          } catch (ex) {
++            pdfManagerPromise.reject(ex);
++          }
++        },
++
++        onDone: function onDone(args) {
++          // the data is array, instantiating directly from it
++          try {
++            pdfManager = new LocalPdfManager(args.chunk, source.password);
++            pdfManagerPromise.resolve();
++          } catch (ex) {
++            pdfManagerPromise.reject(ex);
++          }
++        },
++
++        onError: function onError(status) {
++          if (status == 404) {
++            var exception = new MissingPDFException( 'Missing PDF "' +
++                source.url + '".');
++            handler.send('MissingPDF', { exception: exception });
++          } else {
++            handler.send('DocError', 'Unexpected server response (' +
++                status + ') while retrieving PDF "' +
++                source.url + '".');
++          }
++        },
++
++        onProgress: function onProgress(evt) {
++          handler.send('DocProgress', {
++            loaded: evt.loaded,
++            total: evt.lengthComputable ? evt.total : source.length
++          });
 +        }
-       }
-       var doc = {
-         numPages: pdfModel.numPages,
-         fingerprint: pdfModel.getFingerprint(),
-         destinations: pdfModel.catalog.destinations,
-         javaScript: pdfModel.catalog.javaScript,
-         outline: pdfModel.catalog.documentOutline,
-         info: pdfModel.getDocumentInfo(),
-         metadata: pdfModel.catalog.metadata,
-         encrypted: !!pdfModel.xref.encrypt
-       };
-       handler.send('GetDoc', {pdfInfo: doc});
++      });
++
++      return pdfManagerPromise;
 +    }
 +
 +    handler.on('test', function wphSetupTest(data) {
 +      // check if Uint8Array can be sent to worker
 +      if (!(data instanceof Uint8Array)) {
 +        handler.send('test', false);
 +        return;
 +      }
++      // making sure postMessage transfers are working
++      var supportTransfers = data[0] === 255;
++      handler.postMessageTransfers = supportTransfers;
 +      // check if the response property is supported by xhr
 +      var xhr = new XMLHttpRequest();
 +      var responseExists = 'response' in xhr;
 +      // check if the property is actually implemented
 +      try {
 +        var dummy = xhr.responseType;
 +      } catch (e) {
 +        responseExists = false;
 +      }
 +      if (!responseExists) {
 +        handler.send('test', false);
 +        return;
 +      }
-       handler.send('test', true);
++      handler.send('test', {
++        supportTypedArray: true,
++        supportTransfers: supportTransfers
++      });
 +    });
 +
 +    handler.on('GetDocRequest', function wphSetupDoc(data) {
-       var source = data.source;
-       if (source.data) {
-         // the data is array, instantiating directly from it
-         loadDocument(source.data, source);
-         return;
-       }
 +
-       PDFJS.getPdf(
-         {
-           url: source.url,
-           progress: function getPDFProgress(evt) {
-             handler.send('DocProgress', {
-               loaded: evt.loaded,
-               total: evt.lengthComputable ? evt.total : void(0)
++      var onSuccess = function(doc) {
++        handler.send('GetDoc', { pdfInfo: doc });
++      };
++
++      var onFailure = function(e) {
++        if (e instanceof PasswordException) {
++          if (e.code === PasswordResponses.NEED_PASSWORD) {
++            handler.send('NeedPassword', {
++              exception: e
 +            });
-           },
-           error: function getPDFError(e) {
-             if (e.target.status == 404) {
-               handler.send('MissingPDF', {
-                 exception: new MissingPDFException(
-                   'Missing PDF \"' + source.url + '\".')});
-             } else {
-               handler.send('DocError', 'Unexpected server response (' +
-                             e.target.status + ') while retrieving PDF \"' +
-                             source.url + '\".');
-             }
-           },
-           headers: source.httpHeaders
-         },
-         function getPDFLoad(data) {
-           loadDocument(data, source);
++          } else if (e.code === PasswordResponses.INCORRECT_PASSWORD) {
++            handler.send('IncorrectPassword', {
++              exception: e
++            });
++          }
++        } else if (e instanceof InvalidPDFException) {
++          handler.send('InvalidPDF', {
++            exception: e
++          });
++        } else if (e instanceof MissingPDFException) {
++          handler.send('MissingPDF', {
++            exception: e
++          });
++        } else {
++          handler.send('UnknownError', {
++            exception: 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;
++
++      getPdfManager(data).then(function () {
++        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);
++            }
++
++            onFailure(ex);
++            return;
++          }
++
++          pdfManager.requestLoadedStream();
++          pdfManager.onLoadedStream().then(function() {
++            loadDocument(true).then(onSuccess, onFailure);
++          });
++        }, onFailure);
++      }, onFailure);
 +    });
 +
 +    handler.on('GetPageRequest', function wphSetupGetPage(data) {
-       var pageNumber = data.pageIndex + 1;
-       var pdfPage = pdfModel.getPage(pageNumber);
-       var page = {
-         pageIndex: data.pageIndex,
-         rotate: pdfPage.rotate,
-         ref: pdfPage.ref,
-         view: pdfPage.view
-       };
-       handler.send('GetPage', {pageInfo: page});
++      var pageIndex = data.pageIndex;
++      pdfManager.getPage(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(
++            function(results) {
++          var page = {
++            pageIndex: data.pageIndex,
++            rotate: results[0],
++            ref: results[1],
++            view: results[2]
++          };
++
++          handler.send('GetPage', { pageInfo: page });
++        });
++      });
 +    });
 +
-     handler.on('GetData', function wphSetupGetData(data, promise) {
-       promise.resolve(pdfModel.stream.bytes);
++    handler.on('GetPageIndex', function wphSetupGetPageIndex(data, deferred) {
++      var ref = new Ref(data.ref.num, data.ref.gen);
++      pdfManager.pdfModel.catalog.getPageIndex(ref).then(function (pageIndex) {
++        deferred.resolve(pageIndex);
++      }, deferred.reject);
 +    });
 +
-     handler.on('GetAnnotationsRequest', function wphSetupGetAnnotations(data) {
-       var pdfPage = pdfModel.getPage(data.pageIndex + 1);
-       handler.send('GetAnnotations', {
-         pageIndex: data.pageIndex,
-         annotations: pdfPage.getAnnotations()
++    handler.on('GetDestinations',
++      function wphSetupGetDestinations(data, deferred) {
++        pdfManager.ensureCatalog('destinations').then(function(destinations) {
++          deferred.resolve(destinations);
++        });
++      }
++    );
++
++    handler.on('GetData', function wphSetupGetData(data, deferred) {
++      pdfManager.requestLoadedStream();
++      pdfManager.onLoadedStream().then(function(stream) {
++        deferred.resolve(stream.bytes);
 +      });
 +    });
 +
-     handler.on('RenderPageRequest', function wphSetupRenderPage(data) {
-       var pageNum = data.pageIndex + 1;
++    handler.on('UpdatePassword', function wphSetupUpdatePassword(data) {
++      pdfManager.updatePassword(data);
++    });
 +
-       // The following code does quite the same as
-       // Page.prototype.startRendering, but stops at one point and sends the
-       // result back to the main thread.
-       var gfx = new CanvasGraphics(null);
++    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
++            });
++          }
++        );
++      });
++    });
 +
-       var start = Date.now();
++    handler.on('RenderPageRequest', function wphSetupRenderPage(data) {
++      pdfManager.getPage(data.pageIndex).then(function(page) {
 +
-       var dependency = [];
-       var operatorList = null;
-       try {
-         var page = pdfModel.getPage(pageNum);
++        var pageNum = data.pageIndex + 1;
++        var start = Date.now();
 +        // Pre compile the pdf page and fetch the fonts/images.
-         operatorList = page.getOperatorList(handler, dependency);
-       } catch (e) {
-         var minimumStackMessage =
-             'worker.js: while trying to getPage() and getOperatorList()';
++        page.getOperatorList(handler, data.intent).then(function(operatorList) {
 +
-         var wrappedException;
++          info('page=' + pageNum + ' - getOperatorList: time=' +
++               (Date.now() - start) + 'ms, len=' + operatorList.fnArray.length);
 +
-         // Turn the error into an obj that can be serialized
-         if (typeof e === 'string') {
-           wrappedException = {
-             message: e,
-             stack: minimumStackMessage
-           };
-         } else if (typeof e === 'object') {
-           wrappedException = {
-             message: e.message || e.toString(),
-             stack: e.stack || minimumStackMessage
-           };
-         } else {
-           wrappedException = {
-             message: 'Unknown exception type: ' + (typeof e),
-             stack: minimumStackMessage
-           };
-         }
++        }, function(e) {
 +
-         handler.send('PageError', {
-           pageNum: pageNum,
-           error: wrappedException
-         });
-         return;
-       }
++          var minimumStackMessage =
++              'worker.js: while trying to getPage() and getOperatorList()';
 +
-       log('page=%d - getOperatorList: time=%dms, len=%d', pageNum,
-                               Date.now() - start, operatorList.fnArray.length);
++          var wrappedException;
 +
-       // Filter the dependecies for fonts.
-       var fonts = {};
-       for (var i = 0, ii = dependency.length; i < ii; i++) {
-         var dep = dependency[i];
-         if (dep.indexOf('g_font_') === 0) {
-           fonts[dep] = true;
-         }
-       }
-       handler.send('RenderPage', {
-         pageIndex: data.pageIndex,
-         operatorList: operatorList,
-         depFonts: Object.keys(fonts)
++          // Turn the error into an obj that can be serialized
++          if (typeof e === 'string') {
++            wrappedException = {
++              message: e,
++              stack: minimumStackMessage
++            };
++          } else if (typeof e === 'object') {
++            wrappedException = {
++              message: e.message || e.toString(),
++              stack: e.stack || minimumStackMessage
++            };
++          } else {
++            wrappedException = {
++              message: 'Unknown exception type: ' + (typeof e),
++              stack: minimumStackMessage
++            };
++          }
++
++          handler.send('PageError', {
++            pageNum: pageNum,
++            error: wrappedException,
++            intent: data.intent
++          });
++        });
 +      });
 +    }, this);
 +
-     handler.on('GetTextContent', function wphExtractText(data, promise) {
-       var pageNum = data.pageIndex + 1;
-       var start = Date.now();
++    handler.on('GetTextContent', function wphExtractText(data, deferred) {
++      pdfManager.getPage(data.pageIndex).then(function(page) {
++        var pageNum = data.pageIndex + 1;
++        var start = Date.now();
++        page.extractTextContent().then(function(textContent) {
++          deferred.resolve(textContent);
++          info('text indexing: page=' + pageNum + ' - time=' +
++               (Date.now() - start) + 'ms');
++        }, function (e) {
++          // Skip errored pages
++          deferred.reject(e);
++        });
++      });
++    });
 +
-       var textContent = '';
-       try {
-         var page = pdfModel.getPage(pageNum);
-         textContent = page.extractTextContent();
-         promise.resolve(textContent);
-       } catch (e) {
-         // Skip errored pages
-         promise.reject(e);
-       }
++    handler.on('Cleanup', function wphCleanup(data, deferred) {
++      pdfManager.cleanup();
++      deferred.resolve(true);
++    });
 +
-       log('text indexing: page=%d - time=%dms',
-                       pageNum, Date.now() - start);
++    handler.on('Terminate', function wphTerminate(data, deferred) {
++      pdfManager.terminate();
++      deferred.resolve();
 +    });
 +  }
 +};
 +
 +var consoleTimer = {};
 +
 +var workerConsole = {
 +  log: function log() {
 +    var args = Array.prototype.slice.call(arguments);
 +    globalScope.postMessage({
 +      action: 'console_log',
 +      data: args
 +    });
 +  },
 +
 +  error: function error() {
 +    var args = Array.prototype.slice.call(arguments);
 +    globalScope.postMessage({
 +      action: 'console_error',
 +      data: args
 +    });
 +    throw 'pdf.js execution error';
 +  },
 +
 +  time: function time(name) {
 +    consoleTimer[name] = Date.now();
 +  },
 +
 +  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;
- 
-   // Add a logger so we can pass warnings on to the main thread, errors will
-   // throw an exception which will be forwarded on automatically.
-   PDFJS.LogManager.addLogger({
-     warn: function(msg) {
-       globalScope.postMessage({
-         action: '_warn',
-         data: msg
-       });
-     }
++  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) {
++    globalScope.postMessage({
++      action: '_unsupported_feature',
++      data: msg
++    });
 +  });
 +
 +  var handler = new MessageHandler('worker_processor', this);
 +  WorkerMessageHandler.setup(handler);
 +}
 +
 +
 +var JpxImage = (function JpxImageClosure() {
 +  // Table E.1
 +  var SubbandsGainLog2 = {
 +    'LL': 0,
 +    'LH': 1,
 +    'HL': 1,
 +    'HH': 2
 +  };
++  var TransformType = {
++    IRREVERSIBLE: 0,
++    REVERSIBLE: 1
++  };
 +  function JpxImage() {
 +    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 = readUint(data, 0, 2);
++      // 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);
 +        position += headerSize;
 +        if (lbox == 1) {
 +          lbox = readUint(data, position, 8);
 +          position += 8;
 +          headerSize += 8;
 +        }
 +        if (lbox === 0)
 +          lbox = length - position + headerSize;
 +        if (lbox < headerSize)
 +          error('JPX error: Invalid box field size');
 +        var dataLength = lbox - headerSize;
 +        var jumpDataLength = true;
 +        switch (tbox) {
 +          case 0x6A501A1A: // 'jP\032\032'
 +            // TODO
 +            break;
 +          case 0x6A703268: // 'jp2h'
 +            jumpDataLength = false; // parsing child boxes
 +            break;
 +          case 0x636F6C72: // 'colr'
 +            // TODO
 +            break;
 +          case 0x6A703263: // 'jp2c'
 +            this.parseCodestream(data, position, position + dataLength);
 +            break;
 +        }
 +        if (jumpDataLength)
 +          position += dataLength;
 +      }
 +    },
 +    parseCodestream: function JpxImage_parseCodestream(data, start, end) {
 +      var context = {};
 +      try {
 +        var position = start;
 +        while (position < end) {
 +          var code = readUint16(data, position);
 +          position += 2;
 +
 +          var length = 0, j;
 +          switch (code) {
 +            case 0xFF4F: // Start of codestream (SOC)
 +              context.mainHeader = true;
 +              break;
 +            case 0xFFD9: // End of codestream (EOC)
 +              break;
 +            case 0xFF51: // Image and tile size (SIZ)
 +              length = readUint16(data, position);
 +              var siz = {};
 +              siz.Xsiz = readUint32(data, position + 4);
 +              siz.Ysiz = readUint32(data, position + 8);
 +              siz.XOsiz = readUint32(data, position + 12);
 +              siz.YOsiz = readUint32(data, position + 16);
 +              siz.XTsiz = readUint32(data, position + 20);
 +              siz.YTsiz = readUint32(data, position + 24);
 +              siz.XTOsiz = readUint32(data, position + 28);
 +              siz.YTOsiz = readUint32(data, position + 32);
 +              var componentsCount = readUint16(data, position + 36);
 +              siz.Csiz = componentsCount;
 +              var components = [];
 +              j = position + 38;
 +              for (var i = 0; i < componentsCount; i++) {
 +                var component = {
 +                  precision: (data[j] & 0x7F) + 1,
 +                  isSigned: !!(data[j] & 0x80),
 +                  XRsiz: data[j + 1],
 +                  YRsiz: data[j + 1]
 +                };
 +                calculateComponentDimensions(component, siz);
 +                components.push(component);
 +              }
 +              context.SIZ = siz;
 +              context.components = components;
 +              calculateTileGrids(context, components);
 +              context.QCC = [];
 +              context.COC = [];
 +              break;
 +            case 0xFF5C: // Quantization default (QCD)
 +              length = readUint16(data, position);
 +              var qcd = {};
 +              j = position + 2;
 +              var sqcd = data[j++];
 +              var spqcdSize, scalarExpounded;
 +              switch (sqcd & 0x1F) {
 +                case 0:
 +                  spqcdSize = 8;
 +                  scalarExpounded = true;
 +                  break;
 +                case 1:
 +                  spqcdSize = 16;
 +                  scalarExpounded = false;
 +                  break;
 +                case 2:
 +                  spqcdSize = 16;
 +                  scalarExpounded = true;
 +                  break;
 +                default:
 +                  throw 'Invalid SQcd value ' + sqcd;
 +              }
 +              qcd.noQuantization = spqcdSize == 8;
 +              qcd.scalarExpounded = scalarExpounded;
 +              qcd.guardBits = sqcd >> 5;
 +              var spqcds = [];
 +              while (j < length + position) {
 +                var spqcd = {};
 +                if (spqcdSize == 8) {
 +                  spqcd.epsilon = data[j++] >> 3;
 +                  spqcd.mu = 0;
 +                } else {
 +                  spqcd.epsilon = data[j] >> 3;
 +                  spqcd.mu = ((data[j] & 0x7) << 8) | data[j + 1];
 +                  j += 2;
 +                }
 +                spqcds.push(spqcd);
 +              }
 +              qcd.SPqcds = spqcds;
 +              if (context.mainHeader)
 +                context.QCD = qcd;
 +              else {
 +                context.currentTile.QCD = qcd;
 +                context.currentTile.QCC = [];
 +              }
 +              break;
 +            case 0xFF5D: // Quantization component (QCC)
 +              length = readUint16(data, position);
 +              var qcc = {};
 +              j = position + 2;
 +              var cqcc;
 +              if (context.SIZ.Csiz < 257)
 +                cqcc = data[j++];
 +              else {
 +                cqcc = readUint16(data, j);
 +                j += 2;
 +              }
 +              var sqcd = data[j++];
 +              var spqcdSize, scalarExpounded;
 +              switch (sqcd & 0x1F) {
 +                case 0:
 +                  spqcdSize = 8;
 +                  scalarExpounded = true;
 +                  break;
 +                case 1:
 +                  spqcdSize = 16;
 +                  scalarExpounded = false;
 +                  break;
 +                case 2:
 +                  spqcdSize = 16;
 +                  scalarExpounded = true;
 +                  break;
 +                default:
 +                  throw 'Invalid SQcd value ' + sqcd;
 +              }
 +              qcc.noQuantization = spqcdSize == 8;
 +              qcc.scalarExpounded = scalarExpounded;
 +              qcc.guardBits = sqcd >> 5;
 +              var spqcds = [];
 +              while (j < length + position) {
 +                var spqcd = {};
 +                if (spqcdSize == 8) {
 +                  spqcd.epsilon = data[j++] >> 3;
 +                  spqcd.mu = 0;
 +                } else {
 +                  spqcd.epsilon = data[j] >> 3;
 +                  spqcd.mu = ((data[j] & 0x7) << 8) | data[j + 1];
 +                  j += 2;
 +                }
 +                spqcds.push(spqcd);
 +              }
 +              qcc.SPqcds = spqcds;
 +              if (context.mainHeader)
 +                context.QCC[cqcc] = qcc;
 +              else
 +                context.currentTile.QCC[cqcc] = qcc;
 +              break;
 +            case 0xFF52: // Coding style default (COD)
 +              length = readUint16(data, position);
 +              var cod = {};
 +              j = position + 2;
 +              var scod = data[j++];
 +              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;
 +              cod.multipleComponentTransform = data[j++];
 +
 +              cod.decompositionLevelsCount = data[j++];
 +              cod.xcb = (data[j++] & 0xF) + 2;
 +              cod.ycb = (data[j++] & 0xF) + 2;
 +              var blockStyle = data[j++];
 +              cod.selectiveArithmeticCodingBypass = !!(blockStyle & 1);
 +              cod.resetContextProbabilities = !!(blockStyle & 2);
 +              cod.terminationOnEachCodingPass = !!(blockStyle & 4);
 +              cod.verticalyStripe = !!(blockStyle & 8);
 +              cod.predictableTermination = !!(blockStyle & 16);
 +              cod.segmentationSymbolUsed = !!(blockStyle & 32);
 +              cod.transformation = 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
 +                  });
 +                }
 +                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)
 +                context.COD = cod;
 +              else {
 +                context.currentTile.COD = cod;
 +                context.currentTile.COC = [];
 +              }
 +              break;
 +            case 0xFF90: // Start of tile-part (SOT)
 +              length = readUint16(data, position);
 +              var tile = {};
 +              tile.index = readUint16(data, position + 2);
 +              tile.length = readUint32(data, position + 4);
 +              tile.dataEnd = tile.length + position - 2;
 +              tile.partIndex = data[position + 8];
 +              tile.partsCount = data[position + 9];
 +
 +              context.mainHeader = false;
 +              if (tile.partIndex === 0) {
 +                // reset component specific settings
 +                tile.COD = context.COD;
 +                tile.COC = context.COC.slice(0); // clone of the global COC
 +                tile.QCD = context.QCD;
 +                tile.QCC = context.QCC.slice(0); // clone of the global COC
 +              }
 +              context.currentTile = tile;
 +              break;
 +            case 0xFF93: // Start of data (SOD)
 +              var tile = context.currentTile;
 +              if (tile.partIndex === 0) {
 +                initializeTile(context, tile.index);
 +                buildPackets(context);
 +              }
 +
 +              // 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;
 +            default:
 +              throw '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');
 +      }
 +      this.tiles = transformComponents(context);
 +      this.width = context.SIZ.Xsiz - context.SIZ.XOsiz;
 +      this.height = context.SIZ.Ysiz - context.SIZ.YOsiz;
 +      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);
 +    component.x1 = Math.ceil(siz.Xsiz / component.XRsiz);
 +    component.y0 = Math.ceil(siz.YOsiz / component.YRsiz);
 +    component.y1 = Math.ceil(siz.Ysiz / component.YRsiz);
 +    component.width = component.x1 - component.x0;
 +    component.height = component.y1 - component.y0;
 +  }
 +  function calculateTileGrids(context, components) {
 +    var siz = context.SIZ;
 +    // Section B.3 Division into tile and tile-components
 +    var 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.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);
 +        tile.ty1 = Math.min(siz.YTOsiz + (q + 1) * siz.YTsiz, siz.Ysiz);
 +        tile.width = tile.tx1 - tile.tx0;
 +        tile.height = tile.ty1 - tile.ty0;
 +        tile.components = [];
 +        tiles.push(tile);
 +      }
 +    }
 +    context.tiles = tiles;
 +
 +    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];
 +        tileComponent.tcx0 = Math.ceil(tile.tx0 / component.XRsiz);
 +        tileComponent.tcy0 = Math.ceil(tile.ty0 / component.YRsiz);
 +        tileComponent.tcx1 = Math.ceil(tile.tx1 / component.XRsiz);
 +        tileComponent.tcy1 = Math.ceil(tile.ty1 / component.YRsiz);
 +        tileComponent.width = tileComponent.tcx1 - tileComponent.tcx0;
 +        tileComponent.height = tileComponent.tcy1 - tileComponent.tcy0;
 +        tile.components[i] = tileComponent;
 +      }
 +    }
 +  }
 +  function getBlocksDimensions(context, component, r) {
 +    var codOrCoc = component.codingStyleParameters;
 +    var result = {};
 +    if (!codOrCoc.entropyCoderWithCustomPrecincts) {
 +      result.PPx = 15;
 +      result.PPy = 15;
 +    } else {
 +      result.PPx = codOrCoc.precinctsSizes[r].PPx;
 +      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);
 +    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 ?
 +      Math.ceil(resolution.trx1 / precinctWidth) -
 +      Math.floor(resolution.trx0 / precinctWidth) : 0;
 +    var numprecinctshigh = resolution.try1 > resolution.try0 ?
 +      Math.ceil(resolution.try1 / precinctHeight) -
 +      Math.floor(resolution.try0 / precinctHeight) : 0;
 +    var numprecincts = numprecinctswide * numprecinctshigh;
 +    var precinctXOffset = Math.floor(resolution.trx0 / precinctWidth) *
 +      precinctWidth;
 +    var precinctYOffset = Math.floor(resolution.try0 / precinctHeight) *
 +      precinctHeight;
 +    resolution.precinctParameters = {
 +      precinctXOffset: precinctXOffset,
 +      precinctYOffset: precinctYOffset,
 +      precinctWidth: precinctWidth,
 +      precinctHeight: precinctHeight,
 +      numprecinctswide: numprecinctswide,
 +      numprecinctshigh: numprecinctshigh,
 +      numprecincts: numprecincts
 +    };
 +  }
 +  function buildCodeblocks(context, subband, dimensions) {
 +    // Section B.7 Division sub-band into code-blocks
 +    var xcb_ = dimensions.xcb_;
 +    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 precinctParameters = subband.resolution.precinctParameters;
 +    var codeblocks = [];
 +    var precincts = [];
 +    for (var j = cby0; j < cby1; j++) {
 +      for (var i = cbx0; i < cbx1; i++) {
 +        var codeblock = {
 +          cbx: i,
 +          cby: j,
 +          tbx0: codeblockWidth * i,
 +          tby0: codeblockHeight * j,
 +          tbx1: codeblockWidth * (i + 1),
 +          tby1: codeblockHeight * (j + 1)
 +        };
 +        // calculate precinct number
 +        var pi = Math.floor((codeblock.tbx0 -
 +          precinctParameters.precinctXOffset) /
 +          precinctParameters.precinctWidth);
 +        var pj = Math.floor((codeblock.tby0 -
 +          precinctParameters.precinctYOffset) /
 +          precinctParameters.precinctHeight);
 +        var 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);
 +        } else {
 +          precincts[precinctNumber] = precinct = {
 +            cbxMin: i,
 +            cbyMin: j,
 +            cbxMax: i,
 +            cbyMax: j
 +          };
 +        }
 +        codeblock.precinct = precinct;
 +      }
 +    }
 +    subband.codeblockParameters = {
 +      codeblockWidth: xcb_,
 +      codeblockHeight: ycb_,
 +      numcodeblockwide: cbx1 - cbx0 + 1,
 +      numcodeblockhigh: cby1 - cby1 + 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) {
 +    var precinctCodeblocks = [];
 +    // Section B.10.8 Order of info in packet
 +    var subbands = resolution.subbands;
 +    // sub-bands already ordered in 'LL', 'HL', 'LH', and 'HH' sequence
 +    for (var i = 0, ii = subbands.length; i < ii; i++) {
 +      var subband = subbands[i];
 +      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);
 +      }
 +    }
 +    return {
 +      layerNumber: layerNumber,
 +      codeblocks: precinctCodeblocks
 +    };
 +  }
 +  function LayerResolutionComponentPositionIterator(context) {
 +    var siz = context.SIZ;
 +    var tileIndex = context.currentTile.index;
 +    var tile = context.tiles[tileIndex];
 +    var layersCount = tile.codingStyleDefaultParameters.layersCount;
 +    var componentsCount = siz.Csiz;
 +    var maxDecompositionLevelsCount = 0;
 +    for (var q = 0; q < componentsCount; q++) {
 +      maxDecompositionLevelsCount = Math.max(maxDecompositionLevelsCount,
 +        tile.components[q].codingStyleParameters.decompositionLevelsCount);
 +    }
 +
 +    var l = 0, r = 0, i = 0, k = 0;
 +
 +    this.nextPacket = function JpxImage_nextPacket() {
 +      // Section B.12.1.1 Layer-resolution-component-position
 +      for (; l < layersCount; l++) {
 +        for (; r <= maxDecompositionLevelsCount; r++) {
 +          for (; i < componentsCount; i++) {
 +            var component = tile.components[i];
 +            if (r > component.codingStyleParameters.decompositionLevelsCount)
 +              continue;
 +
 +            var resolution = component.resolutions[r];
 +            var numprecincts = resolution.precinctParameters.numprecincts;
 +            for (; k < numprecincts;) {
 +              var packet = createPacket(resolution, k, l);
 +              k++;
 +              return packet;
 +            }
 +            k = 0;
 +          }
 +          i = 0;
 +        }
 +        r = 0;
 +      }
 +      throw 'Out of packets';
 +    };
 +  }
 +  function ResolutionLayerComponentPositionIterator(context) {
 +    var siz = context.SIZ;
 +    var tileIndex = context.currentTile.index;
 +    var tile = context.tiles[tileIndex];
 +    var layersCount = tile.codingStyleDefaultParameters.layersCount;
 +    var componentsCount = siz.Csiz;
 +    var maxDecompositionLevelsCount = 0;
 +    for (var q = 0; q < componentsCount; q++) {
 +      maxDecompositionLevelsCount = Math.max(maxDecompositionLevelsCount,
 +        tile.components[q].codingStyleParameters.decompositionLevelsCount);
 +    }
 +
 +    var r = 0, l = 0, i = 0, k = 0;
 +
 +    this.nextPacket = function JpxImage_nextPacket() {
 +      // Section B.12.1.2 Resolution-layer-component-position
 +      for (; r <= maxDecompositionLevelsCount; r++) {
 +        for (; l < layersCount; l++) {
 +          for (; i < componentsCount; i++) {
 +            var component = tile.components[i];
 +            if (r > component.codingStyleParameters.decompositionLevelsCount)
 +              continue;
 +
 +            var resolution = component.resolutions[r];
 +            var numprecincts = resolution.precinctParameters.numprecincts;
 +            for (; k < numprecincts;) {
 +              var packet = createPacket(resolution, k, l);
 +              k++;
 +              return packet;
 +            }
 +            k = 0;
 +          }
 +          i = 0;
 +        }
 +        l = 0;
 +      }
 +      throw 'Out of packets';
 +    };
 +  }
 +  function buildPackets(context) {
 +    var siz = context.SIZ;
 +    var tileIndex = context.currentTile.index;
 +    var tile = context.tiles[tileIndex];
 +    var componentsCount = siz.Csiz;
 +    // Creating resolutions and sub-bands for each component
 +    for (var c = 0; c < componentsCount; c++) {
 +      var component = tile.components[c];
 +      var decompositionLevelsCount =
 +        component.codingStyleParameters.decompositionLevelsCount;
 +      // Section B.5 Resolution levels and sub-bands
 +      var resolutions = [];
 +      var subbands = [];
 +      for (var r = 0; r <= decompositionLevelsCount; r++) {
 +        var blocksDimensions = getBlocksDimensions(context, component, r);
 +        var resolution = {};
 +        var scale = 1 << (decompositionLevelsCount - r);
 +        resolution.trx0 = Math.ceil(component.tcx0 / scale);
 +        resolution.try0 = Math.ceil(component.tcy0 / scale);
 +        resolution.trx1 = Math.ceil(component.tcx1 / scale);
 +        resolution.try1 = Math.ceil(component.tcy1 / scale);
 +        buildPrecincts(context, resolution, blocksDimensions);
 +        resolutions.push(resolution);
 +
 +        var subband;
 +        if (r === 0) {
 +          // one sub-band (LL) with last decomposition
 +          subband = {};
 +          subband.type = 'LL';
 +          subband.tbx0 = Math.ceil(component.tcx0 / scale);
 +          subband.tby0 = Math.ceil(component.tcy0 / scale);
 +          subband.tbx1 = Math.ceil(component.tcx1 / scale);
 +          subband.tby1 = Math.ceil(component.tcy1 / scale);
 +          subband.resolution = resolution;
 +          buildCodeblocks(context, subband, blocksDimensions);
 +          subbands.push(subband);
 +          resolution.subbands = [subband];
 +        } else {
 +          var bscale = 1 << (decompositionLevelsCount - r + 1);
 +          var resolutionSubbands = [];
 +          // three sub-bands (HL, LH and HH) with rest of decompositions
 +          subband = {};
 +          subband.type = 'HL';
 +          subband.tbx0 = Math.ceil(component.tcx0 / bscale - 0.5);
 +          subband.tby0 = Math.ceil(component.tcy0 / bscale);
 +          subband.tbx1 = Math.ceil(component.tcx1 / bscale - 0.5);
 +          subband.tby1 = Math.ceil(component.tcy1 / bscale);
 +          subband.resolution = resolution;
 +          buildCodeblocks(context, subband, blocksDimensions);
 +          subbands.push(subband);
 +          resolutionSubbands.push(subband);
 +
 +          subband = {};
 +          subband.type = 'LH';
 +          subband.tbx0 = Math.ceil(component.tcx0 / bscale);
 +          subband.tby0 = Math.ceil(component.tcy0 / bscale - 0.5);
 +          subband.tbx1 = Math.ceil(component.tcx1 / bscale);
 +          subband.tby1 = Math.ceil(component.tcy1 / bscale - 0.5);
 +          subband.resolution = resolution;
 +          buildCodeblocks(context, subband, blocksDimensions);
 +          subbands.push(subband);
 +          resolutionSubbands.push(subband);
 +
 +          subband = {};
 +          subband.type = 'HH';
 +          subband.tbx0 = Math.ceil(component.tcx0 / bscale - 0.5);
 +          subband.tby0 = Math.ceil(component.tcy0 / bscale - 0.5);
 +          subband.tbx1 = Math.ceil(component.tcx1 / bscale - 0.5);
 +          subband.tby1 = Math.ceil(component.tcy1 / bscale - 0.5);
 +          subband.resolution = resolution;
 +          buildCodeblocks(context, subband, blocksDimensions);
 +          subbands.push(subband);
 +          resolutionSubbands.push(subband);
 +
 +          resolution.subbands = resolutionSubbands;
 +        }
 +      }
 +      component.resolutions = resolutions;
 +      component.subbands = subbands;
 +    }
 +    // Generate the packets sequence
 +    var progressionOrder = tile.codingStyleDefaultParameters.progressionOrder;
 +    var packetsIterator;
 +    switch (progressionOrder) {
 +      case 0:
 +        tile.packetsIterator =
 +          new LayerResolutionComponentPositionIterator(context);
 +        break;
 +      case 1:
 +        tile.packetsIterator =
 +          new ResolutionLayerComponentPositionIterator(context);
 +        break;
 +      default:
 +        throw 'Unsupported progression order ' + progressionOrder;
 +    }
 +  }
 +  function parseTilePackets(context, data, offset, dataLength) {
 +    var position = 0;
 +    var buffer, bufferSize = 0, skipNextBit = false;
 +    function readBits(count) {
 +      while (bufferSize < count) {
 +        var b = data[offset + position];
 +        position++;
 +        if (skipNextBit) {
 +          buffer = (buffer << 7) | b;
 +          bufferSize += 7;
 +          skipNextBit = false;
 +        } else {
 +          buffer = (buffer << 8) | b;
 +          bufferSize += 8;
 +        }
 +        if (b == 0xFF) {
 +          skipNextBit = true;
 +        }
 +      }
 +      bufferSize -= count;
 +      return (buffer >>> bufferSize) & ((1 << count) - 1);
 +    }
 +    function alignToByte() {
 +      bufferSize = 0;
 +      if (skipNextBit) {
 +        position++;
 +        skipNextBit = false;
 +      }
 +    }
 +    function readCodingpasses() {
 +      var value = readBits(1);
-       if (value === 0)
++      if (value === 0) {
 +        return 1;
++      }
 +      value = (value << 1) | readBits(1);
-       if (value == 0x02)
++      if (value == 0x02) {
 +        return 2;
++      }
 +      value = (value << 2) | readBits(2);
-       if (value <= 0x0E)
++      if (value <= 0x0E) {
 +        return (value & 0x03) + 3;
++      }
 +      value = (value << 5) | readBits(5);
-       if (value <= 0x1FE)
++      if (value <= 0x1FE) {
 +        return (value & 0x1F) + 6;
++      }
 +      value = (value << 7) | readBits(7);
 +      return (value & 0x7F) + 37;
 +    }
 +    var tileIndex = context.currentTile.index;
 +    var tile = context.tiles[tileIndex];
 +    var packetsIterator = tile.packetsIterator;
 +    while (position < dataLength) {
 +      var packet = packetsIterator.nextPacket();
 +      if (!readBits(1)) {
 +        alignToByte();
 +        continue;
 +      }
 +      var layerNumber = packet.layerNumber;
 +      var queue = [];
 +      for (var i = 0, ii = packet.codeblocks.length; i < ii; i++) {
 +        var 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;
 +        if ('included' in codeblock) {
 +          codeblockIncluded = !!readBits(1);
 +        } else {
 +          // reading inclusion tree
 +          var precinct = codeblock.precinct;
 +          var inclusionTree, zeroBitPlanesTree;
 +          if ('inclusionTree' in precinct) {
 +            inclusionTree = precinct.inclusionTree;
 +          } else {
 +            // building inclusion and zero bit-planes trees
 +            var width = precinct.cbxMax - precinct.cbxMin + 1;
 +            var height = precinct.cbyMax - precinct.cbyMin + 1;
 +            inclusionTree = new InclusionTree(width, height, layerNumber);
 +            zeroBitPlanesTree = new TagTree(width, height);
 +            precinct.inclusionTree = inclusionTree;
 +            precinct.zeroBitPlanesTree = zeroBitPlanesTree;
 +          }
 +
 +          if (inclusionTree.reset(codeblockColumn, codeblockRow, layerNumber)) {
 +            while (true) {
 +              if (readBits(1)) {
 +                var valueReady = !inclusionTree.nextLevel();
 +                if (valueReady) {
 +                  codeblock.included = true;
 +                  codeblockIncluded = firstTimeInclusion = true;
 +                  break;
 +                }
 +              } else {
 +                inclusionTree.incrementValue(layerNumber);
 +                break;
 +              }
 +            }
 +          }
 +        }
-         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)
++              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)) ?
 +          codingpassesLog2 - 1 : codingpassesLog2) + codeblock.Lblock;
 +        var codedDataLength = readBits(bits);
 +        queue.push({
 +          codeblock: codeblock,
 +          codingpasses: codingpasses,
 +          dataLength: codedDataLength
 +        });
 +      }
 +      alignToByte();
 +      while (queue.length > 0) {
 +        var packetItem = queue.shift();
 +        var codeblock = packetItem.codeblock;
-         if (!('data' in codeblock))
++        if (!('data' in codeblock)) {
 +          codeblock.data = [];
++        }
 +        codeblock.data.push({
 +          data: data,
 +          start: offset + position,
 +          end: offset + position + packetItem.dataLength,
 +          codingpasses: packetItem.codingpasses
 +        });
 +        position += packetItem.dataLength;
 +      }
 +    }
 +    return position;
 +  }
 +  function copyCoefficients(coefficients, x0, y0, width, height,
 +                            delta, mb, codeblocks, transformation,
 +                            segmentationSymbolUsed) {
-     var r = 0.5; // formula (E-6)
 +    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);
 +      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];
 +        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 chunk = dataItem.data.subarray(dataItem.start, dataItem.end);
 +        encodedData.set(chunk, k);
 +        k += chunk.length;
 +      }
 +      // decoding the item
 +      var decoder = new ArithmeticDecoder(encodedData, 0, totalLength);
 +      bitModel.setDecoder(decoder);
 +
 +      for (var q = 0; q < codingpasses; q++) {
 +        switch (currentCodingpassType) {
 +          case 0:
 +            bitModel.runSignificancePropogationPass();
 +            break;
 +          case 1:
 +            bitModel.runMagnitudeRefinementPass();
 +            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;
++      var n, nb, correction, position = 0;
++      var irreversible = (transformation === TransformType.IRREVERSIBLE);
++      var sign = bitModel.coefficentsSign;
++      var magnitude = bitModel.coefficentsMagnitude;
++      var bitsDecoded = bitModel.bitsDecoded;
 +      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;
++          n = (sign[position] ? -1 : 1) * magnitude[position];
++          nb = bitsDecoded[position];
++          correction = (irreversible || mb > nb) ? 1 << (mb - nb) : 1;
 +          coefficients[offset++] = n * correction * delta;
 +          position++;
 +        }
 +        offset += width - blockWidth;
 +      }
 +    }
 +  }
 +  function transformTile(context, tile, c) {
 +    var component = tile.components[c];
 +    var codingStyleParameters = component.codingStyleParameters;
 +    var quantizationParameters = component.quantizationParameters;
 +    var decompositionLevelsCount =
 +      codingStyleParameters.decompositionLevelsCount;
 +    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 transformation = codingStyleParameters.transformation;
++    var transform = transformation === TransformType.IRREVERSIBLE ?
++      new IrreversibleTransform() : new ReversibleTransform();
++
 +    var subbandCoefficients = [];
 +    var k = 0, b = 0;
 +    for (var i = 0; i <= decompositionLevelsCount; i++) {
 +      var resolution = component.resolutions[i];
 +
 +      for (var j = 0, jj = resolution.subbands.length; j < jj; j++) {
 +        var mu, epsilon;
 +        if (!scalarExpounded) {
 +          // formula E-5
 +          mu = spqcds[0].mu;
 +          epsilon = spqcds[0].epsilon + (i > 0 ? 1 - i : 0);
 +        } else {
 +          mu = spqcds[b].mu;
 +          epsilon = spqcds[b].epsilon;
 +        }
 +
 +        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 = transformation === TransformType.IRREVERSIBLE ?
++          Math.pow(2, precision + gainLog2 - epsilon) * (1 + mu / 2048) : 1;
 +        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++;
 +      }
 +    }
 +
-     var transformation = codingStyleParameters.transformation;
-     var transform = transformation === 0 ? new IrreversibleTransform() :
-       new ReversibleTransform();
 +    var result = transform.calculate(subbandCoefficients,
 +      component.tcx0, component.tcy0);
 +    return {
 +      left: component.tcx0,
 +      top: component.tcy0,
 +      width: result.width,
 +      height: result.height,
 +      items: result.items
 +    };
 +  }
 +  function transformComponents(context) {
 +    var siz = context.SIZ;
 +    var components = context.components;
 +    var componentsCount = siz.Csiz;
 +    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);
 +      }
 +
 +      // Section G.2.2 Inverse multi component transform
 +      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 component0 = tile.components[0];
++        var transformation = component0.codingStyleParameters.transformation;
++        if (transformation === TransformType.IRREVERSIBLE) {
++          // inverse irreversible multiple component transform
++          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];
++            y0items[j] = y0 + 1.402 * y2 + 0.5;
++            y1items[j] = y0 - 0.34413 * y1 - 0.71414 * y2 + 0.5;
++            y2items[j] = y0 + 1.772 * y1 + 0.5;
++          }
++        } else {
++          // inverse reversible multiple component transform
++          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;
++          }
 +        }
 +      }
 +
 +      // Section G.1 DC level shifting to unsigned component values
 +      for (var c = 0; c < componentsCount; c++) {
 +        var component = components[c];
-         if (component.isSigned)
++        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++)
++        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;
 +  }
 +  function initializeTile(context, tileIndex) {
 +    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;
 +      component.quantizationParameters = qcdOrQcc;
 +      var codOrCoc = c in context.currentTile.COC ?
 +        context.currentTile.COC[c] : context.currentTile.COD;
 +      component.codingStyleParameters = codOrCoc;
 +    }
 +    tile.codingStyleDefaultParameters = context.currentTile.COD;
 +  }
 +
 +  // Section B.10.2 Tag trees
 +  var TagTree = (function TagTreeClosure() {
 +    function TagTree(width, height) {
 +      var levelsLength = log2(Math.max(width, height)) + 1;
 +      this.levels = [];
 +      for (var i = 0; i < levelsLength; i++) {
 +        var level = {
 +          width: width,
 +          height: height,
 +          items: []
 +        };
 +        this.levels.push(level);
 +        width = Math.ceil(width / 2);
 +        height = Math.ceil(height / 2);
 +      }
 +    }
 +    TagTree.prototype = {
 +      reset: function TagTree_reset(i, j) {
 +        var currentLevel = 0, value = 0;
 +        while (currentLevel < this.levels.length) {
 +          var level = this.levels[currentLevel];
 +          var index = i + j * level.width;
 +          if (index in level.items) {
 +            value = level.items[index];
 +            break;
 +          }
 +          level.index = index;
 +          i >>= 1;
 +          j >>= 1;
 +          currentLevel++;
 +        }
 +        currentLevel--;
 +        var level = this.levels[currentLevel];
 +        level.items[level.index] = value;
 +        this.currentLevel = currentLevel;
 +        delete this.value;
 +      },
 +      incrementValue: function TagTree_incrementValue() {
 +        var level = this.levels[this.currentLevel];
 +        level.items[level.index]++;
 +      },
 +      nextLevel: function TagTree_nextLevel() {
 +        var currentLevel = this.currentLevel;
 +        var level = this.levels[currentLevel];
 +        var value = level.items[level.index];
 +        currentLevel--;
 +        if (currentLevel < 0) {
 +          this.value = value;
 +          return false;
 +        }
 +
 +        this.currentLevel = currentLevel;
 +        var level = this.levels[currentLevel];
 +        level.items[level.index] = value;
 +        return true;
 +      }
 +    };
 +    return TagTree;
 +  })();
 +
 +  var InclusionTree = (function InclusionTreeClosure() {
 +    function InclusionTree(width, height,  defaultValue) {
 +      var levelsLength = log2(Math.max(width, height)) + 1;
 +      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,
 +          height: height,
 +          items: items
 +        };
 +        this.levels.push(level);
 +
 +        width = Math.ceil(width / 2);
 +        height = Math.ceil(height / 2);
 +      }
 +    }
 +    InclusionTree.prototype = {
 +      reset: function InclusionTree_reset(i, j, stopValue) {
 +        var currentLevel = 0;
 +        while (currentLevel < this.levels.length) {
 +          var level = this.levels[currentLevel];
 +          var index = i + j * level.width;
 +          level.index = index;
 +          var value = level.items[index];
 +
-           if (value == 0xFF)
++          if (value == 0xFF) {
 +            break;
++          }
 +
 +          if (value > stopValue) {
 +            this.currentLevel = currentLevel;
 +            // already know about this one, propagating the value to top levels
 +            this.propagateValues();
 +            return false;
 +          }
 +
 +          i >>= 1;
 +          j >>= 1;
 +          currentLevel++;
 +        }
 +        this.currentLevel = currentLevel - 1;
 +        return true;
 +      },
 +      incrementValue: function InclusionTree_incrementValue(stopValue) {
 +        var level = this.levels[this.currentLevel];
 +        level.items[level.index] = stopValue + 1;
 +        this.propagateValues();
 +      },
 +      propagateValues: function InclusionTree_propagateValues() {
 +        var levelIndex = this.currentLevel;
 +        var level = this.levels[levelIndex];
 +        var currentValue = level.items[level.index];
 +        while (--levelIndex >= 0) {
 +          var level = this.levels[levelIndex];
 +          level.items[level.index] = currentValue;
 +        }
 +      },
 +      nextLevel: function InclusionTree_nextLevel() {
 +        var currentLevel = this.currentLevel;
 +        var level = this.levels[currentLevel];
 +        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.items[level.index] = value;
 +        return true;
 +      }
 +    };
 +    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)
++          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() {
 +    // 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)
 +    var LLAndLHContextsLabel = new Uint8Array([
 +      0, 5, 8, 0, 3, 7, 8, 0, 4, 7, 8, 0, 0, 0, 0, 0, 1, 6, 8, 0, 3, 7, 8, 0, 4,
 +      7, 8, 0, 0, 0, 0, 0, 2, 6, 8, 0, 3, 7, 8, 0, 4, 7, 8, 0, 0, 0, 0, 0, 2, 6,
 +      8, 0, 3, 7, 8, 0, 4, 7, 8, 0, 0, 0, 0, 0, 2, 6, 8, 0, 3, 7, 8, 0, 4, 7, 8
 +    ]);
 +    var HLContextLabel = new Uint8Array([
 +      0, 3, 4, 0, 5, 7, 7, 0, 8, 8, 8, 0, 0, 0, 0, 0, 1, 3, 4, 0, 6, 7, 7, 0, 8,
 +      8, 8, 0, 0, 0, 0, 0, 2, 3, 4, 0, 6, 7, 7, 0, 8, 8, 8, 0, 0, 0, 0, 0, 2, 3,
 +      4, 0, 6, 7, 7, 0, 8, 8, 8, 0, 0, 0, 0, 0, 2, 3, 4, 0, 6, 7, 7, 0, 8, 8, 8
 +    ]);
 +    var HHContextLabel = new Uint8Array([
 +      0, 1, 2, 0, 1, 2, 2, 0, 2, 2, 2, 0, 0, 0, 0, 0, 3, 4, 5, 0, 4, 5, 5, 0, 5,
 +      5, 5, 0, 0, 0, 0, 0, 6, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 0, 0, 0, 0, 8, 8,
 +      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)
++        if (!sign1) {
 +          return significance0 ? (!sign0 ? 1 : 0) : 1;
-         else
++        } else {
 +          return significance0 ? (!sign0 ? 0 : -1) : -1;
-       } else
++        }
++      } 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) {
 +      this.width = width;
 +      this.height = height;
 +
 +      this.contextLabelTable = subband == 'HH' ? HHContextLabel :
 +        subband == 'HL' ? HLContextLabel : LLAndLHContextsLabel;
 +
 +      var coefficientCount = width * height;
 +
 +      // coefficients outside the encoding region treated as insignificant
 +      // add border state cells for significanceState
 +      this.neighborsSignificance = new Uint8Array(coefficientCount);
 +      this.coefficentsSign = new Uint8Array(coefficientCount);
 +      this.coefficentsMagnitude = new Uint32Array(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;
 +      this.bitsDecoded = bitsDecoded;
 +
 +      this.reset();
 +    }
 +
 +    BitModel.prototype = {
 +      setDecoder: function BitModel_setDecoder(decoder) {
 +        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++)
++        for (var i = 1; i <= 16; i++) {
 +          this.contexts.push({index: 0, mps: 0});
++        }
 +      },
 +      setNeighborsSignificance:
 +        function BitModel_setNeighborsSignificance(row, column) {
 +        var neighborsSignificance = this.neighborsSignificance;
 +        var width = this.width, height = this.height;
 +        var index = row * width + column;
 +        if (row > 0) {
-           if (column > 0)
++          if (column > 0) {
 +            neighborsSignificance[index - width - 1] += 0x10;
-           if (column + 1 < width)
++          }
++          if (column + 1 < width) {
 +            neighborsSignificance[index - width + 1] += 0x10;
++          }
 +          neighborsSignificance[index - width] += 0x04;
 +        }
 +        if (row + 1 < height) {
-           if (column > 0)
++          if (column > 0) {
 +            neighborsSignificance[index + width - 1] += 0x10;
-           if (column + 1 < width)
++          }
++          if (column + 1 < width) {
 +            neighborsSignificance[index + width + 1] += 0x10;
++          }
 +          neighborsSignificance[index + width] += 0x04;
 +        }
-         if (column > 0)
++        if (column > 0) {
 +          neighborsSignificance[index - 1] += 0x01;
-         if (column + 1 < width)
++        }
++        if (column + 1 < width) {
 +          neighborsSignificance[index + 1] += 0x01;
++        }
 +        neighborsSignificance[index] |= 0x80;
 +      },
 +      runSignificancePropogationPass:
 +        function BitModel_runSignificancePropogationPass() {
 +        var decoder = this.decoder;
 +        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++)
++        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;
++              }
 +
 +              if (coefficentsMagnitude[index] || !neighborsSignificance[index])
 +                continue;
 +
 +              var contextLabel = labels[neighborsSignificance[index]];
 +              var cx = contexts[contextLabel];
 +              var decision = decoder.readBit(cx);
 +              if (decision) {
 +                var sign = this.decodeSignBit(i, j);
 +                coefficentsSign[index] = sign;
 +                coefficentsMagnitude[index] = 1;
 +                this.setNeighborsSignificance(i, j);
 +                processingFlags[index] |= firstMagnitudeBitMask;
 +              }
 +              bitsDecoded[index]++;
 +              processingFlags[index] |= processedMask;
 +            }
 +          }
 +        }
 +      },
 +      decodeSignBit: function BitModel_decodeSignBit(row, column) {
 +        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 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;
 +      },
 +      runMagnitudeRefinementPass:
 +        function BitModel_runMagnitudeRefinementPass() {
 +        var decoder = this.decoder;
 +        var width = this.width, height = this.height;
 +        var coefficentsMagnitude = this.coefficentsMagnitude;
 +        var neighborsSignificance = this.neighborsSignificance;
 +        var contexts = this.contexts;
 +        var bitsDecoded = this.bitsDecoded;
 +        var processingFlags = this.processingFlags;
 +        var processedMask = 1;
 +        var firstMagnitudeBitMask = 2;
 +        for (var i0 = 0; i0 < height; i0 += 4) {
 +          for (var j = 0; j < width; j++) {
 +            for (var i1 = 0; i1 < 4; i1++) {
 +              var i = i0 + i1;
-               if (i >= height)
++              if (i >= height) {
 +                break;
++              }
 +              var index = i * width + j;
 +
 +              // 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);
 +              coefficentsMagnitude[index] =
 +                (coefficentsMagnitude[index] << 1) | bit;
 +              bitsDecoded[index]++;
 +              processingFlags[index] |= processedMask;
 +            }
 +          }
 +        }
 +      },
 +      runCleanupPass: function BitModel_runCleanupPass() {
 +        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;
 +        var labels = this.contextLabelTable;
 +        var bitsDecoded = this.bitsDecoded;
 +        var processingFlags = this.processingFlags;
 +        var processedMask = 1;
 +        var firstMagnitudeBitMask = 2;
 +        var oneRowDown = width;
 +        var twoRowsDown = width * 2;
 +        var threeRowsDown = width * 3;
 +        for (var i0 = 0; i0 < height; i0 += 4) {
 +          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 &&
 +              processingFlags[index0] === 0 &&
 +              processingFlags[index0 + oneRowDown] === 0 &&
 +              processingFlags[index0 + twoRowsDown] === 0 &&
 +              processingFlags[index0 + threeRowsDown] === 0 &&
 +              neighborsSignificance[index0] === 0 &&
 +              neighborsSignificance[index0 + oneRowDown] === 0 &&
 +              neighborsSignificance[index0 + twoRowsDown] === 0 &&
 +              neighborsSignificance[index0 + threeRowsDown] === 0;
 +            var i1 = 0, index = index0;
 +            var cx, i;
 +            if (allEmpty) {
 +              cx = this.runLengthContext;
 +              var hasSignificantCoefficent = decoder.readBit(cx);
 +              if (!hasSignificantCoefficent) {
 +                bitsDecoded[index0]++;
 +                bitsDecoded[index0 + oneRowDown]++;
 +                bitsDecoded[index0 + twoRowsDown]++;
 +                bitsDecoded[index0 + threeRowsDown]++;
 +                continue; // next column
 +              }
 +              cx = this.uniformContext;
 +              i1 = (decoder.readBit(cx) << 1) | decoder.readBit(cx);
 +              i = i0 + i1;
 +              index += i1 * width;
 +
 +              var sign = this.decodeSignBit(i, j);
 +              coefficentsSign[index] = sign;
 +              coefficentsMagnitude[index] = 1;
 +              this.setNeighborsSignificance(i, j);
 +              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)
++              if (i >= height) {
 +                break;
++              }
 +
 +              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);
 +                coefficentsSign[index] = sign;
 +                coefficentsMagnitude[index] = 1;
 +                this.setNeighborsSignificance(i, j);
 +                processingFlags[index] |= firstMagnitudeBitMask;
 +              }
 +              bitsDecoded[index]++;
 +            }
 +          }
 +        }
 +      },
 +      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)
++        if (symbol != 0xA) {
 +          throw 'Invalid segmentation symbol';
++        }
 +      }
 +    };
 +
 +    return BitModel;
 +  })();
 +
 +  // Section F, Discrete wavelet transofrmation
 +  var Transform = (function TransformClosure() {
 +    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);
 +      }
 +      return ll;
 +    };
++    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) {
 +      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;
 +
 +      // 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 i, j, k, l;
++
++      for (i = 0; i < llHeight; i++) {
 +        var k = i * llWidth, l = i * 2 * width;
-         for (var j = 0, jj = llWidth; j < jj; j++, k++, l += 2)
++        for (var 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)
++      for (i = 0; i < hlHeight; i++) {
++        k = i * hlWidth; l = i * 2 * width + 1;
++        for (j = 0; j < hlWidth; 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)
++      for (i = 0; i < lhHeight; i++) {
++        k = i * lhWidth; l = (i * 2 + 1) * width;
++        for (j = 0; j < lhWidth; 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)
++      for (i = 0; i < hhHeight; i++) {
++        k = i * hhWidth; l = (i * 2 + 1) * width + 1;
++        for (j = 0; j < hhWidth; j++, k++, l += 2) {
 +          items[l] = hhItems[k];
++        }
 +      }
 +
 +      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;
 +          }
 +          continue;
 +        }
++        k = v * 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];
- 
-         // Section F.3.7 extending... using max extension of 4
-         var i1 = bufferPadding - 1, j1 = bufferPadding + 1;
-         var i2 = bufferPadding + width - 2, j2 = bufferPadding + width;
-         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--];
++        this.extend(rowBuffer, bufferPadding, width);
++        this.filter(rowBuffer, bufferPadding, width, u0, rowBuffer);
 +
-         this.filter(buffer, bufferPadding, width, u0, bufferOut);
++        items.set(rowBuffer.subarray(bufferPadding, bufferPadding + width), k);
++      }
 +
-         k = v * width;
-         l = bufferPadding;
-         for (var u = 0; u < width; u++, k++, l++)
-           items[k] = bufferOut[l];
++      // 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, when v0 even keep items as is, when odd divide by 2
 +          if ((v0 % 1) !== 0) {
 +            items[u] /= 2;
 +          }
 +          continue;
 +        }
 +
-         var k = u;
-         var l = bufferPadding;
-         for (var v = 0; v < height; v++, k += width, l++)
-           buffer[l] = items[k];
- 
-         // Section F.3.7 extending... using max extension of 4
-         var i1 = bufferPadding - 1, j1 = bufferPadding + 1;
-         var i2 = bufferPadding + height - 2, j2 = bufferPadding + height;
-         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--];
++        // 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;
++        }
 +
-         this.filter(buffer, bufferPadding, height, v0, bufferOut);
++        currentBuffer--;
++        var buffer = colBuffers[currentBuffer];
++        this.extend(buffer, bufferPadding, height);
++        this.filter(buffer, bufferPadding, height, v0, buffer);
 +
-         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,
 +        items: items
 +      };
 +    };
 +    return Transform;
 +  })();
 +
 +  // Section 3.8.2 Irreversible 9-7 filter
 +  var IrreversibleTransform = (function IrreversibleTransformClosure() {
 +    function IrreversibleTransform() {
 +      Transform.call(this);
 +    }
 +
 +    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);
 +
 +      var alpha = -1.586134342059924;
 +      var beta = -0.052980118572961;
 +      var gamma = 0.882911075530934;
 +      var delta = 0.443506852043971;
 +      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 2
 +      var j = offset_ - 3;
 +      for (var n = i0_ - 2, nn = i1_ + 2; n < nn; n++, j += 2)
 +        x[j] = K_ * y[j];
 +
 +      // 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 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]);
 +
 +      // 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]);
 +
 +      // 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]);
 +    };
 +
 +    return IrreversibleTransform;
 +  })();
 +
 +  // Section 3.8.1 Reversible 5-3 filter
 +  var ReversibleTransform = (function ReversibleTransformClosure() {
 +    function ReversibleTransform() {
 +      Transform.call(this);
 +    }
 +
 +    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);
 +
 +      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 (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);
 +    };
 +
 +    return ReversibleTransform;
 +  })();
 +
 +  return JpxImage;
 +})();
 +
 +
 +
 +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(cx) {
-         var qeIcx = QeTable[cx.index].qe;
++      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) {
-           var d = this.exchangeLps(cx);
-           this.renormD();
-           return d;
++          // 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) {
-             var d = this.exchangeMps(cx);
-             this.renormD();
-             return d;
++          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 {
-             return cx.mps;
++            d = cx_mps;
++            cx_index = nmpsIcx;
 +          }
 +        }
-       },
-       renormD: function ArithmeticDecoder_renormD() {
++        // 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;
-         }
++        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)
 +        return this[id];
-       return (this[id] = []);
++      return (this[id] = new Int8Array(1<<16));
 +    }
 +  };
 +
 +  function DecodingContext(data, start, end) {
 +    this.data = data;
 +    this.start = start;
 +    this.end = end;
 +  }
 +
 +  DecodingContext.prototype = {
 +    get decoder() {
 +      var decoder = new ArithmeticDecoder(this.data, this.start, this.end);
 +      return shadow(this, 'decoder', decoder);
 +    },
 +    get contextCache() {
 +      var cache = new ContextCache();
 +      return shadow(this, 'contextCache', cache);
 +    }
 +  };
 +
 +  // Annex A. Arithmetic Integer Decoding Procedure
 +  // 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 cx = contexts[prev];
-       if (!cx)
-         contexts[prev] = cx = {index: 0, mps: 0};
-       var bit = decoder.readBit(cx);
++      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;
 +      }
 +      state++;
 +    }
 +    v += offset;
 +    return !s ? v : v > 0 ? -v : null;
 +  }
 +
 +  // A.3 The IAID decoding procedure
 +  function decodeIAID(contextCache, decoder, codeLength) {
 +    var contexts = contextCache.getContexts('IAID');
 +
 +    var prev = 1;
 +    for (var i = 0; i < codeLength; i++) {
-       var cx = contexts[prev];
-       if (!cx)
-         contexts[prev] = cx = {index: 0, mps: 0};
-       var bit = decoder.readBit(cx);
++      var bit = decoder.readBit(contexts, prev);
 +      prev = (prev * 2) + bit;
 +    }
 +    if (codeLength < 31)
 +      return prev & ((1 << codeLength) - 1);
 +    else
 +      return prev - Math.pow(2, codeLength);
 +  }
 +
 +  // 7.3 Segment types
 +  var SegmentTypes = [
 +    'SymbolDictionary', null, null, null, 'IntermediateTextRegion', null,
 +    'ImmediateTextRegion', 'ImmediateLosslessTextRegion', null, null, null,
 +    null, null, null, null, null, 'patternDictionary', null, null, null,
 +    'IntermediateHalftoneRegion', null, 'ImmediateHalftoneRegion',
 +    'ImmediateLosslessHalftoneRegion', null, null, null, null, null, null, null,
 +    null, null, null, null, null, 'IntermediateGenericRegion', null,
 +    'ImmediateGenericRegion', 'ImmediateLosslessGenericRegion',
 +    'IntermediateGenericRefinementRegion', null,
 +    'ImmediateGenericRefinementRegion',
 +    'ImmediateLosslessGenericRefinementRegion', null, null, null, null,
 +    'PageInformation', 'EndOfPage', 'EndOfStripe', 'EndOfFile', 'Profiles',
 +    'Tables', null, null, null, null, null, null, null, null,
 +    'Extension'
 +  ];
 +
 +  var CodingTemplates = [
 +    [{x: -1, y: -2}, {x: 0, y: -2}, {x: 1, y: -2}, {x: -2, y: -1},
 +     {x: -1, y: -1}, {x: 0, y: -1}, {x: 1, y: -1}, {x: 2, y: -1},
 +     {x: -4, y: 0}, {x: -3, y: 0}, {x: -2, y: 0}, {x: -1, y: 0}],
 +    [{x: -1, y: -2}, {x: 0, y: -2}, {x: 1, y: -2}, {x: 2, y: -2},
 +     {x: -2, y: -1}, {x: -1, y: -1}, {x: 0, y: -1}, {x: 1, y: -1},
 +     {x: 2, y: -1}, {x: -3, y: 0}, {x: -2, y: 0}, {x: -1, y: 0}],
 +    [{x: -1, y: -2}, {x: 0, y: -2}, {x: 1, y: -2}, {x: -2, y: -1},
 +     {x: -1, y: -1}, {x: 0, y: -1}, {x: 1, y: -1}, {x: -2, y: 0},
 +     {x: -1, y: 0}],
 +    [{x: -3, y: -1}, {x: -2, y: -1}, {x: -1, y: -1}, {x: 0, y: -1},
 +     {x: 1, y: -1}, {x: -4, y: 0}, {x: -3, y: 0}, {x: -2, y: 0}, {x: -1, y: 0}]
 +  ];
 +
 +  var RefinementTemplates = [
 +    {
 +      coding: [{x: 0, y: -1}, {x: 1, y: -1}, {x: -1, y: 0}],
 +      reference: [{x: 0, y: -1}, {x: 1, y: -1}, {x: -1, y: 0}, {x: 0, y: 0},
 +                  {x: 1, y: 0}, {x: -1, y: 1}, {x: 0, y: 1}, {x: 1, y: 1}]
 +    },
 +    {
 +      coding: [{x: -1, y: -1}, {x: 0, y: -1}, {x: 1, y: -1}, {x: -1, y: 0}],
 +      reference: [{x: 0, y: -1}, {x: -1, y: 0}, {x: 0, y: 0}, {x: 1, y: 0},
 +                  {x: 0, y: 1}, {x: 1, y: 1}]
 +    }
 +  ];
 +
 +  var ReusedContexts = [
 +    0x1CD3, // '00111001101' (template) + '0011' (at),
 +    0x079A, // '001111001101' + '0',
 +    0x00E3, // '001110001' + '1',
 +    0x018B  // '011000101' + '1'
 +  ];
 +
 +  var RefinementReusedContexts = [
 +    0x0020, // '000' + '0' (coding) + '00010000' + '0' (reference)
 +    0x0008  // '0000' + '001000'
 +  ];
 +
 +  function log2(x) {
 +    var n = 1, i = 0;
 +    while (x > n) {
 +      n <<= 1;
 +      i++;
 +    }
 +    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;
 +  }
 +
 +  // 6.2 Generic Region Decoding Procedure
 +  function decodeBitmap(mmr, width, height, templateIndex, prediction, skip, at,
 +                        decodingContext) {
 +    if (mmr)
 +      error('JBIG2 error: MMR encoding is not supported');
 +
 +    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);
++    var templateX = new Int8Array(templateLength);
++    var templateY = new Int8Array(templateLength);
++    var changingTemplateEntries = [];
++    var reuseMask = 0, minX = 0, maxX = 0, minY = 0;
++
 +    for (var 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);
++      }
 +    }
++    changingTemplateEntries = new Uint8Array(changingTemplateEntries);
++    var changingEntriesLength = changingTemplateEntries.length;
 +
 +    var pseudoPixelContext = ReusedContexts[templateIndex];
 +    var bitmap = [];
 +
 +    var decoder = decodingContext.decoder;
 +    var contexts = decodingContext.contextCache.getContexts('GB');
 +
-     var ltp = 0;
++    var ltp = 0, c, j, i0, j0, k, contextLabel = 0;
 +    for (var i = 0; i < height; i++) {
 +      if (prediction) {
-         var cx = contexts[pseudoPixelContext];
-         if (!cx)
-           contexts[pseudoPixelContext] = cx = {index: 0, mps: 0};
-         var sltp = decoder.readBit(cx);
++        var sltp = decoder.readBit(contexts, pseudoPixelContext);
 +        ltp ^= sltp;
 +      }
 +      if (ltp) {
 +        bitmap.push(bitmap[bitmap.length - 1]); // duplicate previous row
 +        continue;
 +      }
 +      var row = new Uint8Array(width);
 +      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 (i + minY > 0 && j + minX >= 0 && j + maxX < width) {
++          // If yes, we can just shift the bits that are reusable and only
++          // fetch the remaining ones.
++          contextLabel = (contextLabel << 1) & reuseMask;
++          for (c = 0; c < changingEntriesLength; c++) {
++            k = changingTemplateEntries[c];
++            i0 = i + templateY[k];
++            j0 = j + templateX[k];
++            contextLabel |= bitmap[i0][j0] << (templateLength - 1 - k);
++          }
++        } else {
++          // compute the contextLabel from scratch
++          contextLabel = 0;
++          for (k = 0; k < templateLength; k++) {
++            i0 = i + templateY[k];
++            j0 = j + templateX[k];
++            if (i0 >= 0 && j0 >= 0 && j0 < width) {
++              contextLabel |= bitmap[i0][j0] << (templateLength - 1 - k);
++            }
++          }
 +        }
-         var cx = contexts[contextLabel];
-         if (!cx)
-           contexts[contextLabel] = cx = {index: 0, mps: 0};
-         var pixel = decoder.readBit(cx);
++        var pixel = decoder.readBit(contexts, contextLabel);
 +        row[j] = pixel;
 +      }
 +    }
 +    return bitmap;
 +  }
 +
 +  // 6.3.2 Generic Refinement Region Decoding Procedure
 +  function decodeRefinement(width, height, templateIndex, referenceBitmap,
 +                            offsetX, offsetY, prediction, at,
 +                            decodingContext) {
 +    var codingTemplate = RefinementTemplates[templateIndex].coding;
 +    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++) {
 +      codingTemplateX[k] = codingTemplate[k].x;
 +      codingTemplateY[k] = codingTemplate[k].y;
 +    }
 +    var referenceTemplate = RefinementTemplates[templateIndex].reference;
 +    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++) {
 +      referenceTemplateX[k] = referenceTemplate[k].x;
 +      referenceTemplateY[k] = referenceTemplate[k].y;
 +    }
 +    var referenceWidth = referenceBitmap[0].length;
 +    var referenceHeight = referenceBitmap.length;
 +
 +    var pseudoPixelContext = RefinementReusedContexts[templateIndex];
 +    var bitmap = [];
 +
 +    var decoder = decodingContext.decoder;
 +    var contexts = decodingContext.contextCache.getContexts('GR');
 +
 +    var ltp = 0;
 +    for (var i = 0; i < height; i++) {
 +      if (prediction) {
-         var cx = contexts[pseudoPixelContext];
-         if (!cx)
-           contexts[pseudoPixelContext] = cx = {index: 0, mps: 0};
-         var sltp = decoder.readBit(cx);
++        var sltp = decoder.readBit(contexts, pseudoPixelContext);
 +        ltp ^= sltp;
 +      }
 +      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 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)
 +            contextLabel <<= 1; // out of bound pixel
 +          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)
 +            contextLabel <<= 1; // out of bound pixel
 +          else
 +            contextLabel = (contextLabel << 1) | referenceBitmap[i0][j0];
 +        }
-         var cx = contexts[contextLabel];
-         if (!cx)
-           contexts[contextLabel] = cx = {index: 0, mps: 0};
-         var pixel = decoder.readBit(cx);
++        var pixel = decoder.readBit(contexts, contextLabel);
 +        row[j] = pixel;
 +      }
 +    }
 +
 +    return bitmap;
 +  }
 +
 +  // 6.5.5 Decoding the symbol dictionary
 +  function decodeSymbolDictionary(huffman, refinement, symbols,
 +                                  numberOfNewSymbols, numberOfExportedSymbols,
 +                                  huffmanTables, templateIndex, at,
 +                                  refinementTemplateIndex, refinementAt,
 +                                  decodingContext) {
 +    if (huffman)
 +      error('JBIG2 error: huffman is not supported');
 +
 +    var newSymbols = [];
 +    var currentHeight = 0;
 +    var symbolCodeLength = log2(symbols.length + numberOfNewSymbols);
 +
 +    var decoder = decodingContext.decoder;
 +    var contextCache = decodingContext.contextCache;
 +
 +    while (newSymbols.length < numberOfNewSymbols) {
 +      var deltaHeight = decodeInteger(contextCache, 'IADH', decoder); // 6.5.6
 +      currentHeight += deltaHeight;
 +      var currentWidth = 0;
 +      var totalWidth = 0;
 +      while (true) {
 +        var deltaWidth = decodeInteger(contextCache, 'IADW', decoder); // 6.5.7
 +        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,
 +            refinementTemplateIndex, symbol, rdx, rdy, false, refinementAt,
 +            decodingContext);
 +        } else {
 +          // 6.5.8.1 Direct-coded symbol bitmap
 +          bitmap = decodeBitmap(false, currentWidth, currentHeight,
 +            templateIndex, false, null, at, decodingContext);
 +        }
 +        newSymbols.push(bitmap);
 +      }
 +    }
 +    // 6.5.10 Exported symbols
 +    var exportedSymbols = [];
 +    var flags = [], currentFlag = false;
 +    var totalSymbolsLength = symbols.length + numberOfNewSymbols;
 +    while (flags.length < totalSymbolsLength) {
 +      var runLength = decodeInteger(contextCache, 'IAEX', decoder);
 +      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]);
 +    return exportedSymbols;
 +  }
 +
 +  function decodeTextRegion(huffman, refinement, width, height,
 +                            defaultPixelValue, numberOfSymbolInstances,
 +                            stripSize, inputSymbols, symbolCodeLength,
 +                            transposed, dsOffset, referenceCorner,
 +                            combinationOperator, huffmanTables,
 +                            refinementTemplateIndex, refinementAt,
 +                            decodingContext) {
 +    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);
 +      if (defaultPixelValue) {
 +        for (var j = 0; j < width; j++)
 +          row[j] = defaultPixelValue;
 +      }
 +      bitmap.push(row);
 +    }
 +
 +    var decoder = decodingContext.decoder;
 +    var contextCache = decodingContext.contextCache;
- 
-     if (transposed)
-       error('JBIG2 error: transposed is not supported');
- 
 +    var stripT = -decodeInteger(contextCache, 'IADT', decoder); // 6.4.6
 +    var firstS = 0;
 +    var i = 0;
 +    while (i < numberOfSymbolInstances) {
 +      var deltaT = decodeInteger(contextCache, 'IADT', decoder); // 6.4.6
 +      stripT += deltaT;
 +
 +      var deltaFirstS = decodeInteger(contextCache, 'IAFS', decoder); // 6.4.7
 +      firstS += deltaFirstS;
 +      var currentS = firstS;
 +      do {
 +        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 symbolBitmap = inputSymbols[symbolId];
 +        var symbolWidth = symbolBitmap[0].length;
 +        var symbolHeight = symbolBitmap.length;
 +        if (applyRefinement) {
 +          var rdw = decodeInteger(contextCache, 'IARDW', decoder); // 6.4.11.1
 +          var rdh = decodeInteger(contextCache, 'IARDH', decoder); // 6.4.11.2
 +          var rdx = decodeInteger(contextCache, 'IARDX', decoder); // 6.4.11.3
 +          var rdy = decodeInteger(contextCache, 'IARDY', decoder); // 6.4.11.4
 +          symbolWidth += rdw;
 +          symbolHeight += rdh;
 +          symbolBitmap = decodeRefinement(symbolWidth, symbolHeight,
 +            refinementTemplateIndex, symbolBitmap, (rdw >> 1) + rdx,
 +            (rdh >> 1) + rdy, false, refinementAt,
 +            decodingContext);
 +        }
 +        var offsetT = t - ((referenceCorner & 1) ? 0 : symbolHeight);
 +        var offsetS = currentS - ((referenceCorner & 2) ? symbolWidth : 0);
-         for (var t2 = 0; t2 < symbolHeight; t2++) {
-           var row = bitmap[offsetT + t2];
-           if (!row) continue;
-           var symbolRow = symbolBitmap[t2];
-           switch (combinationOperator) {
-             case 0: // OR
-               for (var s2 = 0; s2 < symbolWidth; s2++)
-                 row[offsetS + s2] |= symbolRow[s2];
-               break;
-             case 2: // XOR
-               for (var s2 = 0; s2 < symbolWidth; s2++)
-                 row[offsetS + s2] ^= symbolRow[s2];
-               break;
-             default:
-               error('JBIG2 error: operator ' + combinationOperator +
-                     ' is not supported');
++        if (transposed) {
++          // Place Symbol Bitmap from T1,S1
++          for (var s2 = 0; s2 < symbolHeight; s2++) {
++            var row = bitmap[offsetS + s2];
++            if (!row) {
++              continue;
++            }
++            var 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++) {
++                  row[offsetT + t2] |= symbolRow[t2];
++                }
++                break;
++              case 2: // XOR
++                for (var t2 = 0; t2 < maxWidth; t2++) {
++                  row[offsetT + t2] ^= symbolRow[t2];
++                }
++                break;
++              default:
++                error('JBIG2 error: operator ' + combinationOperator +
++                      ' is not supported');
++            }
 +          }
++          currentS += symbolHeight - 1;
++        } else {
++          for (var t2 = 0; t2 < symbolHeight; t2++) {
++            var row = bitmap[offsetT + t2];
++            if (!row) {
++              continue;
++            }
++            var symbolRow = symbolBitmap[t2];
++            switch (combinationOperator) {
++              case 0: // OR
++                for (var s2 = 0; s2 < symbolWidth; s2++) {
++                  row[offsetS + s2] |= symbolRow[s2];
++                }
++                break;
++              case 2: // XOR
++                for (var s2 = 0; s2 < symbolWidth; s2++) {
++                  row[offsetS + s2] ^= symbolRow[s2];
++                }
++                break;
++              default:
++                error('JBIG2 error: operator ' + combinationOperator +
++                      ' is not supported');
++            }
++          }
++          currentS += symbolWidth - 1;
 +        }
- 
-         currentS += symbolWidth - 1;
 +        i++;
- 
 +        var deltaS = decodeInteger(contextCache, 'IADS', decoder); // 6.4.8
 +        if (deltaS === null)
 +          break; // OOB
 +        currentS += deltaS + dsOffset;
 +      } while (true);
 +    }
 +    return bitmap;
 +  }
 +
 +  function readSegmentHeader(data, start) {
 +    var segmentHeader = {};
 +    segmentHeader.number = readUint32(data, start);
 +    var flags = data[start + 4];
 +    var segmentType = flags & 0x3F;
 +    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;
 +      position += 3;
 +      var bytes = (referredToCount + 7) >> 3;
 +      retainBits[0] = data[position++];
 +      while (--bytes > 0) {
 +        retainBits.push(data[position++]);
 +      }
 +    } 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 referredTo = [];
 +    for (var 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)
 +      segmentHeader.pageAssociation = data[position++];
 +    else {
 +      segmentHeader.pageAssociation = readUint32(data, position);
 +      position += 4;
 +    }
 +    segmentHeader.length = readUint32(data, position);
 +    position += 4;
 +    if (segmentHeader.length == 0xFFFFFFFF) {
 +      // 7.2.7 Segment data length, unknown segment length
 +      if (segmentType === 38) { // ImmediateGenericRegion
 +        var genericRegionInfo = readRegionSegmentInformation(data, position);
 +        var genericRegionSegmentFlags = data[position +
 +          RegionSegmentInformationFieldLength];
 +        var genericRegionMmr = !!(genericRegionSegmentFlags & 1);
 +        // searching for the segment end
 +        var searchPatternLength = 6;
 +        var searchPattern = new Uint8Array(searchPatternLength);
 +        if (!genericRegionMmr) {
 +          searchPattern[0] = 0xFF;
 +          searchPattern[1] = 0xAC;
 +        }
 +        searchPattern[2] = (genericRegionInfo.height >>> 24) & 0xFF;
 +        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++) {
 +          var j = 0;
 +          while (j < searchPatternLength && searchPattern[j] === data[i + j]) {
 +            j++;
 +          }
 +          if (j == searchPatternLength) {
 +            segmentHeader.length = i + searchPatternLength;
 +            break;
 +          }
 +        }
 +        if (segmentHeader.length == 0xFFFFFFFF) {
 +          error('JBIG2 error: segment end was not found');
 +        }
 +      } else {
 +        error('JBIG2 error: invalid unknown segment length');
 +      }
 +    }
 +    segmentHeader.headerEnd = position;
 +    return segmentHeader;
 +  }
 +
 +  function readSegments(header, data, start, end) {
 +    var segments = [];
 +    var position = start;
 +    while (position < end) {
 +      var segmentHeader = readSegmentHeader(data, position);
 +      position = segmentHeader.headerEnd;
 +      var segment = {
 +        header: segmentHeader,
 +        data: data
 +      };
 +      if (!header.randomAccess) {
 +        segment.start = position;
 +        position += segmentHeader.length;
 +        segment.end = position;
 +      }
 +      segments.push(segment);
 +      if (segmentHeader.type == 51)
 +        break; // end of file is found
 +    }
 +    if (header.randomAccess) {
 +      for (var i = 0, ii = segments.length; i < ii; i++) {
 +        segments[i].start = position;
 +        position += segments[i].header.length;
 +        segments[i].end = position;
 +      }
 +    }
 +    return segments;
 +  }
 +
 +  // 7.4.1 Region segment information field
 +  function readRegionSegmentInformation(data, start) {
 +    return {
 +      width: readUint32(data, start),
 +      height: readUint32(data, start + 4),
 +      x: readUint32(data, start + 8),
 +      y: readUint32(data, start + 12),
 +      combinationOperator: data[start + 16] & 7
 +    };
 +  }
 +  var RegionSegmentInformationFieldLength = 17;
 +
 +  function processSegment(segment, visitor) {
 +    var header = segment.header;
 +
 +    var data = segment.data, position = segment.start, end = segment.end;
 +    var args;
 +    switch (header.type) {
 +      case 0: // SymbolDictionary
 +        // 7.4.2 Symbol dictionary segment syntax
 +        var dictionary = {};
 +        var dictionaryFlags = readUint16(data, position); // 7.4.2.1.1
 +        dictionary.huffman = !!(dictionaryFlags & 1);
 +        dictionary.refinement = !!(dictionaryFlags & 2);
 +        dictionary.huffmanDHSelector = (dictionaryFlags >> 2) & 3;
 +        dictionary.huffmanDWSelector = (dictionaryFlags >> 4) & 3;
 +        dictionary.bitmapSizeSelector = (dictionaryFlags >> 6) & 1;
 +        dictionary.aggregationInstancesSelector = (dictionaryFlags >> 7) & 1;
 +        dictionary.bitmapCodingContextUsed = !!(dictionaryFlags & 256);
 +        dictionary.bitmapCodingContextRetained = !!(dictionaryFlags & 512);
 +        dictionary.template = (dictionaryFlags >> 10) & 3;
 +        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++) {
 +            at.push({
 +              x: readInt8(data, position),
 +              y: readInt8(data, position + 1)
 +            });
 +            position += 2;
 +          }
 +          dictionary.at = at;
 +        }
 +        if (dictionary.refinement && !dictionary.refinementTemplate) {
 +          var at = [];
 +          for (var i = 0; i < 2; i++) {
 +            at.push({
 +              x: readInt8(data, position),
 +              y: readInt8(data, position + 1)
 +            });
 +            position += 2;
 +          }
 +          dictionary.refinementAt = at;
 +        }
 +        dictionary.numberOfExportedSymbols = readUint32(data, position);
 +        position += 4;
 +        dictionary.numberOfNewSymbols = readUint32(data, position);
 +        position += 4;
 +        args = [dictionary, header.number, header.referredTo,
 +                data, position, end];
 +        break;
 +      case 6: // ImmediateTextRegion
 +      case 7: // ImmediateLosslessTextRegion
 +        var textRegion = {};
 +        textRegion.info = readRegionSegmentInformation(data, position);
 +        position += RegionSegmentInformationFieldLength;
 +        var textRegionSegmentFlags = readUint16(data, position);
 +        position += 2;
 +        textRegion.huffman = !!(textRegionSegmentFlags & 1);
 +        textRegion.refinement = !!(textRegionSegmentFlags & 2);
 +        textRegion.stripSize = 1 << ((textRegionSegmentFlags >> 2) & 3);
 +        textRegion.referenceCorner = (textRegionSegmentFlags >> 4) & 3;
 +        textRegion.transposed = !!(textRegionSegmentFlags & 64);
 +        textRegion.combinationOperator = (textRegionSegmentFlags >> 7) & 3;
 +        textRegion.defaultPixelValue = (textRegionSegmentFlags >> 9) & 1;
 +        textRegion.dsOffset = (textRegionSegmentFlags << 17) >> 27;
 +        textRegion.refinementTemplate = (textRegionSegmentFlags >> 15) & 1;
 +        if (textRegion.huffman) {
 +          var textRegionHuffmanFlags = readUint16(data, position);
 +          position += 2;
 +          textRegion.huffmanFS = (textRegionHuffmanFlags) & 3;
 +          textRegion.huffmanDS = (textRegionHuffmanFlags >> 2) & 3;
 +          textRegion.huffmanDT = (textRegionHuffmanFlags >> 4) & 3;
 +          textRegion.huffmanRefinementDW = (textRegionHuffmanFlags >> 6) & 3;
 +          textRegion.huffmanRefinementDH = (textRegionHuffmanFlags >> 8) & 3;
 +          textRegion.huffmanRefinementDX = (textRegionHuffmanFlags >> 10) & 3;
 +          textRegion.huffmanRefinementDY = (textRegionHuffmanFlags >> 12) & 3;
 +          textRegion.huffmanRefinementSizeSelector =
 +            !!(textRegionHuffmanFlags & 14);
 +        }
 +        if (textRegion.refinement && !textRegion.refinementTemplate) {
 +          var at = [];
 +          for (var i = 0; i < 2; i++) {
 +            at.push({
 +              x: readInt8(data, position),
 +              y: readInt8(data, position + 1)
 +            });
 +            position += 2;
 +          }
 +          textRegion.refinementAt = at;
 +        }
 +        textRegion.numberOfSymbolInstances = readUint32(data, position);
 +        position += 4;
 +        // TODO 7.4.3.1.7 Symbol ID Huffman table decoding
 +        if (textRegion.huffman)
 +          error('JBIG2 error: huffman is not supported');
 +        args = [textRegion, header.referredTo, data, position, end];
 +        break;
 +      case 38: // ImmediateGenericRegion
 +      case 39: // ImmediateLosslessGenericRegion
 +        var genericRegion = {};
 +        genericRegion.info = readRegionSegmentInformation(data, position);
 +        position += RegionSegmentInformationFieldLength;
 +        var genericRegionSegmentFlags = data[position++];
 +        genericRegion.mmr = !!(genericRegionSegmentFlags & 1);
 +        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++) {
 +            at.push({
 +              x: readInt8(data, position),
 +              y: readInt8(data, position + 1)
 +            });
 +            position += 2;
 +          }
 +          genericRegion.at = at;
 +        }
 +        args = [genericRegion, data, position, end];
 +        break;
 +      case 48: // PageInformation
 +        var pageInfo = {
 +          width: readUint32(data, position),
 +          height: readUint32(data, position + 4),
 +          resolutionX: readUint32(data, position + 8),
 +          resolutionY: readUint32(data, position + 12)
 +        };
 +        if (pageInfo.height == 0xFFFFFFFF)
 +          delete pageInfo.height;
 +        var pageSegmentFlags = data[position + 16];
 +        var pageStripingInformatiom = readUint16(data, position + 17);
 +        pageInfo.lossless = !!(pageSegmentFlags & 1);
 +        pageInfo.refinement = !!(pageSegmentFlags & 2);
 +        pageInfo.defaultPixelValue = (pageSegmentFlags >> 2) & 1;
 +        pageInfo.combinationOperator = (pageSegmentFlags >> 3) & 3;
 +        pageInfo.requiresBuffer = !!(pageSegmentFlags & 32);
 +        pageInfo.combinationOperatorOverride = !!(pageSegmentFlags & 64);
 +        args = [pageInfo];
 +        break;
 +      case 49: // EndOfPage
 +        break;
 +      case 50: // EndOfStripe
 +        break;
 +      case 51: // EndOfFile
 +        break;
++      case 62: // 7.4.15 defines 2 extension types which
++               // are comments and can be ignored.
++        break;
 +      default:
 +        error('JBIG2 error: segment type ' + header.typeName + '(' +
 +              header.type + ') is not implemented');
 +    }
 +    var callbackName = 'on' + header.typeName;
 +    if (callbackName in visitor)
 +      visitor[callbackName].apply(visitor, args);
 +  }
 +
 +  function processSegments(segments, visitor) {
 +    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)
 +      error('JBIG2 error: invalid header');
 +    var header = {};
 +    position += 8;
 +    var flags = data[position++];
 +    header.randomAccess = !(flags & 1);
 +    if (!(flags & 2)) {
 +      header.numberOfPages = readUint32(data, position);
 +      position += 4;
 +    }
 +    var segments = readSegments(header, data, position, end);
 +    error('Not implemented');
 +    // processSegments(segments, new SimpleSegmentVisitor());
 +  }
 +
 +  function parseJbig2Chunks(chunks) {
 +    var visitor = new SimpleSegmentVisitor();
 +    for (var i = 0, ii = chunks.length; i < ii; i++) {
 +      var chunk = chunks[i];
 +      var segments = readSegments({}, chunk.data, chunk.start, chunk.end);
 +      processSegments(segments, visitor);
 +    }
 +    return visitor.buffer;
 +  }
 +
 +  function SimpleSegmentVisitor() {}
 +
 +  SimpleSegmentVisitor.prototype = {
 +    onPageInformation: function SimpleSegmentVisitor_onPageInformation(info) {
 +      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) {
 +      var pageInfo = this.currentPageInfo;
 +      var width = regionInfo.width, height = regionInfo.height;
 +      var rowSize = (pageInfo.width + 7) >> 3;
 +      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;
 +              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;
 +              mask >>= 1;
 +              if (!mask) {
 +                mask = 128;
 +                offset++;
 +              }
 +            }
 +            break;
 +          default:
 +            error('JBIG2 error: operator ' + combinationOperator +
 +                  ' is not supported');
 +        }
 +      }
 +    },
 +    onImmediateGenericRegion:
 +      function SimpleSegmentVisitor_onImmediateGenericRegion(region, data,
 +                                                             start, end) {
 +      var regionInfo = region.info;
 +      var decodingContext = new DecodingContext(data, start, end);
 +      var bitmap = decodeBitmap(region.mmr, regionInfo.width, regionInfo.height,
 +                                region.template, region.prediction, null,
 +                                region.at, decodingContext);
 +      this.drawBitmap(regionInfo, bitmap);
 +    },
 +    onImmediateLosslessGenericRegion:
 +      function SimpleSegmentVisitor_onImmediateLosslessGenericRegion() {
 +      this.onImmediateGenericRegion.apply(this, arguments);
 +    },
 +    onSymbolDictionary:
 +      function SimpleSegmentVisitor_onSymbolDictionary(dictionary,
 +                                                       currentSegment,
 +                                                       referredSegments,
 +                                                       data, start, end) {
 +      var huffmanTables;
 +      if (dictionary.huffman)
 +        error('JBIG2 error: huffman is not supported');
 +
 +      // Combines exported symbols from all referred segments
 +      var symbols = this.symbols;
 +      if (!symbols)
 +        this.symbols = symbols = {};
 +
 +      var inputSymbols = [];
 +      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,
 +        dictionary.refinement, inputSymbols, dictionary.numberOfNewSymbols,
 +        dictionary.numberOfExportedSymbols, huffmanTables,
 +        dictionary.template, dictionary.at,
 +        dictionary.refinementTemplate, dictionary.refinementAt,
 +        decodingContext);
 +    },
 +    onImmediateTextRegion:
 +      function SimpleSegmentVisitor_onImmediateTextRegion(region,
 +                                                          referredSegments,
 +                                                          data, start, end) {
 +      var regionInfo = region.info;
 +      var huffmanTables;
 +
 +      // Combines exported symbols from all referred segments
 +      var symbols = this.symbols;
 +      var inputSymbols = [];
 +      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);
 +      var bitmap = decodeTextRegion(region.huffman, region.refinement,
 +        regionInfo.width, regionInfo.height, region.defaultPixelValue,
 +        region.numberOfSymbolInstances, region.stripSize, inputSymbols,
 +        symbolCodeLength, region.transposed, region.dsOffset,
 +        region.referenceCorner, region.combinationOperator, huffmanTables,
 +        region.refinementTemplate, region.refinementAt, decodingContext);
 +      this.drawBitmap(regionInfo, bitmap);
 +    },
 +    onImmediateLosslessTextRegion:
 +      function SimpleSegmentVisitor_onImmediateLosslessTextRegion() {
 +        this.onImmediateTextRegion.apply(this, arguments);
 +    }
 +  };
 +
 +  function Jbig2Image() {}
 +
 +  Jbig2Image.prototype = {
 +    parseChunks: function Jbig2Image_parseChunks(chunks) {
 +      return parseJbig2Chunks(chunks);
 +    }
 +  };
 +
 +  return Jbig2Image;
 +})();
 +
 +
 +var bidi = PDFJS.bidi = (function bidiClosure() {
 +  // Character types for symbols from 0000 to 00FF.
 +  var baseTypes = [
 +    'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'S', 'B', 'S', 'WS',
 +    'B', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN',
 +    'BN', 'BN', 'B', 'B', 'B', 'S', 'WS', 'ON', 'ON', 'ET', 'ET', 'ET', 'ON',
 +    'ON', 'ON', 'ON', 'ON', 'ON', 'CS', 'ON', 'CS', 'ON', 'EN', 'EN', 'EN',
 +    'EN', 'EN', 'EN', 'EN', 'EN', 'EN', 'EN', 'ON', 'ON', 'ON', 'ON', 'ON',
 +    'ON', 'ON', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L',
 +    'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'ON', 'ON',
 +    'ON', 'ON', 'ON', 'ON', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L',
 +    'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L',
 +    'L', 'ON', 'ON', 'ON', 'ON', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'B', 'BN',
 +    'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN',
 +    'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN', 'BN',
 +    'BN', 'CS', 'ON', 'ET', 'ET', 'ET', 'ET', 'ON', 'ON', 'ON', 'ON', 'L', 'ON',
 +    'ON', 'ON', 'ON', 'ON', 'ET', 'ET', 'EN', 'EN', 'ON', 'L', 'ON', 'ON', 'ON',
 +    'EN', 'L', 'ON', 'ON', 'ON', 'ON', 'ON', 'L', 'L', 'L', 'L', 'L', 'L', 'L',
 +    'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L',
 +    'L', 'ON', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L',
 +    'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L',
 +    'L', 'L', 'L', 'ON', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L'
 +  ];
 +
 +  // Character types for symbols from 0600 to 06FF
 +  var arabicTypes = [
 +    'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
 +    'CS', 'AL', 'ON', 'ON', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'AL',
 +    'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
 +    'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
 +    'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
 +    'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
 +    'AL', 'AL', 'AL', 'AL', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM',
 +    'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'AL', 'AL', 'AL', 'AL',
 +    'AL', 'AL', 'AL', 'AN', 'AN', 'AN', 'AN', 'AN', 'AN', 'AN', 'AN', 'AN',
 +    'AN', 'ET', 'AN', 'AN', 'AL', 'AL', 'AL', 'NSM', 'AL', 'AL', 'AL', 'AL',
 +    'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
 +    'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
 +    'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
 +    'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
 +    'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
 +    'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
 +    'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
 +    'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
 +    'AL', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM',
 +    'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'NSM', 'ON', 'NSM',
 +    'NSM', 'NSM', 'NSM', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL',
 +    'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL', 'AL'
 +  ];
 +
 +  function isOdd(i) {
 +    return (i & 1) !== 0;
 +  }
 +
 +  function isEven(i) {
 +    return (i & 1) === 0;
 +  }
 +
 +  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;
 +  }
 +
 +  function setValues(arr, start, end, value) {
 +    for (var j = start; j < end; ++j) {
 +      arr[j] = value;
 +    }
 +  }
 +
 +  function reverseValues(arr, start, end) {
 +    for (var i = start, j = end - 1; i < j; ++i, --j) {
 +      var temp = arr[i];
 +      arr[i] = arr[j];
 +      arr[j] = temp;
 +    }
 +  }
 +
 +  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 BidiResult(str, isLTR, vertical) {
 +    this.str = str;
-     this.dir = vertical ? 'ttb' : isLTR ? 'ltr' : 'rtl';
++    this.dir = (vertical ? 'ttb' : (isLTR ? 'ltr' : 'rtl'));
 +  }
 +
 +  function bidi(str, startLevel, vertical) {
 +    var isLTR = true;
 +    var strLength = str.length;
-     if (strLength === 0 || vertical)
++    if (strLength === 0 || vertical) {
 +      return new BidiResult(str, isLTR, vertical);
++    }
 +
-     // get types, fill arrays
- 
++    // Get types and fill arrays
 +    var chars = [];
 +    var types = [];
-     var oldtypes = [];
 +    var numBidi = 0;
 +
 +    for (var 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);
 +    }
 +
 +    if (startLevel == -1) {
 +      if ((strLength / numBidi) < 0.3) {
 +        isLTR = true;
 +        startLevel = 0;
 +      } else {
 +        isLTR = false;
 +        startLevel = 1;
 +      }
 +    }
 +
 +    var levels = [];
- 
 +    for (var 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;
 +
 +    /*
 +     W1. Examine each non-spacing mark (NSM) in the level run, and change the
 +     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')
++      if (types[i] == 'NSM') {
 +        types[i] = lastType;
-       else
++      } else {
 +        lastType = types[i];
++      }
 +    }
 +
 +    /*
 +     W2. Search backwards from each instance of a European number until the
 +     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')
++      if (t == 'EN') {
 +        types[i] = (lastType == 'AL') ? 'AN' : 'EN';
-       else if (t == 'R' || t == 'L' || t == 'AL')
++      } 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')
++      if (t == 'AL') {
 +        types[i] = 'R';
++      }
 +    }
 +
 +    /*
 +     W4. A single European separator between two European numbers changes to a
 +     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')
++      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])
++          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') {
 +        // do before
 +        for (var j = i - 1; j >= 0; --j) {
-           if (types[j] != 'ET')
++          if (types[j] != 'ET') {
 +            break;
++          }
 +          types[j] = 'EN';
 +        }
 +        // do after
 +        for (var j = i + 1; j < strLength; --j) {
-           if (types[j] != 'ET')
++          if (types[j] != 'ET') {
 +            break;
++          }
 +          types[j] = 'EN';
 +        }
 +      }
 +    }
 +
 +    /*
 +     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')
++      if (t == 'WS' || t == 'ES' || t == 'ET' || t == 'CS') {
 +        types[i] = 'ON';
++      }
 +    }
 +
 +    /*
 +     W7. Search backwards from each instance of a European number until the
 +     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')
++      if (t == 'EN') {
++        types[i] = ((lastType == 'L') ? 'L' : 'EN');
++      } else if (t == 'R' || t == 'L') {
 +        lastType = t;
++      }
 +    }
 +
 +    /*
 +     N1. A sequence of neutrals takes the direction of the surrounding strong
 +     text if the text on both sides has the same direction. European and Arabic
 +     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') {
 +        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)
 +      }
 +    }
 +
 +    /*
 +     N2. Any remaining neutrals take the embedding direction.
 +     */
- 
 +    for (var i = 0; i < strLength; ++i) {
-       if (types[i] == 'ON')
++      if (types[i] == 'ON') {
 +        types[i] = e;
++      }
 +    }
 +
 +    /*
 +     I1. For all characters with an even (left-to-right) embedding direction,
 +     those of type R go up one level and those of type AN or EN go up two
 +     levels.
 +     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];
 +      if (isEven(levels[i])) {
 +        if (t == 'R') {
 +          levels[i] += 1;
 +        } else if (t == 'AN' || t == 'EN') {
 +          levels[i] += 2;
 +        }
-       } else { // isOdd, so
++      } else { // isOdd
 +        if (t == 'L' || t == 'AN' || t == 'EN') {
 +          levels[i] += 1;
 +        }
 +      }
 +    }
 +
 +    /*
 +     L1. On each line, reset the embedding level of the following characters to
 +     the paragraph embedding level:
 +
 +     segment separators,
 +     paragraph separators,
 +     any sequence of whitespace characters preceding a segment separator or
 +     paragraph separator, and any sequence of white space characters at the end
 +     of the line.
 +     */
 +
 +    // don't bother as text is only single line
 +
 +    /*
 +     L2. From the highest level found in the text to the lowest odd level on
 +     each line, reverse any contiguous sequence of characters that are at that
 +     level or higher.
 +     */
 +
 +    // 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)
++      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) {
 +      // find segments to reverse
 +      var start = -1;
 +      for (var i = 0, ii = levels.length; i < ii; ++i) {
 +        if (levels[i] < level) {
 +          if (start >= 0) {
 +            reverseValues(chars, start, i);
 +            start = -1;
 +          }
 +        } else if (start < 0) {
 +          start = i;
 +        }
 +      }
 +      if (start >= 0) {
 +        reverseValues(chars, start, levels.length);
 +      }
 +    }
 +
 +    /*
 +     L3. Combining marks applied to a right-to-left base character will at this
 +     point precede their base character. If the rendering engine expects them to
 +     follow the base characters in the final display process, then the ordering
 +     of the marks and the base character must be reversed.
 +     */
 +
 +    // don't bother for now
 +
 +    /*
 +     L4. A character that possesses the mirrored property as specified by
 +     Section 4.7, Mirrored, must be depicted by a mirrored glyph if the resolved
 +     directionality of that character is R.
 +     */
 +
 +    // 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) {
 +      var ch = chars[i];
-       if (ch != '<' && ch != '>')
++      if (ch != '<' && ch != '>') {
 +        result += ch;
++      }
 +    }
- 
 +    return new BidiResult(result, isLTR);
 +  }
 +
 +  return bidi;
 +})();
 +
 +
 +
- var Metadata = PDFJS.Metadata = (function MetadataClosure() {
-   function fixMetadata(meta) {
-     return meta.replace(/>\\376\\377([^<]+)/g, function(all, codes) {
-       var bytes = codes.replace(/\\([0-3])([0-7])([0-7])/g,
-                                 function(code, d1, d2, d3) {
-         return String.fromCharCode(d1 * 64 + d2 * 8 + d3 * 1);
-       });
-       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) :
-           '&#x' + (0x10000 + code).toString(16).substring(1) + ';';
-       }
-       return '>' + chars;
-     });
++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);
++    },
 +
-   function Metadata(meta) {
-     if (typeof meta === 'string') {
-       // Ghostscript produces invalid metadata
-       meta = fixMetadata(meta);
++    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;
++      }
++    },
 +
-       var parser = new DOMParser();
-       meta = parser.parseFromString(meta, 'application/xml');
-     } else if (!(meta instanceof Document)) {
-       error('Metadata: Invalid metadata object');
++    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];
 +    }
 +
-     this.metaDocument = meta;
-     this.metadata = {};
-     this.parse();
++  };
++  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, {});
 +
-   Metadata.prototype = {
-     parse: function Metadata_parse() {
-       var doc = this.metaDocument;
-       var rdf = doc.documentElement;
++  return IdentityCMap;
++})();
 +
-       if (rdf.nodeName.toLowerCase() !== 'rdf:rdf') { // Wrapped in <xmpmeta>
-         rdf = rdf.firstChild;
-         while (rdf && rdf.nodeName.toLowerCase() !== 'rdf:rdf')
-           rdf = rdf.nextSibling;
-       }
++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;
++  }
 +
-       var nodeName = (rdf) ? rdf.nodeName.toLowerCase() : null;
-       if (!rdf || nodeName !== 'rdf:rdf' || !rdf.hasChildNodes())
-         return;
++  function expectString(obj) {
++    if (!isString(obj)) {
++      error('Malformed CMap: expected string.');
++    }
++  }
 +
-       var children = rdf.childNodes, desc, entry, name, i, ii, length, iLength;
++  function expectInt(obj) {
++    if (!isInt(obj)) {
++      error('Malformed CMap: expected int.');
++    }
++  }
 +
-       for (i = 0, length = children.length; i < length; i++) {
-         desc = children[i];
-         if (desc.nodeName.toLowerCase() !== 'rdf:description')
-           continue;
++  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);
++    }
++  }
 +
-         for (ii = 0, iLength = desc.childNodes.length; ii < iLength; ii++) {
-           if (desc.childNodes[ii].nodeName.toLowerCase() !== '#text') {
-             entry = desc.childNodes[ii];
-             name = entry.nodeName.toLowerCase();
-             this.metadata[name] = entry.textContent.trim();
-           }
++  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.');
++  }
 +
-     get: function Metadata_get(name) {
-       return this.metadata[name] || null;
-     },
++  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);
++    }
++  }
 +
-     has: function Metadata_has(name) {
-       return typeof this.metadata[name] !== 'undefined';
++  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);
 +    }
-   };
++  }
 +
-   return Metadata;
++  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 -*- /
 +/* 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
 +
 +       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.
 +*/
 +
 +// - 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 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 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);
++    var R = new Int32Array(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) {
++    function quantizeAndInverse(zz, p) {
 +      var qt = component.quantizationTable;
 +      var v0, v1, v2, v3, v4, v5, v6, v7, t;
-       var p = dataIn;
 +      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;
++          t = (dctSqrt2 * p[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;
++        p[i] = clampTo8bit((p[i] + 2056) >> 4);
 +      }
 +    }
 +
 +    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);
++        quantizeAndInverse(component.blocks[blockRow][blockCol], 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++];
++            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;
 +          }
 +        }
 +        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));
++                row.push(new Int16Array(64));
 +              blocks.push(row);
 +            }
 +            component.blocksPerLine = blocksPerLine;
 +            component.blocksPerColumn = blocksPerColumn;
 +            component.blocks = blocks;
 +          }
 +        }
 +        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();
 +
 +            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 component, componentLine, componentScaleX, componentScaleY;
++      var x, y, i;
 +      var offset = 0;
 +      var Y, Cb, Cr, K, C, M, Ye, R, G, B;
 +      var colorTransform;
-       var dataLength = width * height * this.components.length;
++      var numComponents = this.components.length;
++      var dataLength = width * height * numComponents;
 +      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;
-             }
++      // First construct image data ...
++      for (i = 0; i < numComponents; i++) {
++        component = this.components[i];
++        componentScaleX = component.scaleX * scaleX;
++        componentScaleY = component.scaleY * scaleY;
++        offset = i;
++        for (y = 0; y < height; y++) {
++          componentLine = component.lines[0 | (y * componentScaleY)];
++          for (x = 0; x < width; x++) {
++            data[offset] = componentLine[0 | (x * componentScaleX)];
++            offset += numComponents;
 +          }
-           break;
++        }
++      }
++
++      // ... then transform colors, if necessary
++      switch (numComponents) {
++        case 1: case 2: break;
++        // no color conversion for one or two compoenents
++
 +        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)];
++          if (colorTransform) {
++            for (i = 0; i < dataLength; i += numComponents) {
++              Y  = data[i    ];
++              Cb = data[i + 1];
++              Cr = data[i + 2];
 +
-                 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));
-               }
++              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;
++              data[i    ] = R;
++              data[i + 1] = G;
++              data[i + 2] = B;
 +            }
 +          }
 +          break;
 +        case 4:
-           if (!this.adobe)
-             throw 'Unsupported color mode (4 components)';
 +          // 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;
++          if (colorTransform) {
++            for (i = 0; i < dataLength; i += numComponents) {
++              Y  = data[i];
++              Cb = data[i + 1];
++              Cr = data[i + 2];
++
++              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[i    ] = C;
++              data[i + 1] = M;
++              data[i + 2] = Ye;
++              // K is unchanged
 +            }
 +          }
 +          break;
 +        default:
 +          throw 'Unsupported color mode';
 +      }
 +      return data;
 +    },
 +    copyToImageData: function copyToImageData(imageData) {
 +      var width = imageData.width, height = imageData.height;
++      var imageDataBytes = width * height * 4;
 +      var imageDataArray = imageData.data;
 +      var data = this.getData(width, height);
-       var i = 0, j = 0, x, y;
++      var i = 0, j = 0;
 +      var Y, K, C, M, R, G, B;
 +      switch (this.components.length) {
 +        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;
-             }
++          while (j < imageDataBytes) {
++            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;
-             }
++          while (j < imageDataBytes) {
++            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;
-             }
++          while (j < imageDataBytes) {
++            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';
 +      }
 +    }
 +  };
 +
 +  return constructor;
 +})();
 +
 +
 +}).call((typeof window === 'undefined') ? this : window);
 +
++if (!PDFJS.workerSrc && typeof document !== 'undefined') {
++  // workerSrc is not set -- using last script url to define default location
++  PDFJS.workerSrc = (function () {
++    'use strict';
++    var scriptTagContainer = document.body ||
++                             document.getElementsByTagName('head')[0];
++    var pdfjsSrc = scriptTagContainer.lastChild.src;
++    return pdfjsSrc && pdfjsSrc.replace(/\.js$/i, '.worker.js');
++  })();
++}
++
 +
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/viewer.css
index 4afa963,0000000..f54f7e6
mode 100644,000000..100644
--- a/apps/files_pdfviewer/3rdparty/pdfjs/viewer.css
+++ b/apps/files_pdfviewer/3rdparty/pdfjs/viewer.css
@@@ -1,1456 -1,0 +1,1934 @@@
 +/* 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.
 + */
 +
 +* {
 +  padding: 0;
 +  margin: 0;
 +}
 +
 +html {
 +  height: 100%;
++  /* Font size is needed to make the activity bar the correct size. */
++  font-size: 10px;
 +}
 +
 +body {
 +  height: 100%;
 +  background-color: #404040;
 +  background-image: url(images/texture.png);
 +}
 +
 +body,
 +input,
 +button,
 +select {
 +  font: message-box;
++  outline: none;
 +}
 +
 +.hidden {
-   display: none;
++  display: none !important;
 +}
 +[hidden] {
 +  display: none !important;
 +}
 +
 +#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;
 +  cursor: none;
 +}
 +
 +#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;
 +  cursor: none;
 +}
 +
++#viewerContainer:-ms-fullscreen {
++  top: 0px !important;
++  border-top: 2px solid transparent;
++  width: 100%;
++  height: 100%;
++  overflow: hidden !important;
++  cursor: none;
++}
++
++#viewerContainer:-ms-fullscreen::-ms-backdrop {
++  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%;
 +}
 +
- #viewerContainer.presentationControls {
++:-webkit-full-screen a:not(.internalLink) {
++  display: none;
++}
++
++:-moz-full-screen a:not(.internalLink) {
++  display: none;
++}
++
++:-ms-fullscreen a:not(.internalLink) {
++  display: none !important;
++}
++
++:fullscreen a:not(.internalLink) {
++  display: none;
++}
++
++:-webkit-full-screen .textLayer > div {
++  cursor: none;
++}
++
++:-moz-full-screen .textLayer > div {
++  cursor: none;
++}
++
++:fullscreen .textLayer > div {
++  cursor: none;
++}
++
++#viewerContainer.presentationControls,
++#viewerContainer.presentationControls .textLayer > div {
 +  cursor: default;
 +}
 +
 +/* outer/inner center provides horizontal center */
++.outerCenter {
++  pointer-events: none;
++  position: relative;
++}
 +html[dir='ltr'] .outerCenter {
 +  float: right;
-   position: relative;
 +  right: 50%;
 +}
 +html[dir='rtl'] .outerCenter {
 +  float: left;
-   position: relative;
 +  left: 50%;
 +}
++.innerCenter {
++  pointer-events: auto;
++  position: relative;
++}
 +html[dir='ltr'] .innerCenter {
 +  float: right;
-   position: relative;
 +  right: -50%;
 +}
 +html[dir='rtl'] .innerCenter {
 +  float: left;
-   position: relative;
 +  left: -50%;
 +}
 +
 +#outerContainer {
 +  width: 100%;
 +  height: 100%;
++  position: relative;
 +}
 +
 +#sidebarContainer {
 +  position: absolute;
 +  top: 0;
 +  bottom: 0;
 +  width: 200px;
 +  visibility: hidden;
 +  -webkit-transition-duration: 200ms;
 +  -webkit-transition-timing-function: ease;
-   -moz-transition-duration: 200ms;
-   -moz-transition-timing-function: ease;
-   -ms-transition-duration: 200ms;
-   -ms-transition-timing-function: ease;
-   -o-transition-duration: 200ms;
-   -o-transition-timing-function: ease;
 +  transition-duration: 200ms;
 +  transition-timing-function: ease;
 +
 +}
 +html[dir='ltr'] #sidebarContainer {
 +  -webkit-transition-property: left;
-   -moz-transition-property: left;
-   -ms-transition-property: left;
-   -o-transition-property: left;
 +  transition-property: left;
 +  left: -200px;
 +}
 +html[dir='rtl'] #sidebarContainer {
 +  -webkit-transition-property: right;
-   -ms-transition-property: right;
-   -o-transition-property: right;
 +  transition-property: right;
 +  right: -200px;
 +}
 +
 +#outerContainer.sidebarMoving > #sidebarContainer,
 +#outerContainer.sidebarOpen > #sidebarContainer {
 +  visibility: visible;
 +}
 +html[dir='ltr'] #outerContainer.sidebarOpen > #sidebarContainer {
 +  left: 0px;
 +}
 +html[dir='rtl'] #outerContainer.sidebarOpen > #sidebarContainer {
 +  right: 0px;
 +}
 +
 +#mainContainer {
 +  position: absolute;
 +  top: 0;
 +  right: 0;
 +  bottom: 0;
 +  left: 0;
 +  min-width: 320px;
 +  -webkit-transition-duration: 200ms;
 +  -webkit-transition-timing-function: ease;
-   -moz-transition-duration: 200ms;
-   -moz-transition-timing-function: ease;
-   -ms-transition-duration: 200ms;
-   -ms-transition-timing-function: ease;
-   -o-transition-duration: 200ms;
-   -o-transition-timing-function: ease;
 +  transition-duration: 200ms;
 +  transition-timing-function: ease;
 +}
 +html[dir='ltr'] #outerContainer.sidebarOpen > #mainContainer {
 +  -webkit-transition-property: left;
-   -moz-transition-property: left;
-   -ms-transition-property: left;
-   -o-transition-property: left;
 +  transition-property: left;
 +  left: 200px;
 +}
 +html[dir='rtl'] #outerContainer.sidebarOpen > #mainContainer {
 +  -webkit-transition-property: right;
-   -moz-transition-property: right;
-   -ms-transition-property: right;
-   -o-transition-property: right;
 +  transition-property: right;
 +  right: 200px;
 +}
 +
 +#sidebarContent {
 +  top: 32px;
 +  bottom: 0;
 +  overflow: auto;
 +  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);
 +  position: absolute;
 +  top: 32px;
 +  right: 0;
 +  bottom: 0;
 +  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: absolute;
++  position: relative;
 +  left: 0;
 +  right: 0;
-   height: 32px;
 +  z-index: 9999;
 +  cursor: default;
 +}
 +
 +#toolbarContainer {
 +  width: 100%;
 +}
 +
 +#toolbarSidebar {
 +  width: 200px;
 +  height: 32px;
-   background-image: url(images/texture.png),
-                     -webkit-linear-gradient(hsla(0,0%,30%,.99), hsla(0,0%,25%,.95));
-   background-image: url(images/texture.png),
-                     -moz-linear-gradient(hsla(0,0%,30%,.99), hsla(0,0%,25%,.95));
-   background-image: url(images/texture.png),
-                     -ms-linear-gradient(hsla(0,0%,30%,.99), hsla(0,0%,25%,.95));
-   background-image: url(images/texture.png),
-                     -o-linear-gradient(hsla(0,0%,30%,.99), hsla(0,0%,25%,.95));
++  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);
++}
 +
- #toolbarViewer, .findbar {
++#toolbarContainer, .findbar, .secondaryToolbar {
 +  position: relative;
 +  height: 32px;
-   background-color: #474747; /* IE9 */
-   background-image: url(images/texture.png),
-                     -webkit-linear-gradient(hsla(0,0%,32%,.99), hsla(0,0%,27%,.95));
-   background-image: url(images/texture.png),
-                     -moz-linear-gradient(hsla(0,0%,32%,.99), hsla(0,0%,27%,.95));
-   background-image: url(images/texture.png),
-                     -ms-linear-gradient(hsla(0,0%,32%,.99), hsla(0,0%,27%,.95));
-   background-image: url(images/texture.png),
-                     -o-linear-gradient(hsla(0,0%,32%,.99), hsla(0,0%,27%,.95));
++  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;
++}
++
++#loadingBar {
++  position: relative;
++  width: 100%;
++  height: 6px;
++  background-color: #333;
++  border-bottom: 1px solid #333;
++}
++
++#loadingBar .progress {
++  position: absolute;
++  top: 0;
++  left: 0;
++  width: 0%;
++  height: 100%;
++  background-color: #ddd;
++  overflow: hidden;
++  -webkit-transition: width 200ms;
++  transition: width 200ms;
++}
++
++ at -webkit-keyframes progressIndeterminate {
++  0% { left: 0%; }
++  50% { left: 100%; }
++  100% { left: 100%; }
++}
++
++ at keyframes progressIndeterminate {
++  0% { left: 0%; }
++  50% { left: 100%; }
++  100% { left: 100%; }
++}
++
++#loadingBar .progress.indeterminate {
++  background-color: #999;
++  -webkit-transition: none;
++  transition: none;
++}
++
++#loadingBar .indeterminate .glimmer {
++  position: absolute;
++  top: 0;
++  left: 0;
++  height: 100%;
++  width: 50px;
 +
- .findbar {
++  background-image: linear-gradient(to right, #999 0%, #fff 50%, #999 100%);
++  background-size: 100% 100%;
++  background-repeat: no-repeat;
++
++  -webkit-animation: progressIndeterminate 2s linear infinite;
++  animation: progressIndeterminate 2s linear infinite;
++}
++
++.findbar, .secondaryToolbar {
 +  top: 32px;
 +  position: absolute;
 +  z-index: 10000;
 +  height: 32px;
 +
 +  min-width: 16px;
 +  padding: 0px 6px 0px 6px;
 +  margin: 4px 2px 4px 2px;
 +  color: hsl(0,0%,85%);
 +  font-size: 12px;
 +  line-height: 14px;
 +  text-align: left;
 +  cursor: default;
 +}
 +
 +html[dir='ltr'] .findbar {
 +  left: 68px;
 +}
 +
 +html[dir='rtl'] .findbar {
 +  right: 68px;
 +}
 +
 +.findbar label {
 +  -webkit-user-select: none;
 +  -moz-user-select: none;
 +}
 +
 +#findInput[data-status="pending"] {
 +  background-image: url(images/loading-small.png);
 +  background-repeat: no-repeat;
 +  background-position: right;
 +}
 +
- .doorHanger {
++.secondaryToolbar {
++  padding: 6px;
++  height: auto;
++  z-index: 30000;
++}
++html[dir='ltr'] .secondaryToolbar {
++  right: 4px;
++}
++html[dir='rtl'] .secondaryToolbar {
++  left: 4px;
++}
++
++#secondaryToolbarButtonContainer {
++  max-width: 200px;
++  max-height: 400px;
++  overflow-y: auto;
++  margin-bottom: -4px;
++}
++
++.doorHanger,
++.doorHangerRight {
 +  border: 1px solid hsla(0,0%,0%,.5);
 +  border-radius: 2px;
 +  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
 +}
- .doorHanger:after, .doorHanger:before {
++.doorHanger:after, .doorHanger:before,
++.doorHangerRight:after, .doorHangerRight:before {
 +  bottom: 100%;
 +  border: solid transparent;
 +  content: " ";
 +  height: 0;
 +  width: 0;
 +  position: absolute;
 +  pointer-events: none;
 +}
- .doorHanger:after {
++.doorHanger:after,
++.doorHangerRight:after {
 +  border-bottom-color: hsla(0,0%,32%,.99);
 +  border-width: 8px;
 +}
- .doorHanger:before {
++.doorHanger:before,
++.doorHangerRight:before {
 +  border-bottom-color: hsla(0,0%,0%,.5);
 +  border-width: 9px;
 +}
 +
- html[dir='ltr'] .doorHanger:after {
++html[dir='ltr'] .doorHanger:after,
++html[dir='rtl'] .doorHangerRight:after {
 +  left: 13px;
 +  margin-left: -8px;
 +}
 +
- html[dir='ltr'] .doorHanger:before {
++html[dir='ltr'] .doorHanger:before,
++html[dir='rtl'] .doorHangerRight:before {
 +  left: 13px;
 +  margin-left: -9px;
 +}
 +
- html[dir='rtl'] .doorHanger:after {
++html[dir='rtl'] .doorHanger:after,
++html[dir='ltr'] .doorHangerRight:after {
 +  right: 13px;
 +  margin-right: -8px;
 +}
 +
- html[dir='rtl'] .doorHanger:before {
++html[dir='rtl'] .doorHanger:before,
++html[dir='ltr'] .doorHangerRight:before {
 +  right: 13px;
 +  margin-right: -9px;
 +}
 +
 +#findMsg {
 +  font-style: italic;
 +  color: #A6B7D0;
 +}
 +
 +.notFound {
 +  background-color: rgb(255, 137, 153);
 +}
 +
 +html[dir='ltr'] #toolbarViewerLeft {
 +  margin-left: -1px;
 +}
 +html[dir='rtl'] #toolbarViewerRight {
-   margin-left: -1px;
++  margin-right: -1px;
 +}
 +
- 
 +html[dir='ltr'] #toolbarViewerLeft,
 +html[dir='rtl'] #toolbarViewerRight {
 +  position: absolute;
 +  top: 0;
-   left: 21px;
++  left: 0;
 +}
 +html[dir='ltr'] #toolbarViewerRight,
 +html[dir='rtl'] #toolbarViewerLeft {
 +  position: absolute;
 +  top: 0;
-   right: 21px;
++  right: 25px;
 +}
 +html[dir='ltr'] #toolbarViewerLeft > *,
 +html[dir='ltr'] #toolbarViewerMiddle > *,
 +html[dir='ltr'] #toolbarViewerRight > *,
 +html[dir='ltr'] .findbar > * {
++  position: relative;
 +  float: left;
 +}
 +html[dir='rtl'] #toolbarViewerLeft > *,
 +html[dir='rtl'] #toolbarViewerMiddle > *,
 +html[dir='rtl'] #toolbarViewerRight > *,
 +html[dir='rtl'] .findbar > * {
++  position: relative;
 +  float: right;
 +}
 +
 +html[dir='ltr'] .splitToolbarButton {
 +  margin: 3px 2px 4px 0;
 +  display: inline-block;
 +}
 +html[dir='rtl'] .splitToolbarButton {
 +  margin: 3px 0 4px 2px;
 +  display: inline-block;
 +}
 +html[dir='ltr'] .splitToolbarButton > .toolbarButton {
 +  border-radius: 0;
 +  float: left;
 +}
 +html[dir='rtl'] .splitToolbarButton > .toolbarButton {
 +  border-radius: 0;
 +  float: right;
 +}
 +
- .toolbarButton {
++.toolbarButton,
++.secondaryToolbarButton {
 +  border: 0 none;
 +  background-color: rgba(0, 0, 0, 0);
 +  width: 32px;
 +  height: 25px;
 +}
 +
 +.toolbarButton > span {
 +  display: inline-block;
 +  width: 0;
 +  height: 0;
 +  overflow: hidden;
 +}
 +
- .toolbarButton[disabled] {
++.toolbarButton[disabled],
++.secondaryToolbarButton[disabled] {
 +  opacity: .5;
 +}
 +
 +.toolbarButton.group {
 +  margin-right: 0;
 +}
 +
 +.splitToolbarButton.toggled .toolbarButton {
 +  margin: 0;
 +}
 +
 +.splitToolbarButton:hover > .toolbarButton,
 +.splitToolbarButton:focus > .toolbarButton,
 +.splitToolbarButton.toggled > .toolbarButton,
 +.toolbarButton.textButton {
 +  background-color: hsla(0,0%,0%,.12);
-   background-image: -webkit-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
-   background-image: -moz-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
-   background-image: -ms-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
-   background-image: -o-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
 +  background-image: linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
 +  background-clip: padding-box;
 +  border: 1px solid hsla(0,0%,0%,.35);
 +  border-color: hsla(0,0%,0%,.32) hsla(0,0%,0%,.38) hsla(0,0%,0%,.42);
 +  box-shadow: 0 1px 0 hsla(0,0%,100%,.05) inset,
 +              0 0 1px hsla(0,0%,100%,.15) inset,
 +              0 1px 0 hsla(0,0%,100%,.05);
 +  -webkit-transition-property: background-color, border-color, box-shadow;
 +  -webkit-transition-duration: 150ms;
 +  -webkit-transition-timing-function: ease;
-   -moz-transition-property: background-color, border-color, box-shadow;
-   -moz-transition-duration: 150ms;
-   -moz-transition-timing-function: ease;
-   -ms-transition-property: background-color, border-color, box-shadow;
-   -ms-transition-duration: 150ms;
-   -ms-transition-timing-function: ease;
-   -o-transition-property: background-color, border-color, box-shadow;
-   -o-transition-duration: 150ms;
-   -o-transition-timing-function: ease;
 +  transition-property: background-color, border-color, box-shadow;
 +  transition-duration: 150ms;
 +  transition-timing-function: ease;
 +
 +}
 +.splitToolbarButton > .toolbarButton:hover,
 +.splitToolbarButton > .toolbarButton:focus,
 +.dropdownToolbarButton:hover,
++.overlayButton:hover,
 +.toolbarButton.textButton:hover,
 +.toolbarButton.textButton:focus {
 +  background-color: hsla(0,0%,0%,.2);
 +  box-shadow: 0 1px 0 hsla(0,0%,100%,.05) inset,
 +              0 0 1px hsla(0,0%,100%,.15) inset,
 +              0 0 1px hsla(0,0%,0%,.05);
 +  z-index: 199;
 +}
 +html[dir='ltr'] .splitToolbarButton > .toolbarButton:first-child,
 +html[dir='rtl'] .splitToolbarButton > .toolbarButton:last-child {
 +  position: relative;
 +  margin: 0;
 +  margin-right: -1px;
 +  border-top-left-radius: 2px;
 +  border-bottom-left-radius: 2px;
 +  border-right-color: transparent;
 +}
 +html[dir='ltr'] .splitToolbarButton > .toolbarButton:last-child,
 +html[dir='rtl'] .splitToolbarButton > .toolbarButton:first-child {
 +  position: relative;
 +  margin: 0;
 +  margin-left: -1px;
 +  border-top-right-radius: 2px;
 +  border-bottom-right-radius: 2px;
 +  border-left-color: transparent;
 +}
 +.splitToolbarButtonSeparator {
 +  padding: 8px 0;
 +  width: 1px;
-   background-color: hsla(0,0%,00%,.5);
++  background-color: hsla(0,0%,0%,.5);
 +  z-index: 99;
 +  box-shadow: 0 0 0 1px hsla(0,0%,100%,.08);
 +  display: inline-block;
 +  margin: 5px 0;
 +}
 +html[dir='ltr'] .splitToolbarButtonSeparator {
 +  float: left;
 +}
 +html[dir='rtl'] .splitToolbarButtonSeparator {
 +  float: right;
 +}
 +.splitToolbarButton:hover > .splitToolbarButtonSeparator,
 +.splitToolbarButton.toggled > .splitToolbarButtonSeparator {
 +  padding: 12px 0;
 +  margin: 1px 0;
 +  box-shadow: 0 0 0 1px hsla(0,0%,100%,.03);
 +  -webkit-transition-property: padding;
 +  -webkit-transition-duration: 10ms;
 +  -webkit-transition-timing-function: ease;
-   -moz-transition-property: padding;
-   -moz-transition-duration: 10ms;
-   -moz-transition-timing-function: ease;
-   -ms-transition-property: padding;
-   -ms-transition-duration: 10ms;
-   -ms-transition-timing-function: ease;
-   -o-transition-property: padding;
-   -o-transition-duration: 10ms;
-   -o-transition-timing-function: ease;
 +  transition-property: padding;
 +  transition-duration: 10ms;
 +  transition-timing-function: ease;
 +}
 +
 +.toolbarButton,
- .dropdownToolbarButton {
++.dropdownToolbarButton,
++.overlayButton,
++.secondaryToolbarButton {
 +  min-width: 16px;
 +  padding: 2px 6px 0;
 +  border: 1px solid transparent;
 +  border-radius: 2px;
-   color: hsl(0,0%,95%);
++  color: hsla(0,0%,100%,.8);
 +  font-size: 12px;
 +  line-height: 14px;
 +  -webkit-user-select: none;
 +  -moz-user-select: none;
 +  -ms-user-select: none;
 +  /* Opera does not support user-select, use <... unselectable="on"> instead */
 +  cursor: default;
 +  -webkit-transition-property: background-color, border-color, box-shadow;
 +  -webkit-transition-duration: 150ms;
 +  -webkit-transition-timing-function: ease;
-   -moz-transition-property: background-color, border-color, box-shadow;
-   -moz-transition-duration: 150ms;
-   -moz-transition-timing-function: ease;
-   -ms-transition-property: background-color, border-color, box-shadow;
-   -ms-transition-duration: 150ms;
-   -ms-transition-timing-function: ease;
-   -o-transition-property: background-color, border-color, box-shadow;
-   -o-transition-duration: 150ms;
-   -o-transition-timing-function: ease;
 +  transition-property: background-color, border-color, box-shadow;
 +  transition-duration: 150ms;
 +  transition-timing-function: ease;
 +}
 +
 +html[dir='ltr'] .toolbarButton,
++html[dir='ltr'] .overlayButton,
 +html[dir='ltr'] .dropdownToolbarButton {
 +  margin: 3px 2px 4px 0;
 +}
 +html[dir='rtl'] .toolbarButton,
++html[dir='rtl'] .overlayButton,
 +html[dir='rtl'] .dropdownToolbarButton {
 +  margin: 3px 0 4px 2px;
 +}
 +
 +.toolbarButton:hover,
 +.toolbarButton:focus,
- .dropdownToolbarButton {
++.dropdownToolbarButton,
++.overlayButton,
++.secondaryToolbarButton:hover,
++.secondaryToolbarButton:focus {
 +  background-color: hsla(0,0%,0%,.12);
-   background-image: -webkit-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
-   background-image: -moz-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
-   background-image: -ms-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
-   background-image: -o-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
 +  background-image: linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
 +  background-clip: padding-box;
 +  border: 1px solid hsla(0,0%,0%,.35);
 +  border-color: hsla(0,0%,0%,.32) hsla(0,0%,0%,.38) hsla(0,0%,0%,.42);
 +  box-shadow: 0 1px 0 hsla(0,0%,100%,.05) inset,
 +              0 0 1px hsla(0,0%,100%,.15) inset,
 +              0 1px 0 hsla(0,0%,100%,.05);
 +}
 +
 +.toolbarButton:hover:active,
- .dropdownToolbarButton:hover:active {
++.overlayButton:hover:active,
++.dropdownToolbarButton:hover:active,
++.secondaryToolbarButton:hover:active {
 +  background-color: hsla(0,0%,0%,.2);
-   background-image: -webkit-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
-   background-image: -moz-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
-   background-image: -ms-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
-   background-image: -o-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
 +  background-image: linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
 +  border-color: hsla(0,0%,0%,.35) hsla(0,0%,0%,.4) hsla(0,0%,0%,.45);
 +  box-shadow: 0 1px 1px hsla(0,0%,0%,.1) inset,
 +              0 0 1px hsla(0,0%,0%,.2) inset,
 +              0 1px 0 hsla(0,0%,100%,.05);
 +  -webkit-transition-property: background-color, border-color, box-shadow;
 +  -webkit-transition-duration: 10ms;
 +  -webkit-transition-timing-function: linear;
-   -moz-transition-property: background-color, border-color, box-shadow;
-   -moz-transition-duration: 10ms;
-   -moz-transition-timing-function: linear;
-   -ms-transition-property: background-color, border-color, box-shadow;
-   -ms-transition-duration: 10ms;
-   -ms-transition-timing-function: linear;
-   -o-transition-property: background-color, border-color, box-shadow;
-   -o-transition-duration: 10ms;
-   -o-transition-timing-function: linear;
 +  transition-property: background-color, border-color, box-shadow;
 +  transition-duration: 10ms;
 +  transition-timing-function: linear;
 +}
 +
 +.toolbarButton.toggled,
- .splitToolbarButton.toggled > .toolbarButton.toggled {
++.splitToolbarButton.toggled > .toolbarButton.toggled,
++.secondaryToolbarButton.toggled {
 +  background-color: hsla(0,0%,0%,.3);
-   background-image: -webkit-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
-   background-image: -moz-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
-   background-image: -ms-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
-   background-image: -o-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
 +  background-image: linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
 +  border-color: hsla(0,0%,0%,.4) hsla(0,0%,0%,.45) hsla(0,0%,0%,.5);
 +  box-shadow: 0 1px 1px hsla(0,0%,0%,.1) inset,
 +              0 0 1px hsla(0,0%,0%,.2) inset,
 +              0 1px 0 hsla(0,0%,100%,.05);
 +  -webkit-transition-property: background-color, border-color, box-shadow;
 +  -webkit-transition-duration: 10ms;
 +  -webkit-transition-timing-function: linear;
-   -moz-transition-property: background-color, border-color, box-shadow;
-   -moz-transition-duration: 10ms;
-   -moz-transition-timing-function: linear;
-   -ms-transition-property: background-color, border-color, box-shadow;
-   -ms-transition-duration: 10ms;
-   -ms-transition-timing-function: linear;
-   -o-transition-property: background-color, border-color, box-shadow;
-   -o-transition-duration: 10ms;
-   -o-transition-timing-function: linear;
 +  transition-property: background-color, border-color, box-shadow;
 +  transition-duration: 10ms;
 +  transition-timing-function: linear;
 +}
 +
 +.toolbarButton.toggled:hover:active,
- .splitToolbarButton.toggled > .toolbarButton.toggled:hover:active {
++.splitToolbarButton.toggled > .toolbarButton.toggled:hover:active,
++.secondaryToolbarButton.toggled:hover:active {
 +  background-color: hsla(0,0%,0%,.4);
 +  border-color: hsla(0,0%,0%,.4) hsla(0,0%,0%,.5) hsla(0,0%,0%,.55);
 +  box-shadow: 0 1px 1px hsla(0,0%,0%,.2) inset,
 +              0 0 1px hsla(0,0%,0%,.3) inset,
 +              0 1px 0 hsla(0,0%,100%,.05);
 +}
 +
 +.dropdownToolbarButton {
 +  width: 120px;
 +  max-width: 120px;
 +  padding: 3px 2px 2px;
 +  overflow: hidden;
 +  background: url(images/toolbarButton-menuArrows.png) no-repeat;
 +}
 +html[dir='ltr'] .dropdownToolbarButton {
 +  background-position: 95%;
 +}
 +html[dir='rtl'] .dropdownToolbarButton {
 +  background-position: 5%;
 +}
 +
 +.dropdownToolbarButton > select {
 +  -webkit-appearance: none;
 +  -moz-appearance: none; /* in the future this might matter, see bugzilla bug #649849 */
 +  min-width: 140px;
 +  font-size: 12px;
 +  color: hsl(0,0%,95%);
 +  margin: 0;
 +  padding: 0;
 +  border: none;
 +  background: rgba(0,0,0,0); /* Opera does not support 'transparent' <select> background */
 +}
 +
 +.dropdownToolbarButton > select > option {
 +  background: hsl(0,0%,24%);
 +}
 +
++.overlayButton {
++  margin: 3px 2px 4px 5px !important;
++  line-height: 16px;
++  padding: 2px 6px 3px 6px;
++}
++
 +#customScaleOption {
 +  display: none;
 +}
 +
 +#pageWidthOption {
 +  border-bottom: 1px rgba(255, 255, 255, .5) solid;
 +}
 +
 +html[dir='ltr'] .splitToolbarButton:first-child,
 +html[dir='ltr'] .toolbarButton:first-child,
 +html[dir='rtl'] .splitToolbarButton:last-child,
 +html[dir='rtl'] .toolbarButton:last-child {
 +  margin-left: 4px;
 +}
 +html[dir='ltr'] .splitToolbarButton:last-child,
 +html[dir='ltr'] .toolbarButton:last-child,
 +html[dir='rtl'] .splitToolbarButton:first-child,
 +html[dir='rtl'] .toolbarButton:first-child {
 +  margin-right: 4px;
 +}
 +
 +.toolbarButtonSpacer {
 +  width: 30px;
 +  display: inline-block;
 +  height: 1px;
 +}
 +
 +.toolbarButtonFlexibleSpacer {
 +  -webkit-box-flex: 1;
 +  -moz-box-flex: 1;
 +  min-width: 30px;
 +}
 +
- .toolbarButton#sidebarToggle::before {
-   display: inline-block;
-   content: url(images/toolbarButton-sidebarToggle.png);
- }
- 
 +html[dir='ltr'] #findPrevious {
 +  margin-left: 3px;
 +}
 +html[dir='ltr'] #findNext {
 +  margin-right: 3px;
 +}
 +
 +html[dir='rtl'] #findPrevious {
 +  margin-right: 3px;
 +}
 +html[dir='rtl'] #findNext {
 +  margin-left: 3px;
 +}
 +
- html[dir='ltr'] .toolbarButton.findPrevious::before {
++.toolbarButton::before,
++.secondaryToolbarButton::before {
++  /* All matching images have a size of 16x16
++   * All relevant containers have a size of 32x25 */
++  position: absolute;
 +  display: inline-block;
-   content: url(images/findbarButton-previous.png);
++  top: 4px;
++  left: 7px;
 +}
 +
++html[dir="ltr"] .secondaryToolbarButton::before {
++  left: 4px;
++}
++html[dir="rtl"] .secondaryToolbarButton::before {
++  right: 4px;
++}
++
++html[dir='ltr'] .toolbarButton#sidebarToggle::before {
++  content: url(images/toolbarButton-sidebarToggle.png);
++}
++html[dir='rtl'] .toolbarButton#sidebarToggle::before {
++  content: url(images/toolbarButton-sidebarToggle-rtl.png);
++}
++
++html[dir='ltr'] .toolbarButton#secondaryToolbarToggle::before {
++  content: url(images/toolbarButton-secondaryToolbarToggle.png);
++}
++html[dir='rtl'] .toolbarButton#secondaryToolbarToggle::before {
++  content: url(images/toolbarButton-secondaryToolbarToggle-rtl.png);
++}
++
++html[dir='ltr'] .toolbarButton.findPrevious::before {
++  content: url(images/findbarButton-previous.png);
++}
 +html[dir='rtl'] .toolbarButton.findPrevious::before {
-   display: inline-block;
 +  content: url(images/findbarButton-previous-rtl.png);
 +}
 +
 +html[dir='ltr'] .toolbarButton.findNext::before {
-   display: inline-block;
 +  content: url(images/findbarButton-next.png);
 +}
- 
 +html[dir='rtl'] .toolbarButton.findNext::before {
-   display: inline-block;
 +  content: url(images/findbarButton-next-rtl.png);
 +}
 +
 +html[dir='ltr'] .toolbarButton.pageUp::before {
-   display: inline-block;
 +  content: url(images/toolbarButton-pageUp.png);
 +}
- 
 +html[dir='rtl'] .toolbarButton.pageUp::before {
-   display: inline-block;
 +  content: url(images/toolbarButton-pageUp-rtl.png);
 +}
 +
 +html[dir='ltr'] .toolbarButton.pageDown::before {
-   display: inline-block;
 +  content: url(images/toolbarButton-pageDown.png);
 +}
- 
 +html[dir='rtl'] .toolbarButton.pageDown::before {
-   display: inline-block;
 +  content: url(images/toolbarButton-pageDown-rtl.png);
 +}
 +
 +.toolbarButton.zoomOut::before {
-   display: inline-block;
 +  content: url(images/toolbarButton-zoomOut.png);
 +}
 +
 +.toolbarButton.zoomIn::before {
-   display: inline-block;
 +  content: url(images/toolbarButton-zoomIn.png);
 +}
 +
- .toolbarButton.fullscreen::before {
-   display: inline-block;
-   content: url(images/toolbarButton-fullscreen.png);
++.toolbarButton.presentationMode::before,
++.secondaryToolbarButton.presentationMode::before {
++  content: url(images/toolbarButton-presentationMode.png);
 +}
 +
- .toolbarButton.print::before {
-   display: inline-block;
++.toolbarButton.print::before,
++.secondaryToolbarButton.print::before {
 +  content: url(images/toolbarButton-print.png);
 +}
 +
- .toolbarButton.openFile::before {
-   display: inline-block;
++.toolbarButton.openFile::before,
++.secondaryToolbarButton.openFile::before {
 +  content: url(images/toolbarButton-openFile.png);
 +}
 +
- .toolbarButton.download::before {
-   display: inline-block;
++.toolbarButton.download::before,
++.secondaryToolbarButton.download::before {
 +  content: url(images/toolbarButton-download.png);
 +}
 +
- .toolbarButton.bookmark {
++.toolbarButton.bookmark,
++.secondaryToolbarButton.bookmark {
 +  -webkit-box-sizing: border-box;
 +  -moz-box-sizing: border-box;
 +  box-sizing: border-box;
-   margin-top: 3px;
++  outline: none;
 +  padding-top: 4px;
++  text-decoration: none;
++}
++.secondaryToolbarButton.bookmark {
++  padding-top: 5px;
 +}
 +
- #viewBookmark[href='#'] {
++.bookmark[href='#'] {
 +  opacity: .5;
 +  pointer-events: none;
 +}
 +
- .toolbarButton.bookmark::before {
++.toolbarButton.bookmark::before,
++.secondaryToolbarButton.bookmark::before {
 +  content: url(images/toolbarButton-bookmark.png);
 +}
 +
 +#viewThumbnail.toolbarButton::before {
-   display: inline-block;
 +  content: url(images/toolbarButton-viewThumbnail.png);
 +}
 +
- #viewOutline.toolbarButton::before {
-   display: inline-block;
++html[dir="ltr"] #viewOutline.toolbarButton::before {
 +  content: url(images/toolbarButton-viewOutline.png);
 +}
++html[dir="rtl"] #viewOutline.toolbarButton::before {
++  content: url(images/toolbarButton-viewOutline-rtl.png);
++}
 +
 +#viewFind.toolbarButton::before {
-   display: inline-block;
 +  content: url(images/toolbarButton-search.png);
 +}
 +
++.secondaryToolbarButton {
++  position: relative;
++  margin: 0 0 4px 0;
++  padding: 3px 0 1px 0;
++  height: auto;
++  min-height: 25px;
++  width: auto;
++  min-width: 100%;
++  white-space: normal;
++}
++html[dir="ltr"] .secondaryToolbarButton {
++  padding-left: 24px;
++  text-align: left;
++}
++html[dir="rtl"] .secondaryToolbarButton {
++  padding-right: 24px;
++  text-align: right;
++}
++html[dir="ltr"] .secondaryToolbarButton.bookmark {
++  padding-left: 27px;
++}
++html[dir="rtl"] .secondaryToolbarButton.bookmark {
++  padding-right: 27px;
++}
++
++html[dir="ltr"] .secondaryToolbarButton > span {
++  padding-right: 4px;
++}
++html[dir="rtl"] .secondaryToolbarButton > span {
++  padding-left: 4px;
++}
++
++.secondaryToolbarButton.firstPage::before {
++  content: url(images/secondaryToolbarButton-firstPage.png);
++}
++
++.secondaryToolbarButton.lastPage::before {
++  content: url(images/secondaryToolbarButton-lastPage.png);
++}
++
++.secondaryToolbarButton.rotateCcw::before {
++  content: url(images/secondaryToolbarButton-rotateCcw.png);
++}
++
++.secondaryToolbarButton.rotateCw::before {
++  content: url(images/secondaryToolbarButton-rotateCw.png);
++}
++
++.secondaryToolbarButton.handTool::before {
++  content: url(images/secondaryToolbarButton-handTool.png);
++}
++
++.secondaryToolbarButton.documentProperties::before {
++  content: url(images/secondaryToolbarButton-documentProperties.png);
++}
++
++.verticalToolbarSeparator {
++  display: block;
++  padding: 8px 0;
++  margin: 8px 4px;
++  width: 1px;
++  background-color: hsla(0,0%,0%,.5);
++  box-shadow: 0 0 0 1px hsla(0,0%,100%,.08);
++}
++html[dir='ltr'] .verticalToolbarSeparator {
++  margin-left: 2px;
++}
++html[dir='rtl'] .verticalToolbarSeparator {
++  margin-right: 2px;
++}
++
++.horizontalToolbarSeparator {
++  display: block; 
++  margin: 0 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);
++}
 +
 +.toolbarField {
 +  padding: 3px 6px;
 +  margin: 4px 0 4px 0;
 +  border: 1px solid transparent;
 +  border-radius: 2px;
 +  background-color: hsla(0,0%,100%,.09);
-   background-image: -moz-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
++  background-image: linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
 +  background-clip: padding-box;
 +  border: 1px solid hsla(0,0%,0%,.35);
 +  border-color: hsla(0,0%,0%,.32) hsla(0,0%,0%,.38) hsla(0,0%,0%,.42);
 +  box-shadow: 0 1px 0 hsla(0,0%,0%,.05) inset,
 +              0 1px 0 hsla(0,0%,100%,.05);
 +  color: hsl(0,0%,95%);
 +  font-size: 12px;
 +  line-height: 14px;
 +  outline-style: none;
-   -moz-transition-property: background-color, border-color, box-shadow;
-   -moz-transition-duration: 150ms;
-   -moz-transition-timing-function: ease;
++  transition-property: background-color, border-color, box-shadow;
++  transition-duration: 150ms;
++  transition-timing-function: ease;
 +}
 +
 +.toolbarField[type=checkbox] {
 +  display: inline-block;
 +  margin: 8px 0px;
 +}
 +
 +.toolbarField.pageNumber {
++  -moz-appearance: textfield; /* hides the spinner in moz */
 +  min-width: 16px;
 +  text-align: right;
 +  width: 40px;
 +}
 +
 +.toolbarField.pageNumber::-webkit-inner-spin-button,
 +.toolbarField.pageNumber::-webkit-outer-spin-button {
 +    -webkit-appearance: none;
 +    margin: 0;
 +}
 +
 +.toolbarField:hover {
 +  background-color: hsla(0,0%,100%,.11);
 +  border-color: hsla(0,0%,0%,.4) hsla(0,0%,0%,.43) hsla(0,0%,0%,.45);
 +}
 +
 +.toolbarField:focus {
 +  background-color: hsla(0,0%,100%,.15);
 +  border-color: hsla(204,100%,65%,.8) hsla(204,100%,65%,.85) hsla(204,100%,65%,.9);
 +}
 +
 +.toolbarLabel {
 +  min-width: 16px;
 +  padding: 3px 6px 3px 2px;
 +  margin: 4px 2px 4px 0;
 +  border: 1px solid transparent;
 +  border-radius: 2px;
 +  color: hsl(0,0%,85%);
 +  font-size: 12px;
 +  line-height: 14px;
 +  text-align: left;
 +  -webkit-user-select: none;
 +  -moz-user-select: none;
 +  cursor: default;
 +}
 +
 +#thumbnailView {
 +  position: absolute;
 +  width: 120px;
 +  top: 0;
 +  bottom: 0;
 +  padding: 10px 40px 0;
 +  overflow: auto;
 +}
 +
 +.thumbnail {
 +  float: left;
++  margin-bottom: 5px;
++}
++
++#thumbnailView > a:last-of-type > .thumbnail {
++  margin-bottom: 10px;
 +}
 +
 +.thumbnail:not([data-loaded]) {
 +  border: 1px dashed rgba(255, 255, 255, 0.5);
 +  margin-bottom: 10px;
 +}
 +
 +.thumbnailImage {
-   -moz-transition-duration: 150ms;
++  transition-duration: 150ms;
 +  border: 1px solid transparent;
 +  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.5), 0 2px 8px rgba(0, 0, 0, 0.3);
 +  opacity: 0.8;
 +  z-index: 99;
 +}
 +
 +.thumbnailSelectionRing {
 +  border-radius: 2px;
 +  padding: 7px;
-   -moz-transition-duration: 150ms;
++  transition-duration: 150ms;
 +}
 +
 +a:focus > .thumbnail > .thumbnailSelectionRing > .thumbnailImage,
 +.thumbnail:hover > .thumbnailSelectionRing > .thumbnailImage {
 +  opacity: .9;
 +}
 +
 +a:focus > .thumbnail > .thumbnailSelectionRing,
 +.thumbnail:hover > .thumbnailSelectionRing {
 +  background-color: hsla(0,0%,100%,.15);
-   background-image: -moz-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
++  background-image: linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
 +  background-clip: padding-box;
 +  box-shadow: 0 1px 0 hsla(0,0%,100%,.05) inset,
 +              0 0 1px hsla(0,0%,100%,.2) inset,
 +              0 0 1px hsla(0,0%,0%,.2);
 +  color: hsla(0,0%,100%,.9);
 +}
 +
 +.thumbnail.selected > .thumbnailSelectionRing > .thumbnailImage {
 +  box-shadow: 0 0 0 1px hsla(0,0%,0%,.5);
 +  opacity: 1;
 +}
 +
 +.thumbnail.selected > .thumbnailSelectionRing {
 +  background-color: hsla(0,0%,100%,.3);
-   background-image: -moz-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
++  background-image: linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
 +  background-clip: padding-box;
 +  box-shadow: 0 1px 0 hsla(0,0%,100%,.05) inset,
 +              0 0 1px hsla(0,0%,100%,.1) inset,
 +              0 0 1px hsla(0,0%,0%,.2);
 +  color: hsla(0,0%,100%,1);
 +}
 +
 +#outlineView {
 +  position: absolute;
 +  width: 192px;
 +  top: 0;
 +  bottom: 0;
 +  padding: 4px 4px 0;
 +  overflow: auto;
 +  -webkit-user-select: none;
 +  -moz-user-select: none;
 +}
 +
 +html[dir='ltr'] .outlineItem > .outlineItems {
 +  margin-left: 20px;
 +}
 +
 +html[dir='rtl'] .outlineItem > .outlineItems {
 +  margin-right: 20px;
 +}
 +
 +.outlineItem > a {
 +  text-decoration: none;
 +  display: inline-block;
 +  min-width: 95%;
 +  height: auto;
 +  margin-bottom: 1px;
 +  border-radius: 2px;
 +  color: hsla(0,0%,100%,.8);
 +  font-size: 13px;
 +  line-height: 15px;
 +  -moz-user-select: none;
 +  white-space: normal;
 +}
 +
 +html[dir='ltr'] .outlineItem > a {
 +  padding: 2px 0 5px 10px;
 +}
 +
 +html[dir='rtl'] .outlineItem > a {
 +  padding: 2px 10px 5px 0;
 +}
 +
 +.outlineItem > a:hover {
 +  background-color: hsla(0,0%,100%,.02);
-   background-image: -moz-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
++  background-image: linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
 +  background-clip: padding-box;
 +  box-shadow: 0 1px 0 hsla(0,0%,100%,.05) inset,
 +              0 0 1px hsla(0,0%,100%,.2) inset,
 +              0 0 1px hsla(0,0%,0%,.2);
 +  color: hsla(0,0%,100%,.9);
 +}
 +
 +.outlineItem.selected {
 +  background-color: hsla(0,0%,100%,.08);
-   background-image: -moz-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
++  background-image: linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
 +  background-clip: padding-box;
 +  box-shadow: 0 1px 0 hsla(0,0%,100%,.05) inset,
 +              0 0 1px hsla(0,0%,100%,.1) inset,
 +              0 0 1px hsla(0,0%,0%,.2);
 +  color: hsla(0,0%,100%,1);
 +}
 +
- .noOutline,
 +.noResults {
 +  font-size: 12px;
 +  color: hsla(0,0%,100%,.8);
 +  font-style: italic;
 +  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: auto;
++  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 {
-   display: block;
-   position: absolute;
- }
- 
- .page > a:hover {
++.annotLink > 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;
 +}
 +
- #loadingBox {
-   position: absolute;
-   top: 50%;
-   margin-top: -25px;
-   left: 0;
-   right: 0;
-   text-align: center;
-   color: #ddd;
-   font-size: 14px;
- }
- 
- #loadingBar {
-   display: inline-block;
-   clear: both;
-   margin: 0px;
-   margin-top: 5px;
-   line-height: 0;
-   border-radius: 2px;
-   width: 200px;
-   height: 25px;
- 
-   background-color: hsla(0,0%,0%,.3);
-   background-image: -moz-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
-   background-image: -webkit-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
-   border: 1px solid #000;
-   box-shadow: 0 1px 1px hsla(0,0%,0%,.1) inset,
-               0 0 1px hsla(0,0%,0%,.2) inset,
-               0 0 1px 1px rgba(255, 255, 255, 0.1);
- }
- 
- #loadingBar .progress {
-   display: inline-block;
-   float: left;
- 
-   background: #666;
-   background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#b2b2b2), color-stop(100%,#898989));
-   background: -webkit-linear-gradient(top, #b2b2b2 0%,#898989 100%);
-   background: -moz-linear-gradient(top, #b2b2b2 0%,#898989 100%);
-   background: -ms-linear-gradient(top, #b2b2b2 0%,#898989 100%);
-   background: -o-linear-gradient(top, #b2b2b2 0%,#898989 100%);
-   background: linear-gradient(top, #b2b2b2 0%,#898989 100%);
- 
-   border-top-left-radius: 2px;
-   border-bottom-left-radius: 2px;
- 
-   width: 0%;
-   height: 100%;
- }
- 
- #loadingBar .progress.full {
-   border-top-right-radius: 2px;
-   border-bottom-right-radius: 2px;
- }
- 
- #loadingBar .progress.indeterminate {
-   width: 100%;
-   height: 25px;
-   background-image: -moz-linear-gradient( 30deg, #404040, #404040 15%, #898989, #404040 85%, #404040);
-   background-image: -webkit-linear-gradient( 30deg, #404040, #404040 15%, #898989, #404040 85%, #404040);
-   background-image: -ms-linear-gradient( 30deg, #404040, #404040 15%, #898989, #404040 85%, #404040);
-   background-image: -o-linear-gradient( 30deg, #404040, #404040 15%, #898989, #404040 85%, #404040);
-   background-size: 75px 25px;
-   -moz-animation: progressIndeterminate 1s linear infinite;
-   -webkit-animation: progressIndeterminate 1s linear infinite;
- }
- 
- @-moz-keyframes progressIndeterminate {
-   from { background-position: 0px 0px; }
-   to { background-position: 75px 0px; }
- }
- 
- @-webkit-keyframes progressIndeterminate {
-   from { background-position: 0px 0px; }
-   to { background-position: 75px 0px; }
- }
- 
 +.textLayer {
 +  position: absolute;
 +  left: 0;
 +  top: 0;
 +  right: 0;
 +  bottom: 0;
 +  color: #000;
 +  font-family: sans-serif;
 +  overflow: hidden;
 +}
 +
 +.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); }
 +
- .annotText > div {
-   z-index: 200;
++.annotationHighlight {
 +  position: absolute;
-   padding: 0.6em;
-   max-width: 20em;
-   background-color: #FFFF99;
-   box-shadow: 0px 2px 10px #333;
-   border-radius: 7px;
++  border: 2px #FFFF99 solid;
 +}
 +
 +.annotText > img {
 +  position: absolute;
-   opacity: 0.6;
++  cursor: pointer;
++}
++
++.annotTextContentWrapper {
++  position: absolute;
++  width: 20em;
 +}
 +
- .annotText > img:hover {
++.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;
-   opacity: 1;
 +}
 +
- .annotText > div > h1 {
-   font-size: 1.2em;
++.annotTextContent > h1 {
++  font-size: 1em;
 +  border-bottom: 1px solid #000000;
-   margin: 0px;
++  padding-bottom: 0.2em;
++}
++
++.annotTextContent > p {
++  padding-top: 0.2em;
++}
++
++.annotLink > a {
++  position: absolute;
++  font-size: 1em;
++  top: 0;
++  left: 0;
++  width: 100%;
++  height: 100%;
 +}
 +
 +#errorWrapper {
 +  background: none repeat scroll 0 0 #FF5555;
 +  color: white;
 +  left: 0;
 +  position: absolute;
 +  right: 0;
-   top: 32px;
 +  z-index: 1000;
 +  padding: 3px;
 +  font-size: 0.8em;
 +}
++.loadingInProgress #errorWrapper {
++  top: 39px;
++}
 +
 +#errorMessageLeft {
 +  float: left;
 +}
 +
 +#errorMessageRight {
 +  float: right;
 +}
 +
 +#errorMoreInfo {
 +  background-color: #FFFFFF;
 +  color: black;
 +  padding: 3px;
 +  margin: 3px;
 +  width: 98%;
 +}
 +
++#overlayContainer {
++  display: table;
++  position: absolute;
++  width: 100%;
++  height: 100%;
++  background-color: hsla(0,0%,0%,.2);
++  z-index: 10000;
++}
++
++#promptContainer {
++  display: table-cell;
++  vertical-align: middle;
++  text-align: center;
++}
++
++#promptContainer > * {
++  display: inline-block;
++}
++
++.prompt {
++  display: table;
++  padding: 15px;
++  border-spacing: 4px;
++  color: hsl(0,0%,85%);
++  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));
++  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);
++}
++
++.prompt > .row {
++  display: table-row;
++}
++
++.prompt > .row > * {
++  display: table-cell;
++}
++
++.prompt .toolbarField {
++  margin: 5px 0;
++  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);
++}
++
++#documentPropertiesContainer {
++  display: table-cell;
++  vertical-align: middle;
++  text-align: center;
++}
++
++#documentPropertiesContainer > * {
++  display: inline-block;
++  padding: 15px;
++  border-spacing: 4px;
++  max-width: 350px;
++  max-height: 350px;
++  color: hsl(0,0%,85%);
++  font-size: 12px;
++  line-height: 14px;
++  text-align: left;
++  cursor: default;
++  background-color: #474747; /* fallback */
++  background-image: url(images/texture.png),
++                    linear-gradient(hsla(0,0%,32%,.99), hsla(0,0%,27%,.95));
++  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);
++}
++
++#documentPropertiesContainer .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);
++}
++
++#documentPropertiesContainer .row {
++  display: table-row;
++}
++
++html[dir='ltr'] #documentPropertiesContainer .row > * {
++  display: table-cell;
++  min-width: 100px;
++}
++
++html[dir='rtl'] #documentPropertiesContainer .row > * {
++  display: table-cell;
++  min-width: 100px;
++  text-align: right;
++}
++
++#documentPropertiesContainer .row span {
++  width: 125px;
++  word-wrap: break-word;
++}
++
++#documentPropertiesContainer .row p {
++  max-width: 225px;
++  word-wrap: break-word;
++}
++
++#documentPropertiesContainer .buttonRow {
++  margin-top: 10px;
++  text-align: center;
++  vertical-align: middle;
++}
++
 +.clearBoth {
 +  clear: both;
 +}
 +
 +.fileInput {
 +  background: white;
 +  color: black;
 +  margin-top: 5px;
++  visibility: hidden;
++  position: fixed;
++  right: 0;
++  top: 0;
 +}
 +
 +#PDFBug {
 +  background: none repeat scroll 0 0 white;
 +  border: 1px solid #666666;
 +  position: fixed;
 +  top: 32px;
 +  right: 0;
 +  bottom: 0;
 +  font-size: 10px;
 +  padding: 0;
 +  width: 300px;
 +}
 +#PDFBug .controls {
 +    background:#EEEEEE;
 +    border-bottom: 1px solid #666666;
 +    padding: 3px;
 +}
 +#PDFBug .panels {
 +  bottom: 0;
 +  left: 0;
 +  overflow: auto;
 +  position: absolute;
 +  right: 0;
 +  top: 27px;
 +}
 +#PDFBug button.active {
 +  font-weight: bold;
 +}
 +.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;
 +  font-size: 10px;
 +  white-space: pre;
 +}
 +#PDFBug .stats .title {
 +    font-weight: bold;
 +}
 +#PDFBug table {
 +  font-size: 10px;
 +}
 +
 +#viewer.textLayer-visible .textLayer > div,
 +#viewer.textLayer-hover .textLayer > div:hover {
 +  background-color: white;
 +  color: black;
 +}
 +
 +#viewer.textLayer-shadow .textLayer > div {
 +  background-color: rgba(255,255,255, .6);
 +  color: black;
 +}
 +
++.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-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;
++
++  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! */
++}
++
 + at page {
 +  margin: 0;
 +}
 +
 +#printContainer {
 +  display: none;
 +}
 +
++ at media screen and (min-resolution: 2dppx) {
++  /* Rules for Retina screens */
++  .toolbarButton::before {
++    transform: scale(0.5);
++    -webkit-transform: scale(0.5);
++    top: -5px;
++  }
++
++  .secondaryToolbarButton::before {
++    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;
++  }
++
++  .dropdownToolbarButton {
++    background: url(images/toolbarButton-menuArrows at 2x.png) no-repeat;
++    background-size: 7px 16px;
++  }
++  
++  html[dir='ltr'] .toolbarButton#sidebarToggle::before {
++    content: url(images/toolbarButton-sidebarToggle at 2x.png);
++  }
++  html[dir='rtl'] .toolbarButton#sidebarToggle::before {
++    content: url(images/toolbarButton-sidebarToggle-rtl at 2x.png);
++  }
++
++  html[dir='ltr'] .toolbarButton#secondaryToolbarToggle::before {
++    content: url(images/toolbarButton-secondaryToolbarToggle at 2x.png);
++  }
++  html[dir='rtl'] .toolbarButton#secondaryToolbarToggle::before {
++    content: url(images/toolbarButton-secondaryToolbarToggle-rtl at 2x.png);
++  }
++
++  html[dir='ltr'] .toolbarButton.findPrevious::before {
++    content: url(images/findbarButton-previous at 2x.png);
++  }
++  html[dir='rtl'] .toolbarButton.findPrevious::before {
++    content: url(images/findbarButton-previous-rtl at 2x.png);
++  }
++
++  html[dir='ltr'] .toolbarButton.findNext::before {
++    content: url(images/findbarButton-next at 2x.png);
++  }
++  html[dir='rtl'] .toolbarButton.findNext::before {
++    content: url(images/findbarButton-next-rtl at 2x.png);
++  }
++
++  html[dir='ltr'] .toolbarButton.pageUp::before {
++    content: url(images/toolbarButton-pageUp at 2x.png);
++  }
++  html[dir='rtl'] .toolbarButton.pageUp::before {
++    content: url(images/toolbarButton-pageUp-rtl at 2x.png);
++  }
++
++  html[dir='ltr'] .toolbarButton.pageDown::before {
++    content: url(images/toolbarButton-pageDown at 2x.png);
++  }
++  html[dir='rtl'] .toolbarButton.pageDown::before {
++    content: url(images/toolbarButton-pageDown-rtl at 2x.png);
++  }
++
++  .toolbarButton.zoomIn::before {
++    content: url(images/toolbarButton-zoomIn at 2x.png);
++  }
++
++  .toolbarButton.zoomOut::before {
++    content: url(images/toolbarButton-zoomOut at 2x.png);
++  }
++
++  .toolbarButton.presentationMode::before,
++  .secondaryToolbarButton.presentationMode::before {
++    content: url(images/toolbarButton-presentationMode at 2x.png);
++  }
++
++  .toolbarButton.print::before,
++  .secondaryToolbarButton.print::before {
++    content: url(images/toolbarButton-print at 2x.png);
++  }
++
++  .toolbarButton.openFile::before,
++  .secondaryToolbarButton.openFile::before {
++    content: url(images/toolbarButton-openFile at 2x.png);
++  }
++
++  .toolbarButton.download::before,
++  .secondaryToolbarButton.download::before {
++    content: url(images/toolbarButton-download at 2x.png);
++  }
++
++  .toolbarButton.bookmark::before,
++  .secondaryToolbarButton.bookmark::before {
++    content: url(images/toolbarButton-bookmark at 2x.png);
++  }
++
++  #viewThumbnail.toolbarButton::before {
++    content: url(images/toolbarButton-viewThumbnail at 2x.png);
++  }
++
++  html[dir="ltr"] #viewOutline.toolbarButton::before {
++    content: url(images/toolbarButton-viewOutline at 2x.png);
++  }
++  html[dir="rtl"] #viewOutline.toolbarButton::before {
++    content: url(images/toolbarButton-viewOutline-rtl at 2x.png);
++  }
++
++  #viewFind.toolbarButton::before {
++    content: url(images/toolbarButton-search at 2x.png);
++  }
++
++  .secondaryToolbarButton.firstPage::before {
++    content: url(images/secondaryToolbarButton-firstPage at 2x.png);
++  }
++
++  .secondaryToolbarButton.lastPage::before {
++    content: url(images/secondaryToolbarButton-lastPage at 2x.png);
++  }
++
++  .secondaryToolbarButton.rotateCcw::before {
++    content: url(images/secondaryToolbarButton-rotateCcw at 2x.png);
++  }
++
++  .secondaryToolbarButton.rotateCw::before {
++    content: url(images/secondaryToolbarButton-rotateCw at 2x.png);
++  }
++
++  .secondaryToolbarButton.handTool::before {
++    content: url(images/secondaryToolbarButton-handTool at 2x.png);
++  }
++
++  .secondaryToolbarButton.documentProperties::before {
++    content: url(images/secondaryToolbarButton-documentProperties at 2x.png);
++  }
++}
++
 + at media print {
++  /* General rules for printing. */
++  body {
++    background: transparent none;
++  }
++
 +  /* Rules for browsers that don't support mozPrintCallback. */
-   #sidebarContainer, .toolbar, #loadingBox, #errorWrapper, .textLayer {
++  #sidebarContainer, #secondaryToolbar, .toolbar, #loadingBox, #errorWrapper, .textLayer {
 +    display: none;
 +  }
++  #viewerContainer {
++    overflow: visible;
++  }
 +
 +  #mainContainer, #viewerContainer, .page, .page canvas {
 +    position: static;
 +    padding: 0;
 +    margin: 0;
 +  }
 +
 +  .page {
 +    float: left;
 +    display: none;
++    border: none;
 +    box-shadow: none;
 +  }
 +
 +  .page[data-loaded] {
 +    display: block;
 +  }
 +
++  .fileInput {
++    display: none;
++  }
++
 +  /* Rules for browsers that support mozPrintCallback */
 +  body[data-mozPrintCallback] #outerContainer {
 +    display: none;
 +  }
 +  body[data-mozPrintCallback] #printContainer {
 +    display: block;
 +  }
 +  #printContainer canvas {
 +    position: relative;
 +    top: 0;
 +    left: 0;
 +  }
 +}
 +
- @media all and (max-width: 950px) {
++.visibleLargeView,
++.visibleMediumView,
++.visibleSmallView {
++  display: none;
++}
++
++ at media all and (max-width: 960px) {
 +  html[dir='ltr'] #outerContainer.sidebarMoving .outerCenter,
 +  html[dir='ltr'] #outerContainer.sidebarOpen .outerCenter {
 +    float: left;
-     left: 180px;
++    left: 205px;
 +  }
 +  html[dir='rtl'] #outerContainer.sidebarMoving .outerCenter,
 +  html[dir='rtl'] #outerContainer.sidebarOpen .outerCenter {
 +    float: right;
-     right: 180px;
++    right: 205px;
++  }
++}
++
++ at media all and (max-width: 900px) {
++  .sidebarOpen .hiddenLargeView {
++    display: none;
++  }
++  .sidebarOpen .visibleLargeView {
++    display: inherit;
++  }
++}
++
++ at media all and (max-width: 860px) {
++  .sidebarOpen .hiddenMediumView {
++    display: none;
++  }
++  .sidebarOpen .visibleMediumView {
++    display: inherit;
 +  }
 +}
 +
 + at media all and (max-width: 770px) {
 +  #sidebarContainer {
-     top: 33px;
++    top: 32px;
 +    z-index: 100;
 +  }
++  .loadingInProgress #sidebarContainer {
++    top: 39px;
++  }
 +  #sidebarContent {
 +    top: 32px;
 +    background-color: hsla(0,0%,0%,.7);
 +  }
 +
 +  html[dir='ltr'] #outerContainer.sidebarOpen > #mainContainer {
 +    left: 0px;
 +  }
 +  html[dir='rtl'] #outerContainer.sidebarOpen > #mainContainer {
 +    right: 0px;
 +  }
 +
 +  html[dir='ltr'] .outerCenter {
 +    float: left;
-     left: 180px;
++    left: 205px;
 +  }
 +  html[dir='rtl'] .outerCenter {
 +    float: right;
-     right: 180px;
++    right: 205px;
++  }
++
++  #outerContainer .hiddenLargeView,
++  #outerContainer .hiddenMediumView {
++    display: inherit;
++  }
++  #outerContainer .visibleLargeView,
++  #outerContainer .visibleMediumView {
++    display: none;
++  }
++}
++
++ at media all and (max-width: 700px) {
++  #outerContainer .hiddenLargeView {
++    display: none;
++  }
++  #outerContainer .visibleLargeView {
++    display: inherit;
++  }
++}
++
++ at media all and (max-width: 660px) {
++  #outerContainer .hiddenMediumView {
++    display: none;
++  }
++  #outerContainer .visibleMediumView {
++    display: inherit;
 +  }
 +}
 +
 + at media all and (max-width: 600px) {
 +  .hiddenSmallView {
 +    display: none;
 +  }
++  .visibleSmallView {
++    display: inherit;
++  }
++  html[dir='ltr'] #outerContainer.sidebarMoving .outerCenter,
++  html[dir='ltr'] #outerContainer.sidebarOpen .outerCenter,
 +  html[dir='ltr'] .outerCenter {
 +    left: 156px;
 +  }
-   html[dir='rtr'] .outerCenter {
++  html[dir='rtl'] #outerContainer.sidebarMoving .outerCenter,
++  html[dir='rtl'] #outerContainer.sidebarOpen .outerCenter,
++  html[dir='rtl'] .outerCenter {
 +    right: 156px;
 +  }
 +  .toolbarButtonSpacer {
 +    width: 0;
 +  }
 +}
 +
- @media all and (max-width: 500px) {
++ at media all and (max-width: 510px) {
 +  #scaleSelectContainer, #pageNumberLabel {
 +    display: none;
 +  }
 +}
 +
diff --cc apps/files_pdfviewer/3rdparty/pdfjs/viewer.js
index 7b0f088,0000000..a48ada5
mode 100644,000000..100644
--- a/apps/files_pdfviewer/3rdparty/pdfjs/viewer.js
+++ b/apps/files_pdfviewer/3rdparty/pdfjs/viewer.js
@@@ -1,3479 -1,0 +1,5636 @@@
 +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 +/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
 +/* 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.
 + */
- /* globals PDFJS, PDFBug, FirefoxCom, Stats */
++/* globals PDFJS, PDFBug, FirefoxCom, Stats, Cache, PDFFindBar, CustomStyle,
++           PDFFindController, ProgressBar, TextLayerBuilder, DownloadManager,
++           getFileName, scrollIntoView, getPDFFileNameFromURL, PDFHistory,
++           Preferences, ViewHistory, PageView, ThumbnailView, URL,
++           noContextMenuHandler, SecondaryToolbar, PasswordPrompt,
++           PresentationMode, HandTool, Promise, DocumentProperties */
 +
 +'use strict';
 +
 +var DEFAULT_URL = 'compressed.tracemonkey-pldi-09.pdf';
 +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 IMAGE_DIR = './images/';
- var SETTINGS_MEMORY = 20;
- var ANNOT_MIN_SIZE = 10;
++var VIEW_HISTORY_MEMORY = 20;
++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 IGNORE_CURRENT_POSITION_ON_ZOOM = false;
 +var RenderingStates = {
 +  INITIAL: 0,
 +  RUNNING: 1,
 +  PAUSED: 2,
 +  FINISHED: 3
 +};
 +var FindStates = {
 +  FIND_FOUND: 0,
 +  FIND_NOTFOUND: 1,
 +  FIND_WRAPPED: 2,
 +  FIND_PENDING: 3
 +};
 +
++PDFJS.imageResourcesPath = './images/';
++  PDFJS.workerSrc = '../build/pdf.worker.js';
++
 +var mozL10n = document.mozL10n || document.webL10n;
 +
++
++// optimised CSS custom property getter/setter
++var CustomStyle = (function CustomStyleClosure() {
++
++  // As noted on: http://www.zachstronaut.com/posts/2009/02/17/
++  //              animate-css-transforms-firefox-webkit.html
++  // in some versions of IE9 it is critical that ms appear in this list
++  // before Moz
++  var prefixes = ['ms', 'Moz', 'Webkit', 'O'];
++  var _cache = { };
++
++  function CustomStyle() {
++  }
++
++  CustomStyle.getProp = function get(propName, element) {
++    // check cache only when no element is given
++    if (arguments.length == 1 && typeof _cache[propName] == 'string') {
++      return _cache[propName];
++    }
++
++    element = element || document.documentElement;
++    var style = element.style, prefixed, uPropName;
++
++    // test standard property first
++    if (typeof style[propName] == 'string') {
++      return (_cache[propName] = propName);
++    }
++
++    // capitalize
++    uPropName = propName.charAt(0).toUpperCase() + propName.slice(1);
++
++    // test vendor specific properties
++    for (var i = 0, l = prefixes.length; i < l; i++) {
++      prefixed = prefixes[i] + uPropName;
++      if (typeof style[prefixed] == 'string') {
++        return (_cache[propName] = prefixed);
++      }
++    }
++
++    //if all fails then set to undefined
++    return (_cache[propName] = 'undefined');
++  };
++
++  CustomStyle.setProp = function set(propName, element, str) {
++    var prop = this.getProp(propName);
++    if (prop != 'undefined')
++      element.style[prop] = str;
++  };
++
++  return CustomStyle;
++})();
++
 +function getFileName(url) {
 +  var anchor = url.indexOf('#');
 +  var query = url.indexOf('?');
 +  var end = Math.min(
 +    anchor > 0 ? anchor : url.length,
 +    query > 0 ? query : url.length);
 +  return url.substring(url.lastIndexOf('/', end) + 1, end);
 +}
 +
++/**
++ * Returns scale factor for the canvas. It makes sense for the HiDPI displays.
++ * @return {Object} The object with horizontal (sx) and vertical (sy)
++                    scales. The scaled property is set to false if scaling is
++                    not required, true otherwise.
++ */
++function getOutputScale(ctx) {
++  var devicePixelRatio = window.devicePixelRatio || 1;
++  var backingStoreRatio = ctx.webkitBackingStorePixelRatio ||
++                          ctx.mozBackingStorePixelRatio ||
++                          ctx.msBackingStorePixelRatio ||
++                          ctx.oBackingStorePixelRatio ||
++                          ctx.backingStorePixelRatio || 1;
++  var pixelRatio = devicePixelRatio / backingStoreRatio;
++  return {
++    sx: pixelRatio,
++    sy: pixelRatio,
++    scaled: pixelRatio != 1
++  };
++}
++
++/**
++ * Scrolls specified element into view of its parent.
++ * element {Object} The element to be visible.
++ * spot {Object} An object with optional top and left properties,
++ *               specifying the offset from the top left edge.
++ */
 +function scrollIntoView(element, spot) {
 +  // Assuming offsetParent is available (it's not available when viewer is in
 +  // hidden iframe or object). We have to scroll: if the offsetParent is not set
 +  // producing the error. See also animationStartedClosure.
 +  var parent = element.offsetParent;
 +  var offsetY = element.offsetTop + element.clientTop;
++  var offsetX = element.offsetLeft + element.clientLeft;
 +  if (!parent) {
 +    console.error('offsetParent is not set -- cannot scroll');
 +    return;
 +  }
-   while (parent.clientHeight == parent.scrollHeight) {
++  while (parent.clientHeight === parent.scrollHeight) {
++    if (parent.dataset._scaleY) {
++      offsetY /= parent.dataset._scaleY;
++      offsetX /= parent.dataset._scaleX;
++    }
 +    offsetY += parent.offsetTop;
++    offsetX += parent.offsetLeft;
 +    parent = parent.offsetParent;
-     if (!parent)
++    if (!parent) {
 +      return; // no need to scroll
++    }
++  }
++  if (spot) {
++    if (spot.top !== undefined) {
++      offsetY += spot.top;
++    }
++    if (spot.left !== undefined) {
++      offsetX += spot.left;
++      parent.scrollLeft = offsetX;
++    }
 +  }
-   if (spot)
-     offsetY += spot.top;
 +  parent.scrollTop = offsetY;
 +}
 +
- var Cache = function cacheCache(size) {
-   var data = [];
-   this.push = function cachePush(view) {
-     var i = data.indexOf(view);
-     if (i >= 0)
-       data.splice(i);
-     data.push(view);
-     if (data.length > size)
-       data.shift().destroy();
-   };
- };
++/**
++ * Event handler to suppress context menu.
++ */
++function noContextMenuHandler(e) {
++  e.preventDefault();
++}
++
++/**
++ * Returns the filename or guessed filename from the url (see issue 3455).
++ * url {String} The original PDF location.
++ * @return {String} Guessed PDF file name.
++ */
++function getPDFFileNameFromURL(url) {
++  var reURI = /^(?:([^:]+:)?\/\/[^\/]+)?([^?#]*)(\?[^#]*)?(#.*)?$/;
++  //            SCHEME      HOST         1.PATH  2.QUERY   3.REF
++  // Pattern to get last matching NAME.pdf
++  var reFilename = /[^\/?#=]+\.pdf\b(?!.*\.pdf\b)/i;
++  var splitURI = reURI.exec(url);
++  var suggestedFilename = reFilename.exec(splitURI[1]) ||
++                           reFilename.exec(splitURI[2]) ||
++                           reFilename.exec(splitURI[3]);
++  if (suggestedFilename) {
++    suggestedFilename = suggestedFilename[0];
++    if (suggestedFilename.indexOf('%') != -1) {
++      // URL-encoded %2Fpath%2Fto%2Ffile.pdf should be file.pdf
++      try {
++        suggestedFilename =
++          reFilename.exec(decodeURIComponent(suggestedFilename))[0];
++      } catch(e) { // Possible (extremely rare) errors:
++        // URIError "Malformed URI", e.g. for "%AA.pdf"
++        // TypeError "null has no properties", e.g. for "%2F.pdf"
++      }
++    }
++  }
++  return suggestedFilename || 'document.pdf';
++}
 +
 +var ProgressBar = (function ProgressBarClosure() {
 +
 +  function clamp(v, min, max) {
 +    return Math.min(Math.max(v, min), max);
 +  }
 +
 +  function ProgressBar(id, opts) {
 +
-     // Fetch the sub-elements for later
++    // Fetch the sub-elements for later.
 +    this.div = document.querySelector(id + ' .progress');
 +
-     // Get options, with sensible defaults
++    // Get the loading bar element, so it can be resized to fit the viewer.
++    this.bar = this.div.parentNode;
++
++    // Get options, with sensible defaults.
 +    this.height = opts.height || 100;
 +    this.width = opts.width || 100;
 +    this.units = opts.units || '%';
 +
-     // Initialize heights
++    // Initialize heights.
 +    this.div.style.height = this.height + this.units;
++    this.percent = 0;
 +  }
 +
 +  ProgressBar.prototype = {
 +
 +    updateBar: function ProgressBar_updateBar() {
 +      if (this._indeterminate) {
 +        this.div.classList.add('indeterminate');
++        this.div.style.width = this.width + this.units;
 +        return;
 +      }
 +
-       var progressSize = this.width * this._percent / 100;
- 
-       if (this._percent > 95)
-         this.div.classList.add('full');
-       else
-         this.div.classList.remove('full');
 +      this.div.classList.remove('indeterminate');
- 
++      var progressSize = this.width * this._percent / 100;
 +      this.div.style.width = progressSize + this.units;
 +    },
 +
 +    get percent() {
 +      return this._percent;
 +    },
 +
 +    set percent(val) {
 +      this._indeterminate = isNaN(val);
 +      this._percent = clamp(val, 0, 100);
 +      this.updateBar();
++    },
++
++    setWidth: function ProgressBar_setWidth(viewer) {
++      if (viewer) {
++        var container = viewer.parentNode;
++        var scrollbarWidth = container.offsetWidth - viewer.offsetWidth;
++        if (scrollbarWidth > 0) {
++          this.bar.setAttribute('style', 'width: calc(100% - ' +
++                                         scrollbarWidth + 'px);');
++        }
++      }
++    },
++
++    hide: function ProgressBar_hide() {
++      this.bar.classList.add('hidden');
++      this.bar.removeAttribute('style');
 +    }
 +  };
 +
 +  return ProgressBar;
 +})();
 +
++var Cache = function cacheCache(size) {
++  var data = [];
++  this.push = function cachePush(view) {
++    var i = data.indexOf(view);
++    if (i >= 0)
++      data.splice(i);
++    data.push(view);
++    if (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
++};
++
++
++var Preferences = (function PreferencesClosure() {
++  function Preferences() {
++    this.prefs = {};
++    this.isInitializedPromiseResolved = false;
++    this.initializedPromise = this.readFromStorage().then(function(prefObj) {
++      this.isInitializedPromiseResolved = true;
++      if (prefObj) {
++        this.prefs = prefObj;
++      }
++    }.bind(this));
++  }
++
++  Preferences.prototype = {
++    writeToStorage: function Preferences_writeToStorage(prefObj) {
++      return;
++    },
++
++    readFromStorage: function Preferences_readFromStorage() {
++      var readFromStoragePromise = Promise.resolve();
++      return readFromStoragePromise;
++    },
++
++    reset: function Preferences_reset() {
++      if (this.isInitializedPromiseResolved) {
++        this.prefs = {};
++        this.writeToStorage(this.prefs);
++      }
++    },
++
++    set: function Preferences_set(name, value) {
++      if (!this.isInitializedPromiseResolved) {
++        return;
++      } else if (DEFAULT_PREFERENCES[name] === undefined) {
++        console.error('Preferences_set: \'' + name + '\' is undefined.');
++        return;
++      } else if (value === undefined) {
++        console.error('Preferences_set: no value is specified.');
++        return;
++      }
++      var valueType = typeof value;
++      var defaultType = typeof DEFAULT_PREFERENCES[name];
++
++      if (valueType !== defaultType) {
++        if (valueType === 'number' && defaultType === 'string') {
++          value = value.toString();
++        } else {
++          console.error('Preferences_set: \'' + value + '\' is a \"' +
++                        valueType + '\", expected a \"' + defaultType + '\".');
++          return;
++        }
++      }
++      this.prefs[name] = value;
++      this.writeToStorage(this.prefs);
++    },
++
++    get: function Preferences_get(name) {
++      var defaultPref = DEFAULT_PREFERENCES[name];
++
++      if (defaultPref === undefined) {
++        console.error('Preferences_get: \'' + name + '\' is undefined.');
++        return;
++      } else if (this.isInitializedPromiseResolved) {
++        var pref = this.prefs[name];
++
++        if (pref !== undefined) {
++          return pref;
++        }
++      }
++      return defaultPref;
++    }
++  };
++
++  return Preferences;
++})();
++
++
++Preferences.prototype.writeToStorage = function(prefObj) {
++  if (isLocalStorageEnabled) {
++    localStorage.setItem('preferences', JSON.stringify(prefObj));
++  }
++};
++
++Preferences.prototype.readFromStorage = function() {
++  var readFromStoragePromise = new Promise(function (resolve) {
++    if (isLocalStorageEnabled) {
++      var readPrefs = JSON.parse(localStorage.getItem('preferences'));
++      resolve(readPrefs);
++    }
++  });
++  return readFromStoragePromise;
++};
++
++
++(function mozPrintCallbackPolyfillClosure() {
++  if ('mozPrintCallback' in document.createElement('canvas')) {
++    return;
++  }
++  // Cause positive result on feature-detection:
++  HTMLCanvasElement.prototype.mozPrintCallback = undefined;
 +
- // Settings Manager - This is a utility for saving settings
- // First we see if localStorage is available
- // If not, we use FUEL in FF
- // Use asyncStorage for B2G
- var Settings = (function SettingsClosure() {
-   var isLocalStorageEnabled = (function localStorageEnabledTest() {
-     // 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
++  var canvases;   // During print task: non-live NodeList of <canvas> elements
++  var index;      // Index of <canvas> element that is being processed
++
++  var print = window.print;
++  window.print = function print() {
++    if (canvases) {
++      console.warn('Ignored window.print() because of a pending print job.');
++      return;
++    }
 +    try {
-       return 'localStorage' in window && window['localStorage'] !== null &&
-           localStorage;
-     } catch (e) {
-       return false;
++      dispatchEvent('beforeprint');
++    } finally {
++      canvases = document.querySelectorAll('canvas');
++      index = -1;
++      next();
++    }
++  };
++
++  function dispatchEvent(eventType) {
++    var event = document.createEvent('CustomEvent');
++    event.initCustomEvent(eventType, false, false, 'custom');
++    window.dispatchEvent(event);
++  }
++
++  function next() {
++    if (!canvases) {
++      return; // Print task cancelled by user (state reset in abort())
++    }
++
++    renderProgress();
++    if (++index < canvases.length) {
++      var canvas = canvases[index];
++      if (typeof canvas.mozPrintCallback === 'function') {
++        canvas.mozPrintCallback({
++          context: canvas.getContext('2d'),
++          abort: abort,
++          done: next
++        });
++      } else {
++        next();
++      }
++    } else {
++      renderProgress();
++      print.call(window);
++      setTimeout(abort, 20); // Tidy-up
++    }
++  }
++
++  function abort() {
++    if (canvases) {
++      canvases = null;
++      renderProgress();
++      dispatchEvent('afterprint');
++    }
++  }
++
++  function renderProgress() {
++    var progressContainer = document.getElementById('mozPrintCallback-shim');
++    if (canvases) {
++      var progress = Math.round(100 * index / canvases.length);
++      var progressBar = progressContainer.querySelector('progress');
++      var progressPerc = progressContainer.querySelector('.relative-progress');
++      progressBar.value = progress;
++      progressPerc.textContent = progress + '%';
++      progressContainer.removeAttribute('hidden');
++      progressContainer.onclick = abort;
++    } else {
++      progressContainer.setAttribute('hidden', '');
++    }
++  }
++
++  var hasAttachEvent = !!document.attachEvent;
++
++  window.addEventListener('keydown', function(event) {
++    // 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
++        // attachEvent is gone in IE11, so the dialog will re-appear in IE11.
++        return;
++      }
++      event.preventDefault();
++      if (event.stopImmediatePropagation) {
++        event.stopImmediatePropagation();
++      } else {
++        event.stopPropagation();
++      }
++      return;
++    }
++    if (event.keyCode === 27 && canvases) { // Esc
++      abort();
++    }
++  }, true);
++  if (hasAttachEvent) {
++    document.attachEvent('onkeydown', function(event) {
++      event = event || window.event;
++      if (event.keyCode === 80/*P*/ && event.ctrlKey) {
++        event.keyCode = 0;
++        return false;
++      }
++    });
++  }
++
++  if ('onbeforeprint' in window) {
++    // Do not propagate before/afterprint events when they are not triggered
++    // from within this polyfill. (FF/IE).
++    var stopPropagationIfNeeded = function(event) {
++      if (event.detail !== 'custom' && event.stopImmediatePropagation) {
++        event.stopImmediatePropagation();
++      }
++    };
++    window.addEventListener('beforeprint', stopPropagationIfNeeded, false);
++    window.addEventListener('afterprint', stopPropagationIfNeeded, false);
++  }
++})();
++
++
++
++var DownloadManager = (function DownloadManagerClosure() {
++
++  function download(blobUrl, filename) {
++    var a = document.createElement('a');
++    if (a.click) {
++      // Use a.click() if available. Otherwise, Chrome might show
++      // "Unsafe JavaScript attempt to initiate a navigation change
++      //  for frame with URL" and not open the PDF at all.
++      // Supported by (not mentioned = untested):
++      // - Firefox 6 - 19 (4- does not support a.click, 5 ignores a.click)
++      // - Chrome 19 - 26 (18- does not support a.click)
++      // - Opera 9 - 12.15
++      // - Internet Explorer 6 - 10
++      // - Safari 6 (5.1- does not support a.click)
++      a.href = blobUrl;
++      a.target = '_parent';
++      // Use a.download if available. This increases the likelihood that
++      // the file is downloaded instead of opened by another PDF plugin.
++      if ('download' in a) {
++        a.download = filename;
++      }
++      // <a> must be in the document for IE and recent Firefox versions.
++      // (otherwise .click() is ignored)
++      (document.body || document.documentElement).appendChild(a);
++      a.click();
++      a.parentNode.removeChild(a);
++    } else {
++      if (window.top === window &&
++          blobUrl.split('#')[0] === window.location.href.split('#')[0]) {
++        // If _parent == self, then opening an identical URL with different
++        // location hash will only cause a navigation, not a download.
++        var padCharacter = blobUrl.indexOf('?') === -1 ? '?' : '&';
++        blobUrl = blobUrl.replace(/#|$/, padCharacter + '$&');
++      }
++      window.open(blobUrl, '_parent');
++    }
++  }
++
++  function DownloadManager() {}
++
++  DownloadManager.prototype = {
++    downloadUrl: function DownloadManager_downloadUrl(url, filename) {
++      if (!PDFJS.isValidUrl(url, true)) {
++        return; // restricted/invalid URL
++      }
++
++      download(url + '#pdfjs.action=download', filename);
++    },
++
++    download: function DownloadManager_download(blob, url, filename) {
++      if (!URL) {
++        // URL.createObjectURL is not supported
++        this.downloadUrl(url, filename);
++        return;
++      }
++
++      if (navigator.msSaveBlob) {
++        // IE10 / IE11
++        if (!navigator.msSaveBlob(blob, filename)) {
++          this.downloadUrl(url, filename);
++        }
++        return;
++      }
++
++      var blobUrl = URL.createObjectURL(blob);
++      download(blobUrl, filename);
 +    }
-   })();
++  };
++
++  return DownloadManager;
++})();
++
++
++
 +
-   function Settings(fingerprint) {
++var cache = new Cache(CACHE_SIZE);
++var currentPageNumber = 1;
++
++
++/**
++ * View History - This is a utility for saving various view parameters for
++ *                recently opened files.
++ *
++ * The way that the view parameters are stored depends on how PDF.js is built,
++ * for 'node make <flag>' the following cases exist:
++ *  - FIREFOX or MOZCENTRAL - uses about:config.
++ *  - B2G                   - uses asyncStorage.
++ *  - GENERIC or CHROME     - uses localStorage, if it is available.
++ */
++var ViewHistory = (function ViewHistoryClosure() {
++  function ViewHistory(fingerprint) {
 +    this.fingerprint = fingerprint;
-     this.initializedPromise = new PDFJS.Promise();
++    var initializedPromiseResolve;
++    this.isInitializedPromiseResolved = false;
++    this.initializedPromise = new Promise(function (resolve) {
++      initializedPromiseResolve = resolve;
++    });
 +
-     var resolvePromise = (function settingsResolvePromise(db) {
++    var resolvePromise = (function ViewHistoryResolvePromise(db) {
++      this.isInitializedPromiseResolved = true;
 +      this.initialize(db || '{}');
-       this.initializedPromise.resolve();
++      initializedPromiseResolve();
 +    }).bind(this);
 +
 +
 +
-     if (isLocalStorageEnabled)
++    if (isLocalStorageEnabled) {
 +      resolvePromise(localStorage.getItem('database'));
++    }
 +  }
 +
-   Settings.prototype = {
-     initialize: function settingsInitialize(database) {
++  ViewHistory.prototype = {
++    initialize: function ViewHistory_initialize(database) {
 +      database = JSON.parse(database);
-       if (!('files' in database))
++      if (!('files' in database)) {
 +        database.files = [];
-       if (database.files.length >= SETTINGS_MEMORY)
++      }
++      if (database.files.length >= VIEW_HISTORY_MEMORY) {
 +        database.files.shift();
++      }
 +      var index;
 +      for (var i = 0, length = database.files.length; i < length; i++) {
 +        var branch = database.files[i];
-         if (branch.fingerprint == this.fingerprint) {
++        if (branch.fingerprint === this.fingerprint) {
 +          index = i;
 +          break;
 +        }
 +      }
-       if (typeof index != 'number')
++      if (typeof index !== 'number') {
 +        index = database.files.push({fingerprint: this.fingerprint}) - 1;
++      }
 +      this.file = database.files[index];
 +      this.database = database;
 +    },
 +
-     set: function settingsSet(name, val) {
-       if (!this.initializedPromise.isResolved)
++    set: function ViewHistory_set(name, val) {
++      if (!this.isInitializedPromiseResolved) {
 +        return;
- 
++      }
 +      var file = this.file;
 +      file[name] = val;
 +      var database = JSON.stringify(this.database);
 +
 +
 +
-       if (isLocalStorageEnabled)
++      if (isLocalStorageEnabled) {
 +        localStorage.setItem('database', database);
++      }
 +    },
 +
-     get: function settingsGet(name, defaultValue) {
-       if (!this.initializedPromise.isResolved)
++    get: function ViewHistory_get(name, defaultValue) {
++      if (!this.isInitializedPromiseResolved) {
 +        return defaultValue;
- 
++      }
 +      return this.file[name] || defaultValue;
 +    }
 +  };
 +
-   return Settings;
++  return ViewHistory;
 +})();
 +
- var cache = new Cache(CACHE_SIZE);
- var currentPageNumber = 1;
 +
- var PDFFindController = {
-   startedTextExtraction: false,
++/* globals PDFFindController, FindStates, mozL10n */
 +
-   extractTextPromises: [],
++/**
++ * 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
++ */
++var PDFFindBar = {
 +
-   // If active, find results will be highlighted.
++  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.';
++    }
++
++    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;
++
++    var self = this;
++    this.toggleButton.addEventListener('click', function() {
++      self.toggle();
++    });
++
++    this.findField.addEventListener('input', function() {
++      self.dispatchEvent('');
++    });
++
++    this.bar.addEventListener('keydown', function(evt) {
++      switch (evt.keyCode) {
++        case 13: // Enter
++          if (evt.target === self.findField) {
++            self.dispatchEvent('again', evt.shiftKey);
++          }
++          break;
++        case 27: // Escape
++          self.close();
++          break;
++      }
++    });
++
++    this.findPreviousButton.addEventListener('click',
++      function() { self.dispatchEvent('again', true); }
++    );
++
++    this.findNextButton.addEventListener('click', function() {
++      self.dispatchEvent('again', false);
++    });
++
++    this.highlightAll.addEventListener('click', function() {
++      self.dispatchEvent('highlightallchange');
++    });
++
++    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();
++    }
++  }
++};
++
++
++
++/* globals PDFFindBar, PDFJS, FindStates, FirefoxCom, Promise */
++
++/**
++ * Provides a "search" or "find" functionality for the PDF.
++ * This object actually performs the search for a given string.
++ */
++
++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,
 +
-   initialize: function() {
++  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;
++
 +    var events = [
 +      'find',
 +      'findagain',
 +      'findhighlightallchange',
 +      'findcasesensitivitychange'
 +    ];
 +
++    this.firstPagePromise = new Promise(function (resolve) {
++      this.resolveFirstPage = resolve;
++    }.bind(this));
 +    this.handleEvent = this.handleEvent.bind(this);
 +
 +    for (var i = 0; i < events.length; i++) {
 +      window.addEventListener(events[i], this.handleEvent);
 +    }
 +  },
 +
++  reset: function pdfFindControllerReset() {
++    this.startedTextExtraction = false;
++    this.extractTextPromises = [];
++    this.active = false;
++  },
++
 +  calcFindMatch: function(pageIndex) {
 +    var pageContent = this.pageContents[pageIndex];
 +    var query = this.state.query;
 +    var caseSensitive = this.state.caseSensitive;
 +    var queryLen = query.length;
 +
 +    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();
++      this.nextPageMatch();
 +    }
 +  },
 +
 +  extractText: function() {
 +    if (this.startedTextExtraction) {
 +      return;
 +    }
 +    this.startedTextExtraction = true;
 +
 +    this.pageContents = [];
-     for (var i = 0, ii = PDFView.pdfDocument.numPages; i < ii; i++) {
-       this.extractTextPromises.push(new PDFJS.Promise());
++    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) {
-       PDFView.pages[pageIndex].getTextContent().then(
-         function textContentResolved(data) {
-           // Build the find string.
-           var bidiTexts = data.bidiTexts;
++      self.pdfPageSource.pages[pageIndex].getTextContent().then(
++        function textContentResolved(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);
 +
-           self.extractTextPromises[pageIndex].resolve(pageIndex);
-           if ((pageIndex + 1) < PDFView.pages.length)
++          extractTextPromisesResolves[pageIndex](pageIndex);
++          if ((pageIndex + 1) < self.pdfPageSource.pages.length)
 +            extractPageText(pageIndex + 1);
 +        }
 +      );
 +    }
 +    extractPageText(0);
-     return this.extractTextPromise;
 +  },
 +
 +  handleEvent: function(e) {
 +    if (this.state === null || e.type !== 'findagain') {
 +      this.dirtyMatch = true;
 +    }
 +    this.state = e.detail;
 +    this.updateUIState(FindStates.FIND_PENDING);
 +
-     this.extractText();
++    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();
-     }
++      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 = PDFView.pages[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 pages = PDFView.pages;
 +    var previous = this.state.findPrevious;
-     var numPages = PDFView.pages.length;
++    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 = previous ? numPages - 1 : 0;
++      this.offset.pageIdx = currentPageIndex;
 +      this.offset.matchIdx = null;
 +      this.hadMatch = false;
-       this.resumeCallback = null;
 +      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.
-         this.extractTextPromises[i].onData(function(pageIdx) {
-           // Use a timeout since all the pages may already be extracted and we
-           // want to start highlighting before finding all the matches.
-           setTimeout(function() {
++        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.resumeCallback) {
++    if (this.resumePageIdx) {
 +      return;
 +    }
 +
 +    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);
 +        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(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;
++      this.updateMatch(true);
++      // matches were found
++      return true;
++    } else {
++      // No matches 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.
++          this.updateMatch(false);
++          // while matches were not found, searching for a page 
++          // with matches should nevertheless halt.
++          return true;
++        }
++      }
++      // matches were not found (and searching is not done)
++      return false;
++    }
++  },
++
 +  nextPageMatch: function() {
-     if (this.resumePageIdx !== null)
++    if (this.resumePageIdx !== null) {
 +      console.error('There can only be one pending page.');
- 
-     var matchesReady = function(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;
-         this.updateMatch(true);
-       } else {
-         // No matches 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.
-             this.updateMatch(false);
-             return;
-           }
-         }
-         // Search the next page.
-         this.nextPageMatch();
-       }
-     }.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]);
++    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));
 +  },
 +
 +  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);
 +      }
 +    }
 +    this.updateUIState(state, this.state.findPrevious);
 +    if (this.selected.pageIdx !== -1) {
 +      this.updatePage(this.selected.pageIdx, true);
 +    }
 +  },
 +
 +  updateUIState: function(state, previous) {
-     if (PDFView.supportsIntegratedFind) {
++    if (this.integratedFind) {
 +      FirefoxCom.request('updateFindControlState',
 +                         {result: state, findPrevious: previous});
 +      return;
 +    }
 +    PDFFindBar.updateUIState(state, previous);
 +  }
 +};
 +
- var PDFFindBar = {
-   // TODO: Enable the FindBar *AFTER* the pagesPromise in the load function
-   // got resolved
- 
-   opened: false,
 +
-   initialize: function() {
-     this.bar = document.getElementById('findbar');
-     this.toggleButton = document.getElementById('viewFind');
-     this.findField = document.getElementById('findInput');
-     this.highlightAll = document.getElementById('findHighlightAll');
-     this.caseSensitive = document.getElementById('findMatchCase');
-     this.findMsg = document.getElementById('findMsg');
-     this.findStatusIcon = document.getElementById('findStatusIcon');
 +
-     var self = this;
-     this.toggleButton.addEventListener('click', function() {
-       self.toggle();
-     });
++var PDFHistory = {
++  initialized: false,
++  initialDestination: null,
 +
-     this.findField.addEventListener('input', function() {
-       self.dispatchEvent('');
-     });
++  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;
++    }
++    this.initialized = true;
++    this.reInitialized = false;
++    this.allowHashChange = true;
++    this.historyUnlocked = true;
++
++    this.previousHash = window.location.hash.substring(1);
++    this.currentBookmark = '';
++    this.currentPage = 0;
++    this.updatePreviousBookmark = false;
++    this.previousBookmark = '';
++    this.previousPage = 0;
++    this.nextHashParam = '';
 +
-     this.bar.addEventListener('keydown', function(evt) {
-       switch (evt.keyCode) {
-         case 13: // Enter
-           if (evt.target === self.findField) {
-             self.dispatchEvent('again', evt.shiftKey);
-           }
-           break;
-         case 27: // Escape
-           self.close();
-           break;
++    this.fingerprint = fingerprint;
++    this.currentUid = this.uid = 0;
++    this.current = {};
++
++    var state = window.history.state;
++    if (this._isStateObjectDefined(state)) {
++      // This corresponds to navigating back to the document
++      // from another page in the browser history.
++      if (state.target.dest) {
++        this.initialDestination = state.target.dest;
++      } else {
++        PDFView.initialBookmark = state.target.hash;
 +      }
-     });
++      this.currentUid = state.uid;
++      this.uid = state.uid + 1;
++      this.current = state.target;
++    } else {
++      // This corresponds to the loading of a new document.
++      if (state && state.fingerprint &&
++          this.fingerprint !== state.fingerprint) {
++        // Reinitialize the browsing history when a new document
++        // is opened in the web viewer.
++        this.reInitialized = true;
++      }
++      this._pushOrReplaceState({ fingerprint: this.fingerprint }, true);
++    }
 +
-     document.getElementById('findPrevious').addEventListener('click',
-       function() { self.dispatchEvent('again', true); }
-     );
++    var self = this;
++    window.addEventListener('popstate', function pdfHistoryPopstate(evt) {
++      evt.preventDefault();
++      evt.stopPropagation();
 +
-     document.getElementById('findNext').addEventListener('click', function() {
-       self.dispatchEvent('again', false);
-     });
++      if (!self.historyUnlocked) {
++        return;
++      }
++      if (evt.state) {
++        // Move back/forward in the history.
++        self._goTo(evt.state);
++      } else {
++        // Handle the user modifying the hash of a loaded document.
++        self.previousHash = window.location.hash.substring(1);
++
++        // If the history is empty when the hash changes,
++        // update the previous entry in the browser history.
++        if (self.uid === 0) {
++          var previousParams = (self.previousHash && self.currentBookmark &&
++                                self.previousHash !== self.currentBookmark) ?
++            { hash: self.currentBookmark, page: self.currentPage } :
++            { page: 1 };
++          self.historyUnlocked = false;
++          self.allowHashChange = false;
++          window.history.back();
++          self._pushToHistory(previousParams, false, true);
++          window.history.forward();
++          self.historyUnlocked = true;
++        }
++        self._pushToHistory({ hash: self.previousHash }, false, true);
++        self._updatePreviousBookmark();
++      }
++    }, false);
 +
-     this.highlightAll.addEventListener('click', function() {
-       self.dispatchEvent('highlightallchange');
-     });
++    function pdfHistoryBeforeUnload() {
++      var previousParams = self._getPreviousParams(null, true);
++      if (previousParams) {
++        var replacePrevious = (!self.current.dest &&
++                               self.current.hash !== self.previousHash);
++        self._pushToHistory(previousParams, false, replacePrevious);
++        self._updatePreviousBookmark();
++      }
++      // Remove the event listener when navigating away from the document,
++      // since 'beforeunload' prevents Firefox from caching the document.
++      window.removeEventListener('beforeunload', pdfHistoryBeforeUnload, false);
++    }
++    window.addEventListener('beforeunload', pdfHistoryBeforeUnload, false);
 +
-     this.caseSensitive.addEventListener('click', function() {
-       self.dispatchEvent('casesensitivitychange');
-     });
++    window.addEventListener('pageshow', function pdfHistoryPageShow(evt) {
++      // If the entire viewer (including the PDF file) is cached in the browser,
++      // we need to reattach the 'beforeunload' event listener since
++      // the 'DOMContentLoaded' event is not fired on 'pageshow'.
++      window.addEventListener('beforeunload', pdfHistoryBeforeUnload, false);
++    }, false);
 +  },
 +
-   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);
++  _isStateObjectDefined: function pdfHistory_isStateObjectDefined(state) {
++    return (state && state.uid >= 0 &&
++            state.fingerprint && this.fingerprint === state.fingerprint &&
++            state.target && state.target.hash) ? true : false;
 +  },
 +
-   updateUIState: function(state, previous) {
-     var notFound = false;
-     var findMsg = '';
-     var status = '';
++  _pushOrReplaceState: function pdfHistory_pushOrReplaceState(stateObj,
++                                                              replace) {
++    if (replace) {
++      window.history.replaceState(stateObj, '', document.URL);
++    } else {
++      window.history.pushState(stateObj, '', document.URL);
++    }
++  },
 +
-     switch (state) {
-       case FindStates.FIND_FOUND:
-         break;
++  get isHashChangeUnlocked() {
++    if (!this.initialized) {
++      return true;
++    }
++    // If the current hash changes when moving back/forward in the history,
++    // this will trigger a 'popstate' event *as well* as a 'hashchange' event.
++    // Since the hash generally won't correspond to the exact the position
++    // stored in the history's state object, triggering the 'hashchange' event
++    // can thus corrupt the browser history.
++    //
++    // When the hash changes during a 'popstate' event, we *only* prevent the
++    // first 'hashchange' event and immediately reset allowHashChange.
++    // If it is not reset, the user would not be able to change the hash.
++
++    var temp = this.allowHashChange;
++    this.allowHashChange = true;
++    return temp;
++  },
 +
-       case FindStates.FIND_PENDING:
-         status = 'pending';
-         break;
++  _updatePreviousBookmark: function pdfHistory_updatePreviousBookmark() {
++    if (this.updatePreviousBookmark &&
++        this.currentBookmark && this.currentPage) {
++      this.previousBookmark = this.currentBookmark;
++      this.previousPage = this.currentPage;
++      this.updatePreviousBookmark = false;
++    }
++  },
 +
-       case FindStates.FIND_NOTFOUND:
-         findMsg = mozL10n.get('find_not_found', null, 'Phrase not found');
-         notFound = true;
-         break;
++  updateCurrentBookmark: function pdfHistoryUpdateCurrentBookmark(bookmark,
++                                                                  pageNum) {
++    if (this.initialized) {
++      this.currentBookmark = bookmark.substring(1);
++      this.currentPage = pageNum | 0;
++      this._updatePreviousBookmark();
++    }
++  },
 +
-       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;
++  updateNextHashParam: function pdfHistoryUpdateNextHashParam(param) {
++    if (this.initialized) {
++      this.nextHashParam = param;
++    }
++  },
++
++  push: function pdfHistoryPush(params, isInitialBookmark) {
++    if (!(this.initialized && this.historyUnlocked)) {
++      return;
++    }
++    if (params.dest && !params.hash) {
++      params.hash = (this.current.hash && this.current.dest &&
++                     this.current.dest === params.dest) ?
++        this.current.hash :
++        PDFView.getDestinationHash(params.dest).split('#')[1];
++    }
++    if (params.page) {
++      params.page |= 0;
++    }
++    if (isInitialBookmark) {
++      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.
++        this._pushToHistory(params, false);
++        this.previousHash = window.location.hash.substring(1);
++      }
++      this.updatePreviousBookmark = this.nextHashParam ? false : true;
++      if (target) {
++        // If the current document is reloaded,
++        // avoid creating duplicate entries in the history.
++        this._updatePreviousBookmark();
++      }
++      return;
++    }
++    if (this.nextHashParam) {
++      if (this.nextHashParam === params.hash) {
++        this.nextHashParam = null;
++        this.updatePreviousBookmark = true;
++        return;
++      } else {
++        this.nextHashParam = null;
++      }
++    }
++
++    if (params.hash) {
++      if (this.current.hash) {
++        if (this.current.hash !== params.hash) {
++          this._pushToHistory(params, true);
++        } else {
++          if (!this.current.page && params.page) {
++            this._pushToHistory(params, false, true);
++          }
++          this.updatePreviousBookmark = true;
++        }
++      } else {
++        this._pushToHistory(params, true);
++      }
++    } else if (this.current.page && params.page &&
++               this.current.page !== params.page) {
++      this._pushToHistory(params, true);
++    }
++  },
++
++  _getPreviousParams: function pdfHistory_getPreviousParams(onlyCheckPage,
++                                                            beforeUnload) {
++    if (!(this.currentBookmark && this.currentPage)) {
++      return null;
++    } else if (this.updatePreviousBookmark) {
++      this.updatePreviousBookmark = false;
++    }
++    if (this.uid > 0 && !(this.previousBookmark && this.previousPage)) {
++      // Prevent the history from getting stuck in the current state,
++      // effectively preventing the user from going back/forward in the history.
++      //
++      // This happens if the current position in the document didn't change when
++      // the history was previously updated. The reasons for this are either:
++      // 1. The current zoom value is such that the document does not need to,
++      //    or cannot, be scrolled to display the destination.
++      // 2. The previous destination is broken, and doesn't actally point to a
++      //    position within the document.
++      //    (This is either due to a bad PDF generator, or the user making a
++      //     mistake when entering a destination in the hash parameters.)
++      return null;
++    }
++    if ((!this.current.dest && !onlyCheckPage) || beforeUnload) {
++      if (this.previousBookmark === this.currentBookmark) {
++        return null;
++      }
++    } else if (this.current.page || onlyCheckPage) {
++      if (this.previousPage === this.currentPage) {
++        return null;
++      }
++    } else {
++      return null;
++    }
++    var params = { hash: this.currentBookmark, page: this.currentPage };
++    if (PresentationMode.active) {
++      params.hash = null;
++    }
++    return params;
++  },
++
++  _stateObj: function pdfHistory_stateObj(params) {
++    return { fingerprint: this.fingerprint, uid: this.uid, target: params };
++  },
++
++  _pushToHistory: function pdfHistory_pushToHistory(params,
++                                                    addPrevious, overwrite) {
++    if (!this.initialized) {
++      return;
++    }
++    if (!params.hash && params.page) {
++      params.hash = ('page=' + params.page);
++    }
++    if (addPrevious && !overwrite) {
++      var previousParams = this._getPreviousParams();
++      if (previousParams) {
++        var replacePrevious = (!this.current.dest &&
++                               this.current.hash !== this.previousHash);
++        this._pushToHistory(previousParams, false, replacePrevious);
++      }
++    }
++    this._pushOrReplaceState(this._stateObj(params),
++                             (overwrite || this.uid === 0));
++    this.currentUid = this.uid++;
++    this.current = params;
++    this.updatePreviousBookmark = true;
++  },
++
++  _goTo: function pdfHistory_goTo(state) {
++    if (!(this.initialized && this.historyUnlocked &&
++          this._isStateObjectDefined(state))) {
++      return;
++    }
++    if (!this.reInitialized && state.uid < this.currentUid) {
++      var previousParams = this._getPreviousParams(true);
++      if (previousParams) {
++        this._pushToHistory(this.current, false);
++        this._pushToHistory(previousParams, false);
++        this.currentUid = state.uid;
++        window.history.back();
++        return;
++      }
++    }
++    this.historyUnlocked = false;
++
++    if (state.target.dest) {
++      PDFView.navigateTo(state.target.dest);
++    } else {
++      PDFView.setHash(state.target.hash);
++    }
++    this.currentUid = state.uid;
++    if (state.uid > this.uid) {
++      this.uid = state.uid;
++    }
++    this.current = state.target;
++    this.updatePreviousBookmark = true;
++
++    var currentHash = window.location.hash.substring(1);
++    if (this.previousHash !== currentHash) {
++      this.allowHashChange = false;
++    }
++    this.previousHash = currentHash;
++
++    this.historyUnlocked = true;
++  },
++
++  back: function pdfHistoryBack() {
++    this.go(-1);
++  },
++
++  forward: function pdfHistoryForward() {
++    this.go(1);
++  },
++
++  go: function pdfHistoryGo(direction) {
++    if (this.initialized && this.historyUnlocked) {
++      var state = window.history.state;
++      if (direction === -1 && state && state.uid > 0) {
++        window.history.back();
++      } else if (direction === 1 && state && state.uid < (this.uid - 1)) {
++        window.history.forward();
++      }
++    }
++  }
++};
++
++
++var SecondaryToolbar = {
++  opened: false,
++  previousContainerHeight: null,
++  newContainerHeight: null,
++
++  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.
++    this.toggleButton = options.toggleButton;
++    this.presentationModeButton = options.presentationModeButton;
++    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 = [
++      // Button to toggle the visibility of the secondary toolbar:
++      { element: this.toggleButton, handler: this.toggle },
++      // All items within the secondary toolbar
++      // (except for toggleHandTool, hand_tool.js is responsible for it):
++      { element: this.presentationModeButton,
++        handler: this.presentationModeClick },
++      { 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.documentPropertiesButton,
++        handler: this.documentPropertiesClick }
++    ];
++
++    for (var item in elements) {
++      var element = elements[item].element;
++      if (element) {
++        element.addEventListener('click', elements[item].handler.bind(this));
++      }
++    }
++  },
++
++  // Event handling functions.
++  presentationModeClick: function secondaryToolbarPresentationModeClick(evt) {
++    this.presentationMode.request();
++    this.close();
++  },
++
++  // openFileClick removed because it is unused
++
++  printClick: function secondaryToolbarPrintClick(evt) {
++    window.print();
++    this.close();
++  },
++
++  downloadClick: function secondaryToolbarDownloadClick(evt) {
++    PDFView.download();
++    this.close();
++  },
++
++  viewBookmarkClick: function secondaryToolbarViewBookmarkClick(evt) {
++    this.close();
++  },
++
++  firstPageClick: function secondaryToolbarFirstPageClick(evt) {
++    PDFView.page = 1;
++    this.close();
++  },
++
++  lastPageClick: function secondaryToolbarLastPageClick(evt) {
++    PDFView.page = PDFView.pdfDocument.numPages;
++    this.close();
++  },
++
++  pageRotateCwClick: function secondaryToolbarPageRotateCwClick(evt) {
++    PDFView.rotatePages(90);
++  },
++
++  pageRotateCcwClick: function secondaryToolbarPageRotateCcwClick(evt) {
++    PDFView.rotatePages(-90);
++  },
++
++  documentPropertiesClick: function secondaryToolbarDocumentPropsClick(evt) {
++    this.documentProperties.show();
++    this.close();
++  },
++
++  // Misc. functions for interacting with the toolbar.
++  setMaxHeight: function secondaryToolbarSetMaxHeight(container) {
++    if (!container || !this.buttonContainer) {
++      return;
++    }
++    this.newContainerHeight = container.clientHeight;
++    if (this.previousContainerHeight === this.newContainerHeight) {
++      return;
++    }
++    this.buttonContainer.setAttribute('style',
++      'max-height: ' + (this.newContainerHeight - SCROLLBAR_PADDING) + 'px;');
++    this.previousContainerHeight = this.newContainerHeight;
++  },
++
++  open: function secondaryToolbarOpen() {
++    if (this.opened) {
++      return;
++    }
++    this.opened = true;
++    this.toggleButton.classList.add('toggled');
++    this.toolbar.classList.remove('hidden');
++  },
++
++  close: function secondaryToolbarClose(target) {
++    if (!this.opened) {
++      return;
++    } else if (target && !this.toolbar.contains(target)) {
++      return;
++    }
++    this.opened = false;
++    this.toolbar.classList.add('hidden');
++    this.toggleButton.classList.remove('toggled');
++  },
++
++  toggle: function secondaryToolbarToggle() {
++    if (this.opened) {
++      this.close();
++    } else {
++      this.open();
++    }
++  }
++};
++
++
++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));
++
++    window.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.overlayContainer.firstElementChild.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');
++    this.overlayContainer.firstElementChild.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,
++  args: null,
++  contextMenuOpen: false,
++  prevCoords: { x: null, y: null },
++
++  initialize: function presentationModeInitialize(options) {
++    this.container = options.container;
++    this.secondaryToolbar = options.secondaryToolbar;
++
++    this.viewer = this.container.firstElementChild;
++
++    this.firstPage = options.firstPage;
++    this.lastPage = options.lastPage;
++    this.pageRotateCw = options.pageRotateCw;
++    this.pageRotateCcw = options.pageRotateCcw;
++
++    this.firstPage.addEventListener('click', function() {
++      this.contextMenuOpen = false;
++      this.secondaryToolbar.firstPageClick();
++    }.bind(this));
++    this.lastPage.addEventListener('click', function() {
++      this.contextMenuOpen = false;
++      this.secondaryToolbar.lastPageClick();
++    }.bind(this));
++
++    this.pageRotateCw.addEventListener('click', function() {
++      this.contextMenuOpen = false;
++      this.secondaryToolbar.pageRotateCwClick();
++    }.bind(this));
++    this.pageRotateCcw.addEventListener('click', function() {
++      this.contextMenuOpen = false;
++      this.secondaryToolbar.pageRotateCcwClick();
++    }.bind(this));
++  },
++
++  get isFullscreen() {
++    return (document.fullscreenElement ||
++            document.mozFullScreen ||
++            document.webkitIsFullScreen ||
++            document.msFullscreenElement);
++  },
++
++  /**
++   * Initialize a timeout that is used to reset PDFView.currentPosition 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;
++    }.bind(this), DELAY_BEFORE_RESETTING_SWITCH_IN_PROGRESS);
++
++    PDFView.currentPosition = null;
++  },
++
++  _resetSwitchInProgress: function presentationMode_resetSwitchInProgress() {
++    if (this.switchInProgress) {
++      clearTimeout(this.switchInProgress);
++      delete this.switchInProgress;
++    }
++  },
++
++  request: function presentationModeRequest() {
++    if (!PDFView.supportsFullscreen || this.isFullscreen ||
++        !this.viewer.hasChildNodes()) {
++      return false;
++    }
++    this._setSwitchInProgress();
++
++    if (this.container.requestFullscreen) {
++      this.container.requestFullscreen();
++    } else if (this.container.mozRequestFullScreen) {
++      this.container.mozRequestFullScreen();
++    } else if (this.container.webkitRequestFullScreen) {
++      this.container.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT);
++    } else if (this.container.msRequestFullscreen) {
++      this.container.msRequestFullscreen();
++    } else {
++      return false;
++    }
++
++    this.args = {
++      page: PDFView.page,
++      previousScale: PDFView.currentScaleValue
++    };
++
++    return true;
++  },
++
++  enter: function presentationModeEnter() {
++    this.active = true;
++    this._resetSwitchInProgress();
++
++    // 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() {
++      PDFView.page = this.args.page;
++      PDFView.setScale('page-fit', true);
++    }.bind(this), 0);
++
++    window.addEventListener('mousemove', this.mouseMove, false);
++    window.addEventListener('mousedown', this.mouseDown, false);
++    window.addEventListener('contextmenu', this.contextMenu, false);
++
++    this.showControls();
++    HandTool.enterPresentationMode();
++    this.contextMenuOpen = false;
++    this.container.setAttribute('contextmenu', 'viewerContextMenu');
++  },
++
++  exit: function presentationModeExit() {
++    var page = PDFView.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() {
++      PDFView.setScale(this.args.previousScale);
++      PDFView.page = page;
++      // Keep Presentation Mode active until the page is scrolled into view,
++      // to prevent issues in non-Mozilla browsers.
++      this.active = false;
++      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();
++    PDFView.clearMouseScrollState();
++    HandTool.exitPresentationMode();
++    this.container.removeAttribute('contextmenu');
++    this.contextMenuOpen = false;
++
++    // Ensure that the thumbnail of the current page is visible
++    // when exiting presentation mode.
++    scrollIntoView(document.getElementById('thumbnailContainer' + page));
++  },
++
++  showControls: function presentationModeShowControls() {
++    if (this.controlsTimeout) {
++      clearTimeout(this.controlsTimeout);
++    } else {
++      this.container.classList.add(SELECTOR);
++    }
++    this.controlsTimeout = setTimeout(function hideControlsTimeout() {
++      this.container.classList.remove(SELECTOR);
++      delete this.controlsTimeout;
++    }.bind(this), DELAY_BEFORE_HIDING_CONTROLS);
++  },
++
++  hideControls: function presentationModeHideControls() {
++    if (!this.controlsTimeout) {
++      return;
++    }
++    this.container.classList.remove(SELECTOR);
++    clearTimeout(this.controlsTimeout);
++    delete this.controlsTimeout;
++  },
++
++  mouseMove: function presentationModeMouseMove(evt) {
++    // Workaround for a bug in WebKit browsers that causes the 'mousemove' event
++    // to be fired when the cursor is changed. For details, see:
++    // http://code.google.com/p/chromium/issues/detail?id=103041.
++
++    var currCoords = { x: evt.clientX, y: evt.clientY };
++    var prevCoords = PresentationMode.prevCoords;
++    PresentationMode.prevCoords = currCoords;
++
++    if (currCoords.x === prevCoords.x && currCoords.y === prevCoords.y) {
++      return;
++    }
++    PresentationMode.showControls();
++  },
++
++  mouseDown: function presentationModeMouseDown(evt) {
++    var self = PresentationMode;
++    if (self.contextMenuOpen) {
++      self.contextMenuOpen = false;
++      evt.preventDefault();
++      return;
++    }
++
++    if (evt.button === 0) {
++      // Enable clicking of links in presentation mode. Please note:
++      // Only links pointing to destinations in the current PDF document work.
++      var isInternalLink = (evt.target.href &&
++                            evt.target.classList.contains('internalLink'));
++      if (!isInternalLink) {
++        // Unless an internal link was clicked, advance one page.
++        evt.preventDefault();
++        PDFView.page += (evt.shiftKey ? -1 : 1);
++      }
++    }
++  },
++
++  contextMenu: function presentationModeContextMenu(evt) {
++    PresentationMode.contextMenuOpen = true;
++  }
++};
++
++(function presentationModeClosure() {
++  function presentationModeChange(e) {
++    if (PresentationMode.isFullscreen) {
++      PresentationMode.enter();
++    } else {
++      PresentationMode.exit();
++    }
++  }
++
++  window.addEventListener('fullscreenchange', presentationModeChange, false);
++  window.addEventListener('mozfullscreenchange', presentationModeChange, false);
++  window.addEventListener('webkitfullscreenchange', presentationModeChange,
++                          false);
++  window.addEventListener('MSFullscreenChange', presentationModeChange, false);
++})();
++
++
++/* Copyright 2013 Rob Wu <gwnRob at gmail.com>
++ * https://github.com/Rob--W/grab-to-pan.js
++ *
++ * 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.
++ */
++
++'use strict';
++
++var GrabToPan = (function GrabToPanClosure() {
++  /**
++   * Construct a GrabToPan instance for a given HTML element.
++   * @param options.element {Element}
++   * @param options.ignoreTarget {function} optional. See `ignoreTarget(node)`
++   * @param options.onActiveChanged {function(boolean)} optional. Called
++   *  when grab-to-pan is (de)activated. The first argument is a boolean that
++   *  shows whether grab-to-pan is activated.
++   */
++  function GrabToPan(options) {
++    this.element = options.element;
++    this.document = options.element.ownerDocument;
++    if (typeof options.ignoreTarget === 'function') {
++      this.ignoreTarget = options.ignoreTarget;
++    }
++    this.onActiveChanged = options.onActiveChanged;
++
++    // Bind the contexts to ensure that `this` always points to
++    // the GrabToPan instance.
++    this.activate = this.activate.bind(this);
++    this.deactivate = this.deactivate.bind(this);
++    this.toggle = this.toggle.bind(this);
++    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',
++
++    /**
++     * Bind a mousedown event to the element to enable grab-detection.
++     */
++    activate: function GrabToPan_activate() {
++      if (!this.active) {
++        this.active = true;
++        this.element.addEventListener('mousedown', this._onmousedown, true);
++        this.element.classList.add(this.CSS_CLASS_GRAB);
++        if (this.onActiveChanged) {
++          this.onActiveChanged(true);
++        }
++      }
++    },
++
++    /**
++     * Removes all events. Any pending pan session is immediately stopped.
++     */
++    deactivate: function GrabToPan_deactivate() {
++      if (this.active) {
++        this.active = false;
++        this.element.removeEventListener('mousedown', this._onmousedown, true);
++        this._endPan();
++        this.element.classList.remove(this.CSS_CLASS_GRAB);
++        if (this.onActiveChanged) {
++          this.onActiveChanged(false);
++        }
++      }
++    },
++
++    toggle: function GrabToPan_toggle() {
++      if (this.active) {
++        this.deactivate();
++      } else {
++        this.activate();
++      }
++    },
++
++    /**
++     * Whether to not pan if the target element is clicked.
++     * Override this method to change the default behaviour.
++     *
++     * @param node {Element} The target of the event
++     * @return {boolean} Whether to not react to the click event.
++     */
++    ignoreTarget: function GrabToPan_ignoreTarget(node) {
++      // Use matchesSelector to check whether the clicked element
++      // is (a child of) an input element / link
++      return node[matchesSelector](
++        'a[href], a[href] *, input, textarea, button, button *, select, option'
++      );
++    },
++
++    /**
++     * @private
++     */
++    _onmousedown: function GrabToPan__onmousedown(event) {
++      if (event.button !== 0 || this.ignoreTarget(event.target)) {
++        return;
++      }
++      if (event.originalTarget) {
++        try {
++          /* jshint expr:true */
++          event.originalTarget.tagName;
++        } catch (e) {
++          // Mozilla-specific: element is a scrollbar (XUL element)
++          return;
++        }
++      }
++
++      this.scrollLeftStart = this.element.scrollLeft;
++      this.scrollTopStart = this.element.scrollTop;
++      this.clientXStart = event.clientX;
++      this.clientYStart = event.clientY;
++      this.document.addEventListener('mousemove', this._onmousemove, true);
++      this.document.addEventListener('mouseup', this._endPan, true);
++      // When a scroll event occurs before a mousemove, assume that the user
++      // dragged a scrollbar (necessary for Opera Presto, Safari and IE)
++      // (not needed for Chrome/Firefox)
++      this.element.addEventListener('scroll', this._endPan, true);
++      event.preventDefault();
++      event.stopPropagation();
++      this.document.documentElement.classList.add(this.CSS_CLASS_GRABBING);
++    },
++
++    /**
++     * @private
++     */
++    _onmousemove: function GrabToPan__onmousemove(event) {
++      this.element.removeEventListener('scroll', this._endPan, true);
++      if (isLeftMouseReleased(event)) {
++        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);
++      }
++    },
++
++    /**
++     * @private
++     */
++    _endPan: function GrabToPan__endPan() {
++      this.element.removeEventListener('scroll', this._endPan, true);
++      this.document.removeEventListener('mousemove', this._onmousemove, true);
++      this.document.removeEventListener('mouseup', this._endPan, true);
++      if (this.overlay.parentNode) {
++        this.overlay.parentNode.removeChild(this.overlay);
++      }
++    }
++  };
++
++  // Get the correct (vendor-prefixed) name of the matches method.
++  var matchesSelector;
++  ['webkitM', 'mozM', 'msM', 'oM', 'm'].some(function(prefix) {
++    var name = prefix + 'atches';
++    if (name in document.documentElement) {
++      matchesSelector = name;
++    }
++    name += 'Selector';
++    if (name in document.documentElement) {
++      matchesSelector = name;
++    }
++    return matchesSelector; // If found, then truthy, and [].some() ends.
++  });
++
++  // Browser sniffing because it's impossible to feature-detect
++  // whether event.which for onmousemove is reliable
++  var isNotIEorIsIE10plus = !document.documentMode || document.documentMode > 9;
++  var chrome = window.chrome;
++  var isChrome15OrOpera15plus = chrome && (chrome.webstore || chrome.app);
++  //                                       ^ Chrome 15+       ^ Opera 15+
++  var isSafari6plus = /Apple/.test(navigator.vendor) &&
++                      /Version\/([6-9]\d*|[1-5]\d+)/.test(navigator.userAgent);
++
++  /**
++   * Whether the left mouse is not pressed.
++   * @param event {MouseEvent}
++   * @return {boolean} True if the left mouse button is not pressed.
++   *                   False if unsure or if the left mouse button is pressed.
++   */
++  function isLeftMouseReleased(event) {
++    if ('buttons' in event && isNotIEorIsIE10plus) {
++      // http://www.w3.org/TR/DOM-Level-3-Events/#events-MouseEvent-buttons
++      // Firefox 15+
++      // Internet Explorer 10+
++      return !(event.buttons | 1);
++    }
++    if (isChrome15OrOpera15plus || isSafari6plus) {
++      // Chrome 14+
++      // Opera 15+
++      // Safari 6.0+
++      return event.which === 0;
++    }
++  }
++
++  return GrabToPan;
++})();
++
++var HandTool = {
++  initialize: function handToolInitialize(options) {
++    var toggleHandTool = options.toggleHandTool;
++    this.handTool = new GrabToPan({
++      element: options.container,
++      onActiveChanged: function(isActive) {
++        if (!toggleHandTool) {
++          return;
++        }
++        if (isActive) {
++          toggleHandTool.title =
++            mozL10n.get('hand_tool_disable.title', null, 'Disable hand tool');
++          toggleHandTool.firstElementChild.textContent =
++            mozL10n.get('hand_tool_disable_label', null, 'Disable hand tool');
++        } else {
++          toggleHandTool.title =
++            mozL10n.get('hand_tool_enable.title', null, 'Enable hand tool');
++          toggleHandTool.firstElementChild.textContent =
++            mozL10n.get('hand_tool_enable_label', null, 'Enable hand tool');
++        }
++      }
++    });
++    if (toggleHandTool) {
++      toggleHandTool.addEventListener('click', this.toggle.bind(this), false);
++    }
++    // TODO: Read global prefs and call this.handTool.activate() if needed.
++  },
++
++  toggle: function handToolToggle() {
++    this.handTool.toggle();
++    SecondaryToolbar.close();
++  },
++
++  enterPresentationMode: function handToolEnterPresentationMode() {
++    if (this.handTool.active) {
++      this.wasActive = true;
++      this.handTool.deactivate();
++    }
++  },
++
++  exitPresentationMode: function handToolExitPresentationMode() {
++    if (this.wasActive) {
++      this.wasActive = null;
++      this.handTool.activate();
 +    }
++  }
++};
 +
-     if (notFound) {
-       this.findField.classList.add('notFound');
-     } else {
-       this.findField.classList.remove('notFound');
++
++var DocumentProperties = {
++  overlayContainer: null,
++  fileName: '',
++  fileSize: '',
++  visible: false,
++
++  // 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,
++
++  initialize: function documentPropertiesInitialize(options) {
++    this.overlayContainer = options.overlayContainer;
++
++    // 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.hide.bind(this));
 +    }
 +
-     this.findField.setAttribute('data-status', status);
-     this.findMsg.textContent = findMsg;
++    // Bind the event listener for the Esc key (to close the dialog).
++    window.addEventListener('keydown',
++      function (e) {
++        if (e.keyCode === 27) { // Esc key
++          this.hide();
++        }
++      }.bind(this));
 +  },
 +
-   open: function() {
-     if (this.opened) return;
++  getProperties: function documentPropertiesGetProperties() {
++    var self = this;
 +
-     this.opened = true;
-     this.toggleButton.classList.add('toggled');
-     this.bar.classList.remove('hidden');
-     this.findField.select();
-     this.findField.focus();
-   },
++    // Get the file name.
++    this.fileName = getPDFFileNameFromURL(PDFView.url);
 +
-   close: function() {
-     if (!this.opened) return;
++    // Get the file size.
++    PDFView.pdfDocument.getDownloadInfo().then(function(data) {
++      self.setFileSize(data.length);
++    });
 +
-     this.opened = false;
-     this.toggleButton.classList.remove('toggled');
-     this.bar.classList.add('hidden');
++    // Get the other document properties.
++    PDFView.pdfDocument.getMetadata().then(function(data) {
++      var fields = [
++        { field: self.fileNameField, content: self.fileName },
++        { field: self.fileSizeField, content: self.fileSize },
++        { field: self.titleField, content: data.info.Title },
++        { field: self.authorField, content: data.info.Author },
++        { field: self.subjectField, content: data.info.Subject },
++        { field: self.keywordsField, content: data.info.Keywords },
++        { field: self.creationDateField,
++          content: self.parseDate(data.info.CreationDate) },
++        { field: self.modificationDateField,
++          content: self.parseDate(data.info.ModDate) },
++        { field: self.creatorField, content: data.info.Creator },
++        { field: self.producerField, content: data.info.Producer },
++        { field: self.versionField, content: data.info.PDFFormatVersion },
++        { field: self.pageCountField, content: PDFView.pdfDocument.numPages }
++      ];
 +
-     PDFFindController.active = false;
++      // Show the properties in the dialog.
++      for (var item in fields) {
++        var element = fields[item];
++        if (element.field && element.content !== undefined &&
++            element.content !== '') {
++          element.field.textContent = element.content;
++        }
++      }
++    });
 +  },
 +
-   toggle: function() {
-     if (this.opened) {
-       this.close();
++  setFileSize: function documentPropertiesSetFileSize(fileSize) {
++    var kb = fileSize / 1024;
++    if (kb < 1024) {
++      this.fileSize = mozL10n.get('document_properties_kb', {
++        size_kb: (+kb.toPrecision(3)).toLocaleString(),
++        size_b: fileSize.toLocaleString()
++      }, '{{size_kb}} KB ({{size_b}} bytes)');
 +    } else {
-       this.open();
++      this.fileSize = mozL10n.get('document_properties_mb', {
++        size_mb: (+(kb / 1024).toPrecision(3)).toLocaleString(),
++        size_b: fileSize.toLocaleString()
++      }, '{{size_mb}} MB ({{size_b}} bytes)');
++    }
++  },
++
++  show: function documentPropertiesShow() {
++    if (this.visible) {
++      return;
++    }
++    this.visible = true;
++    this.overlayContainer.classList.remove('hidden');
++    this.overlayContainer.lastElementChild.classList.remove('hidden');
++    this.getProperties();
++  },
++
++  hide: function documentPropertiesClose() {
++    if (!this.visible) {
++      return;
++    }
++    this.visible = false;
++    this.overlayContainer.classList.add('hidden');
++    this.overlayContainer.lastElementChild.classList.add('hidden');
++  },
++
++  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 PDFView = {
 +  pages: [],
 +  thumbnails: [],
 +  currentScale: UNKNOWN_SCALE,
 +  currentScaleValue: null,
 +  initialBookmark: document.location.hash.substring(1),
-   startedTextExtraction: false,
-   pageText: [],
 +  container: null,
 +  thumbnailContainer: null,
 +  initialized: false,
 +  fellback: false,
 +  pdfDocument: null,
 +  sidebarOpen: false,
 +  pageViewScroll: null,
 +  thumbnailViewScroll: null,
-   isFullscreen: false,
-   previousScale: null,
 +  pageRotation: 0,
 +  mouseScrollTimeStamp: 0,
 +  mouseScrollDelta: 0,
 +  lastScroll: 0,
 +  previousPageNumber: 1,
++  isViewerEmbedded: (window.parent !== window),
++  idleTimeout: null,
++  currentPosition: null,
 +
 +  // 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 thumbnailContainer = this.thumbnailContainer =
 +                             document.getElementById('thumbnailView');
 +    this.thumbnailViewScroll = {};
 +    this.watchScroll(thumbnailContainer, this.thumbnailViewScroll,
 +                     this.renderHighestPriority.bind(this));
 +
-     PDFFindBar.initialize();
-     PDFFindController.initialize();
++    PDFFindBar.initialize({
++      bar: document.getElementById('findbar'),
++      toggleButton: document.getElementById('viewFind'),
++      findField: document.getElementById('findInput'),
++      highlightAllCheckbox: document.getElementById('findHighlightAll'),
++      caseSensitiveCheckbox: document.getElementById('findMatchCase'),
++      findMsg: document.getElementById('findMsg'),
++      findStatusIcon: document.getElementById('findStatusIcon'),
++      findPreviousButton: document.getElementById('findPrevious'),
++      findNextButton: document.getElementById('findNext')
++    });
++
++    PDFFindController.initialize({
++      pdfPageSource: this,
++      integratedFind: this.supportsIntegratedFind
++    });
++
++    HandTool.initialize({
++      container: container,
++      toggleHandTool: document.getElementById('toggleHandTool')
++    });
++
++    SecondaryToolbar.initialize({
++      toolbar: document.getElementById('secondaryToolbar'),
++      presentationMode: PresentationMode,
++      toggleButton: document.getElementById('secondaryToolbarToggle'),
++      presentationModeButton:
++        document.getElementById('secondaryPresentationMode'),
++      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'),
++      documentProperties: DocumentProperties,
++      documentPropertiesButton: document.getElementById('documentProperties')
++    });
++
++    PasswordPrompt.initialize({
++      overlayContainer: document.getElementById('overlayContainer'),
++      passwordField: document.getElementById('password'),
++      passwordText: document.getElementById('passwordText'),
++      passwordSubmit: document.getElementById('passwordSubmit'),
++      passwordCancel: document.getElementById('passwordCancel')
++    });
++
++    PresentationMode.initialize({
++      container: container,
++      secondaryToolbar: SecondaryToolbar,
++      firstPage: document.getElementById('contextFirstPage'),
++      lastPage: document.getElementById('contextLastPage'),
++      pageRotateCw: document.getElementById('contextPageRotateCw'),
++      pageRotateCcw: document.getElementById('contextPageRotateCcw')
++    });
++
++    DocumentProperties.initialize({
++      overlayContainer: document.getElementById('overlayContainer'),
++      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')
++    });
 +
 +    this.initialized = true;
 +    container.addEventListener('scroll', function() {
 +      self.lastScroll = Date.now();
 +    }, false);
 +  },
 +
 +  getPage: function pdfViewGetPage(n) {
 +    return this.pdfDocument.getPage(n);
 +  },
 +
 +  // 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);
 +  },
 +
-   setScale: function pdfViewSetScale(val, resetAutoSettings, noScroll) {
-     if (val == this.currentScale)
++  _setScaleUpdatePages: function pdfView_setScaleUpdatePages(
++      newScale, newValue, resetAutoSettings, noScroll) {
++    this.currentScaleValue = newValue;
++    if (newScale === this.currentScale) {
 +      return;
- 
-     var pages = this.pages;
-     for (var i = 0; i < pages.length; i++)
-       pages[i].update(val * CSS_UNITS);
- 
-     if (!noScroll && this.currentScale != val)
-       this.pages[this.page - 1].scrollIntoView();
-     this.currentScale = val;
- 
++    }
++    for (var i = 0, ii = this.pages.length; i < ii; i++) {
++      this.pages[i].update(newScale);
++    }
++    this.currentScale = newScale;
++
++    if (!noScroll) {
++      var page = this.page, dest;
++      if (this.currentPosition && !IGNORE_CURRENT_POSITION_ON_ZOOM) {
++        page = this.currentPosition.page;
++        dest = [null, { name: 'XYZ' }, this.currentPosition.left,
++                this.currentPosition.top, null];
++      }
++      this.pages[page - 1].scrollIntoView(dest);
++    }
 +    var event = document.createEvent('UIEvents');
 +    event.initUIEvent('scalechange', false, false, window, 0);
-     event.scale = val;
++    event.scale = newScale;
 +    event.resetAutoSettings = resetAutoSettings;
 +    window.dispatchEvent(event);
 +  },
 +
-   parseScale: function pdfViewParseScale(value, resetAutoSettings, noScroll) {
-     if ('custom' == value)
-       return;
- 
-     var scale = parseFloat(value);
-     this.currentScaleValue = value;
-     if (scale) {
-       this.setScale(scale, true, noScroll);
++  setScale: function pdfViewSetScale(value, resetAutoSettings, noScroll) {
++    if (value === 'custom') {
 +      return;
 +    }
++    var scale = parseFloat(value);
 +
-     var container = this.container;
-     var currentPage = this.pages[this.page - 1];
-     if (!currentPage) {
-       return;
-     }
++    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.');
++          return;
++      }
++      this._setScaleUpdatePages(scale, value, resetAutoSettings, noScroll);
 +
-     var pageWidthScale = (container.clientWidth - SCROLLBAR_PADDING) /
-                           currentPage.width * currentPage.scale / CSS_UNITS;
-     var pageHeightScale = (container.clientHeight - VERTICAL_PADDING) /
-                            currentPage.height * currentPage.scale / CSS_UNITS;
-     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(1.0, pageWidthScale);
-         break;
++      selectScaleOption(value);
 +    }
-     this.setScale(scale, resetAutoSettings, noScroll);
- 
-     selectScaleOption(value);
 +  },
 +
-   zoomIn: function pdfViewZoomIn() {
-     var newScale = (this.currentScale * DEFAULT_SCALE_DELTA).toFixed(2);
-     newScale = Math.ceil(newScale * 10) / 10;
-     newScale = Math.min(MAX_SCALE, newScale);
-     this.parseScale(newScale, true);
++  zoomIn: function pdfViewZoomIn(ticks) {
++    var newScale = this.currentScale;
++    do {
++      newScale = (newScale * DEFAULT_SCALE_DELTA).toFixed(2);
++      newScale = Math.ceil(newScale * 10) / 10;
++      newScale = Math.min(MAX_SCALE, newScale);
++    } while (--ticks && newScale < MAX_SCALE);
++    this.setScale(newScale, true);
 +  },
 +
-   zoomOut: function pdfViewZoomOut() {
-     var newScale = (this.currentScale / DEFAULT_SCALE_DELTA).toFixed(2);
-     newScale = Math.floor(newScale * 10) / 10;
-     newScale = Math.max(MIN_SCALE, newScale);
-     this.parseScale(newScale, true);
++  zoomOut: function pdfViewZoomOut(ticks) {
++    var newScale = this.currentScale;
++    do {
++      newScale = (newScale / DEFAULT_SCALE_DELTA).toFixed(2);
++      newScale = Math.floor(newScale * 10) / 10;
++      newScale = Math.max(MIN_SCALE, newScale);
++    } while (--ticks && newScale > MIN_SCALE);
++    this.setScale(newScale, true);
 +  },
 +
 +  set page(val) {
 +    var pages = this.pages;
-     var input = document.getElementById('pageNumber');
 +    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)
++    if (updateViewarea.inProgress) {
 +      return;
- 
++    }
 +    // Avoid scrolling the first page during loading
-     if (this.loading && val == 1)
++    if (this.loading && val === 1) {
 +      return;
- 
++    }
 +    pages[val - 1].scrollIntoView();
 +  },
 +
 +  get page() {
 +    return currentPageNumber;
 +  },
 +
 +  get supportsPrinting() {
 +    var canvas = document.createElement('canvas');
 +    var value = 'mozPrintCallback' in canvas;
 +    // shadow
 +    Object.defineProperty(this, 'supportsPrinting', { value: value,
 +                                                      enumerable: true,
 +                                                      configurable: true,
 +                                                      writable: false });
 +    return value;
 +  },
 +
 +  get supportsFullscreen() {
 +    var doc = document.documentElement;
 +    var support = doc.requestFullscreen || doc.mozRequestFullScreen ||
-                   doc.webkitRequestFullScreen;
++                  doc.webkitRequestFullScreen || doc.msRequestFullscreen;
 +
-     // Disable fullscreen button if we're in an iframe
-     if (!!window.frameElement)
++    if (document.fullscreenEnabled === false ||
++        document.mozFullScreenEnabled === false ||
++        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 '<object>' tags.
++      support = false;
++    }
 +
-     Object.defineProperty(this, 'supportsFullScreen', { value: support,
++    Object.defineProperty(this, 'supportsFullscreen', { value: support,
 +                                                        enumerable: true,
 +                                                        configurable: true,
 +                                                        writable: false });
 +    return support;
 +  },
 +
 +  get supportsIntegratedFind() {
 +    var support = false;
 +    Object.defineProperty(this, 'supportsIntegratedFind', { value: support,
 +                                                            enumerable: true,
 +                                                            configurable: true,
 +                                                            writable: false });
 +    return support;
 +  },
 +
 +  get supportsDocumentFonts() {
 +    var support = true;
 +    Object.defineProperty(this, 'supportsDocumentFonts', { value: support,
 +                                                           enumerable: true,
 +                                                           configurable: true,
 +                                                           writable: false });
 +    return support;
 +  },
 +
-   get isHorizontalScrollbarEnabled() {
-     var div = document.getElementById('viewerContainer');
-     return div.scrollWidth > div.clientWidth;
++  get supportsDocumentColors() {
++    var support = true;
++    Object.defineProperty(this, 'supportsDocumentColors', { value: support,
++                                                            enumerable: true,
++                                                            configurable: true,
++                                                            writable: false });
++    return support;
 +  },
 +
-   initPassiveLoading: function pdfViewInitPassiveLoading() {
-     if (!PDFView.loadingBar) {
-       PDFView.loadingBar = new ProgressBar('#loadingBar', {});
-     }
- 
-     window.addEventListener('message', function window_message(e) {
-       var args = e.data;
++  get loadingBar() {
++    var bar = new ProgressBar('#loadingBar', {});
++    Object.defineProperty(this, 'loadingBar', { value: bar,
++                                                enumerable: true,
++                                                configurable: true,
++                                                writable: false });
++    return bar;
++  },
 +
-       if (typeof args !== 'object' || !('pdfjsLoadAction' in args))
-         return;
-       switch (args.pdfjsLoadAction) {
-         case 'progress':
-           PDFView.progress(args.loaded / args.total);
-           break;
-         case 'complete':
-           if (!args.data) {
-             PDFView.error(mozL10n.get('loading_error', null,
-                           'An error occurred while loading the PDF.'), e);
-             break;
-           }
-           PDFView.open(args.data, 0);
-           break;
-       }
-     });
-     FirefoxCom.requestSync('initPassiveLoading', null);
++  get isHorizontalScrollbarEnabled() {
++    return (PresentationMode.active ? false :
++            (this.container.scrollWidth > this.container.clientWidth));
 +  },
 +
++
 +  setTitleUsingUrl: function pdfViewSetTitleUsingUrl(url) {
 +    this.url = url;
 +    try {
 +      this.setTitle(decodeURIComponent(getFileName(url)) || url);
 +    } catch (e) {
 +      // decodeURIComponent may throw URIError,
 +      // fall back to using the unprocessed url in that case
 +      this.setTitle(url);
 +    }
 +  },
 +
 +  setTitle: function pdfViewSetTitle(title) {
 +    document.title = title;
 +  },
 +
-   open: function pdfViewOpen(url, scale, password) {
++  // TODO(mack): This function signature should really be pdfViewOpen(url, args)
++  open: function pdfViewOpen(url, scale, password,
++                             pdfDataRangeTransport, args) {
 +    var parameters = {password: password};
 +    if (typeof url === 'string') { // URL
 +      this.setTitleUsingUrl(url);
 +      parameters.url = url;
 +    } else if (url && 'byteLength' in url) { // ArrayBuffer
 +      parameters.data = url;
 +    }
- 
-     if (!PDFView.loadingBar) {
-       PDFView.loadingBar = new ProgressBar('#loadingBar', {});
++    if (args) {
++      for (var prop in args) {
++        parameters[prop] = args[prop];
++      }
 +    }
 +
++    // Terminate worker of the previous document if any.
++    if (this.pdfDocument) {
++      this.pdfDocument.destroy();
++    }
 +    this.pdfDocument = null;
 +    var self = this;
 +    self.loading = true;
-     PDFJS.getDocument(parameters).then(
++    var passwordNeeded = function passwordNeeded(updatePassword, reason) {
++      PasswordPrompt.updatePassword = updatePassword;
++      PasswordPrompt.reason = reason;
++      PasswordPrompt.show();
++    };
++
++    function getDocumentProgress(progressData) {
++      self.progress(progressData.loaded / progressData.total);
++    }
++
++    PDFJS.getDocument(parameters, pdfDataRangeTransport, passwordNeeded,
++                      getDocumentProgress).then(
 +      function getDocumentCallback(pdfDocument) {
 +        self.load(pdfDocument, scale);
 +        self.loading = false;
 +      },
 +      function getDocumentError(message, exception) {
-         if (exception && exception.name === 'PasswordException') {
-           if (exception.code === 'needpassword') {
-             var promptString = mozL10n.get('request_password', null,
-                                       'PDF is protected by a password:');
-             password = prompt(promptString);
-             if (password && password.length > 0) {
-               return PDFView.open(url, scale, password);
-             }
-           }
-         }
- 
 +        var loadingErrorMessage = mozL10n.get('loading_error', null,
 +          'An error occurred while loading the PDF.');
 +
 +        if (exception && exception.name === 'InvalidPDFException') {
 +          // change error message also for other builds
 +          var loadingErrorMessage = mozL10n.get('invalid_file_error', null,
 +                                        'Invalid or corrupted PDF file.');
 +        }
 +
 +        if (exception && exception.name === 'MissingPDFException') {
 +          // special message for missing PDF's
 +          var loadingErrorMessage = mozL10n.get('missing_file_error', null,
 +                                        'Missing PDF file.');
 +
 +        }
 +
-         var loadingIndicator = document.getElementById('loading');
-         loadingIndicator.textContent = mozL10n.get('loading_error_indicator',
-           null, 'Error');
 +        var moreInfo = {
 +          message: message
 +        };
 +        self.error(loadingErrorMessage, moreInfo);
 +        self.loading = false;
-       },
-       function getDocumentProgress(progressData) {
-         self.progress(progressData.loaded / progressData.total);
 +      }
 +    );
 +  },
 +
 +  download: function pdfViewDownload() {
 +    function noData() {
-       FirefoxCom.request('download', { originalUrl: url });
++      downloadManager.downloadUrl(url, filename);
 +    }
++
 +    var url = this.url.split('#')[0];
-     url += '#pdfjs.action=download';
-     window.open(url, '_parent');
++    var filename = getPDFFileNameFromURL(url);
++    var downloadManager = new DownloadManager();
++    downloadManager.onerror = function (err) {
++      // This error won't really be helpful because it's likely the
++      // fallback won't work either (or is already open).
++      PDFView.error('PDF failed to download.');
++    };
++
++    if (!this.pdfDocument) { // the PDF is not ready yet
++      noData();
++      return;
++    }
++
++    this.pdfDocument.getData().then(
++      function getDataSuccess(data) {
++        var blob = PDFJS.createBlob(data, 'application/pdf');
++        downloadManager.download(blob, url, filename);
++      },
++      noData // Error occurred try downloading with just the url.
++    ).then(null, noData);
 +  },
 +
-   fallback: function pdfViewFallback() {
++  fallback: function pdfViewFallback(featureId) {
 +    return;
 +  },
 +
 +  navigateTo: function pdfViewNavigateTo(dest) {
-     if (typeof dest === 'string')
-       dest = this.destinations[dest];
-     if (!(dest instanceof Array))
-       return; // invalid destination
-     // dest array looks like that: <page-ref> </XYZ|FitXXX> <args..>
-     var destRef = dest[0];
-     var pageNumber = destRef instanceof Object ?
-       this.pagesRefMap[destRef.num + ' ' + destRef.gen + ' R'] : (destRef + 1);
-     if (pageNumber > this.pages.length)
-       pageNumber = this.pages.length;
-     if (pageNumber) {
-       this.page = pageNumber;
-       var currentPage = this.pages[pageNumber - 1];
-       if (!this.isFullscreen) { // Avoid breaking fullscreen mode.
++    var destString = '';
++    var self = this;
++
++    var goToDestination = function(destRef) {
++      self.pendingRefStr = null;
++      // dest array looks like that: <page-ref> </XYZ|FitXXX> <args..>
++      var pageNumber = destRef instanceof Object ?
++        self.pagesRefMap[destRef.num + ' ' + destRef.gen + ' R'] :
++        (destRef + 1);
++      if (pageNumber) {
++        if (pageNumber > self.pages.length) {
++          pageNumber = self.pages.length;
++        }
++        var currentPage = self.pages[pageNumber - 1];
 +        currentPage.scrollIntoView(dest);
++
++        // Update the browsing history.
++        PDFHistory.push({ dest: dest, hash: destString, page: pageNumber });
++      } else {
++        self.pdfDocument.getPageIndex(destRef).then(function (pageIndex) {
++          var pageNum = pageIndex + 1;
++          self.pagesRefMap[destRef.num + ' ' + destRef.gen + ' R'] = pageNum;
++          goToDestination(destRef);
++        });
 +      }
-     }
++    };
++
++    this.destinationsPromise.then(function() {
++      if (typeof dest === 'string') {
++        destString = dest;
++        dest = self.destinations[dest];
++      }
++      if (!(dest instanceof Array)) {
++        return; // invalid destination
++      }
++      goToDestination(dest[0]);
++    });
 +  },
 +
 +  getDestinationHash: function pdfViewGetDestinationHash(dest) {
 +    if (typeof dest === 'string')
 +      return PDFView.getAnchorUrl('#' + escape(dest));
 +    if (dest instanceof Array) {
 +      var destRef = dest[0]; // see navigateTo method for dest format
 +      var pageNumber = destRef instanceof Object ?
 +        this.pagesRefMap[destRef.num + ' ' + destRef.gen + ' R'] :
 +        (destRef + 1);
 +      if (pageNumber) {
 +        var pdfOpenParams = PDFView.getAnchorUrl('#page=' + pageNumber);
 +        var destKind = dest[1];
 +        if (typeof destKind === 'object' && 'name' in destKind &&
 +            destKind.name == 'XYZ') {
-           var scale = (dest[4] || this.currentScale);
-           pdfOpenParams += '&zoom=' + (scale * 100);
++          var scale = (dest[4] || this.currentScaleValue);
++          var scaleNumber = parseFloat(scale);
++          if (scaleNumber) {
++            scale = scaleNumber * 100;
++          }
++          pdfOpenParams += '&zoom=' + scale;
 +          if (dest[2] || dest[3]) {
 +            pdfOpenParams += ',' + (dest[2] || 0) + ',' + (dest[3] || 0);
 +          }
 +        }
 +        return pdfOpenParams;
 +      }
 +    }
 +    return '';
 +  },
 +
 +  /**
-    * For the firefox extension we prefix the full url on anchor links so they
-    * don't come up as resource:// urls and so open in new tab/window works.
-    * @param {String} anchor The anchor hash include the #.
++   * Prefix the full url on anchor links to make sure that links are resolved
++   * relative to the current URL instead of the one defined in <base href>.
++   * @param {String} anchor The anchor hash, including the #.
 +   */
 +  getAnchorUrl: function getAnchorUrl(anchor) {
 +    return anchor;
 +  },
 +
 +  /**
-    * Returns scale factor for the canvas. It makes sense for the HiDPI displays.
-    * @return {Object} The object with horizontal (sx) and vertical (sy)
-                       scales. The scaled property is set to false if scaling is
-                       not required, true otherwise.
-    */
-   getOutputScale: function pdfViewGetOutputDPI() {
-     var pixelRatio = 'devicePixelRatio' in window ? window.devicePixelRatio : 1;
-     return {
-       sx: pixelRatio,
-       sy: pixelRatio,
-       scaled: pixelRatio != 1
-     };
-   },
- 
-   /**
 +   * Show the error box.
 +   * @param {String} message A message that is human readable.
 +   * @param {Object} moreInfo (optional) Further information about the error
 +   *                            that is more technical.  Should have a 'message'
 +   *                            and optionally a 'stack' property.
 +   */
 +  error: function pdfViewError(message, moreInfo) {
 +    var moreInfoText = mozL10n.get('error_version_info',
 +      {version: PDFJS.version || '?', build: PDFJS.build || '?'},
 +      'PDF.js v{{version}} (build: {{build}})') + '\n';
 +    if (moreInfo) {
 +      moreInfoText +=
 +        mozL10n.get('error_message', {message: moreInfo.message},
 +        'Message: {{message}}');
 +      if (moreInfo.stack) {
 +        moreInfoText += '\n' +
 +          mozL10n.get('error_stack', {stack: moreInfo.stack},
 +          'Stack: {{stack}}');
 +      } else {
 +        if (moreInfo.filename) {
 +          moreInfoText += '\n' +
 +            mozL10n.get('error_file', {file: moreInfo.filename},
 +            'File: {{file}}');
 +        }
 +        if (moreInfo.lineNumber) {
 +          moreInfoText += '\n' +
 +            mozL10n.get('error_line', {line: moreInfo.lineNumber},
 +            'Line: {{line}}');
 +        }
 +      }
 +    }
 +
-     var loadingBox = document.getElementById('loadingBox');
-     loadingBox.setAttribute('hidden', 'true');
- 
 +    var errorWrapper = document.getElementById('errorWrapper');
 +    errorWrapper.removeAttribute('hidden');
 +
 +    var errorMessage = document.getElementById('errorMessage');
 +    errorMessage.textContent = message;
 +
 +    var closeButton = document.getElementById('errorClose');
 +    closeButton.onclick = function() {
 +      errorWrapper.setAttribute('hidden', 'true');
 +    };
 +
 +    var errorMoreInfo = document.getElementById('errorMoreInfo');
 +    var moreInfoButton = document.getElementById('errorShowMore');
 +    var lessInfoButton = document.getElementById('errorShowLess');
 +    moreInfoButton.onclick = function() {
 +      errorMoreInfo.removeAttribute('hidden');
 +      moreInfoButton.setAttribute('hidden', 'true');
 +      lessInfoButton.removeAttribute('hidden');
++      errorMoreInfo.style.height = errorMoreInfo.scrollHeight + 'px';
 +    };
 +    lessInfoButton.onclick = function() {
 +      errorMoreInfo.setAttribute('hidden', 'true');
 +      moreInfoButton.removeAttribute('hidden');
 +      lessInfoButton.setAttribute('hidden', 'true');
 +    };
++    moreInfoButton.oncontextmenu = noContextMenuHandler;
++    lessInfoButton.oncontextmenu = noContextMenuHandler;
++    closeButton.oncontextmenu = noContextMenuHandler;
 +    moreInfoButton.removeAttribute('hidden');
 +    lessInfoButton.setAttribute('hidden', 'true');
 +    errorMoreInfo.value = moreInfoText;
- 
-     errorMoreInfo.rows = moreInfoText.split('\n').length - 1;
 +  },
 +
 +  progress: function pdfViewProgress(level) {
 +    var percent = Math.round(level * 100);
-     PDFView.loadingBar.percent = percent;
++    // When we transition from full request to range requests, it's possible
++    // that we discard some of the loaded data. This can cause the loading
++    // bar to move backwards. So prevent this by only updating the bar if it
++    // increases.
++    if (percent > PDFView.loadingBar.percent) {
++      PDFView.loadingBar.percent = percent;
++    }
 +  },
 +
 +  load: function pdfViewLoad(pdfDocument, scale) {
++    var self = this;
++    var isOnePageRenderedResolved = false;
++    var resolveOnePageRendered = null;
++    var onePageRendered = new Promise(function (resolve) {
++      resolveOnePageRendered = resolve;
++    });
 +    function bindOnAfterDraw(pageView, thumbnailView) {
 +      // when page is painted, using the image as thumbnail base
 +      pageView.onAfterDraw = function pdfViewLoadOnAfterDraw() {
++        if (!isOnePageRenderedResolved) {
++          isOnePageRenderedResolved = true;
++          resolveOnePageRendered();
++        }
 +        thumbnailView.setImage(pageView.canvas);
 +      };
 +    }
 +
++    PDFFindController.reset();
++
 +    this.pdfDocument = pdfDocument;
 +
 +    var errorWrapper = document.getElementById('errorWrapper');
 +    errorWrapper.setAttribute('hidden', 'true');
 +
-     var loadingBox = document.getElementById('loadingBox');
-     loadingBox.setAttribute('hidden', 'true');
-     var loadingIndicator = document.getElementById('loading');
-     loadingIndicator.textContent = '';
++    pdfDocument.getDownloadInfo().then(function() {
++      PDFView.loadingBar.hide();
++      var outerContainer = document.getElementById('outerContainer');
++      outerContainer.classList.remove('loadingInProgress');
++    });
 +
 +    var thumbsView = document.getElementById('thumbnailView');
 +    thumbsView.parentNode.scrollTop = 0;
 +
 +    while (thumbsView.hasChildNodes())
 +      thumbsView.removeChild(thumbsView.lastChild);
 +
 +    if ('_loadingInterval' in thumbsView)
 +      clearInterval(thumbsView._loadingInterval);
 +
 +    var container = document.getElementById('viewer');
 +    while (container.hasChildNodes())
 +      container.removeChild(container.lastChild);
 +
 +    var pagesCount = pdfDocument.numPages;
++
 +    var id = pdfDocument.fingerprint;
 +    document.getElementById('numPages').textContent =
 +      mozL10n.get('page_of', {pageCount: pagesCount}, 'of {{pageCount}}');
 +    document.getElementById('pageNumber').max = pagesCount;
 +
++    var prefs = PDFView.prefs = new Preferences();
 +    PDFView.documentFingerprint = id;
-     var store = PDFView.store = new Settings(id);
++    var store = PDFView.store = new ViewHistory(id);
 +
 +    this.pageRotation = 0;
 +
 +    var pages = this.pages = [];
-     this.pageText = [];
-     this.startedTextExtraction = false;
 +    var pagesRefMap = this.pagesRefMap = {};
 +    var thumbnails = this.thumbnails = [];
 +
-     var pagesPromise = new PDFJS.Promise();
-     var self = this;
++    var resolvePagesPromise;
++    var pagesPromise = new Promise(function (resolve) {
++      resolvePagesPromise = resolve;
++    });
++    this.pagesPromise = pagesPromise;
 +
 +    var firstPagePromise = pdfDocument.getPage(1);
 +
 +    // Fetch a single page so we can get a viewport that will be the default
 +    // viewport for all pages
 +    firstPagePromise.then(function(pdfPage) {
-       var viewport = pdfPage.getViewport(scale || 1.0);
-       var pagePromises = [];
++      var viewport = pdfPage.getViewport((scale || 1.0) * CSS_UNITS);
 +      for (var pageNum = 1; pageNum <= pagesCount; ++pageNum) {
 +        var viewportClone = viewport.clone();
 +        var pageView = new PageView(container, pageNum, scale,
 +                                    self.navigateTo.bind(self),
 +                                    viewportClone);
 +        var thumbnailView = new ThumbnailView(thumbsView, pageNum,
 +                                              viewportClone);
 +        bindOnAfterDraw(pageView, thumbnailView);
 +        pages.push(pageView);
 +        thumbnails.push(thumbnailView);
 +      }
 +
++      // 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 = 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('documentload', true, true, {});
 +      window.dispatchEvent(event);
 +
-       for (var pageNum = 1; pageNum <= pagesCount; ++pageNum) {
-         var pagePromise = pdfDocument.getPage(pageNum);
-         pagePromise.then(function(pdfPage) {
-           var pageNum = pdfPage.pageNumber;
-           var pageView = pages[pageNum - 1];
-           if (!pageView.pdfPage) {
-             // The pdfPage might already be set if we've already entered
-             // pageView.draw()
-             pageView.setPdfPage(pdfPage);
-           }
-           var thumbnailView = thumbnails[pageNum - 1];
-           if (!thumbnailView.pdfPage) {
-             thumbnailView.setPdfPage(pdfPage);
-           }
- 
-           var pageRef = pdfPage.ref;
-           var refStr = pageRef.num + ' ' + pageRef.gen + ' R';
-           pagesRefMap[refStr] = pdfPage.pageNumber;
-         });
-         pagePromises.push(pagePromise);
-       }
++      PDFView.loadingBar.setWidth(container);
 +
-       PDFJS.Promise.all(pagePromises).then(function(pages) {
-         pagesPromise.resolve(pages);
-       });
++      PDFFindController.resolveFirstPage();
 +    });
 +
++    var prefsPromise = prefs.initializedPromise;
 +    var storePromise = store.initializedPromise;
-     PDFJS.Promise.all([firstPagePromise, storePromise]).then(function() {
++    Promise.all([firstPagePromise, prefsPromise, storePromise]).
++        then(function() {
++      var showPreviousViewOnLoad = prefs.get('showPreviousViewOnLoad');
++      var defaultZoomValue = prefs.get('defaultZoomValue');
++
 +      var storedHash = null;
-       if (store.get('exists', false)) {
++      if (showPreviousViewOnLoad && store.get('exists', false)) {
 +        var pageNum = store.get('page', '1');
-         var zoom = store.get('zoom', PDFView.currentScale);
++        var zoom = defaultZoomValue || store.get('zoom', PDFView.currentScale);
 +        var left = store.get('scrollLeft', '0');
 +        var top = store.get('scrollTop', '0');
 +
 +        storedHash = 'page=' + pageNum + '&zoom=' + zoom + ',' +
-                     left + ',' + top;
++                     left + ',' + top;
++      } else if (defaultZoomValue) {
++        storedHash = 'page=1&zoom=' + defaultZoomValue;
 +      }
++      // Initialize the browsing history.
++      PDFHistory.initialize(self.documentFingerprint);
++
 +      self.setInitialView(storedHash, scale);
++
++      // Make all navigation keys work on document load,
++      // unless the viewer is embedded in a web page.
++      if (!self.isViewerEmbedded) {
++        self.container.focus();
++      }
 +    });
 +
 +    pagesPromise.then(function() {
 +      if (PDFView.supportsPrinting) {
 +        pdfDocument.getJavaScript().then(function(javaScript) {
 +          if (javaScript.length) {
 +            console.warn('Warning: JavaScript is not supported');
-             PDFView.fallback();
++            PDFView.fallback(PDFJS.UNSUPPORTED_FEATURES.javaScript);
 +          }
 +          // Hack to support auto printing.
 +          var regex = /\bprint\s*\(/g;
 +          for (var i = 0, ii = javaScript.length; i < ii; i++) {
 +            var js = javaScript[i];
 +            if (js && regex.test(js)) {
 +              setTimeout(function() {
 +                window.print();
 +              });
 +              return;
 +            }
 +          }
 +        });
 +      }
 +    });
 +
-     var destinationsPromise = pdfDocument.getDestinations();
++    var destinationsPromise =
++      this.destinationsPromise = pdfDocument.getDestinations();
 +    destinationsPromise.then(function(destinations) {
 +      self.destinations = destinations;
 +    });
 +
 +    // outline depends on destinations and pagesRefMap
 +    var promises = [pagesPromise, destinationsPromise,
 +                    PDFView.animationStartedPromise];
-     PDFJS.Promise.all(promises).then(function() {
++    Promise.all(promises).then(function() {
 +      pdfDocument.getOutline().then(function(outline) {
 +        self.outline = new DocumentOutlineView(outline);
-       });
++        document.getElementById('viewOutline').disabled = !outline;
 +
-       // Make all navigation keys work on document load,
-       // unless the viewer is embedded in another page.
-       if (window.parent.location === window.location) {
-         PDFView.container.focus();
-       }
++        if (outline && prefs.get('ifAvailableShowOutlineOnLoad')) {
++          if (!self.sidebarOpen) {
++            document.getElementById('sidebarToggle').click();
++          }
++          self.switchSidebarView('outline');
++        }
++      });
 +    });
 +
 +    pdfDocument.getMetadata().then(function(data) {
 +      var info = data.info, metadata = data.metadata;
 +      self.documentInfo = info;
 +      self.metadata = metadata;
 +
 +      // Provides some basic debug information
 +      console.log('PDF ' + pdfDocument.fingerprint + ' [' +
 +                  info.PDFFormatVersion + ' ' + (info.Producer || '-') +
 +                  ' / ' + (info.Creator || '-') + ']' +
 +                  (PDFJS.version ? ' (PDF.js: ' + PDFJS.version + ')' : ''));
 +
 +      var pdfTitle;
 +      if (metadata) {
 +        if (metadata.has('dc:title'))
 +          pdfTitle = metadata.get('dc:title');
 +      }
 +
 +      if (!pdfTitle && info && info['Title'])
 +        pdfTitle = info['Title'];
 +
 +      if (pdfTitle)
 +        self.setTitle(pdfTitle + ' - ' + document.title);
 +
 +      if (info.IsAcroFormPresent) {
 +        console.warn('Warning: AcroForm/XFA is not supported');
-         PDFView.fallback();
++        PDFView.fallback(PDFJS.UNSUPPORTED_FEATURES.forms);
 +      }
++
 +    });
 +  },
 +
 +  setInitialView: function pdfViewSetInitialView(storedHash, scale) {
 +    // Reset the current scale, as otherwise the page's scale might not get
 +    // updated if the zoom level stayed the same.
 +    this.currentScale = 0;
 +    this.currentScaleValue = null;
-     if (this.initialBookmark) {
++    // When opening a new file (when one is already loaded in the viewer):
++    // Reset 'currentPageNumber', since otherwise the page's scale will be wrong
++    // if 'currentPageNumber' is larger than the number of pages in the file.
++    document.getElementById('pageNumber').value = currentPageNumber = 1;
++    // Reset the current position when loading a new file,
++    // to prevent displaying the wrong position in the document.
++    this.currentPosition = null;
++
++    if (PDFHistory.initialDestination) {
++      this.navigateTo(PDFHistory.initialDestination);
++      PDFHistory.initialDestination = null;
++    } else if (this.initialBookmark) {
 +      this.setHash(this.initialBookmark);
++      PDFHistory.push({ hash: this.initialBookmark }, !!this.initialBookmark);
 +      this.initialBookmark = null;
-     }
-     else if (storedHash)
++    } else if (storedHash) {
 +      this.setHash(storedHash);
-     else if (scale) {
-       this.parseScale(scale, true);
++    } else if (scale) {
++      this.setScale(scale, true);
 +      this.page = 1;
 +    }
 +
 +    if (PDFView.currentScale === UNKNOWN_SCALE) {
 +      // Scale was not initialized: invalid bookmark or scale was not specified.
 +      // Setting the default one.
-       this.parseScale(DEFAULT_SCALE, true);
++      this.setScale(DEFAULT_SCALE, true);
 +    }
 +  },
 +
 +  renderHighestPriority: function pdfViewRenderHighestPriority() {
++    if (PDFView.idleTimeout) {
++      clearTimeout(PDFView.idleTimeout);
++      PDFView.idleTimeout = null;
++    }
++
 +    // Pages have a higher priority than thumbnails, so check them first.
 +    var visiblePages = this.getVisiblePages();
 +    var pageView = this.getHighestPriority(visiblePages, this.pages,
 +                                           this.pageViewScroll.down);
 +    if (pageView) {
 +      this.renderView(pageView, 'page');
 +      return;
 +    }
 +    // No pages needed rendering so check thumbnails.
 +    if (this.sidebarOpen) {
 +      var visibleThumbs = this.getVisibleThumbs();
 +      var thumbView = this.getHighestPriority(visibleThumbs,
 +                                              this.thumbnails,
 +                                              this.thumbnailViewScroll.down);
-       if (thumbView)
++      if (thumbView) {
 +        this.renderView(thumbView, 'thumbnail');
++        return;
++      }
++    }
++
++    PDFView.idleTimeout = setTimeout(function () {
++      PDFView.cleanup();
++    }, CLEANUP_TIMEOUT);
++  },
++
++  cleanup: function pdfViewCleanup() {
++    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();
++      }
 +    }
++    this.pdfDocument.cleanup();
 +  },
 +
 +  getHighestPriority: function pdfViewGetHighestPriority(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 false;
 +  },
 +
-   isViewFinished: function pdfViewNeedsRendering(view) {
++  isViewFinished: function pdfViewIsViewFinished(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.
 +  renderView: function pdfViewRender(view, type) {
 +    var state = view.renderingState;
 +    switch (state) {
 +      case RenderingStates.FINISHED:
 +        return false;
 +      case RenderingStates.PAUSED:
 +        PDFView.highestPriorityPage = type + view.id;
 +        view.resume();
 +        break;
 +      case RenderingStates.RUNNING:
 +        PDFView.highestPriorityPage = type + view.id;
 +        break;
 +      case RenderingStates.INITIAL:
 +        PDFView.highestPriorityPage = type + view.id;
 +        view.draw(this.renderHighestPriority.bind(this));
 +        break;
 +    }
 +    return true;
 +  },
 +
 +  setHash: function pdfViewSetHash(hash) {
 +    if (!hash)
 +      return;
 +
 +    if (hash.indexOf('=') >= 0) {
 +      var params = PDFView.parseQueryString(hash);
 +      // borrowing syntax from "Parameters for Opening PDF Files"
 +      if ('nameddest' in params) {
++        PDFHistory.updateNextHashParam(params.nameddest);
 +        PDFView.navigateTo(params.nameddest);
 +        return;
 +      }
++      var pageNumber, dest;
 +      if ('page' in params) {
-         var pageNumber = (params.page | 0) || 1;
-         if ('zoom' in params) {
-           var zoomArgs = params.zoom.split(','); // scale,left,top
-           // building destination array
- 
-           // If the zoom value, it has to get divided by 100. If it is a string,
-           // it should stay as it is.
-           var zoomArg = zoomArgs[0];
-           var zoomArgNumber = parseFloat(zoomArg);
-           if (zoomArgNumber)
-             zoomArg = zoomArgNumber / 100;
- 
-           var dest = [null, {name: 'XYZ'},
-                       zoomArgs.length > 1 ? (zoomArgs[1] | 0) : null,
-                       zoomArgs.length > 2 ? (zoomArgs[2] | 0) : null,
-                       zoomArg];
-           var currentPage = this.pages[pageNumber - 1];
-           currentPage.scrollIntoView(dest);
-         } else {
-           this.page = pageNumber; // simple page
++        pageNumber = (params.page | 0) || 1;
++      }
++      if ('zoom' in params) {
++        var zoomArgs = params.zoom.split(','); // scale,left,top
++        // building destination array
++
++        // If the zoom value, it has to get divided by 100. If it is a string,
++        // it should stay as it is.
++        var zoomArg = zoomArgs[0];
++        var zoomArgNumber = parseFloat(zoomArg);
++        if (zoomArgNumber) {
++          zoomArg = zoomArgNumber / 100;
 +        }
++        dest = [null, {name: 'XYZ'},
++                zoomArgs.length > 1 ? (zoomArgs[1] | 0) : null,
++                zoomArgs.length > 2 ? (zoomArgs[2] | 0) : null,
++                zoomArg];
++      }
++      if (dest) {
++        var currentPage = this.pages[(pageNumber || this.page) - 1];
++        currentPage.scrollIntoView(dest);
++      } else if (pageNumber) {
++        this.page = pageNumber; // simple page
 +      }
 +      if ('pagemode' in params) {
 +        var toggle = document.getElementById('sidebarToggle');
 +        if (params.pagemode === 'thumbs' || params.pagemode === 'bookmarks') {
 +          if (!this.sidebarOpen) {
 +            toggle.click();
 +          }
 +          this.switchSidebarView(params.pagemode === 'thumbs' ?
 +                                 'thumbs' : 'outline');
 +        } else if (params.pagemode === 'none' && this.sidebarOpen) {
 +          toggle.click();
 +        }
 +      }
-     } else if (/^\d+$/.test(hash)) // page number
++    } else if (/^\d+$/.test(hash)) { // page number
 +      this.page = hash;
-     else // named destination
++    } else { // named destination
++      PDFHistory.updateNextHashParam(unescape(hash));
 +      PDFView.navigateTo(unescape(hash));
++    }
 +  },
 +
 +  switchSidebarView: function pdfViewSwitchSidebarView(view) {
 +    var thumbsView = document.getElementById('thumbnailView');
 +    var outlineView = document.getElementById('outlineView');
 +
 +    var thumbsButton = document.getElementById('viewThumbnail');
 +    var outlineButton = document.getElementById('viewOutline');
 +
 +    switch (view) {
 +      case 'thumbs':
 +        var wasOutlineViewVisible = thumbsView.classList.contains('hidden');
 +
 +        thumbsButton.classList.add('toggled');
 +        outlineButton.classList.remove('toggled');
 +        thumbsView.classList.remove('hidden');
 +        outlineView.classList.add('hidden');
 +
 +        PDFView.renderHighestPriority();
 +
 +        if (wasOutlineViewVisible) {
 +          // Ensure that the thumbnail of the current page is visible
 +          // when switching from the outline view.
 +          scrollIntoView(document.getElementById('thumbnailContainer' +
 +                                                 this.page));
 +        }
 +        break;
 +
 +      case 'outline':
 +        thumbsButton.classList.remove('toggled');
 +        outlineButton.classList.add('toggled');
 +        thumbsView.classList.add('hidden');
 +        outlineView.classList.remove('hidden');
 +
 +        if (outlineButton.getAttribute('disabled'))
 +          return;
 +        break;
 +    }
 +  },
 +
 +  getVisiblePages: function pdfViewGetVisiblePages() {
-     if (!this.isFullscreen) {
++    if (!PresentationMode.active) {
 +      return this.getVisibleElements(this.container, this.pages, true);
 +    } else {
-       // The algorithm in getVisibleElements is broken in fullscreen mode.
-       var visible = [], page = this.page;
-       var currentPage = this.pages[page - 1];
++      // The algorithm in getVisibleElements doesn't work in all browsers and
++      // configurations when presentation mode is active.
++      var visible = [];
++      var currentPage = this.pages[this.page - 1];
 +      visible.push({ id: currentPage.id, view: currentPage });
- 
-       return { first: currentPage, last: currentPage, views: visible};
++      return { first: currentPage, last: currentPage, views: visible };
 +    }
 +  },
 +
 +  getVisibleThumbs: function pdfViewGetVisibleThumbs() {
 +    return this.getVisibleElements(this.thumbnailContainer, this.thumbnails);
 +  },
 +
 +  // Generic helper to find out what elements are visible within a scroll pane.
 +  getVisibleElements: function pdfViewGetVisibleElements(
 +      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, y: currentHeight,
++      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};
 +  },
 +
 +  // Helper function to parse query string (e.g. ?param1=value&parm2=...).
 +  parseQueryString: function pdfViewParseQueryString(query) {
 +    var parts = query.split('&');
 +    var params = {};
 +    for (var i = 0, ii = parts.length; i < parts.length; ++i) {
 +      var param = parts[i].split('=');
 +      var key = param[0];
 +      var value = param.length > 1 ? param[1] : null;
-       params[unescape(key)] = unescape(value);
++      params[decodeURIComponent(key)] = decodeURIComponent(value);
 +    }
 +    return params;
 +  },
 +
 +  beforePrint: function pdfViewSetupBeforePrint() {
 +    if (!this.supportsPrinting) {
 +      var printMessage = mozL10n.get('printing_not_supported', null,
 +          'Warning: Printing is not fully supported by this browser.');
 +      this.error(printMessage);
 +      return;
 +    }
 +
 +    var alertNotReady = false;
 +    if (!this.pages.length) {
 +      alertNotReady = true;
 +    } else {
 +      for (var i = 0, ii = this.pages.length; i < ii; ++i) {
 +        if (!this.pages[i].pdfPage) {
 +          alertNotReady = true;
 +          break;
 +        }
 +      }
 +    }
 +    if (alertNotReady) {
 +      var notReadyMessage = mozL10n.get('printing_not_ready', null,
 +          'Warning: The PDF is not fully loaded for printing.');
-       window.alert(notReadyMessage);
-       return;
-     }
- 
-     var body = document.querySelector('body');
-     body.setAttribute('data-mozPrintCallback', true);
-     for (var i = 0, ii = this.pages.length; i < ii; ++i) {
-       this.pages[i].beforePrint();
-     }
-   },
- 
-   afterPrint: function pdfViewSetupAfterPrint() {
-     var div = document.getElementById('printContainer');
-     while (div.hasChildNodes())
-       div.removeChild(div.lastChild);
-   },
- 
-   fullscreen: function pdfViewFullscreen() {
-     var isFullscreen = document.fullscreenElement || document.mozFullScreen ||
-         document.webkitIsFullScreen;
- 
-     if (isFullscreen) {
-       return false;
-     }
- 
-     var wrapper = document.getElementById('viewerContainer');
-     if (document.documentElement.requestFullscreen) {
-       wrapper.requestFullscreen();
-     } else if (document.documentElement.mozRequestFullScreen) {
-       wrapper.mozRequestFullScreen();
-     } else if (document.documentElement.webkitRequestFullScreen) {
-       wrapper.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT);
-     } else {
-       return false;
-     }
- 
-     this.isFullscreen = true;
-     var currentPage = this.pages[this.page - 1];
-     this.previousScale = this.currentScaleValue;
-     this.parseScale('page-fit', true);
- 
-     // Wait for fullscreen to take effect
-     setTimeout(function() {
-       currentPage.scrollIntoView();
-     }, 0);
- 
-     this.showPresentationControls();
-     return true;
-   },
- 
-   exitFullscreen: function pdfViewExitFullscreen() {
-     this.isFullscreen = false;
-     this.parseScale(this.previousScale);
-     this.page = this.page;
-     this.clearMouseScrollState();
-     this.hidePresentationControls();
- 
-     // Ensure that the thumbnail of the current page is visible
-     // when exiting fullscreen mode.
-     scrollIntoView(document.getElementById('thumbnailContainer' + this.page));
-   },
- 
-   showPresentationControls: function pdfViewShowPresentationControls() {
-     var DELAY_BEFORE_HIDING_CONTROLS = 3000;
-     var wrapper = document.getElementById('viewerContainer');
-     if (this.presentationControlsTimeout) {
-       clearTimeout(this.presentationControlsTimeout);
-     } else {
-       wrapper.classList.add('presentationControls');
-     }
-     this.presentationControlsTimeout = setTimeout(function hideControls() {
-       wrapper.classList.remove('presentationControls');
-       delete PDFView.presentationControlsTimeout;
-     }, DELAY_BEFORE_HIDING_CONTROLS);
-   },
- 
-   hidePresentationControls: function pdfViewShowPresentationControls() {
-     if (!this.presentationControlsTimeout) {
++      window.alert(notReadyMessage);
 +      return;
 +    }
-     clearTimeout(this.presentationControlsTimeout);
-     delete this.presentationControlsTimeout;
 +
-     var wrapper = document.getElementById('viewerContainer');
-     wrapper.classList.remove('presentationControls');
++    var body = document.querySelector('body');
++    body.setAttribute('data-mozPrintCallback', true);
++    for (var i = 0, ii = this.pages.length; i < ii; ++i) {
++      this.pages[i].beforePrint();
++    }
 +  },
 +
-   rotatePages: function pdfViewPageRotation(delta) {
++  afterPrint: function pdfViewSetupAfterPrint() {
++    var div = document.getElementById('printContainer');
++    while (div.hasChildNodes())
++      div.removeChild(div.lastChild);
++  },
 +
++  rotatePages: function pdfViewRotatePages(delta) {
++    var currentPage = this.pages[this.page - 1];
 +    this.pageRotation = (this.pageRotation + 360 + delta) % 360;
 +
 +    for (var i = 0, l = this.pages.length; i < l; i++) {
 +      var page = this.pages[i];
 +      page.update(page.scale, this.pageRotation);
 +    }
 +
 +    for (var i = 0, l = this.thumbnails.length; i < l; i++) {
 +      var thumb = this.thumbnails[i];
 +      thumb.update(this.pageRotation);
 +    }
 +
-     this.parseScale(this.currentScaleValue, true);
++    this.setScale(this.currentScaleValue, true, true);
 +
 +    this.renderHighestPriority();
 +
-     var currentPage = this.pages[this.page - 1];
-     if (!currentPage) {
-       return;
-     }
- 
-     // Wait for fullscreen to take effect
-     setTimeout(function() {
++    if (currentPage) {
 +      currentPage.scrollIntoView();
-     }, 0);
++    }
 +  },
 +
 +  /**
 +   * This function flips the page in presentation mode if the user scrolls up
 +   * or down with large enough motion and prevents page flipping too often.
 +   *
 +   * @this {PDFView}
 +   * @param {number} mouseScrollDelta The delta value from the mouse event.
 +   */
 +  mouseScroll: function pdfViewMouseScroll(mouseScrollDelta) {
 +    var MOUSE_SCROLL_COOLDOWN_TIME = 50;
 +
 +    var currentTime = (new Date()).getTime();
 +    var storedTime = this.mouseScrollTimeStamp;
 +
 +    // In case one page has already been flipped there is a cooldown time
 +    // which has to expire before next page can be scrolled on to.
 +    if (currentTime > storedTime &&
 +        currentTime - storedTime < MOUSE_SCROLL_COOLDOWN_TIME)
 +      return;
 +
 +    // In case the user decides to scroll to the opposite direction than before
 +    // clear the accumulated delta.
 +    if ((this.mouseScrollDelta > 0 && mouseScrollDelta < 0) ||
 +        (this.mouseScrollDelta < 0 && mouseScrollDelta > 0))
 +      this.clearMouseScrollState();
 +
 +    this.mouseScrollDelta += mouseScrollDelta;
 +
 +    var PAGE_FLIP_THRESHOLD = 120;
 +    if (Math.abs(this.mouseScrollDelta) >= PAGE_FLIP_THRESHOLD) {
 +
 +      var PageFlipDirection = {
 +        UP: -1,
 +        DOWN: 1
 +      };
 +
-       // In fullscreen mode scroll one page at a time.
++      // In presentation mode scroll one page at a time.
 +      var pageFlipDirection = (this.mouseScrollDelta > 0) ?
 +                                PageFlipDirection.UP :
 +                                PageFlipDirection.DOWN;
 +      this.clearMouseScrollState();
 +      var currentPage = this.page;
 +
 +      // In case we are already on the first or the last page there is no need
 +      // to do anything.
 +      if ((currentPage == 1 && pageFlipDirection == PageFlipDirection.UP) ||
 +          (currentPage == this.pages.length &&
 +           pageFlipDirection == PageFlipDirection.DOWN))
 +        return;
 +
 +      this.page += pageFlipDirection;
 +      this.mouseScrollTimeStamp = currentTime;
 +    }
 +  },
 +
 +  /**
 +   * This function clears the member attributes used with mouse scrolling in
 +   * presentation mode.
 +   *
 +   * @this {PDFView}
 +   */
 +  clearMouseScrollState: function pdfViewClearMouseScrollState() {
 +    this.mouseScrollTimeStamp = 0;
 +    this.mouseScrollDelta = 0;
 +  }
 +};
 +
++
 +var PageView = function pageView(container, id, scale,
 +                                 navigateTo, defaultViewport) {
 +  this.id = id;
 +
 +  this.rotation = 0;
 +  this.scale = scale || 1.0;
 +  this.viewport = defaultViewport;
-   this.pdfPageRotate = defaultViewport.rotate;
++  this.pdfPageRotate = defaultViewport.rotation;
 +
 +  this.renderingState = RenderingStates.INITIAL;
 +  this.resume = null;
 +
-   this.textContent = 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;
-     this.viewport = pdfPage.getViewport(this.scale);
++    var totalRotation = (this.rotation + this.pdfPageRotate) % 360;
++    this.viewport = pdfPage.getViewport(this.scale * CSS_UNITS, totalRotation);
 +    this.stats = pdfPage.stats;
-     this.update();
++    this.reset();
 +  };
 +
 +  this.destroy = function pageViewDestroy() {
-     this.update();
++    this.zoomLayer = null;
++    this.reset();
 +    if (this.pdfPage) {
 +      this.pdfPage.destroy();
 +    }
 +  };
 +
-   this.update = function pageViewUpdate(scale, rotation) {
-     this.renderingState = RenderingStates.INITIAL;
++  this.reset = function pageViewReset() {
++    if (this.renderTask) {
++      this.renderTask.cancel();
++    }
 +    this.resume = null;
++    this.renderingState = RenderingStates.INITIAL;
 +
-     if (typeof rotation !== 'undefined') {
-       this.rotation = rotation;
++    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) {
++        continue;
++      }
++      div.removeChild(node);
 +    }
++    div.removeAttribute('data-loaded');
++
++    this.annotationLayer = null;
++
++    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,
++      scale: this.scale * CSS_UNITS,
 +      rotation: totalRotation
 +    });
 +
-     div.style.width = Math.floor(this.viewport.width) + 'px';
-     div.style.height = Math.floor(this.viewport.height) + 'px';
- 
-     while (div.hasChildNodes())
-       div.removeChild(div.lastChild);
-     div.removeAttribute('data-loaded');
++    if (USE_ONLY_CSS_ZOOM && this.canvas) {
++      this.cssTransform(this.canvas);
++      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();
++  };
 +
-     delete this.canvas;
++  this.cssTransform = function pageCssTransform(canvas) {
++    // 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 textRelativeRotation = this.viewport.rotation -
++                                 this.textLayer.viewport.rotation;
++      var textAbsRotation = Math.abs(textRelativeRotation);
++      var scale = (width / canvas.width);
++      if (textAbsRotation === 90 || textAbsRotation === 270) {
++        scale = width / canvas.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%');
++    }
 +
-     this.loadingIconDiv = document.createElement('div');
-     this.loadingIconDiv.className = 'loadingIcon';
-     div.appendChild(this.loadingIconDiv);
++    if (USE_ONLY_CSS_ZOOM && 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
 +  });
 +
-   function setupAnnotations(pdfPage, viewport) {
++  var self = this;
++
++  function setupAnnotations(pageDiv, pdfPage, viewport) {
++
 +    function bindLink(link, dest) {
 +      link.href = PDFView.getDestinationHash(dest);
 +      link.onclick = function pageViewSetupLinksOnclick() {
-         if (dest)
++        if (dest) {
 +          PDFView.navigateTo(dest);
++        }
 +        return false;
 +      };
++      if (dest) {
++        link.className = 'internalLink';
++      }
 +    }
-     function createElementWithStyle(tagName, item, rect) {
-       if (!rect) {
-         rect = viewport.convertToViewportRectangle(item.rect);
-         rect = PDFJS.Util.normalizeRect(rect);
-       }
-       var element = document.createElement(tagName);
-       element.style.left = Math.floor(rect[0]) + 'px';
-       element.style.top = Math.floor(rect[1]) + 'px';
-       element.style.width = Math.ceil(rect[2] - rect[0]) + 'px';
-       element.style.height = Math.ceil(rect[3] - rect[1]) + 'px';
-       return element;
-     }
-     function createTextAnnotation(item) {
-       var container = document.createElement('section');
-       container.className = 'annotText';
- 
-       var rect = viewport.convertToViewportRectangle(item.rect);
-       rect = PDFJS.Util.normalizeRect(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 image = createElementWithStyle('img', item, rect);
-       var iconName = item.name;
-       image.src = IMAGE_DIR + 'annotation-' +
-         iconName.toLowerCase() + '.svg';
-       image.alt = mozL10n.get('text_annotation_type', {type: iconName},
-         '[{{type}} Annotation]');
-       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]) + 'px';
-       content.style.top = Math.floor(rect[1]) + 'px';
-       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);
-         image.addEventListener('mouseover', function annotationImageOver() {
-            content.removeAttribute('hidden');
-         }, false);
- 
-         image.addEventListener('mouseout', function annotationImageOut() {
-            content.setAttribute('hidden', true);
-         }, false);
-       }
- 
-       content.appendChild(title);
-       content.appendChild(text);
-       container.appendChild(image);
-       container.appendChild(content);
- 
-       return container;
-     }
- 
-     pdfPage.getAnnotations().then(function(items) {
-       for (var i = 0; i < items.length; i++) {
-         var item = items[i];
-         switch (item.type) {
-           case 'Link':
-             var link = createElementWithStyle('a', item);
-             link.href = item.url || '';
-             if (!item.url)
-               bindLink(link, ('dest' in item) ? item.dest : null);
-             div.appendChild(link);
++
++    function bindNamedAction(link, action) {
++      link.href = PDFView.getAnchorUrl('');
++      link.onclick = function pageViewSetupNamedActionOnClick() {
++        // See PDF reference, table 8.45 - Named action
++        switch (action) {
++          case 'GoToPage':
++            document.getElementById('pageNumber').focus();
 +            break;
-           case 'Text':
-             var textAnnotation = createTextAnnotation(item);
-             if (textAnnotation)
-               div.appendChild(textAnnotation);
++
++          case 'GoBack':
++            PDFHistory.back();
++            break;
++
++          case 'GoForward':
++            PDFHistory.forward();
++            break;
++
++          case 'Find':
++            if (!PDFView.supportsIntegratedFind) {
++              PDFFindBar.toggle();
++            }
++            break;
++
++          case 'NextPage':
++            PDFView.page++;
 +            break;
++
++          case 'PrevPage':
++            PDFView.page--;
++            break;
++
++          case 'LastPage':
++            PDFView.page = PDFView.pages.length;
++            break;
++
++          case 'FirstPage':
++            PDFView.page = 1;
++            break;
++
++          default:
++            break; // No action according to spec
++        }
++        return false;
++      };
++      link.className = 'internalLink';
++    }
++
++    pdfPage.getAnnotations().then(function(annotationsData) {
++      if (self.annotationLayer) {
++        // If an annotationLayer already exists, delete it to avoid creating
++        // duplicate annotations when rapidly re-zooming the document.
++        pageDiv.removeChild(self.annotationLayer);
++        self.annotationLayer = null;
++      }
++      viewport = viewport.clone({ dontFlip: true });
++      for (var i = 0; i < annotationsData.length; i++) {
++        var data = annotationsData[i];
++        var annotation = PDFJS.Annotation.fromData(data);
++        if (!annotation || !annotation.hasHtml()) {
++          continue;
++        }
++
++        var element = annotation.getHtmlElement(pdfPage.commonObjs);
++        mozL10n.translate(element);
++
++        data = annotation.getData();
++        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';
++
++        var transform = viewport.transform;
++        var transformStr = 'matrix(' + transform.join(',') + ')';
++        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.scrollIntoView = function pageViewScrollIntoView(dest) {
-       if (!dest) {
-         scrollIntoView(div);
++    if (PresentationMode.active) {
++      if (PDFView.page !== this.id) {
++        // Avoid breaking PDFView.getVisiblePages in presentation mode.
++        PDFView.page = this.id;
 +        return;
 +      }
++      dest = null;
++      PDFView.setScale(PDFView.currentScaleValue, true, true);
++    }
++    if (!dest) {
++      scrollIntoView(div);
++      return;
++    }
 +
-       var x = 0, y = 0;
-       var width = 0, height = 0, widthScale, heightScale;
-       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 : this.height / this.scale;
-           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];
-           scale = 'page-height';
-           break;
-         case 'FitR':
-           x = dest[2];
-           y = dest[3];
-           width = dest[4] - x;
-           height = dest[5] - y;
-           widthScale = (this.container.clientWidth - SCROLLBAR_PADDING) /
-             width / CSS_UNITS;
-           heightScale = (this.container.clientHeight - SCROLLBAR_PADDING) /
-             height / CSS_UNITS;
-           scale = Math.min(widthScale, heightScale);
-           break;
-         default:
-           return;
-       }
++    var x = 0, y = 0;
++    var width = 0, height = 0, widthScale, heightScale;
++    var changeOrientation = !!(this.rotation % 180);
++    var pageWidth = (changeOrientation ? this.height : this.width) /
++      this.scale / CSS_UNITS;
++    var pageHeight = (changeOrientation ? this.width : this.height) /
++      this.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;
++        widthScale = (PDFView.container.clientWidth - SCROLLBAR_PADDING) /
++          width / CSS_UNITS;
++        heightScale = (PDFView.container.clientHeight - SCROLLBAR_PADDING) /
++          height / CSS_UNITS;
++        scale = Math.min(Math.abs(widthScale), Math.abs(heightScale));
++        break;
++      default:
++        return;
++    }
 +
-       if (scale && scale !== PDFView.currentScale)
-         PDFView.parseScale(scale, true, true);
-       else if (PDFView.currentScale === UNKNOWN_SCALE)
-         PDFView.parseScale(DEFAULT_SCALE, true, true);
++    if (scale && scale !== PDFView.currentScale) {
++      PDFView.setScale(scale, true, true);
++    } else if (PDFView.currentScale === UNKNOWN_SCALE) {
++      PDFView.setScale(DEFAULT_SCALE, true, true);
++    }
 +
-       var boundingRect = [
-         this.viewport.convertToViewportPoint(x, y),
-         this.viewport.convertToViewportPoint(x + width, y + height)
-       ];
-       setTimeout(function pageViewScrollIntoViewRelayout() {
-         // letting page to re-layout before scrolling
-         var scale = PDFView.currentScale;
-         var x = Math.min(boundingRect[0][0], boundingRect[1][0]);
-         var y = Math.min(boundingRect[0][1], boundingRect[1][1]);
-         var width = Math.abs(boundingRect[0][0] - boundingRect[1][0]);
-         var height = Math.abs(boundingRect[0][1] - boundingRect[1][1]);
- 
-         scrollIntoView(div, {left: x, top: y, width: width, height: height});
-       }, 0);
++    if (scale === 'page-fit' && !dest[4]) {
++      scrollIntoView(div);
++      return;
++    }
++
++    var boundingRect = [
++      this.viewport.convertToViewportPoint(x, y),
++      this.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(div, { left: left, top: top });
 +  };
 +
 +  this.getTextContent = function pageviewGetTextContent() {
-     if (!this.textContent) {
-       this.textContent = this.pdfPage.getTextContent();
-     }
-     return this.textContent;
++    return PDFView.getPage(this.id).then(function(pdfPage) {
++      return pdfPage.getTextContent();
++    });
 +  };
 +
 +  this.draw = function pageviewDraw(callback) {
 +    var pdfPage = this.pdfPage;
 +
++    if (this.pagePdfPromise) {
++      return;
++    }
 +    if (!pdfPage) {
 +      var promise = PDFView.getPage(this.id);
 +      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;
-     div.appendChild(canvas);
++    canvasWrapper.appendChild(canvas);
++    div.appendChild(canvasWrapper);
 +    this.canvas = canvas;
 +
-     var scale = this.scale, viewport = this.viewport;
-     var outputScale = PDFView.getOutputScale();
-     canvas.width = Math.floor(viewport.width) * outputScale.sx;
-     canvas.height = Math.floor(viewport.height) * outputScale.sy;
++    var scale = this.scale;
++    var ctx = canvas.getContext('2d');
++    var outputScale = getOutputScale(ctx);
++
++    if (USE_ONLY_CSS_ZOOM) {
++      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;
++    }
++
++    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;
 +    if (!PDFJS.disableTextLayer) {
 +      textLayerDiv = document.createElement('div');
 +      textLayerDiv.className = 'textLayer';
 +      textLayerDiv.style.width = canvas.width + 'px';
 +      textLayerDiv.style.height = canvas.height + 'px';
 +      div.appendChild(textLayerDiv);
 +    }
 +    var textLayer = this.textLayer =
-           textLayerDiv ? new TextLayerBuilder(textLayerDiv, this.id - 1) : null;
- 
-     if (outputScale.scaled) {
-       var cssScale = 'scale(' + (1 / outputScale.sx) + ', ' +
-                                 (1 / outputScale.sy) + ')';
-       CustomStyle.setProp('transform' , canvas, cssScale);
-       CustomStyle.setProp('transformOrigin' , canvas, '0% 0%');
-       if (textLayerDiv) {
-         CustomStyle.setProp('transform' , textLayerDiv, cssScale);
-         CustomStyle.setProp('transformOrigin' , textLayerDiv, '0% 0%');
-       }
-     }
- 
-     var ctx = canvas.getContext('2d');
-     ctx.clearRect(0, 0, canvas.width, canvas.height);
++      textLayerDiv ? new TextLayerBuilder({
++        textLayerDiv: textLayerDiv,
++        pageIndex: this.id - 1,
++        lastScrollSource: PDFView,
++        viewport: this.viewport,
++        isViewerInPresentationMode: PresentationMode.active
++      }) : null;
 +    // 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);
 +    }
++    if (outputScale.scaled && textLayerDiv) {
++      var cssScale = 'scale(' + (1 / outputScale.sx) + ', ' +
++                                (1 / outputScale.sy) + ')';
++      CustomStyle.setProp('transform' , textLayerDiv, cssScale);
++      CustomStyle.setProp('transformOrigin' , textLayerDiv, '0% 0%');
++      textLayerDiv.dataset._scaleX = outputScale.sx;
++      textLayerDiv.dataset._scaleY = outputScale.sy;
++    }
 +
 +    // Rendering area
 +
 +    var self = this;
-     var renderingWasReset = false;
 +    function pageViewDrawCallback(error) {
-       if (renderingWasReset) {
++      // 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;
++      }
++
 +      if (error) {
 +        PDFView.error(mozL10n.get('rendering_error', null,
 +          'An error occurred while rendering the page.'), error);
 +      }
 +
 +      self.stats = pdfPage.stats;
 +      self.updateStats();
-       if (self.onAfterDraw)
++      if (self.onAfterDraw) {
 +        self.onAfterDraw();
++      }
 +
 +      cache.push(self);
 +
 +      var event = document.createEvent('CustomEvent');
 +      event.initCustomEvent('pagerender', true, true, {
 +        pageNumber: pdfPage.pageNumber
 +      });
 +      div.dispatchEvent(event);
 +
 +      callback();
 +    }
 +
 +    var renderContext = {
 +      canvasContext: ctx,
 +      viewport: this.viewport,
 +      textLayer: textLayer,
++      // intent: 'default', // === 'display'
 +      continueCallback: function pdfViewcContinueCallback(cont) {
-         if (self.renderingState === RenderingStates.INITIAL) {
-           // The page update() was called, we just need to abort any rendering.
-           renderingWasReset = true;
-           return;
-         }
- 
 +        if (PDFView.highestPriorityPage !== 'page' + self.id) {
 +          self.renderingState = RenderingStates.PAUSED;
 +          self.resume = function resumeCallback() {
 +            self.renderingState = RenderingStates.RUNNING;
 +            cont();
 +          };
 +          return;
 +        }
 +        cont();
 +      }
 +    };
-     this.pdfPage.render(renderContext).then(
++    var renderTask = this.renderTask = this.pdfPage.render(renderContext);
++
++    this.renderTask.promise.then(
 +      function pdfPageRenderCallback() {
 +        pageViewDrawCallback(null);
 +      },
 +      function pdfPageRenderError(error) {
 +        pageViewDrawCallback(error);
 +      }
 +    );
 +
 +    if (textLayer) {
 +      this.getTextContent().then(
 +        function textContentResolved(textContent) {
 +          textLayer.setTextContent(textContent);
 +        }
 +      );
 +    }
 +
-     setupAnnotations(this.pdfPage, this.viewport);
++    setupAnnotations(div, pdfPage, this.viewport);
 +    div.setAttribute('data-loaded', true);
 +  };
 +
 +  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 = this.canvas = document.createElement('canvas');
++    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');
-     printContainer.appendChild(canvas);
++    var canvasWrapper = document.createElement('div');
++    canvasWrapper.style.width = viewport.width + 'pt';
++    canvasWrapper.style.height = viewport.height + 'pt';
++    canvasWrapper.appendChild(canvas);
++    printContainer.appendChild(canvasWrapper);
 +
 +    var self = this;
 +    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
++        viewport: viewport,
++        intent: 'print'
 +      };
 +
-       pdfPage.render(renderContext).then(function() {
++      pdfPage.render(renderContext).promise.then(function() {
 +        // Tell the printEngine that rendering this canvas/page has finished.
 +        obj.done();
-         self.pdfPage.destroy();
 +      }, 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)
++        if ('abort' in obj) {
 +          obj.abort();
-         else
++        } else {
 +          obj.done();
-         self.pdfPage.destroy();
++        }
 +      });
 +    };
 +  };
 +
 +  this.updateStats = function pageViewUpdateStats() {
 +    if (!this.stats) {
 +      return;
 +    }
 +
 +    if (PDFJS.pdfBug && Stats.enabled) {
 +      var stats = this.stats;
 +      Stats.add(this.id, stats);
 +    }
 +  };
 +};
 +
++
 +var ThumbnailView = function thumbnailView(container, id, defaultViewport) {
 +  var anchor = document.createElement('a');
 +  anchor.href = PDFView.getAnchorUrl('#page=' + id);
 +  anchor.title = mozL10n.get('thumb_page_title', {page: id}, 'Page {{page}}');
 +  anchor.onclick = function stopNavigation() {
 +    PDFView.page = id;
 +    return false;
 +  };
 +
- 
 +  this.pdfPage = undefined;
 +  this.viewport = defaultViewport;
-   this.pdfPageRotate = defaultViewport.rotate;
++  this.pdfPageRotate = defaultViewport.rotation;
 +
 +  this.rotation = 0;
 +  this.pageWidth = this.viewport.width;
 +  this.pageHeight = this.viewport.height;
 +  this.pageRatio = this.pageWidth / this.pageHeight;
 +  this.id = id;
 +
 +  this.canvasWidth = 98;
 +  this.canvasHeight = this.canvasWidth / this.pageWidth * this.pageHeight;
 +  this.scale = (this.canvasWidth / this.pageWidth);
 +
 +  var div = this.el = document.createElement('div');
 +  div.id = 'thumbnailContainer' + id;
 +  div.className = 'thumbnail';
 +
 +  if (id === 1) {
 +    // Highlight the thumbnail of the first page when no page number is
 +    // specified (or exists in cache) when the document is loaded.
 +    div.classList.add('selected');
 +  }
 +
 +  var ring = document.createElement('div');
 +  ring.className = 'thumbnailSelectionRing';
 +  ring.style.width = this.canvasWidth + 'px';
 +  ring.style.height = this.canvasHeight + 'px';
 +
 +  div.appendChild(ring);
 +  anchor.appendChild(div);
 +  container.appendChild(anchor);
 +
 +  this.hasImage = false;
 +  this.renderingState = RenderingStates.INITIAL;
 +
 +  this.setPdfPage = function thumbnailViewSetPdfPage(pdfPage) {
 +    this.pdfPage = pdfPage;
 +    this.pdfPageRotate = pdfPage.rotate;
-     this.viewport = pdfPage.getViewport(1);
++    var totalRotation = (this.rotation + this.pdfPageRotate) % 360;
++    this.viewport = pdfPage.getViewport(1, totalRotation);
 +    this.update();
 +  };
 +
-   this.update = function thumbnailViewUpdate(rot) {
-     if (!this.pdfPage) {
-       return;
-     }
- 
-     if (rot !== undefined) {
-       this.rotation = rot;
++  this.update = function thumbnailViewUpdate(rotation) {
++    if (rotation !== undefined) {
++      this.rotation = rotation;
 +    }
- 
-     var totalRotation = (this.rotation + this.pdfPage.rotate) % 360;
++    var totalRotation = (this.rotation + this.pdfPageRotate) % 360;
 +    this.viewport = this.viewport.clone({
 +      scale: 1,
 +      rotation: totalRotation
 +    });
 +    this.pageWidth = this.viewport.width;
 +    this.pageHeight = this.viewport.height;
 +    this.pageRatio = this.pageWidth / this.pageHeight;
 +
 +    this.canvasHeight = this.canvasWidth / this.pageWidth * this.pageHeight;
 +    this.scale = (this.canvasWidth / this.pageWidth);
 +
 +    div.removeAttribute('data-loaded');
 +    ring.textContent = '';
 +    ring.style.width = this.canvasWidth + 'px';
 +    ring.style.height = this.canvasHeight + 'px';
 +
 +    this.hasImage = false;
 +    this.renderingState = RenderingStates.INITIAL;
 +    this.resume = null;
 +  };
 +
 +  this.getPageDrawContext = function thumbnailViewGetPageDrawContext() {
 +    var canvas = document.createElement('canvas');
 +    canvas.id = 'thumbnail' + id;
 +
 +    canvas.width = this.canvasWidth;
 +    canvas.height = this.canvasHeight;
 +    canvas.className = 'thumbnailImage';
 +    canvas.setAttribute('aria-label', mozL10n.get('thumb_page_canvas',
 +      {page: id}, 'Thumbnail of Page {{page}}'));
 +
 +    div.setAttribute('data-loaded', true);
 +
 +    ring.appendChild(canvas);
 +
 +    var ctx = canvas.getContext('2d');
 +    ctx.save();
 +    ctx.fillStyle = 'rgb(255, 255, 255)';
 +    ctx.fillRect(0, 0, this.canvasWidth, this.canvasHeight);
 +    ctx.restore();
 +    return ctx;
 +  };
 +
 +  this.drawingRequired = function thumbnailViewDrawingRequired() {
 +    return !this.hasImage;
 +  };
 +
 +  this.draw = function thumbnailViewDraw(callback) {
 +    if (!this.pdfPage) {
 +      var promise = PDFView.getPage(this.id);
 +      promise.then(function(pdfPage) {
 +        this.setPdfPage(pdfPage);
 +        this.draw(callback);
 +      }.bind(this));
 +      return;
 +    }
 +
 +    if (this.renderingState !== RenderingStates.INITIAL) {
 +      console.error('Must be in new state before drawing');
 +    }
 +
 +    this.renderingState = RenderingStates.RUNNING;
 +    if (this.hasImage) {
 +      callback();
 +      return;
 +    }
 +
 +    var self = this;
 +    var ctx = this.getPageDrawContext();
 +    var drawViewport = this.viewport.clone({ scale: this.scale });
 +    var renderContext = {
 +      canvasContext: ctx,
 +      viewport: drawViewport,
 +      continueCallback: function(cont) {
 +        if (PDFView.highestPriorityPage !== 'thumbnail' + self.id) {
 +          self.renderingState = RenderingStates.PAUSED;
 +          self.resume = function() {
 +            self.renderingState = RenderingStates.RUNNING;
 +            cont();
 +          };
 +          return;
 +        }
 +        cont();
 +      }
 +    };
-     this.pdfPage.render(renderContext).then(
++    this.pdfPage.render(renderContext).promise.then(
 +      function pdfPageRenderCallback() {
 +        self.renderingState = RenderingStates.FINISHED;
 +        callback();
-       },
-       function pdfPageRenderError(error) {
-         self.renderingState = RenderingStates.FINISHED;
-         callback();
-       }
-     );
-     this.hasImage = true;
-   };
- 
-   this.setImage = function thumbnailViewSetImage(img) {
-     if (this.hasImage || !img)
-       return;
-     this.renderingState = RenderingStates.FINISHED;
-     var ctx = this.getPageDrawContext();
-     ctx.drawImage(img, 0, 0, img.width, img.height,
-                   0, 0, ctx.canvas.width, ctx.canvas.height);
- 
-     this.hasImage = true;
-   };
- };
- 
- var DocumentOutlineView = function documentOutlineView(outline) {
-   var outlineView = document.getElementById('outlineView');
-   while (outlineView.firstChild)
-     outlineView.removeChild(outlineView.firstChild);
- 
-   function bindItemLink(domObj, item) {
-     domObj.href = PDFView.getDestinationHash(item.dest);
-     domObj.onclick = function documentOutlineViewOnclick(e) {
-       PDFView.navigateTo(item.dest);
-       return false;
-     };
-   }
- 
-   if (!outline) {
-     var noOutline = document.createElement('div');
-     noOutline.classList.add('noOutline');
-     noOutline.textContent = mozL10n.get('no_outline', null,
-       'No Outline Available');
-     outlineView.appendChild(noOutline);
-     return;
-   }
- 
-   var queue = [{parent: outlineView, items: outline}];
-   while (queue.length > 0) {
-     var levelData = queue.shift();
-     var i, n = levelData.items.length;
-     for (i = 0; i < n; i++) {
-       var item = levelData.items[i];
-       var div = document.createElement('div');
-       div.className = 'outlineItem';
-       var a = document.createElement('a');
-       bindItemLink(a, item);
-       a.textContent = item.title;
-       div.appendChild(a);
- 
-       if (item.items.length > 0) {
-         var itemsDiv = document.createElement('div');
-         itemsDiv.className = 'outlineItems';
-         div.appendChild(itemsDiv);
-         queue.push({parent: itemsDiv, items: item.items});
-       }
- 
-       levelData.parent.appendChild(div);
-     }
-   }
- };
- 
- // optimised CSS custom property getter/setter
- var CustomStyle = (function CustomStyleClosure() {
- 
-   // As noted on: http://www.zachstronaut.com/posts/2009/02/17/
-   //              animate-css-transforms-firefox-webkit.html
-   // in some versions of IE9 it is critical that ms appear in this list
-   // before Moz
-   var prefixes = ['ms', 'Moz', 'Webkit', 'O'];
-   var _cache = { };
- 
-   function CustomStyle() {
-   }
- 
-   CustomStyle.getProp = function get(propName, element) {
-     // check cache only when no element is given
-     if (arguments.length == 1 && typeof _cache[propName] == 'string') {
-       return _cache[propName];
-     }
- 
-     element = element || document.documentElement;
-     var style = element.style, prefixed, uPropName;
++      },
++      function pdfPageRenderError(error) {
++        self.renderingState = RenderingStates.FINISHED;
++        callback();
++      }
++    );
++    this.hasImage = true;
++  };
 +
-     // test standard property first
-     if (typeof style[propName] == 'string') {
-       return (_cache[propName] = propName);
++  this.setImage = function thumbnailViewSetImage(img) {
++    if (!this.pdfPage) {
++      var promise = PDFView.getPage(this.id);
++      promise.then(function(pdfPage) {
++        this.setPdfPage(pdfPage);
++        this.setImage(img);
++      }.bind(this));
++      return;
 +    }
- 
-     // capitalize
-     uPropName = propName.charAt(0).toUpperCase() + propName.slice(1);
- 
-     // test vendor specific properties
-     for (var i = 0, l = prefixes.length; i < l; i++) {
-       prefixed = prefixes[i] + uPropName;
-       if (typeof style[prefixed] == 'string') {
-         return (_cache[propName] = prefixed);
-       }
++    if (this.hasImage || !img) {
++      return;
 +    }
++    this.renderingState = RenderingStates.FINISHED;
++    var ctx = this.getPageDrawContext();
++    ctx.drawImage(img, 0, 0, img.width, img.height,
++                  0, 0, ctx.canvas.width, ctx.canvas.height);
 +
-     //if all fails then set to undefined
-     return (_cache[propName] = 'undefined');
++    this.hasImage = true;
 +  };
++};
 +
-   CustomStyle.setProp = function set(propName, element, str) {
-     var prop = this.getProp(propName);
-     if (prop != 'undefined')
-       element.style[prop] = str;
-   };
 +
-   return CustomStyle;
- })();
++var FIND_SCROLL_OFFSET_TOP = -50;
++var FIND_SCROLL_OFFSET_LEFT = -400;
 +
- var TextLayerBuilder = function textLayerBuilder(textLayerDiv, pageIdx) {
++/**
++ * TextLayerBuilder provides text-selection
++ * functionality for the PDF. It does this
++ * by creating overlay divs over the PDF
++ * text. This divs contain text that matches
++ * the PDF text they are overlaying. This
++ * object also provides for a way to highlight
++ * text that is being searched for.
++ */
++var TextLayerBuilder = function textLayerBuilder(options) {
 +  var textLayerFrag = document.createDocumentFragment();
 +
-   this.textLayerDiv = textLayerDiv;
++  this.textLayerDiv = options.textLayerDiv;
 +  this.layoutDone = false;
 +  this.divContentDone = false;
-   this.pageIdx = pageIdx;
++  this.pageIdx = options.pageIndex;
 +  this.matches = [];
++  this.lastScrollSource = options.lastScrollSource;
++  this.viewport = options.viewport;
++  this.isViewerInPresentationMode = options.isViewerInPresentationMode;
++
++  if(typeof PDFFindController === 'undefined') {
++      window.PDFFindController = null;
++  }
++
++  if(typeof this.lastScrollSource === 'undefined') {
++      this.lastScrollSource = null;
++  }
 +
 +  this.beginLayout = function textLayerBuilderBeginLayout() {
 +    this.textDivs = [];
-     this.textLayerQueue = [];
 +    this.renderingDone = false;
 +  };
 +
 +  this.endLayout = function textLayerBuilderEndLayout() {
 +    this.layoutDone = true;
 +    this.insertDivContent();
 +  };
 +
 +  this.renderLayer = function textLayerBuilderRenderLayer() {
-     var self = this;
 +    var textDivs = this.textDivs;
-     var bidiTexts = this.textContent.bidiTexts;
-     var textLayerDiv = this.textLayerDiv;
 +    var canvas = document.createElement('canvas');
 +    var ctx = canvas.getContext('2d');
 +
 +    // No point in rendering so many divs as it'd make the browser unusable
 +    // even after the divs are rendered
 +    var MAX_TEXT_DIVS_TO_RENDER = 100000;
 +    if (textDivs.length > MAX_TEXT_DIVS_TO_RENDER)
 +      return;
 +
 +    for (var i = 0, ii = textDivs.length; i < ii; i++) {
 +      var textDiv = textDivs[i];
 +      if ('isWhitespace' in textDiv.dataset) {
 +        continue;
 +      }
-       textLayerFrag.appendChild(textDiv);
 +
 +      ctx.font = textDiv.style.fontSize + ' ' + textDiv.style.fontFamily;
 +      var width = ctx.measureText(textDiv.textContent).width;
 +
 +      if (width > 0) {
++        textLayerFrag.appendChild(textDiv);
 +        var textScale = textDiv.dataset.canvasWidth / width;
- 
++        var rotation = textDiv.dataset.angle;
 +        var transform = 'scale(' + textScale + ', 1)';
-         if (bidiTexts[i].dir === 'ttb') {
-           transform = 'rotate(90deg) ' + transform;
-         }
++        transform = 'rotate(' + rotation + 'deg) ' + transform;
 +        CustomStyle.setProp('transform' , textDiv, transform);
 +        CustomStyle.setProp('transformOrigin' , textDiv, '0% 0%');
- 
-         textLayerDiv.appendChild(textDiv);
 +      }
 +    }
 +
++    this.textLayerDiv.appendChild(textLayerFrag);
 +    this.renderingDone = true;
 +    this.updateMatches();
- 
-     textLayerDiv.appendChild(textLayerFrag);
 +  };
 +
 +  this.setupRenderLayoutTimer = function textLayerSetupRenderLayoutTimer() {
 +    // Schedule renderLayout() if user has been scrolling, otherwise
 +    // run it right away
 +    var RENDER_DELAY = 200; // in ms
 +    var self = this;
-     if (Date.now() - PDFView.lastScroll > RENDER_DELAY) {
++    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);
 +    }
 +  };
 +
 +  this.appendText = function textLayerBuilderAppendText(geom) {
 +    var textDiv = document.createElement('div');
 +
 +    // vScale and hScale already contain the scaling to pixel units
 +    var fontHeight = geom.fontSize * Math.abs(geom.vScale);
-     textDiv.dataset.canvasWidth = geom.canvasWidth * geom.hScale;
++    textDiv.dataset.canvasWidth = geom.canvasWidth * Math.abs(geom.hScale);
 +    textDiv.dataset.fontName = geom.fontName;
++    textDiv.dataset.angle = geom.angle * (180 / Math.PI);
 +
 +    textDiv.style.fontSize = fontHeight + 'px';
 +    textDiv.style.fontFamily = geom.fontFamily;
-     textDiv.style.left = geom.x + 'px';
-     textDiv.style.top = (geom.y - fontHeight) + 'px';
++    var fontAscent = geom.ascent ? geom.ascent * fontHeight :
++      geom.descent ? (1 + geom.descent) * fontHeight : fontHeight;
++    textDiv.style.left = (geom.x + (fontAscent * Math.sin(geom.angle))) + 'px';
++    textDiv.style.top = (geom.y - (fontAscent * Math.cos(geom.angle))) + 'px';
 +
 +    // The content of the div is set in the `setTextContent` function.
 +
 +    this.textDivs.push(textDiv);
 +  };
 +
 +  this.insertDivContent = function textLayerUpdateTextContent() {
 +    // Only set the content of the divs once layout has finished, the content
 +    // for the divs is available and content is not yet set on the divs.
 +    if (!this.layoutDone || this.divContentDone || !this.textContent)
 +      return;
 +
 +    this.divContentDone = true;
 +
 +    var textDivs = this.textDivs;
-     var bidiTexts = this.textContent.bidiTexts;
++    var bidiTexts = this.textContent;
 +
 +    for (var i = 0; i < bidiTexts.length; i++) {
 +      var bidiText = bidiTexts[i];
 +      var textDiv = textDivs[i];
 +      if (!/\S/.test(bidiText.str)) {
 +        textDiv.dataset.isWhitespace = true;
 +        continue;
 +      }
 +
 +      textDiv.textContent = bidiText.str;
++      // TODO refactor text layer to use text content position
++      /**
++       * var arr = this.viewport.convertToViewportPoint(bidiText.x, bidiText.y);
++       * textDiv.style.left = arr[0] + 'px';
++       * textDiv.style.top = arr[1] + 'px';
++       */
 +      // bidiText.dir may be 'ttb' for vertical texts.
-       textDiv.dir = bidiText.dir === 'rtl' ? 'rtl' : 'ltr';
++      textDiv.dir = bidiText.dir;
 +    }
 +
 +    this.setupRenderLayoutTimer();
 +  };
 +
 +  this.setTextContent = function textLayerBuilderSetTextContent(textContent) {
 +    this.textContent = textContent;
 +    this.insertDivContent();
 +  };
 +
 +  this.convertMatches = function textLayerBuilderConvertMatches(matches) {
 +    var i = 0;
 +    var iIndex = 0;
-     var bidiTexts = this.textContent.bidiTexts;
++    var bidiTexts = this.textContent;
 +    var end = bidiTexts.length - 1;
-     var queryLen = PDFFindController.state.query.length;
++    var queryLen = PDFFindController === null ?
++        0 : PDFFindController.state.query.length;
 +
 +    var lastDivIdx = -1;
 +    var pos;
 +
 +    var ret = [];
 +
 +    // Loop over all the matches.
 +    for (var m = 0; m < matches.length; m++) {
 +      var matchIdx = matches[m];
 +      // # Calculate the begin position.
 +
 +      // Loop over the divIdxs.
 +      while (i !== end && matchIdx >= (iIndex + bidiTexts[i].str.length)) {
 +        iIndex += bidiTexts[i].str.length;
 +        i++;
 +      }
 +
 +      // TODO: Do proper handling here if something goes wrong.
 +      if (i == bidiTexts.length) {
 +        console.error('Could not find matching mapping');
 +      }
 +
 +      var match = {
 +        begin: {
 +          divIdx: i,
 +          offset: matchIdx - iIndex
 +        }
 +      };
 +
 +      // # Calculate the end position.
 +      matchIdx += queryLen;
 +
 +      // Somewhat same array as above, but use a > 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;
 +  };
 +
 +  this.renderMatches = function textLayerBuilder_renderMatches(matches) {
 +    // Early exit if there is nothing to render.
 +    if (matches.length === 0) {
 +      return;
 +    }
 +
-     var bidiTexts = this.textContent.bidiTexts;
++    var bidiTexts = this.textContent;
 +    var textDivs = this.textDivs;
 +    var prevEnd = null;
-     var isSelectedPage = this.pageIdx === PDFFindController.selected.pageIdx;
-     var selectedMatchIdx = PDFFindController.selected.matchIdx;
-     var highlightAll = PDFFindController.state.highlightAll;
++    var isSelectedPage = PDFFindController === null ?
++        false : (this.pageIdx === PDFFindController.selected.pageIdx);
++
++    var selectedMatchIdx = PDFFindController === null ?
++        -1 : PDFFindController.selected.matchIdx;
++
++    var highlightAll = PDFFindController === null ?
++        false : PDFFindController.state.highlightAll;
 +
 +    var infty = {
 +      divIdx: -1,
 +      offset: undefined
 +    };
 +
 +    function beginText(begin, className) {
 +      var divIdx = begin.divIdx;
 +      var div = textDivs[divIdx];
 +      div.textContent = '';
 +
 +      var content = bidiTexts[divIdx].str.substring(0, begin.offset);
 +      var node = document.createTextNode(content);
 +      if (className) {
 +        var isSelected = isSelectedPage &&
 +                          divIdx === selectedMatchIdx;
 +        var span = document.createElement('span');
 +        span.className = className + (isSelected ? ' selected' : '');
 +        span.appendChild(node);
 +        div.appendChild(span);
 +        return;
 +      }
 +      div.appendChild(node);
 +    }
 +
 +    function appendText(from, to, className) {
 +      var divIdx = from.divIdx;
 +      var div = textDivs[divIdx];
 +
 +      var content = bidiTexts[divIdx].str.substring(from.offset, to.offset);
 +      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);
 +    }
 +
 +    function highlightDiv(divIdx, className) {
 +      textDivs[divIdx].className = className;
 +    }
 +
 +    var i0 = selectedMatchIdx, i1 = i0 + 1, i;
 +
 +    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 (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)
-         scrollIntoView(textDivs[begin.divIdx], {top: -50});
++      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) {
 +          appendText(prevEnd, infty);
 +        }
 +        // clears the divs and set the content until the begin point.
 +        beginText(begin);
 +      } else {
 +        appendText(prevEnd, begin);
 +      }
 +
 +      if (begin.divIdx === end.divIdx) {
 +        appendText(begin, end, 'highlight' + highlightSuffix);
 +      } else {
 +        appendText(begin, infty, 'highlight begin' + highlightSuffix);
 +        for (var n = begin.divIdx + 1; n < end.divIdx; n++) {
 +          highlightDiv(n, 'highlight middle' + highlightSuffix);
 +        }
 +        beginText(end, 'highlight end' + highlightSuffix);
 +      }
 +      prevEnd = end;
 +    }
 +
 +    if (prevEnd) {
 +      appendText(prevEnd, infty);
 +    }
 +  };
 +
 +  this.updateMatches = function textLayerUpdateMatches() {
 +    // Only show matches, once all rendering is done.
 +    if (!this.renderingDone)
 +      return;
 +
 +    // Clear out all matches.
 +    var matches = this.matches;
 +    var textDivs = this.textDivs;
-     var bidiTexts = this.textContent.bidiTexts;
++    var bidiTexts = this.textContent;
 +    var clearedUntilDivIdx = -1;
 +
 +    // Clear out all current matches.
 +    for (var i = 0; i < matches.length; i++) {
 +      var match = matches[i];
 +      var begin = Math.max(clearedUntilDivIdx, match.begin.divIdx);
 +      for (var n = begin; n <= match.end.divIdx; n++) {
 +        var div = textDivs[n];
 +        div.textContent = bidiTexts[n].str;
 +        div.className = '';
 +      }
 +      clearedUntilDivIdx = match.end.divIdx + 1;
 +    }
 +
-     if (!PDFFindController.active)
++    if (PDFFindController === null || !PDFFindController.active)
 +      return;
 +
 +    // Convert the matches on the page controller into the match format used
 +    // for the textLayer.
 +    this.matches = matches =
-       this.convertMatches(PDFFindController.pageMatches[this.pageIdx] || []);
++      this.convertMatches(PDFFindController === null ?
++          [] : (PDFFindController.pageMatches[this.pageIdx] || []));
 +
 +    this.renderMatches(this.matches);
 +  };
 +};
 +
- document.addEventListener('DOMContentLoaded', function webViewerLoad(evt) {
-   PDFView.initialize();
-   var params = PDFView.parseQueryString(document.location.search.substring(1));
 +
-   var file = params.file || DEFAULT_URL;
 +
-   if (!window.File || !window.FileReader || !window.FileList || !window.Blob) {
-     document.getElementById('openFile').setAttribute('hidden', 'true');
-   } else {
-     document.getElementById('fileInput').value = null;
++var DocumentOutlineView = function documentOutlineView(outline) {
++  var outlineView = document.getElementById('outlineView');
++  var outlineButton = document.getElementById('viewOutline');
++  while (outlineView.firstChild)
++    outlineView.removeChild(outlineView.firstChild);
++
++  if (!outline) {
++    if (!outlineView.classList.contains('hidden'))
++      PDFView.switchSidebarView('thumbs');
++
++    return;
++  }
++
++  function bindItemLink(domObj, item) {
++    domObj.href = PDFView.getDestinationHash(item.dest);
++    domObj.onclick = function documentOutlineViewOnclick(e) {
++      PDFView.navigateTo(item.dest);
++      return false;
++    };
++  }
++
++
++  var queue = [{parent: outlineView, items: outline}];
++  while (queue.length > 0) {
++    var levelData = queue.shift();
++    var i, n = levelData.items.length;
++    for (i = 0; i < n; i++) {
++      var item = levelData.items[i];
++      var div = document.createElement('div');
++      div.className = 'outlineItem';
++      var a = document.createElement('a');
++      bindItemLink(a, item);
++      a.textContent = item.title;
++      div.appendChild(a);
++
++      if (item.items.length > 0) {
++        var itemsDiv = document.createElement('div');
++        itemsDiv.className = 'outlineItems';
++        div.appendChild(itemsDiv);
++        queue.push({parent: itemsDiv, items: item.items});
++      }
++
++      levelData.parent.appendChild(div);
++    }
 +  }
++};
++
++
++function webViewerLoad(evt) {
++  PDFView.initialize();
++
++  var params = PDFView.parseQueryString(document.location.search.substring(1));
++  var file = 'file' in params ? params.file : DEFAULT_URL;
++
++  // fileInput element removed because it is unused
 +
 +  // Special debugging flags in the hash section of the URL.
 +  var hash = document.location.hash.substring(1);
 +  var hashParams = PDFView.parseQueryString(hash);
 +
-   if ('disableWorker' in hashParams)
++  if ('disableWorker' in hashParams) {
 +    PDFJS.disableWorker = (hashParams['disableWorker'] === 'true');
++  }
++
++  if ('disableRange' in hashParams) {
++    PDFJS.disableRange = (hashParams['disableRange'] === 'true');
++  }
++
++  if ('disableAutoFetch' in hashParams) {
++    PDFJS.disableAutoFetch = (hashParams['disableAutoFetch'] === 'true');
++  }
++
++  if ('disableFontFace' in hashParams) {
++    PDFJS.disableFontFace = (hashParams['disableFontFace'] === 'true');
++  }
++
++  if ('disableHistory' in hashParams) {
++    PDFJS.disableHistory = (hashParams['disableHistory'] === 'true');
++  }
++
++  if ('useOnlyCssZoom' in hashParams) {
++    USE_ONLY_CSS_ZOOM = (hashParams['useOnlyCssZoom'] === 'true');
++  }
++
++  if ('verbosity' in hashParams) {
++    PDFJS.verbosity = hashParams['verbosity'] | 0;
++  }
++
++  if ('ignoreCurrentPositionOnZoom' in hashParams) {
++    IGNORE_CURRENT_POSITION_ON_ZOOM =
++      (hashParams['ignoreCurrentPositionOnZoom'] === 'true');
++  }
 +
-   var locale = navigator.language;
++  var locale = PDFJS.locale || navigator.language;
 +  if ('locale' in hashParams)
 +    locale = hashParams['locale'];
 +  mozL10n.setLanguage(locale);
 +
 +  if ('textLayer' in hashParams) {
 +    switch (hashParams['textLayer']) {
 +      case 'off':
 +        PDFJS.disableTextLayer = true;
 +        break;
 +      case 'visible':
 +      case 'shadow':
 +      case 'hover':
 +        var viewer = document.getElementById('viewer');
 +        viewer.classList.add('textLayer-' + hashParams['textLayer']);
 +        break;
 +    }
 +  }
 +
 +  if ('pdfBug' in hashParams) {
 +    PDFJS.pdfBug = true;
 +    var pdfBug = hashParams['pdfBug'];
 +    var enabled = pdfBug.split(',');
 +    PDFBug.enable(enabled);
 +    PDFBug.init();
 +  }
 +
 +  if (!PDFView.supportsPrinting) {
 +    document.getElementById('print').classList.add('hidden');
++    document.getElementById('secondaryPrint').classList.add('hidden');
 +  }
 +
 +  if (!PDFView.supportsFullscreen) {
-     document.getElementById('fullscreen').classList.add('hidden');
++    document.getElementById('presentationMode').classList.add('hidden');
++    document.getElementById('secondaryPresentationMode').
++      classList.add('hidden');
 +  }
 +
 +  if (PDFView.supportsIntegratedFind) {
-     document.querySelector('#viewFind').classList.add('hidden');
++    document.getElementById('viewFind').classList.add('hidden');
 +  }
 +
-   // Listen for warnings to trigger the fallback UI.  Errors should be caught
-   // and call PDFView.error() so we don't need to listen for those.
-   PDFJS.LogManager.addLogger({
-     warn: function() {
-       PDFView.fallback();
-     }
-   });
++  // Listen for unsuporrted features to trigger the fallback UI.
++  PDFJS.UnsupportedManager.listen(PDFView.fallback.bind(PDFView));
++
++  // Suppress context menus for some controls
++  document.getElementById('scaleSelect').oncontextmenu = noContextMenuHandler;
 +
 +  var mainContainer = document.getElementById('mainContainer');
 +  var outerContainer = document.getElementById('outerContainer');
 +  mainContainer.addEventListener('transitionend', function(e) {
 +    if (e.target == mainContainer) {
 +      var event = document.createEvent('UIEvents');
 +      event.initUIEvent('resize', false, false, window, 0);
 +      window.dispatchEvent(event);
 +      outerContainer.classList.remove('sidebarMoving');
 +    }
 +  }, true);
 +
 +  document.getElementById('sidebarToggle').addEventListener('click',
 +    function() {
 +      this.classList.toggle('toggled');
 +      outerContainer.classList.add('sidebarMoving');
 +      outerContainer.classList.toggle('sidebarOpen');
 +      PDFView.sidebarOpen = outerContainer.classList.contains('sidebarOpen');
 +      PDFView.renderHighestPriority();
 +    });
 +
 +  document.getElementById('viewThumbnail').addEventListener('click',
 +    function() {
 +      PDFView.switchSidebarView('thumbs');
 +    });
 +
 +  document.getElementById('viewOutline').addEventListener('click',
 +    function() {
 +      PDFView.switchSidebarView('outline');
 +    });
 +
 +  document.getElementById('previous').addEventListener('click',
 +    function() {
 +      PDFView.page--;
 +    });
 +
 +  document.getElementById('next').addEventListener('click',
 +    function() {
 +      PDFView.page++;
 +    });
 +
-   document.querySelector('.zoomIn').addEventListener('click',
++  document.getElementById('zoomIn').addEventListener('click',
 +    function() {
 +      PDFView.zoomIn();
 +    });
 +
-   document.querySelector('.zoomOut').addEventListener('click',
++  document.getElementById('zoomOut').addEventListener('click',
 +    function() {
 +      PDFView.zoomOut();
 +    });
 +
-   document.getElementById('fullscreen').addEventListener('click',
-     function() {
-       PDFView.fullscreen();
-     });
- 
-   document.getElementById('openFile').addEventListener('click',
-     function() {
-       document.getElementById('fileInput').click();
-     });
- 
-   document.getElementById('print').addEventListener('click',
-     function() {
-       window.print();
-     });
- 
-   document.getElementById('download').addEventListener('click',
-     function() {
-       PDFView.download();
-     });
- 
 +  document.getElementById('pageNumber').addEventListener('click',
 +    function() {
 +      this.select();
 +    });
 +
 +  document.getElementById('pageNumber').addEventListener('change',
 +    function() {
 +      // Handle the user inputting a floating point number.
 +      PDFView.page = (this.value | 0);
 +
 +      if (this.value !== (this.value | 0).toString()) {
 +        this.value = PDFView.page;
 +      }
 +    });
 +
 +  document.getElementById('scaleSelect').addEventListener('change',
 +    function() {
-       PDFView.parseScale(this.value);
++      PDFView.setScale(this.value);
 +    });
 +
-   document.getElementById('first_page').addEventListener('click',
-     function() {
-       PDFView.page = 1;
-     });
++  document.getElementById('presentationMode').addEventListener('click',
++    SecondaryToolbar.presentationModeClick.bind(SecondaryToolbar));
 +
-   document.getElementById('last_page').addEventListener('click',
-     function() {
-       PDFView.page = PDFView.pdfDocument.numPages;
-     });
++  document.getElementById('print').addEventListener('click',
++    SecondaryToolbar.printClick.bind(SecondaryToolbar));
 +
-   document.getElementById('page_rotate_ccw').addEventListener('click',
-     function() {
-       PDFView.rotatePages(-90);
-     });
++  document.getElementById('download').addEventListener('click',
++    SecondaryToolbar.downloadClick.bind(SecondaryToolbar));
 +
-   document.getElementById('page_rotate_cw').addEventListener('click',
-     function() {
-       PDFView.rotatePages(90);
-     });
 +
++  if (file) {
++	// owncould customization to load file from files app
++	PDFView.open(OC.linkTo('files', 'ajax/download.php')+"?files="+encodeURIComponent(window.file)+"&dir="+encodeURIComponent(window.dir), 1.0);
++  }
 +
-   PDFView.open(OC.linkTo('files', 'ajax/download.php')+"?files="+encodeURIComponent(window.file)+"&dir="+encodeURIComponent(window.dir), 1.0);
- }, true);
++}
++
++document.addEventListener('DOMContentLoaded', webViewerLoad, true);
 +
 +function updateViewarea() {
 +
 +  if (!PDFView.initialized)
 +    return;
 +  var visible = PDFView.getVisiblePages();
 +  var visiblePages = visible.views;
 +  if (visiblePages.length === 0) {
 +    return;
 +  }
 +
 +  PDFView.renderHighestPriority();
 +
 +  var currentId = PDFView.page;
 +  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 === PDFView.page) {
 +      stillFullyVisible = true;
 +      break;
 +    }
 +  }
 +
 +  if (!stillFullyVisible) {
 +    currentId = visiblePages[0].id;
 +  }
 +
-   if (!PDFView.isFullscreen) {
++  if (!PresentationMode.active) {
 +    updateViewarea.inProgress = true; // used in "set page"
 +    PDFView.page = currentId;
 +    updateViewarea.inProgress = false;
 +  }
 +
 +  var currentScale = PDFView.currentScale;
 +  var currentScaleValue = PDFView.currentScaleValue;
-   var normalizedScaleValue = currentScaleValue == currentScale ?
-     currentScale * 100 : currentScaleValue;
++  var normalizedScaleValue = parseFloat(currentScaleValue) === currentScale ?
++    Math.round(currentScale * 10000) / 100 : currentScaleValue;
 +
 +  var pageNumber = firstPage.id;
 +  var pdfOpenParams = '#page=' + pageNumber;
 +  pdfOpenParams += '&zoom=' + normalizedScaleValue;
 +  var currentPage = PDFView.pages[pageNumber - 1];
-   var topLeft = currentPage.getPagePoint(PDFView.container.scrollLeft,
-     (PDFView.container.scrollTop - firstPage.y));
-   pdfOpenParams += ',' + Math.round(topLeft[0]) + ',' + Math.round(topLeft[1]);
++  var container = PDFView.container;
++  var topLeft = currentPage.getPagePoint((container.scrollLeft - firstPage.x),
++                                         (container.scrollTop - firstPage.y));
++  var intLeft = Math.round(topLeft[0]);
++  var intTop = Math.round(topLeft[1]);
++  pdfOpenParams += ',' + intLeft + ',' + intTop;
++
++  if (PresentationMode.active || PresentationMode.switchInProgress) {
++    PDFView.currentPosition = null;
++  } else {
++    PDFView.currentPosition = { page: pageNumber, left: intLeft, top: intTop };
++  }
 +
 +  var store = PDFView.store;
 +  store.initializedPromise.then(function() {
 +    store.set('exists', true);
 +    store.set('page', pageNumber);
 +    store.set('zoom', normalizedScaleValue);
-     store.set('scrollLeft', Math.round(topLeft[0]));
-     store.set('scrollTop', Math.round(topLeft[1]));
++    store.set('scrollLeft', intLeft);
++    store.set('scrollTop', intTop);
 +  });
 +  var href = PDFView.getAnchorUrl(pdfOpenParams);
 +  document.getElementById('viewBookmark').href = href;
++  document.getElementById('secondaryViewBookmark').href = href;
++
++  // Update the current bookmark in the browsing history.
++  PDFHistory.updateCurrentBookmark(pdfOpenParams, pageNumber);
 +}
 +
 +window.addEventListener('resize', function webViewerResize(evt) {
 +  if (PDFView.initialized &&
 +      (document.getElementById('pageWidthOption').selected ||
-       document.getElementById('pageFitOption').selected ||
-       document.getElementById('pageAutoOption').selected))
-       PDFView.parseScale(document.getElementById('scaleSelect').value);
++       document.getElementById('pageFitOption').selected ||
++       document.getElementById('pageAutoOption').selected)) {
++    PDFView.setScale(document.getElementById('scaleSelect').value);
++  }
 +  updateViewarea();
++
++  // Set the 'max-height' CSS property of the secondary toolbar.
++  SecondaryToolbar.setMaxHeight(PDFView.container);
 +});
 +
 +window.addEventListener('hashchange', function webViewerHashchange(evt) {
-   PDFView.setHash(document.location.hash.substring(1));
++  if (PDFHistory.isHashChangeUnlocked) {
++    PDFView.setHash(document.location.hash.substring(1));
++  }
 +});
 +
 +window.addEventListener('change', function webViewerChange(evt) {
 +  var files = evt.target.files;
 +  if (!files || files.length === 0)
 +    return;
 +
-   // Read the local file into a Uint8Array.
-   var fileReader = new FileReader();
-   fileReader.onload = function webViewerChangeFileReaderOnload(evt) {
-     var buffer = evt.target.result;
-     var uint8Array = new Uint8Array(buffer);
-     PDFView.open(uint8Array, 0);
-   };
- 
 +  var file = files[0];
-   fileReader.readAsArrayBuffer(file);
++
++  if (!PDFJS.disableCreateObjectURL &&
++      typeof URL !== 'undefined' && URL.createObjectURL) {
++    PDFView.open(URL.createObjectURL(file), 0);
++  } else {
++    // Read the local file into a Uint8Array.
++    var fileReader = new FileReader();
++    fileReader.onload = function webViewerChangeFileReaderOnload(evt) {
++      var buffer = evt.target.result;
++      var uint8Array = new Uint8Array(buffer);
++      PDFView.open(uint8Array, 0);
++    };
++    fileReader.readAsArrayBuffer(file);
++  }
++
 +  PDFView.setTitleUsingUrl(file.name);
 +
 +  // URL does not reflect proper document location - hiding some icons.
 +  document.getElementById('viewBookmark').setAttribute('hidden', 'true');
++  document.getElementById('secondaryViewBookmark').
++    setAttribute('hidden', 'true');
 +  document.getElementById('download').setAttribute('hidden', 'true');
++  document.getElementById('secondaryDownload').setAttribute('hidden', 'true');
 +}, true);
 +
 +function selectScaleOption(value) {
 +  var options = document.getElementById('scaleSelect').options;
 +  var predefinedValueFound = false;
 +  for (var i = 0; i < options.length; i++) {
 +    var option = options[i];
 +    if (option.value != value) {
 +      option.selected = false;
 +      continue;
 +    }
 +    option.selected = true;
 +    predefinedValueFound = true;
 +  }
 +  return predefinedValueFound;
 +}
 +
 +window.addEventListener('localized', function localized(evt) {
 +  document.getElementsByTagName('html')[0].dir = mozL10n.getDirection();
 +
-   // Adjust the width of the zoom box to fit the content.
-   PDFView.animationStartedPromise.then(
-     function() {
-       var container = document.getElementById('scaleSelectContainer');
++  PDFView.animationStartedPromise.then(function() {
++    // Adjust the width of the zoom box to fit the content.
++    // Note: This is only done if the zoom box is actually visible,
++    // since otherwise element.clientWidth will return 0.
++    var container = document.getElementById('scaleSelectContainer');
++    if (container.clientWidth > 0) {
 +      var select = document.getElementById('scaleSelect');
 +      select.setAttribute('style', 'min-width: inherit;');
-       var width = select.clientWidth + 8;
-       select.setAttribute('style', 'min-width: ' + (width + 20) + 'px;');
++      var width = select.clientWidth + SCALE_SELECT_CONTAINER_PADDING;
++      select.setAttribute('style', 'min-width: ' +
++                                   (width + SCALE_SELECT_PADDING) + 'px;');
 +      container.setAttribute('style', 'min-width: ' + width + 'px; ' +
 +                                      'max-width: ' + width + 'px;');
++    }
++
++    // Set the 'max-height' CSS property of the secondary toolbar.
++    SecondaryToolbar.setMaxHeight(PDFView.container);
 +  });
 +}, true);
 +
 +window.addEventListener('scalechange', function scalechange(evt) {
++  document.getElementById('zoomOut').disabled = (evt.scale === MIN_SCALE);
++  document.getElementById('zoomIn').disabled = (evt.scale === MAX_SCALE);
++
 +  var customScaleOption = document.getElementById('customScaleOption');
 +  customScaleOption.selected = false;
 +
 +  if (!evt.resetAutoSettings &&
-        (document.getElementById('pageWidthOption').selected ||
-         document.getElementById('pageFitOption').selected ||
-         document.getElementById('pageAutoOption').selected)) {
-       updateViewarea();
-       return;
++      (document.getElementById('pageWidthOption').selected ||
++       document.getElementById('pageFitOption').selected ||
++       document.getElementById('pageAutoOption').selected)) {
++    updateViewarea();
++    return;
 +  }
 +
 +  var predefinedValueFound = selectScaleOption('' + evt.scale);
 +  if (!predefinedValueFound) {
 +    customScaleOption.textContent = Math.round(evt.scale * 10000) / 100 + '%';
 +    customScaleOption.selected = true;
 +  }
-   
-   document.getElementById('zoom_out').disabled = (evt.scale === MIN_SCALE);
-   document.getElementById('zoom_in').disabled = (evt.scale === MAX_SCALE);
- 
 +  updateViewarea();
 +}, true);
 +
 +window.addEventListener('pagechange', function pagechange(evt) {
 +  var page = evt.pageNumber;
 +  if (PDFView.previousPageNumber !== page) {
 +    document.getElementById('pageNumber').value = page;
 +    var selected = document.querySelector('.thumbnail.selected');
-     if (selected)
++    if (selected) {
 +      selected.classList.remove('selected');
++    }
 +    var thumbnail = document.getElementById('thumbnailContainer' + page);
 +    thumbnail.classList.add('selected');
 +    var visibleThumbs = PDFView.getVisibleThumbs();
 +    var numVisibleThumbs = visibleThumbs.views.length;
-     // If the thumbnail isn't currently visible scroll it into view.
++
++    // If the thumbnail isn't currently visible, scroll it into view.
 +    if (numVisibleThumbs > 0) {
 +      var first = visibleThumbs.first.id;
 +      // Account for only one thumbnail being visible.
-       var last = numVisibleThumbs > 1 ?
-                   visibleThumbs.last.id : first;
-       if (page <= first || page >= last)
-         scrollIntoView(thumbnail);
++      var last = (numVisibleThumbs > 1 ? visibleThumbs.last.id : first);
++      if (page <= first || page >= last) {
++        scrollIntoView(thumbnail, { top: THUMBNAIL_SCROLL_MARGIN });
++      }
 +    }
- 
 +  }
 +  document.getElementById('previous').disabled = (page <= 1);
 +  document.getElementById('next').disabled = (page >= PDFView.pages.length);
 +}, true);
 +
- // Firefox specific event, so that we can prevent browser from zooming
- window.addEventListener('DOMMouseScroll', function(evt) {
-   if (evt.ctrlKey) {
-     evt.preventDefault();
- 
-     var ticks = evt.detail;
-     var direction = (ticks > 0) ? 'zoomOut' : 'zoomIn';
-     for (var i = 0, length = Math.abs(ticks); i < length; i++)
-       PDFView[direction]();
-   } else if (PDFView.isFullscreen) {
-     var FIREFOX_DELTA_FACTOR = -40;
-     PDFView.mouseScroll(evt.detail * FIREFOX_DELTA_FACTOR);
-   }
- }, false);
++function handleMouseWheel(evt) {
++  var MOUSE_WHEEL_DELTA_FACTOR = 40;
++  var ticks = (evt.type === 'DOMMouseScroll') ? -evt.detail :
++              evt.wheelDelta / MOUSE_WHEEL_DELTA_FACTOR;
++  var direction = (ticks < 0) ? 'zoomOut' : 'zoomIn';
 +
- window.addEventListener('mousemove', function mousemove(evt) {
-   if (PDFView.isFullscreen) {
-     PDFView.showPresentationControls();
++  if (evt.ctrlKey) { // Only zoom the pages, not the entire viewer
++    evt.preventDefault();
++    PDFView[direction](Math.abs(ticks));
++  } else if (PresentationMode.active) {
++    PDFView.mouseScroll(ticks * MOUSE_WHEEL_DELTA_FACTOR);
 +  }
- }, false);
++}
 +
- window.addEventListener('mousedown', function mousedown(evt) {
-   if (PDFView.isFullscreen && evt.button === 0) {
-     // Enable clicking of links in fullscreen mode.
-     // Note: Only links that point to the currently loaded PDF document works.
-     var targetHref = evt.target.href;
-     var internalLink = targetHref && (targetHref.replace(/#.*$/, '') ===
-                                       window.location.href.replace(/#.*$/, ''));
-     if (!internalLink) {
-       // Unless an internal link was clicked, advance a page in fullscreen mode.
-       evt.preventDefault();
-       PDFView.page++;
-     }
-   }
- }, false);
++window.addEventListener('DOMMouseScroll', handleMouseWheel);
++window.addEventListener('mousewheel', handleMouseWheel);
 +
 +window.addEventListener('click', function click(evt) {
-   if (PDFView.isFullscreen && evt.button === 0) {
++  if (!PresentationMode.active) {
++    if (SecondaryToolbar.opened && PDFView.container.contains(evt.target)) {
++      SecondaryToolbar.close();
++    }
++  } else if (evt.button === 0) {
 +    // Necessary since preventDefault() in 'mousedown' won't stop
-     // the event propagation in all circumstances.
++    // the event propagation in all circumstances in presentation mode.
 +    evt.preventDefault();
 +  }
 +}, false);
 +
 +window.addEventListener('keydown', function keydown(evt) {
++  if (PasswordPrompt.visible) {
++    return;
++  }
++
 +  var handled = false;
 +  var cmd = (evt.ctrlKey ? 1 : 0) |
 +            (evt.altKey ? 2 : 0) |
 +            (evt.shiftKey ? 4 : 0) |
 +            (evt.metaKey ? 8 : 0);
 +
 +  // First, handle the key bindings that are independent whether an input
 +  // control is selected or not.
 +  if (cmd === 1 || cmd === 8 || cmd === 5 || cmd === 12) {
 +    // either CTRL or META key with optional SHIFT.
 +    switch (evt.keyCode) {
-       case 70:
++      case 70: // f
++        if (!PDFView.supportsIntegratedFind) {
++          PDFFindBar.open();
++          handled = true;
++        }
++        break;
++      case 71: // g
 +        if (!PDFView.supportsIntegratedFind) {
-           PDFFindBar.toggle();
++          PDFFindBar.dispatchEvent('again', cmd === 5 || cmd === 12);
 +          handled = true;
 +        }
 +        break;
 +      case 61: // FF/Mac '='
 +      case 107: // FF '+' and '='
 +      case 187: // Chrome '+'
 +      case 171: // FF with German keyboard
 +        PDFView.zoomIn();
 +        handled = true;
 +        break;
 +      case 173: // FF/Mac '-'
 +      case 109: // FF '-'
 +      case 189: // Chrome '-'
 +        PDFView.zoomOut();
 +        handled = true;
 +        break;
 +      case 48: // '0'
 +      case 96: // '0' on Numpad of Swedish keyboard
-         PDFView.parseScale(DEFAULT_SCALE, true);
-         handled = false; // keeping it unhandled (to restore page zoom to 100%)
++        // keeping it unhandled (to restore page zoom to 100%)
++        setTimeout(function () {
++          // ... and resetting the scale after browser adjusts its scale
++          PDFView.setScale(DEFAULT_SCALE, true);
++        });
++        handled = false;
++        break;
++    }
++  }
++
++  // CTRL or META without shift
++  if (cmd === 1 || cmd === 8) {
++    switch (evt.keyCode) {
++      case 83: // s
++        PDFView.download();
++        handled = true;
 +        break;
 +    }
 +  }
 +
-   // CTRL or META with or without SHIFT.
-   if (cmd == 1 || cmd == 8 || cmd == 5 || cmd == 12) {
++  // CTRL+ALT or Option+Command
++  if (cmd === 3 || cmd === 10) {
 +    switch (evt.keyCode) {
++      case 80: // p
++        SecondaryToolbar.presentationModeClick();
++        handled = true;
++        break;
 +      case 71: // g
-         if (!PDFView.supportsIntegratedFind) {
-           PDFFindBar.dispatchEvent('again', cmd == 5 || cmd == 12);
-           handled = true;
-         }
++        // focuses input#pageNumber field
++        document.getElementById('pageNumber').select();
++        handled = true;
 +        break;
 +    }
 +  }
 +
 +  if (handled) {
 +    evt.preventDefault();
 +    return;
 +  }
 +
 +  // Some shortcuts should not get handled if a control/input element
 +  // is selected.
-   var curElement = document.activeElement;
-   if (curElement && (curElement.tagName == 'INPUT' ||
-                      curElement.tagName == 'SELECT')) {
-     return;
-   }
-   var controlsElement = document.getElementById('toolbar');
-   while (curElement) {
-     if (curElement === controlsElement && !PDFView.isFullscreen)
-       return; // ignoring if the 'toolbar' element is focused
-     curElement = curElement.parentNode;
++  var curElement = document.activeElement || document.querySelector(':focus');
++  var curElementTagName = curElement && curElement.tagName.toUpperCase();
++  if (curElementTagName === 'INPUT' ||
++      curElementTagName === 'TEXTAREA' ||
++      curElementTagName === 'SELECT') {
++    // Make sure that the secondary toolbar is closed when Escape is pressed.
++    if (evt.keyCode !== 27) { // 'Esc'
++      return;
++    }
 +  }
 +
 +  if (cmd === 0) { // no control key pressed at all.
 +    switch (evt.keyCode) {
 +      case 38: // up arrow
 +      case 33: // pg up
 +      case 8: // backspace
-         if (!PDFView.isFullscreen && PDFView.currentScaleValue !== 'page-fit') {
++        if (!PresentationMode.active &&
++            PDFView.currentScaleValue !== 'page-fit') {
 +          break;
 +        }
-         /* in fullscreen mode */
++        /* in presentation mode */
 +        /* falls through */
 +      case 37: // left arrow
 +        // horizontal scrolling using arrow keys
 +        if (PDFView.isHorizontalScrollbarEnabled) {
 +          break;
 +        }
 +        /* falls through */
 +      case 75: // 'k'
 +      case 80: // 'p'
 +        PDFView.page--;
 +        handled = true;
 +        break;
 +      case 27: // esc key
++        if (SecondaryToolbar.opened) {
++          SecondaryToolbar.close();
++          handled = true;
++        }
 +        if (!PDFView.supportsIntegratedFind && PDFFindBar.opened) {
 +          PDFFindBar.close();
 +          handled = true;
 +        }
 +        break;
 +      case 40: // down arrow
 +      case 34: // pg down
 +      case 32: // spacebar
-         if (!PDFView.isFullscreen && PDFView.currentScaleValue !== 'page-fit') {
++        if (!PresentationMode.active &&
++            PDFView.currentScaleValue !== 'page-fit') {
 +          break;
 +        }
 +        /* falls through */
 +      case 39: // right arrow
 +        // horizontal scrolling using arrow keys
 +        if (PDFView.isHorizontalScrollbarEnabled) {
 +          break;
 +        }
 +        /* falls through */
 +      case 74: // 'j'
 +      case 78: // 'n'
 +        PDFView.page++;
 +        handled = true;
 +        break;
 +
 +      case 36: // home
-         if (PDFView.isFullscreen) {
++        if (PresentationMode.active) {
 +          PDFView.page = 1;
 +          handled = true;
 +        }
 +        break;
 +      case 35: // end
-         if (PDFView.isFullscreen) {
++        if (PresentationMode.active) {
 +          PDFView.page = PDFView.pdfDocument.numPages;
 +          handled = true;
 +        }
 +        break;
 +
++      case 72: // 'h'
++        if (!PresentationMode.active) {
++          HandTool.toggle();
++        }
++        break;
 +      case 82: // 'r'
 +        PDFView.rotatePages(90);
 +        break;
 +    }
 +  }
 +
-   if (cmd == 4) { // shift-key
++  if (cmd === 4) { // shift-key
 +    switch (evt.keyCode) {
++      case 32: // spacebar
++        if (!PresentationMode.active &&
++            PDFView.currentScaleValue !== 'page-fit') {
++          break;
++        }
++        PDFView.page--;
++        handled = true;
++        break;
++
 +      case 82: // 'r'
 +        PDFView.rotatePages(-90);
 +        break;
 +    }
 +  }
 +
++  if (!handled && !PresentationMode.active) {
++    // 33=Page Up  34=Page Down  35=End    36=Home
++    // 37=Left     38=Up         39=Right  40=Down
++    if (evt.keyCode >= 33 && evt.keyCode <= 40 &&
++        !PDFView.container.contains(curElement)) {
++      // The page container is not focused, but a page navigation key has been
++      // pressed. Change the focus to the viewer container to make sure that
++      // navigation by keyboard works as expected.
++      PDFView.container.focus();
++    }
++    // 32=Spacebar
++    if (evt.keyCode === 32 && curElementTagName !== 'BUTTON') {
++      if (!PDFView.container.contains(curElement)) {
++        PDFView.container.focus();
++      }
++    }
++  }
++
++  if (cmd === 2) { // alt-key
++    switch (evt.keyCode) {
++      case 37: // left arrow
++        if (PresentationMode.active) {
++          PDFHistory.back();
++          handled = true;
++        }
++        break;
++      case 39: // right arrow
++        if (PresentationMode.active) {
++          PDFHistory.forward();
++          handled = true;
++        }
++        break;
++    }
++  }
++
 +  if (handled) {
 +    evt.preventDefault();
 +    PDFView.clearMouseScrollState();
 +  }
 +});
 +
 +window.addEventListener('beforeprint', function beforePrint(evt) {
 +  PDFView.beforePrint();
 +});
 +
 +window.addEventListener('afterprint', function afterPrint(evt) {
 +  PDFView.afterPrint();
 +});
 +
- (function fullscreenClosure() {
-   function fullscreenChange(e) {
-     var isFullscreen = document.fullscreenElement || document.mozFullScreen ||
-         document.webkitIsFullScreen;
- 
-     if (!isFullscreen) {
-       PDFView.exitFullscreen();
-     }
-   }
- 
-   window.addEventListener('fullscreenchange', fullscreenChange, false);
-   window.addEventListener('mozfullscreenchange', fullscreenChange, false);
-   window.addEventListener('webkitfullscreenchange', fullscreenChange, false);
- })();
- 
 +(function animationStartedClosure() {
 +  // The offsetParent is not set until the pdf.js iframe or object is visible.
 +  // Waiting for first animation.
 +  var requestAnimationFrame = window.requestAnimationFrame ||
 +                              window.mozRequestAnimationFrame ||
 +                              window.webkitRequestAnimationFrame ||
 +                              window.oRequestAnimationFrame ||
 +                              window.msRequestAnimationFrame ||
 +                              function startAtOnce(callback) { callback(); };
-   PDFView.animationStartedPromise = new PDFJS.Promise();
-   requestAnimationFrame(function onAnimationFrame() {
-     PDFView.animationStartedPromise.resolve();
++  PDFView.animationStartedPromise = new Promise(function (resolve) {
++    requestAnimationFrame(function onAnimationFrame() {
++      resolve();
++    });
 +  });
 +})();
 +
 +
diff --cc apps/files_pdfviewer/appinfo/version
index 2f45361,0000000..be58634
mode 100644,000000..100644
--- a/apps/files_pdfviewer/appinfo/version
+++ b/apps/files_pdfviewer/appinfo/version
@@@ -1,1 -1,0 +1,1 @@@
- 0.2
++0.3
diff --cc apps/files_pdfviewer/js/files.php
index c4d0165,0000000..de68a30
mode 100644,000000..100644
--- a/apps/files_pdfviewer/js/files.php
+++ b/apps/files_pdfviewer/js/files.php
@@@ -1,28 -1,0 +1,28 @@@
 +<?php
 +/**
 + * Copyright (c) 2013 Lukas Reschke <lukas at statuscode.ch>
 + * This file is licensed under the Affero General Public License version 3 or
 + * later.
 + * See the COPYING-README file.
 + */
 +
 +// Set the content type to Javascript
 +header("Content-type: text/javascript");
 +
 +// Disallow caching
 +header("Cache-Control: no-cache, must-revalidate"); 
 +header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); 
 +
 +$dir = isset($_GET['dir']) ? $_GET['dir'] : '';
 +$file = isset($_GET['file']) ? $_GET['file'] : '';
 +
 +$array = array(
- 	"PDFJS.workerSrc" => OCP\Util::linkTo('files_pdfviewer', '3rdparty/pdfjs/pdf.js'),
++	"PDFJS.workerSrc" => OCP\Util::linkTo('files_pdfviewer', '3rdparty/pdfjs/pdf.worker.js'),
 +	"window.dir" => $dir,
 +	"window.file" => $file,
 +	);
 +
 +// Echo it
 +foreach ($array as  $setting => $value) {
 +	echo($setting ."=".json_encode($value).";\n");
- }
++}
diff --cc apps/files_pdfviewer/js/loader.js
index 5d00d2e,0000000..99683d6
mode 100644,000000..100644
--- a/apps/files_pdfviewer/js/loader.js
+++ b/apps/files_pdfviewer/js/loader.js
@@@ -1,54 -1,0 +1,51 @@@
 +function hidePDFviewer() {
 +	$('#content table').show();
 +	$("#controls").show();
 +	$("#editor").show();
 +	$('#pdframe, #pdfbar').remove();
 +	if ($('#isPublic').val()){
 +		$('#preview').css({height: null});
 +	}
 +}
 +
- function showPDFviewer(dir,filename){
- 	if(!showPDFviewer.shown){
++function showPDFviewer(dir,filename) {
++	if(!showPDFviewer.shown) {
 +		var $iframe;
 +		$("#editor").hide();
 +		$('#content table').hide();
 +		$("#controls").hide();
- 		var oldcontent = $("#content").html();
 +		var viewer = OC.linkTo('files_pdfviewer', 'viewer.php')+'?dir='+encodeURIComponent(dir).replace(/%2F/g, '/')+'&file='+encodeURIComponent(filename);
 +		$iframe = $('<iframe id="pdframe" style="width:100%;height:100%;display:block;" src="'+viewer+'" /><div id="pdfbar"><a id="close" title="Close">X</a></div>');
- 		if ($('#isPublic').val()){
++		if ($('#isPublic').val()) {
 +			// force the preview to adjust its height
 +			$('#preview').append($iframe).css({height: '100%'});
- 		}
- 		else{
++		} else {
 +			$('#content').append($iframe);
 +		}
- 		$("#pageWidthOption").attr("selected","selected");	
- 		$('#pdfbar').css({position:'absolute',top:'5px',right:'5px'});
++		$("#pageWidthOption").attr("selected","selected");
++		$('#pdfbar').css({position:'absolute',top:'6px',right:'5px'});
 +		// if a filelist is present, the PDF viewer can be closed to go back there
- 		if ($('#fileList').length){
- 			$('#close').css({display:'block',padding:'0 5px',color:'#BBBBBB','font-weight':'900',height:'18px',background:'transparent'}).click(function(){
++		if ($('#fileList').length) {
++				$('#close').css({display:'block',padding:'0 5px',color:'#BBBBBB','font-weight':'900','font-size':'16px',height:'18px',background:'transparent'}).click(function(){
 +				hidePDFviewer();
 +			});
- 		}
- 		else{
++		} else {
 +			$('#close').css({display:'none'});
 +		}
 +	}
 +
 +}
 +showPDFviewer.oldCode='';
 +showPDFviewer.lastTitle='';
 +
 +$(document).ready(function(){
 +	// doesn't work in IE or public link mode
 +	if(!$.browser.msie && !$('#isPublic').val()){
 +		if ($('#filesApp').val() && typeof FileActions!=='undefined'){
 +			FileActions.register('application/pdf','Edit', OC.PERMISSION_READ, '',function(filename){
 +				showPDFviewer($('#dir').val(),filename);
 +			});
 +			FileActions.setDefault('application/pdf','Edit');
 +		}
 +	}
 +});
diff --cc apps/files_pdfviewer/templates/pdf.php
index b8e90c9,0000000..82a21d5
mode 100644,000000..100644
--- a/apps/files_pdfviewer/templates/pdf.php
+++ b/apps/files_pdfviewer/templates/pdf.php
@@@ -1,194 -1,0 +1,405 @@@
- <!DOCTYPE html>
++<!DOCTYPE html>
++<!--
++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.
++-->
 +<html dir="ltr" mozdisallowselectionprint moznomarginboxes>
 +  <head>
 +    <meta charset="utf-8">
 +    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
++    <meta name="google" content="notranslate">
 +    <title>PDF.js viewer</title>
 +
 +
 +    <link rel="stylesheet" href="<?php print_unescaped(OCP\Util::linkTo('files_pdfviewer', '3rdparty/pdfjs/viewer.css')); ?>"/>
 +
 +    <!-- oC changes-->
-     <script type="text/javascript" src="<?php print_unescaped(OCP\Util::linkTo('core', 'js/jquery-1.10.0.min.js')); ?>"></script>
-     <script type="text/javascript" src="<?php print_unescaped(OCP\Util::linkToRoute('js_config'));?>"></script>
++	<script type="text/javascript" src="<?php print_unescaped(OCP\Util::linkTo('core', 'js/jquery-1.10.0.min.js')); ?>"></script>
++	<script type="text/javascript" src="<?php print_unescaped(OCP\Util::linkTo('core', 'js/jquery-migrate-1.2.1.min.js')); ?>"></script>
++	<script type="text/javascript" src="<?php print_unescaped(OC_Helper::linkTo('core', 'js/jquery-showpassword.js')); ?>"></script>
++	<script type="text/javascript" src="<?php print_unescaped(OC_Helper::linkTo('core', 'js/jquery-tipsy.js')); ?>"></script>
++	<script type="text/javascript" src="<?php print_unescaped(OC_Helper::linkTo('core', 'js/jquery.infieldlabel.js')); ?>"></script>
++	<script type="text/javascript" src="<?php print_unescaped(OCP\Util::linkToRoute('js_config'));?>"></script>
 +    <script type="text/javascript" src="<?php print_unescaped(OCP\Util::linkTo('core', 'js/oc-dialogs.js')); ?>"></script>
-     <script type="text/javascript" src="<?php print_unescaped(OCP\Util::linkTo('core', 'js/js.js')); ?>"></script>
-     <script type="text/javascript" src="<?php print_unescaped(OCP\Util::linkTo('core', 'js/router.js')); ?>"></script>
++	<script type="text/javascript" src="<?php print_unescaped(OCP\Util::linkTo('core', 'js/js.js')); ?>"></script>
++	<script type="text/javascript" src="<?php print_unescaped(OCP\Util::linkTo('core', 'js/router.js')); ?>"></script>
 +    <!-- oC changes -->
 +
 +    <script type="text/javascript" src="<?php print_unescaped(OCP\Util::linkTo('files_pdfviewer', '3rdparty/pdfjs/compatibility.js')); ?>"></script>
 +
 +
-     <link rel="resource" type="application/l10n" href="<?php print_unescaped(OCP\Util::linkTo('files_pdfviewer', '3rdparty/pdfjs/locale/locale.properties')); ?>"/>
-     <script type="text/javascript" src="<?php print_unescaped(OCP\Util::linkTo('files_pdfviewer', '3rdparty/pdfjs/l10n.js')); ?>"></script>
++
++    <!-- This snippet is used in production, see Makefile -->
++    <link rel="resource" type="application/l10n" href="<?php print_unescaped(OCP\Util::linkTo('files_pdfviewer', '3rdparty/pdfjs/locale/locale.properties')); ?>" />
++    <script type="text/javascript" src=<?php print_unescaped(OCP\Util::linkTo('files_pdfviewer', '3rdparty/pdfjs/l10n.js')); ?>></script>
 +    <script type="text/javascript" src="<?php print_unescaped(OCP\Util::linkTo('files_pdfviewer', '3rdparty/pdfjs/pdf.js')); ?>"></script>
 +
-     <script type="text/javascript" src="<?php print_unescaped(OCP\Util::linkTo('files_pdfviewer', 'js/files.php')); ?>?file=<?php print_unescaped(urlencode($_['file'])); ?>&dir=<?php print_unescaped(urlencode($_['dir'])); ?>"></script>
++
++
 +    <script type="text/javascript" src="<?php print_unescaped(OCP\Util::linkTo('files_pdfviewer', '3rdparty/pdfjs/viewer.js')); ?>"></script>
++    <script type="text/javascript" src="<?php print_unescaped(OCP\Util::linkTo('files_pdfviewer', 'js/files.php')); ?>?file=<?php print_unescaped(urlencode($_['file'])); ?>&dir=<?php print_unescaped(urlencode($_['dir'])); ?>"></script>
++
 +  </head>
 +
-   <body>
-     <div id="outerContainer">
++  <body tabindex="1">
++    <div id="outerContainer" class="loadingInProgress">
 +
 +      <div id="sidebarContainer">
 +        <div id="toolbarSidebar">
 +          <div class="splitToolbarButton toggled">
 +            <button id="viewThumbnail" class="toolbarButton group toggled" title="Show Thumbnails" tabindex="2" data-l10n-id="thumbs">
 +               <span data-l10n-id="thumbs_label">Thumbnails</span>
 +            </button>
 +            <button id="viewOutline" class="toolbarButton group" title="Show Document Outline" tabindex="3" data-l10n-id="outline">
 +               <span data-l10n-id="outline_label">Document Outline</span>
 +            </button>
 +          </div>
 +        </div>
 +        <div id="sidebarContent">
 +          <div id="thumbnailView">
 +          </div>
 +          <div id="outlineView" class="hidden">
 +          </div>
 +        </div>
 +      </div>  <!-- sidebarContainer -->
 +
 +      <div id="mainContainer">
 +        <div class="findbar hidden doorHanger hiddenSmallView" id="findbar">
 +          <label for="findInput" class="toolbarLabel" data-l10n-id="find_label">Find:</label>
-           <input id="findInput" class="toolbarField" tabindex="21">
++          <input id="findInput" class="toolbarField" tabindex="41">
 +          <div class="splitToolbarButton">
-             <button class="toolbarButton findPrevious" title="" id="findPrevious" tabindex="22" data-l10n-id="find_previous">
++            <button class="toolbarButton findPrevious" title="" id="findPrevious" tabindex="42" data-l10n-id="find_previous">
 +              <span data-l10n-id="find_previous_label">Previous</span>
 +            </button>
 +            <div class="splitToolbarButtonSeparator"></div>
-             <button class="toolbarButton findNext" title="" id="findNext" tabindex="23" data-l10n-id="find_next">
++            <button class="toolbarButton findNext" title="" id="findNext" tabindex="43" data-l10n-id="find_next">
 +              <span data-l10n-id="find_next_label">Next</span>
 +            </button>
 +          </div>
 +          <input type="checkbox" id="findHighlightAll" class="toolbarField">
-           <label for="findHighlightAll" class="toolbarLabel" tabindex="24" data-l10n-id="find_highlight">Highlight all</label>
++          <label for="findHighlightAll" class="toolbarLabel" tabindex="44" data-l10n-id="find_highlight">Highlight all</label>
 +          <input type="checkbox" id="findMatchCase" class="toolbarField">
-           <label for="findMatchCase" class="toolbarLabel" tabindex="25" data-l10n-id="find_match_case_label">Match case</label>
++          <label for="findMatchCase" class="toolbarLabel" tabindex="45" data-l10n-id="find_match_case_label">Match case</label>
 +          <span id="findMsg" class="toolbarLabel"></span>
-         </div>
++        </div>  <!-- findbar -->
++
++        <div id="secondaryToolbar" class="secondaryToolbar hidden doorHangerRight">
++          <div id="secondaryToolbarButtonContainer">
++            <button id="secondaryPresentationMode" class="secondaryToolbarButton presentationMode visibleLargeView" title="Switch to Presentation Mode" tabindex="18" data-l10n-id="presentation_mode">
++              <span data-l10n-id="presentation_mode_label">Presentation Mode</span>
++            </button>
++
++            <button id="secondaryPrint" class="secondaryToolbarButton print visibleMediumView" title="Print" tabindex="20" data-l10n-id="print">
++              <span data-l10n-id="print_label">Print</span>
++            </button>
++
++            <button id="secondaryDownload" class="secondaryToolbarButton download visibleMediumView" title="Download" tabindex="21" data-l10n-id="download">
++              <span data-l10n-id="download_label">Download</span>
++            </button>
++
++            <a href="#" id="secondaryViewBookmark" class="secondaryToolbarButton bookmark visibleSmallView" title="Current view (copy or open in new window)" tabindex="22" data-l10n-id="bookmark">
++              <span data-l10n-id="bookmark_label">Current View</span>
++            </a>
++
++            <div class="horizontalToolbarSeparator visibleLargeView"></div>
++
++            <button id="firstPage" class="secondaryToolbarButton firstPage" title="Go to First Page" tabindex="23" data-l10n-id="first_page">
++              <span data-l10n-id="first_page_label">Go to First Page</span>
++            </button>
++            <button id="lastPage" class="secondaryToolbarButton lastPage" title="Go to Last Page" tabindex="24" data-l10n-id="last_page">
++              <span data-l10n-id="last_page_label">Go to Last Page</span>
++            </button>
++
++            <div class="horizontalToolbarSeparator"></div>
++
++            <button id="pageRotateCw" class="secondaryToolbarButton rotateCw" title="Rotate Clockwise" tabindex="25" data-l10n-id="page_rotate_cw">
++              <span data-l10n-id="page_rotate_cw_label">Rotate Clockwise</span>
++            </button>
++            <button id="pageRotateCcw" class="secondaryToolbarButton rotateCcw" title="Rotate Counterclockwise" tabindex="26" data-l10n-id="page_rotate_ccw">
++              <span data-l10n-id="page_rotate_ccw_label">Rotate Counterclockwise</span>
++            </button>
++
++            <div class="horizontalToolbarSeparator"></div>
++
++            <button id="toggleHandTool" class="secondaryToolbarButton handTool" title="Enable hand tool" tabindex="27" data-l10n-id="hand_tool_enable">
++              <span data-l10n-id="hand_tool_enable_label">Enable hand tool</span>
++            </button>
++            
++            <div class="horizontalToolbarSeparator"></div>
++
++            <button id="documentProperties" class="secondaryToolbarButton documentProperties" title="Document Properties…" tabindex="28" data-l10n-id="document_properties">
++              <span data-l10n-id="document_properties_label">Document Properties…</span>
++            </button>
++          </div>
++        </div>  <!-- secondaryToolbar -->
++
 +        <div class="toolbar">
 +          <div id="toolbarContainer">
 +            <div id="toolbarViewer">
 +              <div id="toolbarViewerLeft">
 +                <button id="sidebarToggle" class="toolbarButton" title="Toggle Sidebar" tabindex="4" data-l10n-id="toggle_sidebar">
 +                  <span data-l10n-id="toggle_sidebar_label">Toggle Sidebar</span>
 +                </button>
 +                <div class="toolbarButtonSpacer"></div>
 +                <button id="viewFind" class="toolbarButton group hiddenSmallView" title="Find in Document" tabindex="5" data-l10n-id="findbar">
 +                   <span data-l10n-id="findbar_label">Find</span>
 +                </button>
 +                <div class="splitToolbarButton">
 +                  <button class="toolbarButton pageUp" title="Previous Page" id="previous" tabindex="6" data-l10n-id="previous">
 +                    <span data-l10n-id="previous_label">Previous</span>
 +                  </button>
 +                  <div class="splitToolbarButtonSeparator"></div>
 +                  <button class="toolbarButton pageDown" title="Next Page" id="next" tabindex="7" data-l10n-id="next">
 +                    <span data-l10n-id="next_label">Next</span>
 +                  </button>
 +                </div>
 +                <label id="pageNumberLabel" class="toolbarLabel" for="pageNumber" data-l10n-id="page_label">Page: </label>
 +                <input type="number" id="pageNumber" class="toolbarField pageNumber" value="1" size="4" min="1" tabindex="8">
-                 </input>
 +                <span id="numPages" class="toolbarLabel"></span>
 +              </div>
 +              <div id="toolbarViewerRight">
-                 <input id="fileInput" class="fileInput" type="file" oncontextmenu="return false;" style="visibility: hidden; position: fixed; right: 0; top: 0" />
- 
-                 <button id="fullscreen" class="toolbarButton fullscreen hiddenSmallView" title="Switch to Presentation Mode" tabindex="12" data-l10n-id="presentation_mode">
++                <button id="presentationMode" class="toolbarButton presentationMode hiddenLargeView" title="Switch to Presentation Mode" tabindex="12" data-l10n-id="presentation_mode">
 +                  <span data-l10n-id="presentation_mode_label">Presentation Mode</span>
 +                </button>
 +
-                 <button id="openFile" class="toolbarButton openFile hiddenSmallView" title="Open File" tabindex="13" data-l10n-id="open_file">
-                    <span data-l10n-id="open_file_label">Open</span>
-                 </button>
- 
-                 <button id="print" class="toolbarButton print" title="Print" tabindex="14" data-l10n-id="print">
++                <button id="print" class="toolbarButton print hiddenMediumView" title="Print" tabindex="14" data-l10n-id="print">
 +                  <span data-l10n-id="print_label">Print</span>
 +                </button>
 +
-                 <button id="download" class="toolbarButton download" title="Download" tabindex="15" data-l10n-id="download">
++                <button id="download" class="toolbarButton download hiddenMediumView" title="Download" tabindex="15" data-l10n-id="download">
 +                  <span data-l10n-id="download_label">Download</span>
-                 </button> 
- 
++                </button>
 +                <!-- <div class="toolbarButtonSpacer"></div> -->
-                 <a href="#" id="viewBookmark" class="toolbarButton bookmark hiddenSmallView" title="Current view (copy or open in new window)" tabindex="16" data-l10n-id="bookmark"><span data-l10n-id="bookmark_label">Current View</span></a>
++                <a href="#" id="viewBookmark" class="toolbarButton bookmark hiddenSmallView" title="Current view (copy or open in new window)" tabindex="16" data-l10n-id="bookmark">
++                  <span data-l10n-id="bookmark_label">Current View</span>
++                </a>
++
++                <div class="verticalToolbarSeparator hiddenSmallView"></div>
++                
++                <button id="secondaryToolbarToggle" class="toolbarButton" title="Tools" tabindex="17" data-l10n-id="tools">
++                  <span data-l10n-id="tools_label">Tools</span>
++                </button> 
 +              </div>
 +              <div class="outerCenter">
 +                <div class="innerCenter" id="toolbarViewerMiddle">
 +                  <div class="splitToolbarButton">
-                     <button class="toolbarButton zoomOut" id="zoom_out" title="Zoom Out" tabindex="9" data-l10n-id="zoom_out">
++                    <button id="zoomOut" class="toolbarButton zoomOut" title="Zoom Out" tabindex="9" data-l10n-id="zoom_out">
 +                      <span data-l10n-id="zoom_out_label">Zoom Out</span>
 +                    </button>
 +                    <div class="splitToolbarButtonSeparator"></div>
-                     <button class="toolbarButton zoomIn" id="zoom_in" title="Zoom In" tabindex="10" data-l10n-id="zoom_in">
++                    <button id="zoomIn" class="toolbarButton zoomIn" title="Zoom In" tabindex="10" data-l10n-id="zoom_in">
 +                      <span data-l10n-id="zoom_in_label">Zoom In</span>
 +                     </button>
 +                  </div>
 +                  <span id="scaleSelectContainer" class="dropdownToolbarButton">
-                      <select id="scaleSelect" title="Zoom" oncontextmenu="return false;" tabindex="11" data-l10n-id="zoom">
++                     <select id="scaleSelect" title="Zoom" tabindex="11" data-l10n-id="zoom">
 +                      <option id="pageAutoOption" value="auto" selected="selected" data-l10n-id="page_scale_auto">Automatic Zoom</option>
 +                      <option id="pageActualOption" value="page-actual" data-l10n-id="page_scale_actual">Actual Size</option>
 +                      <option id="pageFitOption" value="page-fit" data-l10n-id="page_scale_fit">Fit Page</option>
 +                      <option id="pageWidthOption" value="page-width" data-l10n-id="page_scale_width">Full Width</option>
 +                      <option id="customScaleOption" value="custom"></option>
 +                      <option value="0.5">50%</option>
 +                      <option value="0.75">75%</option>
 +                      <option value="1">100%</option>
 +                      <option value="1.25">125%</option>
 +                      <option value="1.5">150%</option>
 +                      <option value="2">200%</option>
 +                    </select>
 +                  </span>
 +                </div>
 +              </div>
 +            </div>
++            <div id="loadingBar">
++              <div class="progress">
++                <div class="glimmer">
++                </div>
++              </div>
++            </div>
 +          </div>
 +        </div>
 +
 +        <menu type="context" id="viewerContextMenu">
-           <menuitem label="First Page" id="first_page"
-                     data-l10n-id="first_page" ></menuitem>
-           <menuitem label="Last Page" id="last_page"
-                     data-l10n-id="last_page" ></menuitem>
-           <menuitem label="Rotate Counter-Clockwise" id="page_rotate_ccw"
-                     data-l10n-id="page_rotate_ccw" ></menuitem>
-           <menuitem label="Rotate Clockwise" id="page_rotate_cw"
-                     data-l10n-id="page_rotate_cw" ></menuitem>
++          <menuitem id="contextFirstPage" label="First Page"
++                    data-l10n-id="first_page"></menuitem>
++          <menuitem id="contextLastPage" label="Last Page"
++                    data-l10n-id="last_page"></menuitem>
++          <menuitem id="contextPageRotateCw" label="Rotate Clockwise"
++                    data-l10n-id="page_rotate_cw"></menuitem>
++          <menuitem id="contextPageRotateCcw" label="Rotate Counter-Clockwise"
++                    data-l10n-id="page_rotate_ccw"></menuitem>
 +        </menu>
 +
-         <div id="viewerContainer" tabindex="1">
-           <div id="viewer" contextmenu="viewerContextMenu"></div>
-         </div>
- 
-         <div id="loadingBox">
-           <div id="loading"></div>
-           <div id="loadingBar"><div class="progress"></div></div>
++        <div id="viewerContainer" tabindex="0">
++          <div id="viewer"></div>
 +        </div>
 +
 +        <div id="errorWrapper" hidden='true'>
 +          <div id="errorMessageLeft">
 +            <span id="errorMessage"></span>
-             <button id="errorShowMore" onclick="" oncontextmenu="return false;" data-l10n-id="error_more_info">
++            <button id="errorShowMore" data-l10n-id="error_more_info">
 +              More Information
 +            </button>
-             <button id="errorShowLess" onclick="" oncontextmenu="return false;" data-l10n-id="error_less_info" hidden='true'>
++            <button id="errorShowLess" data-l10n-id="error_less_info" hidden='true'>
 +              Less Information
 +            </button>
 +          </div>
 +          <div id="errorMessageRight">
-             <button id="errorClose" oncontextmenu="return false;" data-l10n-id="error_close">
++            <button id="errorClose" data-l10n-id="error_close">
 +              Close
 +            </button>
 +          </div>
 +          <div class="clearBoth"></div>
 +          <textarea id="errorMoreInfo" hidden='true' readonly="readonly"></textarea>
 +        </div>
 +      </div> <!-- mainContainer -->
 +
++      <div id="overlayContainer" class="hidden">
++        <div id="promptContainer" class="hidden">
++          <div id="passwordContainer" class="prompt doorHanger">
++            <div class="row">
++              <p id="passwordText" data-l10n-id="password_label">Enter the password to open this PDF file:</p>
++            </div>
++            <div class="row">
++              <input type="password" id="password" class="toolbarField" />
++            </div>
++            <div class="buttonRow">
++              <button id="passwordCancel" class="overlayButton"><span data-l10n-id="password_cancel">Cancel</span></button>
++              <button id="passwordSubmit" class="overlayButton"><span data-l10n-id="password_ok">OK</span></button>
++            </div>
++          </div>
++        </div>
++        <div id="documentPropertiesContainer" class="hidden">
++          <div class="doorHanger">
++            <div class="row">
++              <span data-l10n-id="document_properties_file_name">File name:</span> <p id="fileNameField">-</p>
++            </div>
++            <div class="row">
++              <span data-l10n-id="document_properties_file_size">File size:</span> <p id="fileSizeField">-</p>
++            </div>
++            <div class="separator"></div>
++            <div class="row">
++              <span data-l10n-id="document_properties_title">Title:</span> <p id="titleField">-</p>
++            </div>
++            <div class="row">
++              <span data-l10n-id="document_properties_author">Author:</span> <p id="authorField">-</p>
++            </div>
++            <div class="row">
++              <span data-l10n-id="document_properties_subject">Subject:</span> <p id="subjectField">-</p>
++            </div>
++            <div class="row">
++              <span data-l10n-id="document_properties_keywords">Keywords:</span> <p id="keywordsField">-</p>
++            </div>
++            <div class="row">
++              <span data-l10n-id="document_properties_creation_date">Creation Date:</span> <p id="creationDateField">-</p>
++            </div>
++            <div class="row">
++              <span data-l10n-id="document_properties_modification_date">Modification Date:</span> <p id="modificationDateField">-</p>
++            </div>
++            <div class="row">
++              <span data-l10n-id="document_properties_creator">Creator:</span> <p id="creatorField">-</p>
++            </div>
++            <div class="separator"></div>
++            <div class="row">
++              <span data-l10n-id="document_properties_producer">PDF Producer:</span> <p id="producerField">-</p>
++            </div>
++            <div class="row">
++              <span data-l10n-id="document_properties_version">PDF Version:</span> <p id="versionField">-</p>
++            </div>
++            <div class="row">
++              <span data-l10n-id="document_properties_page_count">Page Count:</span> <p id="pageCountField">-</p>
++            </div>
++            <div class="buttonRow">
++	          <button id="documentPropertiesClose" class="overlayButton"><span data-l10n-id="document_properties_close">Close</span></button>
++            </div>
++          </div>
++        </div>
++      </div>  <!-- overlayContainer -->
++
 +    </div> <!-- outerContainer -->
 +    <div id="printContainer"></div>
++<div id="mozPrintCallback-shim" hidden>
++  <style scoped>
++#mozPrintCallback-shim {
++  position: fixed;
++  top: 0;
++  left: 0;
++  height: 100%;
++  width: 100%;
++  z-index: 9999999;
++
++  display: block;
++  text-align: center;
++  background-color: rgba(0, 0, 0, 0.5);
++}
++#mozPrintCallback-shim[hidden] {
++  display: none;
++}
++ at media print {
++  #mozPrintCallback-shim {
++    display: none;
++  }
++}
++
++#mozPrintCallback-shim .mozPrintCallback-dialog-box {
++  display: inline-block;
++  margin: -50px auto 0;
++  position: relative;
++  top: 45%;
++  left: 0;
++  min-width: 220px;
++  max-width: 400px;
++
++  padding: 9px;
++
++  border: 1px solid hsla(0, 0%, 0%, .5);
++  border-radius: 2px;
++  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
++
++  background-color: #474747;
++
++  color: hsl(0, 0%, 85%);
++  font-size: 16px;
++  line-height: 20px;
++}
++#mozPrintCallback-shim .progress-row {
++  clear: both;
++  padding: 1em 0;
++}
++#mozPrintCallback-shim progress {
++  width: 100%;
++}
++#mozPrintCallback-shim .relative-progress {
++  clear: both;
++  float: right;
++}
++#mozPrintCallback-shim .progress-actions {
++  clear: both;
++}
++  </style>
++  <div class="mozPrintCallback-dialog-box">
++    <!-- TODO: Localise the following strings -->
++    Preparing document for printing...
++    <div class="progress-row">
++      <progress value="0" max="100"></progress>
++      <span class="relative-progress">0%</span>
++    </div>
++    <div class="progress-actions">
++      <input type="button" value="Cancel" class="mozPrintCallback-cancel">
++    </div>
++  </div>
++</div>
++
 +  </body>
 +</html>
 +
diff --cc apps/gallery/templates/public.php
index 0684b20,0000000..c929142
mode 100644,000000..100644
--- a/apps/gallery/templates/public.php
+++ b/apps/gallery/templates/public.php
@@@ -1,34 -1,0 +1,34 @@@
 +<div class="wrapper"><!-- for sticky footer -->
 +
 +<header>
 +	<div id="header">
 +		<a href="<?php print_unescaped(link_to('', 'index.php')); ?>" title="" id="owncloud">
 +			<img class="svg" src="<?php print_unescaped(image_path('', 'logo-wide.svg')); ?>" alt="<?php p($theme->getName()); ?>" /></a>
 +		<div id="logo-claim" style="display:none;"><?php p($theme->getLogoClaim()); ?></div>
 +		<div class="header-right">
- 			<span id="details"><?php print_unescaped($l->t('shared by %s', $_['displayName'])) ?></span>
++			<span id="details"><?php p($l->t('shared by %s', $_['displayName'])) ?></span>
 +		</div>
 +	</div>
 +</header>
 +<div id="content" data-albumname="<?php p($_['albumName'])?>">
 +	<div id="controls">
 +		<div id="breadcrumbs"></div>
 +		<!-- toggle for opening shared picture view as file list -->
 +		<div id="openAsFileListButton" class="button">
 +			<img class="svg"
 +				src="<?php print_unescaped(image_path('core', 'actions/toggle-filelist.svg')); ?>"
 +				alt="<?php p($l->t('File list')); ?>" />
 +		</div>
 +	</div>
 +
 +	<div id='gallery' class="hascontrols" data-token="<?php isset($_['token']) ? p($_['token']) : p(false) ?>"></div>
 +</div>
 +
 +	<div class="push"></div><!-- for sticky footer -->
 +</div>
 +
 +<footer>
 +	<p class="info">
 +		<?php print_unescaped($theme->getLongFooter()); ?>
 +	</p>
 +</footer>
diff --cc apps/updater/ajax/update.php
index f371fa5,0000000..30f9fb9
mode 100644,000000..100644
--- a/apps/updater/ajax/update.php
+++ b/apps/updater/ajax/update.php
@@@ -1,147 -1,0 +1,147 @@@
 +<?php
 +
 +/**
 + * ownCloud - Updater plugin
 + *
 + * @author Victor Dubiniuk
 + * @copyright 2013 Victor Dubiniuk victor.dubiniuk at gmail.com
 + *
 + * This file is licensed under the Affero General Public License version 3 or
 + * later.
 + */
 +
 +namespace OCA\Updater;
 +
 +\OCP\JSON::checkAdminUser();
 +\OCP\JSON::callCheck();
 +
 +set_time_limit(0);
 +
 +$updateEventSource = new \OC_EventSource();
 +$watcher = new UpdateWatcher($updateEventSource);
 +\OCP\Util::connectHook('update', 'success', $watcher, 'success');
 +\OCP\Util::connectHook('update', 'failure', $watcher, 'failure');
 +
 +$watcher->success((string) App::$l10n->t('Checking your installation...'));
 +// Check if we have enough permissions
 +$installed = Helper::getDirectories();
 +$thirdPartyUpdater = new Location_3rdparty($installed[Helper::THIRDPARTY_DIRNAME], '');
 +$coreUpdater = new Location_Core($installed[Helper::CORE_DIRNAME], '');
 +$appsUpdater = new Location_Apps('', '');
 +
 +$errors = array_merge(
 +	$thirdPartyUpdater->check(), $coreUpdater->check(), $appsUpdater->check()
 +);
 +
 +if (count($errors)) {
 +	$message = App::$l10n->t('Upgrade is not possible. Make sure that your webserver has write access to the following files and directories:');
 +	$message .= '<br /><br />' . implode('<br />', $errors);
 +	$watcher->failure($message);
 +}
 +
 +// Download package
 +// Url to download package e.g. http://download.owncloud.org/releases/owncloud-4.0.5.tar.bz2
 +$packageUrl = 'https://download.owncloud.com/download/community/owncloud-latest.zip';
 +
 +//Package version e.g. 4.0.4
 +$packageVersion = '';
 +$updateData = \OC_Updater::check();
 +
 +if (isset($updateData['version'])) {
 +	$packageVersion = $updateData['version'];
 +}
 +if (isset($updateData['url']) && extension_loaded('bz2')) {
 +	$packageUrl = $updateData['url'];
 +}
 +if (!strlen($packageVersion) || !strlen($packageUrl)) {
 +	App::log('Invalid response from update feed.');
 +	$watcher->failure((string) App::$l10n->t('Version not found'));
 +}
 +
 +
 +//Some cleanup first
 +Downloader::cleanUp($packageVersion);
 +if (!Downloader::isClean($packageVersion)){
 +	$message = App::$l10n->t('Upgrade is not possible. Your webserver has not enough permissions to remove the following directory:');
 +	$message .= '<br />' . Downloader::getPackageDir($packageVersion);
 +	$message .= '<br />' . App::$l10n->t('Update permissions on this directory and its content or remove it manually first.');
 +	$watcher->failure($message);
 +}
 +
 +Updater::cleanUp();
 +if (!Updater::isClean()){
 +	$message = App::$l10n->t('Upgrade is not possible. Your webserver has not enough permissions to remove the following directory:');
 +	$message .= '<br />' . Updater::getTempDir();
 +	$message .= '<br />' . App::$l10n->t('Update permissions on this directory and its content or remove it manually first.');
 +	$watcher->failure($message);
 +}
 +
 +// Downloading new version
 +try {
 +	$watcher->success((string)  App::$l10n->t('Downloading package...'));
 +	Downloader::getPackage($packageUrl, $packageVersion);
 +} catch (\Exception $e) {
 +	App::log($e->getMessage());
 +	$watcher->failure((string) App::$l10n->t('Unable to fetch package'));
 +}
 +
 +// Create Backup 
 +try {
 +	$watcher->success((string) App::$l10n->t('Creating backup...'));
 +	$backupPath = Backup::create();
 +	$watcher->success((string) App::$l10n->t('Here is your backup: ') . $backupPath . '.zip');
 +} catch (\Exception $e){
 +	App::log($e->getMessage());
 +	$watcher->failure((string) App::$l10n->t('Failed to create backup'));
 +}
 +
 +try {
 +	$watcher->success((string) App::$l10n->t('Moving files...'));
 +	Updater::update($packageVersion, $backupPath);
 +	
 +	// We are done. Some cleanup
 +	Downloader::cleanUp($packageVersion);
 +	Updater::cleanUp();
 +	$watcher->success((string) App::$l10n->t('All done. Click to the link below to start database upgrade.'));
 +	$watcher->done();
 +} catch (\Exception $e){
 +	App::log($e->getMessage());
- 	$watcher->failure((string) App::$l10n->t('Update failed'));
++	$watcher->failure((string) App::$l10n->t('Update failed') . '<br /><br />' . $e->getMessage());
 +}
 +
 +class UpdateWatcher {
 +
 +	/**
 +	 * @var \OC_EventSource $eventSource;
 +	 */
 +	private $eventSource;
 +
 +	public function __construct($eventSource) {
 +		$this->eventSource = $eventSource;
 +	}
 +	
 +	public function error($message) {
 +		\OC_Util::obEnd();
 +		$this->eventSource->send('error', $message);
 +		ob_start();
 +	}
 +
 +	public function success($message) {
 +		\OC_Util::obEnd();
 +		$this->eventSource->send('success', $message);
 +		ob_start();
 +	}
 +
 +	public function failure($message) {
 +		\OC_Util::obEnd();
 +		$this->eventSource->send('failure', $message);
 +		$this->eventSource->close();
 +		die();
 +	}
 +
 +	public function done() {
 +		\OC_Util::obEnd();
 +		$this->eventSource->send('done', '');
 +		$this->eventSource->close();
 +	}
 +}
diff --cc core/doc/admin/_images/edit_encrypted_file.png
index 7a570bf,0000000..7a570bf
mode 100644,000000..100644
Binary files differ
diff --cc core/doc/admin/_images/untrusted-domain.png
index 0000000,0000000..f92c678
new file mode 100644
Binary files differ
diff --cc core/doc/admin/_sources/apps/activity/index.txt
index c40cbc8,0000000..1dbf992
mode 100644,000000..100644
--- a/core/doc/admin/_sources/apps/activity/index.txt
+++ b/core/doc/admin/_sources/apps/activity/index.txt
@@@ -1,10 -1,0 +1,170 @@@
- **ownCloud Activity**
++========
++Activity
++========
 +
- .. toctree::
-     :maxdepth: 2
++The ownCloud Activity app shows an activity feed where users can see what they did in the past and what happened to
++their files and what others did with their shared files.
++
++The Activity Stream introduces a central interface where all events that happen in a user’s ownCloud instance are shown.
++
++The following can be seen in the new interface:
++
++*   Creation, edit or deletion of files along with a thumbnail and date and path
++*   If someone shared a file with you
++*   If someone created, edited or deleted something in a folder you shared to them.
++
++All the events are presented with endless scrolling and also in an RSS feed which a user can subscribe to.
++
++Configuration
++=============
++
++The Activity App is enabled by default.  To verify or to disable, navigate to the APPS page and search for ``Activity``.
++
++.. image:: images/10000000000002F3000000926CA65D02.png
++    :width: 6.5in
++    :height: 1.2571in
++
++Utilization
++===========
++
++The Activities can be viewed by selecting
++Activity
++in the App bar on the left side of the ownCloud browser interface
++
++|1000000000000050000000DB83B8FA5B_png|
++
++This will bring up the Activity interface showing all the activities which occurred for this user’s instance.
++
++Sample Activities
++-----------------
++
++This section will show how the different activities may appear within this interface
++
++Create file
++~~~~~~~~~~~
++
++The following shows a file entitled
++DeleteMe.txt
++being created 3 days ago.
++
++|10000000000000F300000068AF0ECD53_png|
++
++Delete File
++~~~~~~~~~~~
++
++The following shows a file entitled ``DeleteMe.txt`` being deleted 3 days ago.
++
++|10000000000000F5000000675DC5F68C_png|
++
++Edit a file
++~~~~~~~~~~~
++
++The following shows a file ``Shared/test.txt`` being edited mere seconds ago.
++
++|10000000000000F1000000F6704F46D3_png|
++
++Share a file with a user
++~~~~~~~~~~~~~~~~~~~~~~~~
++
++The following shows the file ``shareMe`` being shared with another user.
++
++|10000000000000F1000000F56125BDBA_png|
++
++
++File shared to user
++~~~~~~~~~~~~~~~~~~~
++
++The following shows the file ``Shared/test.txt`` being shared with this user almost an hour ago.
++
++|10000000000000F60000006754ED2A1E_png|
++
++File created by another user in Shared folder
++~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++
++The following is shown when another user creates a file in your shared folder.
++
++|10000000000000F500000067A8845EF8_png|
++
++Shared file modified
++~~~~~~~~~~~~~~~~~~~~
++
++The following shows a file ``BoB/test.txt`` modified by a user who this file was shared to.
++
++|10000000000000F6000000685DFB3767_png|
++
++
++
++Combined activities
++~~~~~~~~~~~~~~~~~~~
++
++The following shows what “combined” activities may look like on the activity interface.
++
++|10000000000000F40000019A110DD159_png|
++
++.. |10000000000000F1000000F56125BDBA_png| image:: images/10000000000000F1000000F56125BDBA.png
++    :width: 2.5102in
++    :height: 2.552in
++
++
++.. |10000000000000F6000000685DFB3767_png| image:: images/10000000000000F6000000685DFB3767.png
++    :width: 2.5626in
++    :height: 1.0835in
++
++
++.. |10000000000000F500000067A8845EF8_png| image:: images/10000000000000F500000067A8845EF8.png
++    :width: 2.552in
++    :height: 1.0728in
++
++
++.. |1000000000000050000000DB83B8FA5B_png| image:: images/1000000000000050000000DB83B8FA5B.png
++    :width: 0.8335in
++    :height: 2.2811in
++
++
++.. |10000000000000F60000006754ED2A1E_png| image:: images/10000000000000F60000006754ED2A1E.png
++    :width: 2.5626in
++    :height: 1.0728in
++
++
++.. |10000000000000F1000000F6704F46D3_png| image:: images/10000000000000F1000000F6704F46D3.png
++    :width: 2.5102in
++    :height: 2.5626in
++
++
++.. |10000000000000F40000019A110DD159_png| image:: images/10000000000000F40000019A110DD159.png
++    :width: 2.5417in
++    :height: 4.2701in
++
++
++.. |10000000000000F5000000675DC5F68C_png| image:: images/10000000000000F5000000675DC5F68C.png
++    :width: 2.552in
++    :height: 1.0728in
++
++
++.. |10000000000000F300000068AF0ECD53_png| image:: images/10000000000000F300000068AF0ECD53.png
++    :width: 2.5311in
++    :height: 1.0835in
++
++RSS Feed
++========
++
++To subscribe to the RSS Feed, navigate to the ``Activity`` page and select ``RSS feed`` in the upper right of the
++browser.
++
++|10000000000001440000005A2989832F_png|
++
++The resulting page will look something like this:
++
++|10000000000002B1000002258C08D304_png|
++
++To subscribe, select the ``Subscribe Now`` button.  The RSS Feed may be viewed via the browser’s capabilities.
++
++.. |10000000000002B1000002258C08D304_png| image:: images/10000000000002B1000002258C08D304.png
++    :width: 6.5in
++    :height: 5.1791in
++
++
++.. |10000000000001440000005A2989832F_png| image:: images/10000000000001440000005A2989832F.png
++    :width: 3.3752in
++    :height: 0.9374in
 +
-     Table_of_Contents
-     Introduction
-     Configuration
-     Utilization
-     RSS_Feed
diff --cc core/doc/admin/_sources/apps/admin_dependencies_chk/index.txt
index d0c0996,0000000..0233927
mode 100644,000000..100644
--- a/core/doc/admin/_sources/apps/admin_dependencies_chk/index.txt
+++ b/core/doc/admin/_sources/apps/admin_dependencies_chk/index.txt
@@@ -1,9 -1,0 +1,34 @@@
- **ownCloud Dependencies**
++===============================
++Finding Deployment Dependencies
++===============================
++
++The ownCloud Dependencies App provides a list of modules required to run the current setup of ownCloud.
++All of the modules listed should be installed on the base operating system prior to using ownCloud.
++
++Configuration
++=============
++
++By default, the ownCloud Dependencies App is disabled.
++To enable, navigate to the Apps page and select “ownCloud dependencies info” and enable.
++
++.. image:: images/10000000000001C9000000AF9C1CE57F.png
++    :width: 4.7602in
++    :height: 1.8228in
++
++Utilization
++===========
++
++Once this app is enabled, navigate to the Admin page and scroll to “Dependencies status”.
++This section will show a list of all modules required to execute this ownCloud
++setup as well as what part of ownCloud uses the given module.
++
++.. image:: images/100000000000013C0000017D4FC6CEF5.png
++    :width: 3.2917in
++    :height: 3.9689in
++
++Modules in green are required and have been installed.  Modules in red are
++required yet have not been installed.  It is recommended to install these
++modules prior to using ownCloud.
++
 +
- .. toctree::
-     :maxdepth: 2
 +
-     Table_of_Contents
-     Introduction
-     Configuration
-     Utilization
diff --cc core/doc/admin/_sources/apps/files_antivirus/index.txt
index 0456002,0000000..3f533a6
mode 100644,000000..100644
--- a/core/doc/admin/_sources/apps/files_antivirus/index.txt
+++ b/core/doc/admin/_sources/apps/files_antivirus/index.txt
@@@ -1,8 -1,0 +1,145 @@@
- **ownCloud Antivirus**
++=====================
++File Antivirus Engine
++=====================
 +
- .. toctree::
-     :maxdepth: 2
++ownCloud integrates with ClamAV, an open source (GPL) antivirus engine, to provide an antivirus solution for files which are uploaded to the ownCloud server.
++Via this method, ownCloud/ClamAV can detect Trojans, viruses, malware and other malicious threats.
++Files are scanned for virus upon initial upload to the ownCloud server.
++
++The ownCloud antivirus app is supported on ownCloud instances which are installed on a Linux operating system.
++
++The antivirus app can run in one of three modes:
++
++*   Executable – ClamAV is running on the same server as the ownCloud instance.
++    For executable mode, the ClamAV process is started and stopped with each file upload.
++*   Daemon – ClamAV is running on a different server from the ownCloud instance
++*   Daemon (Socket) – ClamAV is running on the same server as the ownCloud instance. In this mode, the ClamAV process is running in the background at all times.
++    It is a bit quicker for scanning than executable mode, but requires system administrator skills and root access.
++
++In addition, there are two possible actions which may occur when an infected file is found:
++
++*   Only Log – A log entry is created when an infected file is found.
++*   Delete File – The infected file is deleted.
++
++Configuration
++=============
++
++Enable The app
++--------------
++
++To enable the Antivirus App, navigate to the Apps page and select “Antivirus App for Files” and enable.
++
++|10000000000001800000009A9494E037_png|
++
++Install ClamAV
++--------------
++
++ClamAV must be installed on the server (either the local for Executable or Daemon Socket mode or a remote server for Daemon mode).
++
++To install, use the repository’s installation method to install “clamav”.
++For example::
++
++  apt-get install clamav
++
++For daemon mode, the ClamAV daemon must also be installed (either on the local machine for Daemon Socket or the remote machine for daemon mode)::
++
++  apt-get install clamav-daemon
++
++Configure Logging
++-----------------
++
++Set log level to Everything in the Admin page.
++
++|10000000000001AC000000477C76808F_png|
++
++Executable Mode
++---------------
++
++To run in executable mode, ClamAV must be installed on the local server.
++From the Admin page, configure Antivirus as follows:
++
++|1000000000000165000000D3FF2168AB_png|
++
++The Stream Length is defined as the ClamAV StreamMaxLengeth Size.
++The default value, according to the ClamAV web site is 10M which equates to 10485760 bytes as shown in the above example.
++
++The Path to clamscan is the path for the executable clamscan file.
++By default it installs in /usr/bin/clamscan.
++
++When files are uploaded, they will be scanned and, if clean, the following logs will appear::
++
++  {"app":"files_antivirus","message":"Scanning file : \/Lab.txt","level":0,"time":"2013-12-17T15:24:05+00:00"}
++  {"app":"files_antivirus","message":"Exec scan: \/Lab.txt","level":0,"time":"2013-12-17T15:24:05+00:00"}
++  {"app":"files_antivirus","message":"Result CLEAN!","level":0,"time":"2013-12-17T15:24:09+00:00"}
++
++
++Daemon Mode
++-----------
++
++When running in Daemon Mode, install ClamAV and clamAV-Daemon on a remote server.
++
++The port, upon which ClamAV listens must be configured.
++To do this, add the following line in ``/etc/clamav/clamd.conf``::
++
++  TCPSocket 3310
++
++Then restart the Clamd service::
++
++  /etc/init.d/clamav-daemon restart
++
++Back on the ownCloud server, navigate to the Admin page and configure the Antivirus Configuration as follows:
++
++|1000000000000194000000FAD39BC0D8_png|
++
++Where the host is the IP of the server running the ClamAV Daemon and the Port is what was configured in the above step.
++
++Upon upload of files to the ownCloud server, the following logs will appear indicating the files are clean::
++
++  {"app":"files_antivirus","message":"Scanning file : \/Lab.txt","level":0,"time":"2013-12-17T17:39:35+00:00"}
++  {"app":"files_antivirus","message":"Response :: stream: OK\n","level":0,"time":"2013-12-17T17:39:48+00:00"}
++
++
++Daemon Socket mode
++------------------
++
++To run in Daemon socket mode, install clamav and clamav-daemon on the ownCloud server.
++
++Configure the Admin page as such:
++
++|1000000000000160000000DBB2FB0223_png|
++
++Where Socket is the location of the Clamd executable.
++
++Upon upload of a clean file to the ownCloud server, the following logs will appear::
++
++  {"app":"files_antivirus","message":"Scanning file : \/Lab.txt","level":0,"time":"2013-12-17T18:19:08+00:00"}
++  {"app":"files_antivirus","message":"Response :: stream: OK\n","level":0,"time":"2013-12-17T18:19:08+00:00"}
++
++
++
++
++
++.. |10000000000001AC000000477C76808F_png| image:: images/10000000000001AC000000477C76808F.png
++    :width: 4.4583in
++    :height: 0.7398in
++
++
++.. |10000000000001800000009A9494E037_png| image:: images/10000000000001800000009A9494E037.png
++    :width: 4in
++    :height: 1.6043in
++
++
++.. |1000000000000194000000FAD39BC0D8_png| image:: images/1000000000000194000000FAD39BC0D8.png
++    :width: 4.2083in
++    :height: 2.6043in
++
++
++.. |1000000000000165000000D3FF2168AB_png| image:: images/1000000000000165000000D3FF2168AB.png
++    :width: 3.7189in
++    :height: 2.198in
++
++
++.. |1000000000000160000000DBB2FB0223_png| image:: images/1000000000000160000000DBB2FB0223.png
++    :width: 3.6665in
++    :height: 2.2811in
 +
-     Table_of_Contents
-     Introduction
-     Configuration
diff --cc core/doc/admin/_sources/apps/files_encryption/index.txt
index 9c66e4b,0000000..768010d
mode 100644,000000..100644
--- a/core/doc/admin/_sources/apps/files_encryption/index.txt
+++ b/core/doc/admin/_sources/apps/files_encryption/index.txt
@@@ -1,9 -1,0 +1,167 @@@
- **ownCloud Enctryption**
++==========
++Encryption
++==========
 +
- .. toctree::
-     :maxdepth: 2
++ownCloud contains an encryption app which, when enabled, encrypts all files stored in ownCloud.
++The encryption is done automatically once the admin enables the app.
++All encryption and decryption occur on the ownCloud server, which allows the
++user to continue to use other apps to view and edit the data.
++
++The user’s password is used as the key to decrypt their data.
++This means that if the user loses their login password, data will be lost.
++To protect against password loss, the recovery key may be used as described in a later section.
++
++What gets encrypted?
++====================
++
++All files stored in ownCloud will be encrypted with the following exceptions:
++
++*   Old versions (versions created prior to enabling the encryption app)
++*   Old files in the trash bin (files deleted prior to enabling the encryption app)
++*   Existing files on external storage.
++    Only new files placed on the external storage mount after encryption was enabled are encrypted.
++*   Image thumbnails from the gallery app
++*   Search index form the full text search app.
++
++Decrypting the data
++===================
++
++If the encryption app is disable, users will get the following message alerting
++them how to decrypt their files.
++
++.. image:: images/100000000000023B000000125381F51B.png
++    :width: 5.948in
++    :height: 0.1874in
++
++Navigating to the Personal settings page, the user can enter their password and
++decrypt all files.
++
++.. image:: images/100000000000018B000000A090F31164.png
++    :width: 4.1146in
++    :height: 1.6665in
++
++Configuration
++=============
++
++To enable the encryption app, navigate to the Apps page and select Encryption, then enable.
++
++.. image:: images/10000000000001A3000000AAFE82893A.png
++
++Once the app is enabled, the following message will appear for all users
++currently logged into the web browser as they navigate to a new page within the
++ownCloud web browser
++
++.. image:: images/10000000000001BF00000012349EAE2F.png
++
++
++It is necessary to logout of ownCloud and re-login to initialize the encryption keys.
++
++Recovery Key
++------------
++
++Enabling the recovery key globally is done by the admin.
++Each user then has the option as to whether they wish to do so for their own account.
++If enabled, the admin will be able to reset the user’s encryption password
++using a predefined recovery password.  This allows for the recovery of a user’s
++files in the event of a password loss.  If recovery key is not enabled, there
++is no way to restore files if the login password is lost.
++
++Admin level
++~~~~~~~~~~~
++
++To enable the recovery key, the Admin must first enable this feature in the Admin page.
++
++.. image:: images/100000000000018E000000C4BA62B2A3.png
++
++Once enabled, the Admin may change the recovery key password at any time.
++
++.. image:: images/1000000000000193000001AE9AB8B0A2.png
++
++User level
++~~~~~~~~~~
++
++The user can then navigate to the Personal page and enable password recovery.
++
++.. image:: images/1000000000000227000000935D9B1EF6.png
++
++Recovery
++~~~~~~~~
++
++In order for the admin to recover the user’s files in the event of a lost
++password, the admin should navigate to the “Users” tab and enter the Recovery
++Key Password into the “Admin Recovery Password” field at the top of the page.
++
++.. image:: images/10000000000003730000002B6865E951.png
++
++This will allow the admin to generate a new encryption password for the user.
++
++*   For local user management, this will generate both a new log-in password as well
++    as a new encryption password for the data.
++*   If LDAP authentication is in use, the admin would need to set the new log-in password
++    in the LDAP server, and then enter the same password in the user management page for
++    the encryption key. It is important that both the password in the LDAP server and the
++    password entered in the user management page are identical.
++
++
++File Systems
++============
++
++Once enabled, all files within ownCloud are encrypted, with the exceptions mentioned above.
++This includes files in local storage, as well as files contained within external storage mounts.
++
++The encryption app creates several key files/folders when enabled.
++``~/data/public-keys`` contains the public keys for all users, and
++``~/data/owncloud_private_keys`` contains system wide private keys utilized for
++public link shares as well as the recovery key.
++
++.. code-block:: console
++
++  root at server:/var/www/owncloud/data# ls
++  files_encryption/  mount.json  owncloud.log           public-keys/ yogi/
++  index.html         oc6admin/   owncloud_private_key/  user1/
++
++The encryption app stores key information in the ``~/data/<user>/files_encryption`` directory.
++
++.. code-block:: console
++
++  root at server:/var/www/owncloud/data/user1/encryption# ls
++  keyfiles/ user1.private.key share-keys/
++
++As mentioned previously, the private key is generated from the user’s password.
++
++Each file that the user owns will have a corresponding keyfile maintained in the keyfiles directory.
++
++.. code-block:: console
++
++  root at server:/var/www/owncloud/data/user1/files_encryption/keyfiles# ls
++  documents/ ownCloud undelete.docx.key photos/
++  music/     ownCloudUserManual.pdf.key test encryption.txt.key
++
++In addition a share key will be generated for each file in the event that there
++is an external storage mount by the admin for multiple users or groups.
++
++.. code-block:: console
++
++  root at server:/var/www/owncloud/data/user1/files_encryption/share-keys# ls
++  documents/
++  music/
++  ownCloud undelete.docx.recovery_5dcce10a.shareKey
++  ownCloud undelete.docx.user1.shareKey
++  ownCloudUserManual.pdf.recovery_5dcce10a.shareKey
++  ownCloudUserManual.pdf.user1.shareKey
++  photos/
++  test encryption.txt.recovery_5dcce10a.shareKey
++  test encryption.txt.user1.shareKey
++  ...
++
++When viewing a file directly on the ownCloud data directory, it will show up as encrypted.
++
++.. code-block:: console
++
++  root at server:/var/www/owncloud/data/user1/files# more test\ encryption.txt
++  2JnmDdDh//8FVcDhLrnD1WH0JjhrzKpFKV6V61pAfUCu9IJX00iv007Yw3Tf/QBbtJFpQFxx
++  
++However, viewing the same file via the browser, the actual contents of the file are displayed.
++
++.. image:: images/edit_encrypted_file.png
 +
-     Table_of_Contents
-     Introduction
-     Configuration
-     File_Systems
diff --cc core/doc/admin/_sources/apps/files_external/index.txt
index 4b32d69,0000000..ecdc13d
mode 100644,000000..100644
--- a/core/doc/admin/_sources/apps/files_external/index.txt
+++ b/core/doc/admin/_sources/apps/files_external/index.txt
@@@ -1,8 -1,0 +1,643 @@@
- **External Storage Mounts**
++========================
++External storage support
++========================
 +
- .. toctree::
-     :maxdepth: 2
++ownCloud provides the ability to mount an external storage device.
++The external storage devices serves as a secondary storage device within ownCloud.
++
++The ownCloud Admin has the ability to create such a mount.
++In addition, the ownCloud Admin may decide to provide the end user the ability to create the mount.
++The mounts may be created on a per-user, per group, or all user basis.
++
++Supported mounts
++================
++
++The following lists the supported storage types.
++
++*   Local
++*   Amazon S3
++*   Dropbox
++*   FTP
++*   Google Drive
++*   OpenStack Object Storage
++*   SMB/CIFS
++*   ownCloud/WebDAV
++*   SFTP
++*   iRODS
++
++Configuration
++=============
++
++Enable the app
++--------------
++
++From the ``APPs`` Page within ownCloud, select ``External Storage Support`` and enable.
++
++|10000000000001980000009271BE0D26_png|
++
++Configure mounts
++----------------
++
++As stated previously, the Admin has the ability to configure these mounts, as
++well as decide whether an end user can configure mounts for themselves.  For
++the Admin, the configuration is performed in the ``Admin`` page.  For end
++users, the configuration is performed in the ``Personal`` Page.  This document
++will discuss how the Admin configures the mounts, however, the configuration is
++the same for the end user.
++
++On the ``Admin`` page, scroll to External Storage:
++
++|1000000000000631000000E19D116AA0_png|
++
++
++Enable users to mount their own devices
++~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++
++In order to allow end users to mount their own devices, select the radio button next to
++Enable User External Storage.
++
++
++Local Storage
++~~~~~~~~~~~~~
++
++This is used to mount storage that is outside ownCloud’s data directory
++
++|10000000000006060000006A0106CA0C_png|
++
++*   Location – The directory to mount
++*   Applicable – A list users of who can see this mount
++
++|10000000000003DF00000071A41D8A1F_png|
++
++Note: When configured correctly, a *Green Light* will appear next to the Folder Name.
++If misconfigured, a *Red Light* will appear.
++
++|10000000000004770000008AAF3CFFDB_png|
++
++Amazon S3
++~~~~~~~~~
++
++This is used to mount to an S3 server
++
++|100000000000061D0000007047877972_png|
++
++*   Access Key – The access key provided by the S3 storage provider
++*   Secret Key – The secret key provided by the S3 storage provider
++*   Bucket – The bucket created within the S3 storage server
++*   Hostname (optional) – The host of the s3 storage server
++*   Port (optional) – The port to communicate to the host on
++*   Region (optional) – The region where the storage exists
++*   Applicable – A list of users who can see this mount
++
++
++
++|10000000000005BB0000007C1DF71FA7_png|
++
++.. note:: When configured correctly, a Green Light will appear next to the Folder Name.
++          If misconfigured, a Red Light will appear.
++
++|100000000000063F00000090AAE1FA4A_png|
++
++Dropbox
++~~~~~~~
++
++Mounts a dropbox in the Dropbox cloud into the virtual file system.
++
++Configure DropBox
++^^^^^^^^^^^^^^^^^
++
++Log onto the `Dropbox Developers page`_:
++
++.. _`Dropbox Developers page`: http://www.dropbox.com/developers
++
++
++Select App Console:
++
++|10000000000000A800000073F49785A6_png|
++
++This will ask you to accept terms and conditions.
++
++Select Dropbox API and configure down the page as follows:
++
++|1000000000000372000002AF943ADDA0_png|
++
++The name can be any unique name desired.
++
++Select Create App
++
++|10000000000000950000004412998BE7_png|
++
++Enter the OAuth redirect URI as follows::
++
++  http://<ownCloud instance>/index.php/settings/personal
++  http://<ownCloud instance>/index.php/settings/admin
++
++|10000000000003A6000002A9C7A660BE_png|
++
++Take note of the App Key and App Secret and enter into ownCloud.
++
++ownCloud Configuration
++^^^^^^^^^^^^^^^^^^^^^^
++
++|100000000000060300000065DF96536B_png|
++
++*   App key – The app key to login to your Dropbox
++*   App secret – The app secret to login to your Dropbox
++*   Applicable – A list users of who can see this mount
++
++|10000000000005EC00000073E678DFEC_png|
++
++Select “Grant Access” and the following appears
++
++|10000000000002950000021E245F6883_png|
++
++Note if you are not logged into Dropbox, you will first be prompted to login.
++Select Allow.
++
++|10000000000005E6000000676902E040_png|
++
++
++.. note:: When configured correctly, a Green Light will appear next to the Folder Name.
++          If misconfigured, a Red Light will appear.
++
++|100000000000061A0000006FC014C3A4_png|
++
++FTP
++~~~
++
++Mounts a folder on a remote FTP or FTPS server
++
++|100000000000061E0000006BCF9ECC0B_png|
++
++*   URL – The hostname of the FTP/FTPS server
++*   Username – The username to login to the FTP/FTPS server
++*   Password – The password to login to the FTP/FTPS esrver
++*   Root – The folder inside the FTP/FTPS server to mount (optional – defaults to ‘/’)
++*   Secure ``ftps://`` -- Whether to use ftps:// to connect to the FTP server instead of ``ftp://``
++*   Applicable – A list users of who can see this mount
++
++|10000000000005AF00000074604B1A67_png|
++
++.. note:: When configured correctly, a Green Light will appear next to the
++          Folder Name.  If misconfigured, a Red Light will appear.
++
++|10000000000005D50000009458C5EE48_png|
++
++GoogleDrive
++~~~~~~~~~~~
++
++Mounts a share in the Google cloud.
++
++Configure GoogleDrive
++^^^^^^^^^^^^^^^^^^^^^
++
++All applications that access a Google API must be registered through the “Google Cloud Console”.
++This can be accessed at the following URL:
++
++`https://cloud.google.com <https://cloud.google.com>`_
++
++Once logged into Google, create a project by selecting
++Create Project
++
++|1000000000000247000000A77440E4D3_png|
++
++Enter a Project name and either keep or enter a new Project ID
++|100000000000027B0000011D10F70F88_png|
++
++
++Select the project and choose the APIs & auth menu entry
++|10000000000000B600000120706C3C75_png|
++
++Enable ``Drive API`` and ``Drive SDK`` and then select the
++
++|100000000000003800000018D49F1CE7_png|
++
++next to either ``Drive API`` or ``Drive SDK``
++
++|10000000000004100000005657010336_png|
++
++Select ``API Access`` on the menu
++
++|10000000000000CD000000ECA8DE7780_png|
++
++Select ``REGISTER APP``
++
++|10000000000001FD000000DF8D2D7546_png|
++
++Enter a name and select ``Web Application``
++
++|10000000000002840000016729388B7F_png|
++
++Expand ``OAuth 2.0 Client ID``
++Enter the following in the ``REDIRECT URI`` field::
++
++  http://<ownCloud instance>/index.php/settings/personal
++  http://<ownCloud instance>/index.php/settings/admin
++
++.. note:: The ``<ownCloud instance>`` must be a Fully Qualified Domain Name.  It cannot be an IP address!
++
++Select ``Generate``
++
++|10000000000003B30000021B5EE5D338_png|
++
++Verify that the required email addresses are in the Permissions tab
++
++|10000000000003A60000011E274A1A28_png|
++
++Configure ownCloud
++^^^^^^^^^^^^^^^^^^
++
++Prior to configuring the mount, an E-mail address needs to be configured in the ``Personal`` tab
++
++|10000000000001880000007EA4444400_png|
++
++|10000000000006000000005EDA7B96BE_png|
++
++*   Client ID – The client id to login to the Google Drive from ``OAuth 2.0 Client ID`` above
++*   Client secret – The client secret to login to the Google Drive from ``OAuth 2.0 Client ID`` above
++*   Applicable – A list users of who can see this mount
++
++Once the required fields are filled in, a ``Grant access`` button appears.  Select this button.
++
++|10000000000005F70000007E43DB8026_png|
++
++The following screen appears. Select ``Accept``
++
++|10000000000001D30000014DC251C948_png|
++
++|10000000000004C0000000795BB2C146_png|
++
++
++|1000000000000552000000BF22E90239_png|
++
++
++.. note:: When configured correctly, a Green Light will appear next to the
++          Folder Name.  If misconfigured, a Red Light will appear.
++
++
++OpenStack Object Storage
++~~~~~~~~~~~~~~~~~~~~~~~~
++
++Mounts a container on an OpenStack Object Storage server.
++
++|100000000000053A00000067708C8F53_png|
++
++|10000000000002170000004A27056037_png|
++
++*   Username
++*   Bucket
++*   Region
++*   API Key
++*   Tenantname
++*   Password
++*   Service Name
++*   URL of identity Endpoint
++*   Timeout of HTTP request
++*   Applicable – A list users of who can see this mount
++
++.. note:: When configured correctly, a Green Light will appear next to the
++          Folder Name.  If misconfigured, a Red Light will appear.
++
++
++SMB/CIFS
++~~~~~~~~
++
++Mounts a folder on a remote Samba server, NAS appliance, or Windows machine.
++
++|10000000000005FA0000005CE8491B77_png|
++
++*   URL – The host name of the Samba server.
++*   Username – The user name used to login to the Samba server.
++*   Password – The password to login to the Samba server.
++*   Share – The share on the Samba server to mount.
++*   Root – The folder inside the Samba share to mount (optional, defaults to ‘/’)
++*   Applicable – A list users of who can see this mount
++
++|10000000000005C30000006CAFFAAD61_png|
++
++.. note:: When configured correctly, a Green Light will appear next to the
++          Folder Name.  If misconfigured, a Red Light will appear.
++
++.. note:: The SMB backend requires ``smbclient`` to be installed on the server.
++
++|10000000000005D00000003B29340A7A_png|
++
++ownCloud/WebDAV
++~~~~~~~~~~~~~~~
++
++Mounts a folder on a WebDAV server (or another ownCloud instance via WebDAV).
++
++|10000000000005F70000005F0912E904_png|
++
++*   URL – The hostname of the WebDAV server.
++*   Username – The username used to login to the WebDAV server.
++*   Password – The password used to login to the WebDAV server.
++*   Root – The folder inside the WebDav server to mount (optional, defaults to ‘/’)
++*   Secure ``https://`` - Whether to use ``https://`` to connect to the WebDav server instead of ``http://``
++*   Applicable – A list users of who can see this mount
++
++|10000000000005B90000007866D92D14_png|
++
++.. note:: When configured correctly, a Green Light will appear next to the
++          Folder Name.  If misconfigured, a Red Light will appear.
++
++|10000000000005E20000009B1BA5A8CF_png|
++
++SFTP
++~~~~
++
++Mounts a folder on a remote SSH server.
++
++|10000000000005FF0000005F35710398_png|
++
++*   URL – The hostname of the SSH server.
++*   Username – The username used to login to the SSH server.
++*   Password – The password used to login to the SSH server.
++*   Root – The folder inside the SSH server to mount (optional, defaults to ‘/’)
++*   Applicable – A list users of who can see this mount
++
++|10000000000005970000006AE23997C9_png|
++
++.. note:: When configured correctly, a Green Light will appear next to the
++          Folder Name.  If misconfigured, a Red Light will appear.
++
++|10000000000005EB000000A68BA73E2D_png|
++
++iRODS
++~~~~~
++
++Mounts a folder on a iRODS server.
++
++|100000000000062A0000005F61A18950_png|
++
++*   Host
++*   Port
++*   Use ownCloud login
++*   Username
++*   Password
++*   Authentication Mode
++*   Zone
++*   Applicable – A list users of who can see this mount
++
++
++.. note:: When configured correctly, a Green Light will appear next to the
++          Folder Name.  If misconfigured, a Red Light will appear.
++
++
++Configuration File
++------------------
++
++The configuration of mounts created within the External Storage App are stored in the
++``data/mount.json`` file.
++This file contains all settings in JSON (JavaScript Object Notation) format.
++Two different types of entries exist:
++
++*   Group mounts -
++    Each entry configures a mount for each user in group
++*   User mount – Each entry configures a mount for a single user or all users.
++
++For each type, there is a JSON array with the user/group name as key and an array of configuration values as the value.
++Each entry consist of the class name of the storage backend and an array of backend specific options (described above) and will be replaced by the user login.
++
++Although configuration may be done by making modifications to the mount.json file, it is recommended to use the Web-GUI in the administrator panel (as described in the above section) to add, remove, or modify mount options in order to prevent any problems.
++
++
++.. |1000000000000552000000BF22E90239_png| image:: images/1000000000000552000000BF22E90239.png
++    :width: 6.5in
++    :height: 0.911in
++
++
++.. |10000000000005EC00000073E678DFEC_png| image:: images/10000000000005EC00000073E678DFEC.png
++    :width: 6.5in
++    :height: 0.4929in
++
++
++.. |100000000000062A0000005F61A18950_png| image:: images/100000000000062A0000005F61A18950.png
++    :width: 6.5in
++    :height: 0.3909in
++
++
++.. |10000000000001FD000000DF8D2D7546_png| image:: images/10000000000001FD000000DF8D2D7546.png
++    :width: 5.302in
++    :height: 2.3228in
++
++
++.. |10000000000001980000009271BE0D26_png| image:: images/10000000000001980000009271BE0D26.png
++    :width: 4.25in
++    :height: 1.5201in
++
++
++.. |10000000000005B90000007866D92D14_png| image:: images/10000000000005B90000007866D92D14.png
++    :width: 6.5in
++    :height: 0.5319in
++
++
++.. |10000000000005D50000009458C5EE48_png| image:: images/10000000000005D50000009458C5EE48.png
++    :width: 6.5in
++    :height: 0.6437in
++
++
++.. |10000000000002170000004A27056037_png| image:: images/10000000000002170000004A27056037.png
++    :width: 5.5728in
++    :height: 0.7701in
++
++
++.. |10000000000005C30000006CAFFAAD61_png| image:: images/10000000000005C30000006CAFFAAD61.png
++    :width: 6.5in
++    :height: 0.4756in
++
++
++.. |100000000000060300000065DF96536B_png| image:: images/100000000000060300000065DF96536B.png
++    :width: 6.5in
++    :height: 0.4264in
++
++
++.. |10000000000003A60000011E274A1A28_png| image:: images/10000000000003A60000011E274A1A28.png
++    :width: 6.5in
++    :height: 1.9902in
++
++
++.. |10000000000001880000007EA4444400_png| image:: images/10000000000001880000007EA4444400.png
++    :width: 4.0835in
++    :height: 1.3126in
++
++
++.. |10000000000005BB0000007C1DF71FA7_png| image:: images/10000000000005BB0000007C1DF71FA7.png
++    :width: 6.5in
++    :height: 0.5492in
++
++
++.. |10000000000005FF0000005F35710398_png| image:: images/10000000000005FF0000005F35710398.png
++    :width: 6.5in
++    :height: 0.402in
++
++
++.. |10000000000005E6000000676902E040_png| image:: images/10000000000005E6000000676902E040.png
++    :width: 6.5in
++    :height: 0.4429in
++
++
++.. |10000000000005F70000007E43DB8026_png| image:: images/10000000000005F70000007E43DB8026.png
++    :width: 6.5in
++    :height: 0.5362in
++
++
++.. |10000000000000950000004412998BE7_png| image:: images/10000000000000950000004412998BE7.png
++    :width: 1.552in
++    :height: 0.7083in
++
++
++.. |100000000000061E0000006BCF9ECC0B_png| image:: images/100000000000061E0000006BCF9ECC0B.png
++    :width: 6.5in
++    :height: 0.4437in
++
++
++.. |100000000000063F00000090AAE1FA4A_png| image:: images/100000000000063F00000090AAE1FA4A.png
++    :width: 6.5in
++    :height: 0.5846in
++
++
++.. |10000000000004C0000000795BB2C146_png| image:: images/10000000000004C0000000795BB2C146.png
++    :width: 6.5in
++    :height: 0.6465in
++
++
++.. |100000000000027B0000011D10F70F88_png| image:: images/100000000000027B0000011D10F70F88.png
++    :width: 6.5in
++    :height: 2.9173in
++
++
++.. |100000000000061A0000006FC014C3A4_png| image:: images/100000000000061A0000006FC014C3A4.png
++    :width: 6.5in
++    :height: 0.461in
++
++
++.. |10000000000005D00000003B29340A7A_png| image:: images/10000000000005D00000003B29340A7A.png
++    :width: 6.5in
++    :height: 0.2575in
++
++
++.. |10000000000006060000006A0106CA0C_png| image:: images/10000000000006060000006A0106CA0C.png
++    :width: 6.5in
++    :height: 0.4465in
++
++
++.. |10000000000000A800000073F49785A6_png| image:: images/10000000000000A800000073F49785A6.png
++    :width: 1.75in
++    :height: 1.198in
++
++
++.. |10000000000000B600000120706C3C75_png| image:: images/10000000000000B600000120706C3C75.png
++    :width: 1.8957in
++    :height: 3in
++
++
++.. |10000000000004770000008AAF3CFFDB_png| image:: images/10000000000004770000008AAF3CFFDB.png
++    :width: 6.5in
++    :height: 0.7846in
++
++
++.. |10000000000002840000016729388B7F_png| image:: images/10000000000002840000016729388B7F.png
++    :width: 6.5in
++    :height: 3.6228in
++
++
++.. |10000000000003B30000021B5EE5D338_png| image:: images/10000000000003B30000021B5EE5D338.png
++    :width: 6.5in
++    :height: 3.6992in
++
++
++.. |10000000000006000000005EDA7B96BE_png| image:: images/10000000000006000000005EDA7B96BE.png
++    :width: 6.5in
++    :height: 0.398in
++
++
++.. |1000000000000372000002AF943ADDA0_png| image:: images/1000000000000372000002AF943ADDA0.png
++    :width: 6.5in
++    :height: 5.0634in
++
++
++.. |100000000000061D0000007047877972_png| image:: images/100000000000061D0000007047877972.png
++    :width: 6.5in
++    :height: 0.4654in
++
++
++.. |10000000000003A6000002A9C7A660BE_png| image:: images/10000000000003A6000002A9C7A660BE.png
++    :width: 6.5in
++    :height: 4.7398in
++
++
++.. |10000000000000CD000000ECA8DE7780_png| image:: images/10000000000000CD000000ECA8DE7780.png
++    :width: 2.1346in
++    :height: 2.4583in
++
++
++.. |100000000000053A00000067708C8F53_png| image:: images/100000000000053A00000067708C8F53.png
++    :width: 6.5in
++    :height: 0.5008in
++
++
++.. |10000000000005970000006AE23997C9_png| image:: images/10000000000005970000006AE23997C9.png
++    :width: 6.5in
++    :height: 0.4811in
++
++
++.. |1000000000000247000000A77440E4D3_png| image:: images/1000000000000247000000A77440E4D3.png
++    :width: 6.0728in
++    :height: 1.7398in
++
++
++.. |10000000000003DF00000071A41D8A1F_png| image:: images/10000000000003DF00000071A41D8A1F.png
++    :width: 6.5in
++    :height: 0.7409in
++
++
++.. |10000000000001D30000014DC251C948_png| image:: images/10000000000001D30000014DC251C948.png
++    :width: 4.8646in
++    :height: 3.4689in
++
++
++.. |10000000000005EB000000A68BA73E2D_png| image:: images/10000000000005EB000000A68BA73E2D.png
++    :width: 6.5in
++    :height: 0.7126in
++
++
++.. |10000000000005E20000009B1BA5A8CF_png| image:: images/10000000000005E20000009B1BA5A8CF.png
++    :width: 6.5in
++    :height: 0.6689in
++
++
++.. |100000000000003800000018D49F1CE7_png| image:: images/100000000000003800000018D49F1CE7.png
++    :width: 0.5835in
++    :height: 0.25in
++
++
++.. |1000000000000631000000E19D116AA0_png| image:: images/1000000000000631000000E19D116AA0.png
++    :width: 6.5in
++    :height: 0.9228in
++
++
++.. |10000000000005AF00000074604B1A67_png| image:: images/10000000000005AF00000074604B1A67.png
++    :width: 6.5in
++    :height: 0.5181in
++
++
++.. |10000000000005F70000005F0912E904_png| image:: images/10000000000005F70000005F0912E904.png
++    :width: 6.5in
++    :height: 0.4043in
++
++
++.. |10000000000002950000021E245F6883_png| image:: images/10000000000002950000021E245F6883.png
++    :width: 6.5in
++    :height: 5.3299in
++
++
++.. |10000000000004100000005657010336_png| image:: images/10000000000004100000005657010336.png
++    :width: 6.5in
++    :height: 0.5374in
++
++
++.. |10000000000005FA0000005CE8491B77_png| image:: images/10000000000005FA0000005CE8491B77.png
++    :width: 6.5in
++    :height: 0.3909in
 +
-     Table_of_Contents
-     Introduction
-     Configuration
diff --cc core/doc/admin/_sources/apps/files_sharing/index.txt
index 8d0385b,0000000..70c4ce9
mode 100644,000000..100644
--- a/core/doc/admin/_sources/apps/files_sharing/index.txt
+++ b/core/doc/admin/_sources/apps/files_sharing/index.txt
@@@ -1,11 -1,0 +1,182 @@@
- **ownCloud Sharing App**
++=======
++Sharing
++=======
 +
++ownCloud allows users to share files and folders with both other ownCloud
++users, as well as publicly via a link.  Sharing may be done either via the web
++interface or via the Sharing API.  This document will discuss the web interface
++and sharing. For information on the Sharing API, please refer to that document.
 +
- .. toctree::
-     :maxdepth: 2
++Configuration
++=============
++
++Enable the app
++--------------
++
++The Share Files app is enabled by default. To verify this and/or disable this functionality,
++navigate to the APPS page in the web interface and select “Share Files”
++
++|1000000000000167000000B43E4BF478_png|
++
++Configuring the permitted functionality
++---------------------------------------
++
++There are several functions which may be enabled or disabled at the admin’s discretion.
++To configure these functions, navigate to the Admin page in the web interface and scroll to the “Sharing” section.
++
++|10000000000001CF00000176B0BE1EBC_png|
++
++The above parameters are self-explanatory and may be enabled or disabled as required.
++
++
++.. |10000000000001CF00000176B0BE1EBC_png| image:: images/10000000000001CF00000176B0BE1EBC.png
++    :width: 4.8228in
++    :height: 3.8957in
++
++
++.. |1000000000000167000000B43E4BF478_png| image:: images/1000000000000167000000B43E4BF478.png
++    :width: 3.7398in
++    :height: 1.8752in
++
++Utilization
++===========
++
++An ownCloud user may share files or entire folders with other individuals.
++The method of sharing is the same.
++
++Share with another ownCloud user
++--------------------------------
++
++Hover over the line containing the file or folder to be shared.
++And then select Share.
++The following dialog appears.
++
++|10000000000003EC000000AB60616FA7_png|
++
++In the “share with user or group” text box, enter the user to share with, or the group to share with.
++Note, as letters are typed, the users and groups who match the typed string will appear.
++As a short cut, simply select the desired user/group
++
++Setting Permissions on the share
++--------------------------------
++
++When a file or folder is shared, the permissions may be modified stating what the other user may do with the file/folder.
++Once the share with user or group has been entered, the dialog will expand as follows.
++
++|1000000000000404000000FCFC13E732_png|
++
++If the shared with user has an email address configured, the sharing user may choose to notify the shared with user of the share.
++To do this, select the checkbox next to “notify by email”.
++It is important to note, this checkbox appears whether or not the shared with user has email configured.
++
++When sharing a file/folder, it is obvious that the file may be viewed or downloaded.
++However, if the shared with user is allowed to modify the file in any way, the “can edit” box should be checked.
++The sharing user may allow the shared with user to update, delete, or re-share the file.
++Note, by default, all permissions are set.
++
++It should be noted that when sharing a folder, an additional permission, “create” is available.
++When enabled, the shared to users can create new files and folders within the shared folder.
++
++Share as a link
++---------------
++
++In the event that an ownCloud user desires to share a file with a non-ownCloud user, the file may be shared as a link.
++To share as a link, hover over the line containing the file and select Share.
++Then select the check box next to “Share link”
++
++|10000000000003E8000001524A147A04_png|
++
++The link is then shown in the text box.
++The link may be copied and pasted into an email and sent to the other user.
++Alternatively, if email is setup within ownCloud, the sharing user may input the shared with user’s email address in the text box and select send.
++The shared user will then receive an email from the ownCloud server with the link.
++
++There may be circumstances where the file owner wants some security on the link so it cannot be accessed by anyone other than the desired person.
++To do this, the link may be Password Protected by selecting the “Password Protect” checkbox and entering a desired password.
++
++|1000000000000403000001632F0B76F6_png|
++
++
++Setting Expiration Date
++-----------------------
++
++ownCloud allows the sharing user to expire a file or folder share at a given date.
++This expiration applies to all shares within the folder as well.
++So, if a user expires a folder share, all files within the folder will no longer be shared.
++
++To set an expiration, select the Set expiration date checkbox and then select the expiration date.
++(The calendar will appear when the mouse is clicked in the Expiration date text box.
++
++|10000000000004010000017E4A6552BC_png|
++
++
++.. |10000000000003E8000001524A147A04_png| image:: images/10000000000003E8000001524A147A04.png
++    :width: 6.5in
++    :height: 2.1965in
++
++
++.. |1000000000000404000000FCFC13E732_png| image:: images/1000000000000404000000FCFC13E732.png
++    :width: 6.5in
++    :height: 1.5929in
++
++
++.. |10000000000004010000017E4A6552BC_png| image:: images/10000000000004010000017E4A6552BC.png
++    :width: 6.5in
++    :height: 2.422in
++
++
++.. |1000000000000403000001632F0B76F6_png| image:: images/1000000000000403000001632F0B76F6.png
++    :width: 6.5in
++    :height: 2.2465in
++
++
++.. |10000000000003EC000000AB60616FA7_png| image:: images/10000000000003EC000000AB60616FA7.png
++    :width: 6.5in
++    :height: 1.1071in
++
++Retrieving shared data
++======================
++
++User/group shares
++-----------------
++
++When the shared with user logs into their ownCloud instance they will see a “Shared” folder.
++
++|100000000000046C000000C2D3E5CF30_png|
++
++Within that Shared folder are all files and folders which have been shared to that user by any other ownCloud user.
++
++|1000000000000462000000D44541CF9A_png|
++
++Share as link
++-------------
++
++To view a file/folder which was shared as a link, simply enter the link into the browser.
++
++|10000000000004CA000002B52116BE0C_png|
++
++To download the file/folder select the Download button on the upper right of the page.
++If this link was password protected, the user will be prompted with a password prior to this page appearing.
++
++|100000000000045800000197FE462F2B_png|
++
++
++.. |100000000000045800000197FE462F2B_png| image:: images/100000000000045800000197FE462F2B.png
++    :width: 6.5in
++    :height: 2.3791in
++
++
++.. |10000000000004CA000002B52116BE0C_png| image:: images/10000000000004CA000002B52116BE0C.png
++    :width: 6.5in
++    :height: 3.6744in
++
++
++.. |100000000000046C000000C2D3E5CF30_png| image:: images/100000000000046C000000C2D3E5CF30.png
++    :width: 6.5in
++    :height: 1.1138in
++
++
++.. |1000000000000462000000D44541CF9A_png| image:: images/1000000000000462000000D44541CF9A.png
++    :width: 6.5in
++    :height: 1.2283in
 +
-     Table_of_Contents
-     Introduction
-     Configuration
-     Utilization
-     Retrieving_shared_data
diff --cc core/doc/admin/_sources/apps/files_trashbin/index.txt
index 13fea91,0000000..7a5adcd
mode 100644,000000..100644
--- a/core/doc/admin/_sources/apps/files_trashbin/index.txt
+++ b/core/doc/admin/_sources/apps/files_trashbin/index.txt
@@@ -1,9 -1,0 +1,198 @@@
- **ownCloud Deleted Files**
++=============
++Deleted Files
++=============
 +
- .. toctree::
-     :maxdepth: 2
++The ownCloud server stores deleted files in a temporary area in the event that the file was inadvertently deleted and/or needs to be restored.
++
++Expiry of deleted files
++=======================
++
++There are two instances in which ownCloud will automatically permanently remove a deleted file.
++
++Disk Utilization
++----------------
++
++To prevent a user from running out of disk space, the ownCloud deleted files app will not utilize more than 50% of the currently available free space for deleted files.
++If the deleted files exceed this limit, ownCloud deletes the oldest files until it gets below this limit.
++
++Age
++---
++
++By default, deleted files remain in the trash bin for 30 days.
++This can be configured using the trashbin_retention_obligation parameter
++in the ``config.php`` file.
++Files older than the configured value (or default 30 days) will be permanently deleted.
++ownCloud checks the age of the files each time a new file is moved to the deleted files bin.
++
++Configuration and storage
++==========================
++
++Configuration
++-------------
++
++By default, the ownCloud deleted files app is enabled.
++To verify or disable, navigate to the apps
++page and select Deleted Files.
++
++|100000000000042F000000CC3EDDE79E_png|
++
++Storage
++-------
++
++Once a file has been deleted by the user, it is moved to the ``~/data/<user>/files_trashbin/files`` folder.
++
++|10000000000002B3000000365E1CD00D_png|
++
++The remaining directories retain information on encryption key files, and versions.
++
++.. |10000000000002B3000000365E1CD00D_png| image:: images/10000000000002B3000000365E1CD00D.png
++    :width: 6.5in
++    :height: 0.5075in
++
++
++.. |100000000000042F000000CC3EDDE79E_png| image:: images/100000000000042F000000CC3EDDE79E.png
++    :width: 6.5in
++    :height: 1.2382in
++
++Utilization
++===========
++
++The deleted files app, when enabled, automatically moves deleted files to the Deleted Files folder and leaves them available for restore or permanent deletion
++
++Delete a file
++-------------
++
++To delete a file, either select the file check box and select Delete
++on the upper right of the screen, or the “x” to the right of the file.
++
++|1000000000000530000001410CF0028A_png|
++
++
++To delete multiple files simultaneously, select the check box on all the desired files, then select Delete
++on the upper right of the screen.
++
++View Deleted Files
++------------------
++
++To view a list of the deleted files, select the Deleted files
++button on the upper right of the browser.
++
++|1000000000000532000000285DDBBF37_png|
++
++Once selected, a list of all deleted files will appear.
++
++
++Restore files
++-------------
++
++As with deleting files, there are two ways to restore a file.
++Either select the check box next to the file (or for bulk restore – files) and select restore
++on the upper right.
++Or hover over the file and select restore
++.
++
++|1000000000000527000000A7AB409FE0_png|
++|100000000000052500000088DBB95005_png|
++
++
++Permanently Delete Files
++------------------------
++
++Files in the Deleted Files
++folder can be permanently deleted.
++To do this, either select the check box next to the file (or for bulk deletion – files) and select Delete in the upper right corner.
++Or hover over the file and select the “x”.
++
++Nested files and restore
++------------------------
++
++If, for instance, the directory structure within ownCloud is
++*~/public/support/documentation/ownCloud undelete*
++.
++
++|1000000000000525000000BE30CF0423_png|
++
++Delete entire directory structure
++~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++
++When the public folder is deleted, all child folders/files will also be deleted.
++
++|100000000000052F000000C2867B7294_png|
++
++Suppose the file “ownCloud undelete.docx” was still required.
++A restore of the file will place it in the ‘root’ directory of the Files folder.
++
++
++Delete only the file
++~~~~~~~~~~~~~~~~~~~~
++
++If the file “ownCloud undelete.docx”
++was accidentally deleted, it may be restored following the steps described in section
++.
++The restore will place the file back into the directory structure from where it came.
++
++Delete the file then the directory structure
++~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++
++If the file “ownCloud undelete.docs”
++is deleted, then the entire directory structure is deleted, the file will appear in the ‘root’ of the Deleted Files folder.
++
++|1000000000000523000000C6F786381C_png|
++
++A restore of “ownCloud undelete.docx”
++will place it in the user’s ownCloud root directory.
++
++|100000000000053100000142D9A4C916_png|
++
++Shared files and restore
++------------------------
++
++When a
++shared file is deleted, the file will be deleted from the shared to user as well.
++Upon restore of the file by the file owner, the file is no longer shared.
++
++Restore files with Versions
++---------------------------
++
++When a file which has versions has been deleted, and then restored, the versions will exist upon restoration.
++
++
++.. |1000000000000525000000BE30CF0423_png| image:: images/1000000000000525000000BE30CF0423.png
++    :width: 6.5in
++    :height: 0.9374in
++
++
++.. |100000000000052F000000C2867B7294_png| image:: images/100000000000052F000000C2867B7294.png
++    :width: 6.5in
++    :height: 0.95in
++
++
++.. |100000000000052500000088DBB95005_png| image:: images/100000000000052500000088DBB95005.png
++    :width: 6.5in
++    :height: 0.6717in
++
++
++.. |1000000000000532000000285DDBBF37_png| image:: images/1000000000000532000000285DDBBF37.png
++    :width: 6.5in
++    :height: 0.1957in
++
++
++.. |1000000000000530000001410CF0028A_png| image:: images/1000000000000530000001410CF0028A.png
++    :width: 6.5in
++    :height: 1.5701in
++
++
++.. |1000000000000523000000C6F786381C_png| image:: images/1000000000000523000000C6F786381C.png
++    :width: 6.5in
++    :height: 0.9783in
++
++
++.. |1000000000000527000000A7AB409FE0_png| image:: images/1000000000000527000000A7AB409FE0.png
++    :width: 6.5in
++    :height: 0.8228in
++
++
++.. |100000000000053100000142D9A4C916_png| image:: images/100000000000053100000142D9A4C916.png
++    :width: 6.5in
++    :height: 1.5752in
 +
-     Table_of_Contents
-     Introduction
-     Configuration_and_storage_
-     Utilization
diff --cc core/doc/admin/_sources/apps/files_versions/index.txt
index 66e4cf2,0000000..e95404c
mode 100644,000000..100644
--- a/core/doc/admin/_sources/apps/files_versions/index.txt
+++ b/core/doc/admin/_sources/apps/files_versions/index.txt
@@@ -1,16 -1,0 +1,191 @@@
- **ownCloud Versioning**
++========
++Versions
++========
 +
- Table of Contents
++The ownCloud Versions app maintains older versions of a file which have been
++modified by an ownCloud user.
 +
- ` <#_Toc374004001>`_
++Expiry of versions
++==================
 +
- Reviewers
++The versions app expires old versions automatically to make certain that the
++user doesn’t run out of space.  The following algorithm is used to delete old
++versions:
 +
- Allen Gigler 12/4/2013
++*   ownCloud keeps one new version every 2 seconds for the first 10 seconds
++*   ownCloud keeps one new version every minute for the first hour
++*   ownCloud keeps one new version every hour for the first 24 hours
++*   ownCloud keeps one new version every day for the first 30 days
++*   ownCloud keeps one new version every week thereafter.
 +
- .. toctree::
-     :maxdepth: 2
++The versions are adjusted along this algorithm every time a new version is created.
++
++Space limitations
++=================
++
++In addition to the expiry of versions, ownCloud’s versions app makes certain
++never to use more than 50% of the user’s currently available free space.  If
++stored versions exceed this limit, ownCloud will delete the oldest versions
++first until it meets this limit.
++
++Configuration and storage
++=========================
++
++Configuration
++-------------
++
++By default, the ownCloud versions app is enabled.
++To verify or disable, navigate to the apps
++page and select Versions.
++
++|1000000000000336000000F38C3FAF84_png|
++
++Storage
++-------
++
++Previous versions of files are stored in the ``data/<user>/files_versions`` folder.
++
++|100000000000021C0000004CACBF786C_png|
++
++This directory is automatically created when the first file version is created.
++
++The naming convention of the files in this directory are::
++
++  <file_name>.v<unix_timestamp>
++
++|10000000000002210000002DE3BE7515_png|
++
++
++.. |1000000000000336000000F38C3FAF84_png| image:: images/1000000000000336000000F38C3FAF84.png
++    :width: 6.5in
++    :height: 1.9217in
++
++
++.. |100000000000021C0000004CACBF786C_png| image:: images/100000000000021C0000004CACBF786C.png
++    :width: 5.6252in
++    :height: 0.7917in
++
++
++.. |10000000000002210000002DE3BE7515_png| image:: images/10000000000002210000002DE3BE7515.png
++    :width: 5.6772in
++    :height: 0.4689in
++
++
++.. |10000000000004ED000000BE3B9E25D5_png| image:: images/10000000000004ED000000BE3B9E25D5.png
++    :width: 6.5in
++    :height: 0.9791in
++
++Utilization
++===========
++
++The versions app, when enabled, automatically creates a new version each time an existing, non-empty file is saved.
++
++Initial File creation
++---------------------
++
++Create a file on the ownCloud server – either directly via the browser, an upload, or a file sync from the client.
++In this example, the file versionText.txt was created via the web browser.
++
++|1000000000000427000000324F58266D_png|
++
++Note
++~~~~
++
++Since this file was initially created via the web browser, it is an empty file.
++
++Edit the file
++-------------
++
++Edit the file through the web browser.
++
++|100000000000019E0000004CD2A0F407_png|
++
++And save.
++
++Notes
++~~~~~
++
++Editing an empty file, as in this instance, for the first time, does not create a new version.
++
++Create version
++--------------
++
++Edit the non-zero byte file either via the web browser, via the sync client or via an upload.
++
++|1000000000000194000000498325A766_png|
++
++And save.
++
++Notes
++~~~~~
++
++When performing an upload of a file which already exists on the server, a dialog box appears asking whether to keep the existing file or the new file.
++
++|10000000000001C1000000FE663748B2_png|
++
++
++
++
++
++
++
++
++In order to create a version, the New File must be selected.
++If the Existing File is selected, the file is not replaced hence no new version is created.
++
++Accessing Versions
++------------------
++
++In order to view what versions exist for a given file, hover over the line containing the file and select Versions
++on the right side.
++
++|1000000000000430000000AF9D6E724E_png|
++
++
++In this case, there are two previous versions of versionTest.txt
++.
++The thumbnail and creation time can be used to identify what was in the file in that version.
++
++Reverting to a different version
++--------------------------------
++
++To revert to a previous version, simply select the restore next to the version as seen in
++.
++
++Notes
++~~~~~
++
++In the instance where a file is reverted to another version, the “existing” version of the file is versioned and can be reverted at a later date.
++
++Sharing and Versions
++--------------------
++
++If user-A shares a file with user-B, user-B may revert the file to any previous version.
++If user-B modifies the file, a new version is created.
++
++
++
++.. |10000000000001C1000000FE663748B2_png| image:: images/10000000000001C1000000FE663748B2.png
++    :width: 4.6772in
++    :height: 2.6457in
++
++
++.. |1000000000000430000000AF9D6E724E_png| image:: images/1000000000000430000000AF9D6E724E.png
++    :width: 6.5in
++    :height: 1.061in
++
++
++.. |1000000000000194000000498325A766_png| image:: images/1000000000000194000000498325A766.png
++    :width: 4.2083in
++    :height: 0.7602in
++
++
++.. |100000000000019E0000004CD2A0F407_png| image:: images/100000000000019E0000004CD2A0F407.png
++    :width: 4.3126in
++    :height: 0.7917in
++
++
++.. |1000000000000427000000324F58266D_png| image:: images/1000000000000427000000324F58266D.png
++    :width: 6.5in
++    :height: 0.3055in
 +
-     Introduction
-     Configuration_and_storage
-     Utilization
diff --cc core/doc/admin/_sources/apps/firstrunwizard/index.txt
index 1f1cc34,0000000..c3abff5
mode 100644,000000..100644
--- a/core/doc/admin/_sources/apps/firstrunwizard/index.txt
+++ b/core/doc/admin/_sources/apps/firstrunwizard/index.txt
@@@ -1,10 -1,0 +1,93 @@@
- **ownCloud First Run Wizard**
++================
++First Run Wizard
++================
 +
- .. toctree::
-     :maxdepth: 2
++The ownCloud First Run Wizard is a welcome screen which links users to the various ownCloud utilities such as the Sync Client, Mobile Apps, and WebDav
++
++Configuration
++=============
++
++The First Run Wizard app is enabled by default.
++To verify or disable this app, navigate to the apps page and select “First Run Wizard”
++
++|1000000000000200000000BCCCC35DEB_png|
++
++.. |1000000000000200000000BCCCC35DEB_png| image:: images/1000000000000200000000BCCCC35DEB.png
++    :width: 5.3335in
++    :height: 1.9583in
++
++Usage
++=====
++
++When enabled, a user entering the ownCloud web browser for the first time will have the Welcome screen popup.
++
++|10000000000004920000028D9C8DC2CB_png|
++
++To close the window, select the ‘x’ in the upper right corner.
++If the user would like to bring up this window at a later time, they may do so by navigating to the Personal menu selection and select “Show First Run Wizard again”
++
++|10000000000002A6000000BFBE298238_png|
++
++.. |10000000000004920000028D9C8DC2CB_png| image:: images/10000000000004920000028D9C8DC2CB.png
++    :width: 6.5in
++    :height: 3.628in
++
++
++.. |10000000000002A6000000BFBE298238_png| image:: images/10000000000002A6000000BFBE298238.png
++    :width: 6.5in
++    :height: 1.8311in
++
++Links
++=====
++
++The wizard contains links for the Desktop app, Android App on Google Play, and iOS on the App store, as well as how to access files via WebDav.
++
++Desktop App
++-----------
++
++Selecting the Desktop App link will bring the user to ownCloud’s web site to download the client.
++
++|1000000000000557000002E148BAB6D4_png|
++
++
++Android App
++-----------
++
++Selecting the Android App will load the web page to purchase the android client from the Google Play store.
++
++|1000000000000668000002D29EAD9899_png|
++
++iOS App
++-------
++
++Selecting the iOS App loads the itunes web page to obtain the ownCloud iOS mobile client.
++
++|10000000000005F30000030F1372448D_png|
++
++Access files via WebDAV
++-----------------------
++
++This link brings up a link with documentation on how to access files on the ownCloud server using WebDAV.
++
++|100000000000066D000001AAD8CE8256_png|
++
++
++.. |1000000000000668000002D29EAD9899_png| image:: images/1000000000000668000002D29EAD9899.png
++    :width: 6.5in
++    :height: 2.861in
++
++
++.. |1000000000000557000002E148BAB6D4_png| image:: images/1000000000000557000002E148BAB6D4.png
++    :width: 6.5in
++    :height: 3.5043in
++
++
++.. |100000000000066D000001AAD8CE8256_png| image:: images/100000000000066D000001AAD8CE8256.png
++    :width: 6.5in
++    :height: 1.6835in
++
++
++.. |10000000000005F30000030F1372448D_png| image:: images/10000000000005F30000030F1372448D.png
++    :width: 6.5in
++    :height: 3.3417in
 +
-     Table_of_Contents
-     Introduction
-     Configuration
-     Usage
-     Links
diff --cc core/doc/admin/_sources/apps/index.txt
index 0000000,0000000..3c56362
new file mode 100644
--- /dev/null
+++ b/core/doc/admin/_sources/apps/index.txt
@@@ -1,0 -1,0 +1,19 @@@
++====
++Apps
++====
++
++.. toctree::
++   :maxdepth: 1
++
++   activity/index
++   admin_dependencies_chk/index
++   files_antivirus/index
++   files_encryption/index
++   files_external/index
++   files_sharing/index
++   files_trashbin/index
++   files_versions/index
++   firstrunwizard/index
++   user_ldap/index
++   viewers/index
++
diff --cc core/doc/admin/_sources/apps/user_ldap/index.txt
index 48bbbf3,0000000..ac8a9b7
mode 100644,000000..100644
--- a/core/doc/admin/_sources/apps/user_ldap/index.txt
+++ b/core/doc/admin/_sources/apps/user_ldap/index.txt
@@@ -1,8 -1,0 +1,503 @@@
- **LDAP Active Directory Integration**
++===========================
++LDAP user and group backend
++===========================
 +
- .. toctree::
-     :maxdepth: 2
++ownCloud ships an LDAP backend, which allows full use of ownCloud for user logging with LDAP credentials including:
++
++*   LDAP group support
++*   File sharing with users and groups
++*   Access via WebDAV and of course ownCloud Desktop Client
++*   Versioning, external Storages and all other ownCloud features.
++
++Configuration
++=============
++
++Enable LDAP app
++---------------
++
++From the APPs page, select “LDAP user and group backend” and select enable
++
++|1000020100000359000000A8B848DE68_png|
++
++Configuring LDAP
++----------------
++
++The configuration of the LDAP feature is performed on the Admin page of the ownCloud web browser.
++The configuration follows a wizard-like approach split into four tabs.
++The first tab must be completed correctly to allow access to subsequent tabs.
++Although the configuration in the remaining tabs is detected automatically, it should be reviewed by the admin to verify correctness.
++An indicator exists on the all pages
++to show whether the configuration is valid, incomplete, or incorrect.
++
++Configuration settings are saved automatically when the cursor is no longer focused on the input element.
++
++Server Tab
++~~~~~~~~~~
++
++The server tab contains basic information on the LDAP server.
++It makes certain that ownCloud can connect to the desired LDAP and read data from it.
++At a minimum, the admin must provide a hostname for the LDAP server.
++If anonymous access to the LDAP server is not allowed, the admin will be required to enter an account Distinguished Name (DN) and password.
++ownCloud will auto-detect the port and base DN.
++
++Server
++^^^^^^
++
++ownCloud can be configured to connect to multiple LDAP servers.
++Using this control you can pick a configuration you want to edit or to add a new one.
++The button
++Delete Configuration deletes the current configuration.
++
++Host
++^^^^
++
++The hostname of the LDAP server.
++It can also be a ``ldaps://`` URI.
++It is possible to pass a port number which will speed up port detection.
++This is especially useful if a custom port is used.
++ownCloud will subsequently move the port value to the port field.
++
++Examples::
++
++  directory.my-company.com
++  ldaps://directory.my-company.com
++  directory.my-company.com:9876
++
++
++
++Port
++^^^^
++
++This is the port which ownCloud should utilize to connect to the LDAP server.
++Upon initial configuration, this field is disabled.
++ownCloud will auto-detect the port if it is running on a standard port (389).
++After ownCloud detects the port, the field will be enabled for admin input.
++A successfully discovered port will be inserted by ownCloud.
++
++
++User DN
++^^^^^^^
++
++The name as DN of a user who is able to do searches in the LDAP directory.
++For anonymous access, leave this field blank.
++It is recommended to have a special system user for ownCloud.
++This information is provided by the LDAP admin.
++
++Password
++^^^^^^^^
++
++The password for the user given above.
++For anonymous access, leave this blank.
++This information is provided by the LDAP admin.
++
++Base DN
++^^^^^^^
++
++The base DM of the LDAP from where all users and groups can be reached.
++It is possible to provide separated base DN’s for users and groups in the advanced tab.
++This is a mandatory field.
++ownCloud will attempt to determine the proper value of this field based on the provided User DN or Host values.
++
++|100000000000043200000169BCD20493_png|
++
++User Filter
++~~~~~~~~~~~
++
++The settings in the User Filter tab determine which LDAP users will appear and will be able to log into ownCloud.
++This may be configured using the wizard or entered via a raw LDAP filter.
++
++Only those object classes
++^^^^^^^^^^^^^^^^^^^^^^^^^
++
++ownCloud will determine the available object classes.
++ownCloud will automatically select the object that contains the highest number of users.
++It is possible to select multiple object classes.
++
++Only from those groups
++^^^^^^^^^^^^^^^^^^^^^^
++
++This is used if the LDAP server supports the member-of-overlay in LDAP filters.
++It allows the admin to define the users from one or more certain groups that are allowed to appear and log into ownCloud.
++No value is selected by default.
++It is possible to select multiple groups.
++
++If the LDAP server does not support member-of-overlay in LDAP filters, the field is disabled.
++
++Edit raw filter instead
++^^^^^^^^^^^^^^^^^^^^^^^
++
++Selecting this text will toggle the filter mode.
++Instead of the wizard’s assistance, the admin may enter the raw LDAP filter in this field.
++
++Example::
++
++  objectClass=inetOrgPerson
++
++
++x users found
++^^^^^^^^^^^^^
++
++Indicates the approximate number of users allowed to access ownCloud.
++This number will update after any changes made to the LDAP configuration.
++
++|100000000000042500000163D2B339D5_png|
++
++
++Login Filter
++~~~~~~~~~~~~
++
++The settings in the login filter tab determine which user information will be compared to login credentials entered by the user.
++It is possible to allow multiple user details.
++It is also possible to enter a raw LDAP filter.
++
++LDAP Username
++^^^^^^^^^^^^^
++
++If checked, the login credentials will be compared to the username in the LDAP directory.
++The corresponding attribute, usually ``uid`` or ``samaccountname`` will be automatically detected by ownCloud.
++
++LDAP Email Address
++^^^^^^^^^^^^^^^^^^
++
++If checked, the login credentials will be compared to an email address in the LDAP directory.
++ownCloud will exmaine the ``mailPrimaryAddress`` and ``mail`` attributes in the LDAP for the email address.
++
++Other attributes
++^^^^^^^^^^^^^^^^
++
++This field allows the admin to select additional attributes for comparison.
++The list is generated automatically based on the attributes contained in the user object of the LDAP server.
++
++Enter raw filter instead
++^^^^^^^^^^^^^^^^^^^^^^^^
++
++Selecting this text will toggle the filter mode.
++Instead of the wizard’s assistance, the admin may enter the raw LDAP filter in this field.
++
++The ``%uid`` placeholder will be replaced with the login name entered by the user upon login.
++
++Examples:
++
++* Username only::
++
++    uid=%iud
++
++* Username or email address::
++
++    (|(uid=%uid)(mail=%uid))
++
++|10000000000004170000016ACB5E15AE_png|
++
++Group Filter
++~~~~~~~~~~~~
++
++The settings in this tab determine which groups will be available in ownCloud.
++This tab does not restrict logins in any manner as that was handled in the prior tabs.
++It is possible to enter a raw LDAP filter as well.
++
++By default, there are no groups available in ownCloud.
++The admin must enable this manually.
++
++Only those object classes
++^^^^^^^^^^^^^^^^^^^^^^^^^
++
++ownCloud will automatically determine which object classes are available in the LDAP.
++ownCloud will only list object classes that return at least one group object.
++It is possible to enter multiple object classes.
++
++Only from those groups
++^^^^^^^^^^^^^^^^^^^^^^
++
++This setting allows the admin to select which groups are available within ownCloud.
++ownCloud will generate a list of available groups found in the LDAP server for the admin to select.
++It is possible to enter multiple groups.
++
++Edit raw filter instead
++^^^^^^^^^^^^^^^^^^^^^^^
++
++Selecting this text will toggle the filter mode.
++Instead of the wizard’s assistance, the admin may enter the raw LDAP filter in this field
++
++Y groups found
++^^^^^^^^^^^^^^
++
++Indicates the approximate number of groups available in ownCloud.
++This number will update after any changes made to the LDAP configuration.
++
++|100000000000043000000164DA0CE8C9_png|
++
++
++Advanced Tab
++~~~~~~~~~~~~
++
++The LDAP Advanced settings section allows the admin to define less common
++options.  These options are not required for a working connection however, they
++can have a positive effect on the performance.
++
++The Advanced Settings tab has three sections
++
++* Connection settings
++* Directory settings
++* Special attributes
++
++Connection Settings
++^^^^^^^^^^^^^^^^^^^
++
++Configuration Active
++""""""""""""""""""""
++
++Allows the admin to enable or disable the current configuration.
++A disabled configuration will not connect to the LDAP server.
++
++By default, this is disabled.
++It is enabled automatically, when using the wizard and configuration is valid and tests successfully.
++
++Backup (Replica) Host
++"""""""""""""""""""""
++
++This is used to define a backup LDAP server.  ownCloud automatically attempts
++to connect to the backup server when the primary server cannot be accessed.  It
++is important that the backup server is an exact replica of the primary server
++as all the object UUIDs must match.
++
++Backup (Replica) Port
++"""""""""""""""""""""
++
++This identifies the port on which ownCloud will connect to the backup LDAP server.
++If no port is provided, ownCloud will utilize the same port as the primary LDAP server.
++
++Disable Main Server
++"""""""""""""""""""
++
++This is used to disable the primary LDAP server so ownCloud will connect only to the backup server.
++This can be useful for planned maintenance on the primary server.
++
++Case insensitive LDAP server (Windows)
++""""""""""""""""""""""""""""""""""""""
++
++Check this if the LDAP server is running on a windows host.
++Not usually necessary.
++
++Turn off SSL certificate validation
++"""""""""""""""""""""""""""""""""""
++
++Disables the check for a valid SSL certificate.
++It is recommended to use for testing only if needed, but not use in production.
++
++Cache Time-To-Live
++""""""""""""""""""
++
++ownCloud caches the information it receives from the LDAP server.  This is
++necessary as the ownCloud server attempts to validate the user with every page
++request or WebDAV interaction.  This time is in seconds.
++
++Note if it is required to have the most up-to-date information from the LDAP,
++it is recommended not to turn off the cache totally, however, to define a
++lifetime of a small duration (15 seconds)
++
++|100000000000042E000001D3EEB9978B_png|
++
++Directory Settings
++^^^^^^^^^^^^^^^^^^
++
++User Display Name Field
++"""""""""""""""""""""""
++
++The attribute that should be used as display name in ownCloud.
++
++Base User Tree
++""""""""""""""
++
++The Base DN of LDAP, from where all users can be reached.
++It needs to be given completely despite to the Base DN from the Basic Settings.
++You can specify multiple base trees, one in each line.
++
++User Search Attributes
++""""""""""""""""""""""
++
++These attributes are used when a search for users with a search string is done.
++This happens in the share dialogue.
++By default the user display name attribute as specified above is used.
++Multiple attributes can be given, one in each line.
++
++Note: if an attribute is not available for a given user object, the user will neither be listed nor able to login.
++
++Group Display Name Field
++""""""""""""""""""""""""
++
++The attribute that should be used as an ownCloud group name.
++ownCloud allows a limited set of characters (regex notation)::
++
++  [a-zA_Z0-9,-_@]
++
++Every other character will be replaced in ownCloud.
++Once a group bane is assigned, it will not be changed.
++
++Base Group Tree
++"""""""""""""""
++
++The base DN of LDAP from where all groups can be reached.
++It needs to be given completely despite to the Base DN from the Basic Settings.
++You can specify multiple base trees, one in each line.
++
++Group Search Attributes
++"""""""""""""""""""""""
++
++These attributes are used when a search for groups with a search string is done.
++This happens in the share dialogue for instance.
++By default the group display name attribute as specified above is being used.
++Multiple attributes can be given, one in each line.
++
++Group Member association
++""""""""""""""""""""""""
++
++The attribute that is used to indicate group memberships.
++
++|10000201000005F90000029D8BA200FB_png|
++
++
++Special Attributes
++^^^^^^^^^^^^^^^^^^
++
++Quota Field
++"""""""""""
++
++This field is used to set a LDAP attribute to define the user quota.
++The attribute should retain a readable value, for example::
++
++  2 GB
++
++Quota Default
++"""""""""""""
++
++This is used to override the ownCloud default quota for LDAP users who do not have an attribute set in the above parameter.
++
++Example::
++
++  15GB
++
++Email Field
++"""""""""""
++
++ownCloud will read the attribute configured here and configure the user’s email.
++
++User Home Folder Naming Rule
++""""""""""""""""""""""""""""
++
++By default, ownCloud creates a user directory which contains all files and meta data based on the ownCloud user name.
++To override this setting and name it after a different attribute, configure that attribute here.
++The attribute can also return an absolute path (such as ``/mnt/storage43/alice``).
++
++|100000000000041D0000017D8D1BC4D9_png|
++
++Expert Tab
++----------
++
++Internal Username
++~~~~~~~~~~~~~~~~~
++
++The internal username is the identifier in ownCloud for LDAP users.
++By default it will be created from the UUID attribute.  By using the UUID
++attribute it is made sure that the username is unique and characters do not
++need to be converted.  The internal username has the restriction that only
++these characters are allowed (regex notation)::
++
++  [a-zA-Z0-0_. at -]
++
++Other characters are replaced with their ASCII correspondence or are simply
++omitted
++
++The LDAP backend ensures that there are no duplicate internal usernames in
++ownCloud, i.e. that it is checking all other activated user back ends
++(including local ownCloud users). On collisions a random number (between 1000
++and 9999) will be attached to the retrieved value. For example, if ``alice``
++exists, the next username may be ``alice_1337``.
++
++The internal username is also the default name for the user home folder in
++ownCloud. It is also a part of remote URLs, for instance for all \*DAV
++services. With this setting the default behavior can be overridden.
++
++Leave it empty for default behavior. Changes will have effect only on newly
++mapped (added) LDAP users.
++
++Override UUID detection
++~~~~~~~~~~~~~~~~~~~~~~~
++
++By default ownCloud auto-detects the UUID attribute.
++The UUID attribute is used to doubtlessly identify LDAP users and groups.
++Also, the internal username will be created based on the UUID, if not specified from above.
++
++You can override the setting and pass an attribute of your choice. You must
++make sure that the attribute of your choice can be fetched for both users and
++groups and it is unique. Leave it empty for default behavior. Changes will have
++effect only on newly mapped (added) LDAP users and groups. It also will have
++effect when a user’s or group’s DN changes and an old UUID was cached: It will
++result in a new user.
++
++Because of this, the setting should be applied before putting ownCloud in
++production use and cleaning the bindings (see below).
++
++Username-LDAP User Mapping
++~~~~~~~~~~~~~~~~~~~~~~~~~~
++
++ownCloud uses the usernames as key to store and assign data.  In order to
++precisely identify and recognize users, each LDAP user will have an internal
++username in ownCloud.  This requires a mapping from ownCloud username to LDAP
++user.  The created username is mapped to the UUID of the LDAP user.
++Additionally the DN is cached as well to reduce LDAP interaction, but is not
++used for identification.  If the DN changes, the change will be detected by
++ownCloud by checking the UUID value.
++
++The same is valid for groups.
++
++The internal ownCloud name is used all over in ownCloud.
++Clearing the mappings will have leftovers everywhere.
++Never clear the mappings in a production environment.
++Only clear mappings in a test or experimental stage.
++
++|10000000000003FB000002359BAFB40E_png|
++
++
++
++
++
++.. |100000000000042500000163D2B339D5_png| image:: images/100000000000042500000163D2B339D5.png
++    :width: 6.5in
++    :height: 2.1752in
++
++
++.. |100000000000043200000169BCD20493_png| image:: images/100000000000043200000169BCD20493.png
++    :width: 6.5in
++    :height: 2.1846in
++
++
++.. |10000000000004170000016ACB5E15AE_png| image:: images/10000000000004170000016ACB5E15AE.png
++    :width: 6.5in
++    :height: 2.2465in
++
++
++.. |100000000000043000000164DA0CE8C9_png| image:: images/100000000000043000000164DA0CE8C9.png
++    :width: 6.5in
++    :height: 2.1583in
++
++
++.. |1000020100000359000000A8B848DE68_png| image:: images/1000020100000359000000A8B848DE68.png
++
++
++.. |10000000000003FB000002359BAFB40E_png| image:: images/10000000000003FB000002359BAFB40E.png
++    :width: 6.5in
++    :height: 3.6043in
++
++
++.. |100000000000042E000001D3EEB9978B_png| image:: images/100000000000042E000001D3EEB9978B.png
++    :width: 6.5in
++    :height: 2.8366in
++
++
++.. |10000201000005F90000029D8BA200FB_png| image:: images/10000201000005F90000029D8BA200FB.png
++
++
++.. |100000000000041D0000017D8D1BC4D9_png| image:: images/100000000000041D0000017D8D1BC4D9.png
++    :width: 6.5in
++    :height: 2.352in
 +
-     Table_of_Contents
-     Introduction
-     CONFIGURATION
diff --cc core/doc/admin/_sources/apps/viewers/index.txt
index 8bae6a8,0000000..e19c3cd
mode 100644,000000..100644
--- a/core/doc/admin/_sources/apps/viewers/index.txt
+++ b/core/doc/admin/_sources/apps/viewers/index.txt
@@@ -1,12 -1,0 +1,58 @@@
- **ownCloud Viewers**
++============
++File Viewers
++============
 +
- Table of Contents
++ownCloud provides apps which allow users to view/edit
++text files and view images which exist on the ownCloud server.
 +
- ` <#_Toc376421150>`_
++Configuration
++=============
 +
- .. toctree::
-     :maxdepth: 2
++Text Editor
++-----------
++
++The Text Editor App allows users to view and edit text files.
++To enable this app, navigate to the Apps page and select “Text Editor” then Enable.
++
++|100000000000012C0000009C444B4720_png|
++
++Image Viewer
++------------
++
++The image viewer app allows users to preview image files within the ownCloud web interface.
++To enable, navigate to the Apps page and select “Image Viewer” then enable.
++
++|10000000000001400000008A557EF7E3_png|
++
++.. |10000000000001400000008A557EF7E3_png| image:: images/10000000000001400000008A557EF7E3.png
++    :width: 3.3335in
++    :height: 1.4374in
++
++
++.. |100000000000012C0000009C444B4720_png| image:: images/100000000000012C0000009C444B4720.png
++    :width: 3.1252in
++    :height: 1.6252in
++
++Utilization
++===========
++
++When the apps are enabled, select the file name on the web interface Files tab and either the text editor or the image will appear.
++
++|10000000000001E50000006E3ECDC427_png|
++
++
++|100000000000044C000002B0B421E27E_png|
++
++
++When the apps are disabled, selecting the file name on the web interface will prompt the user to download the specified file.
++
++
++.. |100000000000044C000002B0B421E27E_png| image:: images/100000000000044C000002B0B421E27E.png
++    :width: 6.5in
++    :height: 4.0654in
++
++
++.. |10000000000001E50000006E3ECDC427_png| image:: images/10000000000001E50000006E3ECDC427.png
++    :width: 5.052in
++    :height: 1.1457in
 +
-     Introduction
-     Configuration
-     Utilization
diff --cc core/doc/admin/_sources/config/apps.txt
index a16b239,0000000..8e99c96
mode 100644,000000..100644
--- a/core/doc/admin/_sources/config/apps.txt
+++ b/core/doc/admin/_sources/config/apps.txt
@@@ -1,50 -1,0 +1,50 @@@
 +APPS
 +====
 +
 +The following parameters are used for ownCloud apps.
 +
 ++-----------------------+-----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+
 +| **Parameter**         | **Format**                                          | **Description**                                                                                                                                           |
 +|                       |                                                     |                                                                                                                                                           |
 ++-----------------------+-----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+
 +| **Apps Paths**        | "apps_paths" => array(                              | Use this parameter to set the location of the apps folder which should be scanned for available apps and/or where user specific apps should be installed. |
 +|                       |                                                     | The path defines the absolute file system path to the app folder.                                                                                         |
- |                       | 0 => array(                                         | The key url defines the http web path to that folder starting at the ownCloud web root.                                                                   |
++|                       | 0 => array(                                         | The key url defines the http web path to that folder starting at the owncloud web root.                                                                   |
 +|                       |                                                     | The key writable indicates if a user can install apps in that folder.                                                                                     |
 +|                       | 'path'=> '/var/www/owncloud/apps',                  |                                                                                                                                                           |
 +|                       |                                                     |                                                                                                                                                           |
 +|                       | 'url' => '/apps',                                   |                                                                                                                                                           |
 +|                       |                                                     |                                                                                                                                                           |
 +|                       | 'writable' => true,                                 |                                                                                                                                                           |
 +|                       |                                                     |                                                                                                                                                           |
 +|                       | ),                                                  |                                                                                                                                                           |
 +|                       |                                                     |                                                                                                                                                           |
 +|                       | 1 => array (                                        |                                                                                                                                                           |
 +|                       |                                                     |                                                                                                                                                           |
 +|                       | ‘path’ =>                                           |                                                                                                                                                           |
 +|                       | ‘/var/www/owncloud/apps2’,                          |                                                                                                                                                           |
 +|                       |                                                     |                                                                                                                                                           |
 +|                       | ‘url’ => ‘/apps2’,                                  |                                                                                                                                                           |
 +|                       |                                                     |                                                                                                                                                           |
 +|                       | Writable => false,                                  |                                                                                                                                                           |
 +|                       |                                                     |                                                                                                                                                           |
 +|                       | ),                                                  |                                                                                                                                                           |
 +|                       |                                                     |                                                                                                                                                           |
 +|                       | ),                                                  |                                                                                                                                                           |
 +|                       |                                                     |                                                                                                                                                           |
 ++-----------------------+-----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+
 +| **App Store Enabled** | "appstoreenabled" => true,                          | When enabled, admins may install apps from the ownCloud app store.                                                                                        |
 +|                       |                                                     |                                                                                                                                                           |
 +|                       |                                                     |                                                                                                                                                           |
 ++-----------------------+-----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+
 +| **App Store URL**     | "appstoreurl" => "http://api.apps.owncloud.com/v1", | The URL of the appstore.                                                                                                                                  |
 +|                       |                                                     |                                                                                                                                                           |
 +|                       |                                                     |                                                                                                                                                           |
 ++-----------------------+-----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+
 +| **App Code Checker**  | "appcodechecker" => "",                             | Checks for malicious code fragments of 3                                                                                                                  |
 +|                       |                                                     | rd                                                                                                                                                        |
 +|                       |                                                     | party apps.                                                                                                                                               |
 +|                       |                                                     |                                                                                                                                                           |
 ++-----------------------+-----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+
 +
 +
diff --cc core/doc/admin/_sources/config/code_locations.txt
index 34785aa,0000000..34785aa
mode 100644,000000..100644
--- a/core/doc/admin/_sources/config/code_locations.txt
+++ b/core/doc/admin/_sources/config/code_locations.txt
diff --cc core/doc/admin/_sources/config/default_parameters.txt
index 0f6db35,0000000..7f28a8b
mode 100644,000000..100644
--- a/core/doc/admin/_sources/config/default_parameters.txt
+++ b/core/doc/admin/_sources/config/default_parameters.txt
@@@ -1,63 -1,0 +1,74 @@@
 +Default Parameters
 +==================
 +
 +The following parameters are automatically configured by ownCloud upon the initial admin login.
 +These parameters are mandatory for the ownCloud instance to operate properly.
 +
 ++---------------------+---------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 +| **Parameter**       | **Format**                | **Description**                                                                                                                                                                     |
 +|                     |                           |                                                                                                                                                                                     |
 ++---------------------+---------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 +| **Debug**           | define("DEBUG", true);    | When set to true, additional information is written to the logs.                                                                                                                    |
 +|                     |                           | This is to be used only for local development and not in a production environment.                                                                                                  |
 +|                     |                           |                                                                                                                                                                                     |
 ++---------------------+---------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 +| **Installed**       | "installed" => false,     | This flag indicates whether the ownCloud instance was installed successfully.                                                                                                       |
 +|                     |                           | When set to true, the install was successful.                                                                                                                                       |
 +|                     |                           | When set to false the instance is not properly installed.                                                                                                                           |
 +|                     |                           |                                                                                                                                                                                     |
 ++---------------------+---------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 +| **DB Type**         | "dbtype" => "sqlite",     | The dbtype indicates what type of database is being used with this install.                                                                                                         |
 +|                     |                           |                                                                                                                                                                                     |
 +|                     |                           |                                                                                                                                                                                     |
 ++---------------------+---------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 +| **DB Name**         | "dbname" => "owncloud",   | The ownCloud database within the SQL instance.                                                                                                                                      |
 +|                     |                           | ownCloud database configuration guides use “owncloud” in the instructions, it is the default for this field.                                                                        |
 +|                     |                           | This may be set to any valid table name.                                                                                                                                            |
 +|                     |                           | If the table doesn’t exist, the setup will attempt to create it, provided it has proper permissions.                                                                                |
 +|                     |                           |                                                                                                                                                                                     |
 ++---------------------+---------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 +| **DB User**         | "dbuser" => "",           | This is the user that ownCloud uses to write to the databse.                                                                                                                        |
 +|                     |                           | This must be unique across ownCloud instances using the same SQL database.                                                                                                          |
 +|                     |                           | The user will be created when the install wizard is complete.                                                                                                                       |
 +|                     |                           | Since the database user in the initial login screen has admin privileges (root), ownCloud creates a new user to ensure ownCloud does not run with unnecessary database permissions. |
 +|                     |                           | ownCloud prefixes “oc_” to the userid to prevent a collision between the ownCloud admin user and any existing database users.                                                       |
 +|                     |                           | This is generated at the time of the initial login and is the Admin User as entered by the ownCloud admin.                                                                          |
 +|                     |                           |                                                                                                                                                                                     |
 ++---------------------+---------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 +| **DB Password**     | "dbpassword" => "",       | When a new database user is created for ownCloud, a password for the database is generated by hashing the admin user password.                                                      |
 +|                     |                           | This hash is stored in this parameter.                                                                                                                                              |
 +|                     |                           |                                                                                                                                                                                     |
 ++---------------------+---------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 +| **DB Host**         | "dbhost" => "",           | This parameter shows the location of the database.                                                                                                                                  |
 +|                     |                           | Can be an IP pointing to the database server, a Fully Qualified Domain Name (FQDN) or localhost.                                                                                    |
 +|                     |                           |                                                                                                                                                                                     |
 ++---------------------+---------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 +| **DB Table Prefix** | "dbtableprefix" => "oc_", | All tables in the database will begin with this prefix.                                                                                                                             |
 +|                     |                           | By default the prefix is “oc_”.                                                                                                                                                     |
 +|                     |                           | If this prefix is changed in the config file, the tables in the database will need to be manually renamed.                                                                          |
 +|                     |                           | ownCloud will not detect a change to this option so changing this prefix without manually renaming the tables will break the instance of ownCloud.                                  |
 +|                     |                           |                                                                                                                                                                                     |
 ++---------------------+---------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 +| **Password Salt**   | "passwordsalt" => "",     | This is the salt used to hash passwords within the ownCloud instance.                                                                                                               |
 +|                     |                           | It is important not to remove or lose this password.                                                                                                                                |
 +|                     |                           | If lost, all passwords within the ownCloud instance will be lost.                                                                                                                   |
 +|                     |                           |                                                                                                                                                                                     |
 ++---------------------+---------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 +| **Data Directory**  | "datadirectory" => "",    | This parameter tells ownCloud where the default data directory is located.                                                                                                          |
 +|                     |                           | It is configured in the installation wizard.                                                                                                                                        |
 +|                     |                           | If using SQLITE, the database is stored in this data directory as well.                                                                                                             |
 +|                     |                           |                                                                                                                                                                                     |
 +|                     |                           |                                                                                                                                                                                     |
 ++---------------------+---------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
++| **Trusted Domains** |   'trusted_domains' =>    | This parameter identifies trusted URL for ownCloud which users may log into.                                                                                                        |
++|                     |                           | The initial entry ‘0’ is automatic.                                                                                                                                                 |
++|                     |   array (                 | If it is desired to have additional entries, these may be added manually.                                                                                                           |
++|                     |                           | This is used to mitigate Header Post Poisoning attacks.                                                                                                                             |
++|                     |     0 => ‘A.B.C.D         |                                                                                                                                                                                     |
++|                     | ',                        |                                                                                                                                                                                     |
++|                     |                           |                                                                                                                                                                                     |
++|                     |   ),                      |                                                                                                                                                                                     |
++|                     |                           |                                                                                                                                                                                     |
++|                     |                           |                                                                                                                                                                                     |
+++---------------------+---------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 +
diff --cc core/doc/admin/_sources/config/deleted_items.txt
index 4ed976d,0000000..4ed976d
mode 100644,000000..100644
--- a/core/doc/admin/_sources/config/deleted_items.txt
+++ b/core/doc/admin/_sources/config/deleted_items.txt
diff --cc core/doc/admin/_sources/config/index.txt
index 9aaf574,0000000..45a8592
mode 100644,000000..100644
--- a/core/doc/admin/_sources/config/index.txt
+++ b/core/doc/admin/_sources/config/index.txt
@@@ -1,20 -1,0 +1,31 @@@
- **ownCloud config.php**
++======================
++The Configuration File
++======================
++
 +
 +.. toctree::
 +    :maxdepth: 2
++    :hidden:
++
++    default_parameters
++    reverse_proxy_configurations
++    user_experience
++    mail_parameters
++    deleted_items
++    verification
++    logging
++    session_info
++    code_locations
++    apps
++    previews
++    maintenance
++    miscellaneous
++
++ownCloud uses a configuration file to set certain parameters.  The
++configuration file is entitled `config.php` and resides in the `config`
++directory of the ownCloud installation. Also residing in that directory is a
++sample configuration file entitled `config.sample.php`.  This file lists all
++the configurable parameters within ownCloud along with a brief description.
++This document will provide more details as to what each parameter is used for.
++
 +
-     Table_of_Contents
-     Introduction
-     Default_Parameters
-     Reverse_Proxy_Configurations
-     User_Experience
-     Mail_Parameters
-     Deleted_Items
-     Verification
-     Logging
-     Session_Info
-     Code_Locations
-     APPS
-     Previews
-     Maintenance
-     Miscellaneous
diff --cc core/doc/admin/_sources/config/logging.txt
index 83b6a14,0000000..83b6a14
mode 100644,000000..100644
--- a/core/doc/admin/_sources/config/logging.txt
+++ b/core/doc/admin/_sources/config/logging.txt
diff --cc core/doc/admin/_sources/config/mail_parameters.txt
index fb44c2e,0000000..7257c34
mode 100644,000000..100644
--- a/core/doc/admin/_sources/config/mail_parameters.txt
+++ b/core/doc/admin/_sources/config/mail_parameters.txt
@@@ -1,63 -1,0 +1,64 @@@
 +Mail Parameters
 +===============
 +
 +These parameters are related to ownCloud’s ability to send emails for lost passwords or file shares.
 +
 ++-------------------------+------------------------------------+--------------------------------------------------------------------------------------------------------------------------------+
 +| **Parameter**           | **Format**                         | **Description**                                                                                                                |
 +|                         |                                    |                                                                                                                                |
 ++-------------------------+------------------------------------+--------------------------------------------------------------------------------------------------------------------------------+
 +| **Mail Domain**         | "mail_domain" => "example.com",    | The domain to use when ownCloud sends emails.                                                                                  |
 +|                         |                                    | Emails can be sent in such instances as to share a public link, share notification or lost password.                           |
 +|                         |                                    |                                                                                                                                |
 ++-------------------------+------------------------------------+--------------------------------------------------------------------------------------------------------------------------------+
 +| **Mail SMTP Debug**     | "mail_smtpdebug" => false,         |                                                                                                                                |
 +|                         |                                    |                                                                                                                                |
 ++-------------------------+------------------------------------+--------------------------------------------------------------------------------------------------------------------------------+
 +| **Mail SMTP Mode**      | "mail_smtpmode" => "sendmail",     | The method used to send mail.                                                                                                  |
 +|                         |                                    | Valid values are smtp, php, sendmail and qmail.                                                                                |
 +|                         |                                    |                                                                                                                                |
 +|                         |                                    | If using local or remote SMTP, set to smtp.                                                                                    |
 +|                         |                                    |                                                                                                                                |
 +|                         |                                    | If using PHP mail it is necessary to have an installed and working email system on the server.                                 |
 +|                         |                                    | The program used to send email is defined in the PHP.ini file.                                                                 |
 +|                         |                                    |                                                                                                                                |
 +|                         |                                    | If using sendmail, it is necessary to have an installed and working email system on the server.                                |
- |                         |                                    | The sendmail binary is /usr/sbin/sendmail and should be installed on your \*nix system.                                         |
++|                         |                                    | The sendmail binary is /usr/sbin/sendmail and should be installed on your *nix system.                                         |
 +|                         |                                    |                                                                                                                                |
- |                         |                                    | If using qmail to send email, the binary is /var/qmail/bin/sendmail and should be installed in your \*nix system.               |
++|                         |                                    | If using qmail to send email, the binary is /var/qmail/bin/sendmail and should be installed in your *nix system.               |
 +|                         |                                    |                                                                                                                                |
 +|                         |                                    |                                                                                                                                |
 ++-------------------------+------------------------------------+--------------------------------------------------------------------------------------------------------------------------------+
 +| **Mail SMTP Host**      | "mail_smtphost" => "127.0.0.1",    | Mail server host.                                                                                                              |
 +|                         |                                    | May contain multiple hosts separated by a semi colon.                                                                          |
 +|                         |                                    | Also possible is to set the port used a particular host by following the host with a colon then the port number.               |
 +|                         |                                    |                                                                                                                                |
 +|                         |                                    |                                                                                                                                |
 ++-------------------------+------------------------------------+--------------------------------------------------------------------------------------------------------------------------------+
 +| **Mail SMTP Port**      | "mail_smtpport" => 25,             | Port used to communicate with the mail server.                                                                                 |
 +|                         |                                    |                                                                                                                                |
 ++-------------------------+------------------------------------+--------------------------------------------------------------------------------------------------------------------------------+
 +| **Mail SMTP TIMEOUT**   | "mail_smtptimeout" => 10,          | In the event that a malware or SPAM scanner is running on the SMTP server, it could be necessary to increase the SMTP timeout. |
 +|                         |                                    | That can be done using this parameter.                                                                                         |
 +|                         |                                    |                                                                                                                                |
 ++-------------------------+------------------------------------+--------------------------------------------------------------------------------------------------------------------------------+
- | **Mail SMTP Secure**    | "mail_smtpsecure" => "",           | Default value is no security.                                                                                                  |
- |                         |                                    | May be ssl or tls depending on the required level of security.                                                                 |
++| **Mail SMTP **          | "mail_smtpsecure" => "",           | Default value is no security.                                                                                                  |
++| **Secure**              |                                    | May be ssl or tls depending                                                                                                    |
++|                         |                                    | on the required level of security.                                                                                             |
 +|                         |                                    |                                                                                                                                |
 ++-------------------------+------------------------------------+--------------------------------------------------------------------------------------------------------------------------------+
 +| **MAIL SMPT AUTH**      | "mail_smtpauth" => false,          | Determine if the mail server requires authentication.                                                                          |
 +|                         |                                    | Default is false.                                                                                                              |
 +|                         |                                    | If true, the following parameters should be configured as well.                                                                |
 +|                         |                                    |                                                                                                                                |
 ++-------------------------+------------------------------------+--------------------------------------------------------------------------------------------------------------------------------+
 +| **Mail SMTP Auth Type** | "mail_smtpauthtype" => "LOGIN",    | If SMTP authentication is required, choose the authentication type as login (default) or plain.                                |
 +|                         |                                    |                                                                                                                                |
 ++-------------------------+------------------------------------+--------------------------------------------------------------------------------------------------------------------------------+
 +| **Mail SMTP Name**      | "mail_smtpname" => "username",     | The username to use when authentication is enabled.                                                                            |
 +|                         |                                    |                                                                                                                                |
 ++-------------------------+------------------------------------+--------------------------------------------------------------------------------------------------------------------------------+
 +| **Mail SMTP Password**  | "mail_smtppassword" => "password", | The password to use when authentication is enabled.                                                                            |
 +|                         |                                    |                                                                                                                                |
 ++-------------------------+------------------------------------+--------------------------------------------------------------------------------------------------------------------------------+
 +
diff --cc core/doc/admin/_sources/config/maintenance.txt
index 7a41846,0000000..7a41846
mode 100644,000000..100644
--- a/core/doc/admin/_sources/config/maintenance.txt
+++ b/core/doc/admin/_sources/config/maintenance.txt
diff --cc core/doc/admin/_sources/config/miscellaneous.txt
index e0cbc00,0000000..fc97dd0
mode 100644,000000..100644
--- a/core/doc/admin/_sources/config/miscellaneous.txt
+++ b/core/doc/admin/_sources/config/miscellaneous.txt
@@@ -1,56 -1,0 +1,56 @@@
 +Miscellaneous
 +=============
 +
 +The remaining parameters are listed below.
 +
 ++-------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 +| **Parameter**     | **Format**                                                                                                                                                                  | **Description**                                                                                                                                                                   |
 +|                   |                                                                                                                                                                             |                                                                                                                                                                                   |
 ++-------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 +| **Open SSL**      | 'openssl' => array(                                                                                                                                                         |                                                                                                                                                                                   |
 +|                   |                                                                                                                                                                             |                                                                                                                                                                                   |
 +|                   | //'config' => '/absolute/location/of/openssl.cnf',                                                                                                                          |                                                                                                                                                                                   |
 +|                   |                                                                                                                                                                             |                                                                                                                                                                                   |
 +|                   | ),                                                                                                                                                                          |                                                                                                                                                                                   |
 +|                   |                                                                                                                                                                             |                                                                                                                                                                                   |
 ++-------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 +| **User Backends** | 'user_backends'=>array(                                                                                                                                                     | It is possible to configure additional user backends in ownCloud.                                                                                                                 |
 +|                   |                                                                                                                                                                             | The “External user Support” (user_external) app provides the following backends: IMAP (OC_User_IMAP), SMB (OC_User_SMB), FTP (OC_User_FTP).                                       |
 +|                   | array(                                                                                                                                                                      |                                                                                                                                                                                   |
 +|                   |                                                                                                                                                                             |                                                                                                                                                                                   |
 +|                   | 'class'=>'OC_User_IMAP',                                                                                                                                                    |                                                                                                                                                                                   |
 +|                   |                                                                                                                                                                             |                                                                                                                                                                                   |
 +|                   | 'arguments'=>array('{imap.gmail.com:993/imap/ssl}INBOX'),                                                                                                                   |                                                                                                                                                                                   |
 +|                   |                                                                                                                                                                             |                                                                                                                                                                                   |
 +|                   | ),                                                                                                                                                                          |                                                                                                                                                                                   |
 +|                   |                                                                                                                                                                             |                                                                                                                                                                                   |
 +|                   | ),                                                                                                                                                                          |                                                                                                                                                                                   |
 +|                   |                                                                                                                                                                             |                                                                                                                                                                                   |
 +|                   |                                                                                                                                                                             |                                                                                                                                                                                   |
 ++-------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
- | **CSP Policy**    | "custom_csp_policy" => "default-src 'self'; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; frame-src \*; img-src \*; font-src 'self' data:; media-src \*", |                                                                                                                                                                                   |
++| **CSP Policy**    | "custom_csp_policy" => "default-src 'self'; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; frame-src *; img-src *; font-src 'self' data:; media-src *", |                                                                                                                                                                                   |
 +|                   |                                                                                                                                                                             |                                                                                                                                                                                   |
 ++-------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 +| **X Frame**       | “xframe_restriction" => true,                                                                                                                                               | XFrame-restriction is a header which                                                                                                                                              |
 +|                   |                                                                                                                                                                             | prevents browsers from showing the site inside an iframe.                                                                                                                         |
 +|                   |                                                                                                                                                                             | This may be used to prevent clickjacking.                                                                                                                                         |
 +|                   |                                                                                                                                                                             |                                                                                                                                                                                   |
 ++-------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 +| **Mem Cache**     | "memcached_server" => array('localhost', 11211),                                                                                                                            | Server details for one or more memcached servers to use for memory caching.                                                                                                       |
 +|                   |                                                                                                                                                                             | Memcache is only used if other memory cache options (xcache, apc, apcu) are not available.                                                                                        |
 +|                   |                                                                                                                                                                             |                                                                                                                                                                                   |
 ++-------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 +| **Force SSL**     | "forcessl" => false,                                                                                                                                                        | If the admin checks “Enforce HTTPS” in the Admin page of the ownCloud WebUI. This will be set to true indicating that only HTTPS may be used to access this instance of ownCloud. |
 +|                   |                                                                                                                                                                             | HTTP requests will be denied.                                                                                                                                                     |
 +|                   |                                                                                                                                                                             |                                                                                                                                                                                   |
 ++-------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 +| **Black List**    | "blacklisted_files" => array('.htaccess'),                                                                                                                                  | Files listed in this array will not be uploaded to ownCloud.                                                                                                                      |
 +|                   |                                                                                                                                                                             | It should be noted that wildcards are not supported in this array.                                                                                                                |
 +|                   |                                                                                                                                                                             | The configured must be exact file names to be blocked.                                                                                                                            |
 +|                   |                                                                                                                                                                             | If wildcards are                                                                                                                                                                  |
 +|                   |                                                                                                                                                                             | required, use the ownCloud firewall.                                                                                                                                              |
 +|                   |                                                                                                                                                                             |                                                                                                                                                                                   |
 ++-------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 +
 +
 +
diff --cc core/doc/admin/_sources/config/previews.txt
index 634b782,0000000..634b782
mode 100644,000000..100644
--- a/core/doc/admin/_sources/config/previews.txt
+++ b/core/doc/admin/_sources/config/previews.txt
diff --cc core/doc/admin/_sources/config/reverse_proxy_configurations.txt
index 2a8da73,0000000..d2d1038
mode 100644,000000..100644
--- a/core/doc/admin/_sources/config/reverse_proxy_configurations.txt
+++ b/core/doc/admin/_sources/config/reverse_proxy_configurations.txt
@@@ -1,51 -1,0 +1,50 @@@
 +Reverse Proxy Configurations
 +============================
 +
 +The following parameters are used in the instance that Proxies are being used within the network.
 +
 ++-------------------------+----------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 +| **Parameter**           | **Format**                             | **Description**                                                                                                                                                                                                                 |
 +|                         |                                        |                                                                                                                                                                                                                                 |
 ++-------------------------+----------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
- | **Overwrite Host**      | "overwritehost" => "",                 | By default, ownCloud attempts to detect what outside host can access the instance (www.example.com                                                                                                                              |
- |                         |                                        | ) for generating URLs.                                                                                                                                                                                                          |
++| **Overwrite Host**      | "overwritehost" => "",                 | By default, ownCloud attempts to detect what outside host can access the instance (www.example.com) for generating URLs.                                                                                                        |
 +|                         |                                        | However, due to some reverse proxies, the automatically detected value may be incorrect (www.example.com:88) which would lead to incorrect URLs being generated.                                                                |
 +|                         |                                        | Use this field to enter the proper URL.                                                                                                                                                                                         |
 +|                         |                                        |                                                                                                                                                                                                                                 |
 +|                         |                                        | If set as follows: “overwritehost” => “http://www.example.com:88”,                                                                                                                                                              |
 +|                         |                                        |                                                                                                                                                                                                                                 |
 +|                         |                                        | When logging into ownCloud, the browser will point to port 88.                                                                                                                                                                  |
 +|                         |                                        |                                                                                                                                                                                                                                 |
 ++-------------------------+----------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 +| **Overwrite Protocol**  | "overwriteprotocol" => "",             | When generating URLs, ownCloud attempts to detect whether the server is accessed via https or http.                                                                                                                             |
 +|                         |                                        | However, if ownCloud is behind a proxy and the proxy handles the https calls, thereby leaving ownCloud running without SSL, ownCloud would not realize that ssl is in use which would result in incorrect URLs being generated. |
 +|                         |                                        | Valid values are “http” and “https”.                                                                                                                                                                                            |
 +|                         |                                        |                                                                                                                                                                                                                                 |
 +|                         |                                        | If set as follows:                                                                                                                                                                                                              |
 +|                         |                                        |                                                                                                                                                                                                                                 |
 +|                         |                                        | “overwriteprotocol” => “https”,                                                                                                                                                                                                 |
 +|                         |                                        |                                                                                                                                                                                                                                 |
 +|                         |                                        | ownCloud will generate all URLs as HTTPS rather than HTTP.                                                                                                                                                                      |
 +|                         |                                        |                                                                                                                                                                                                                                 |
 ++-------------------------+----------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 +| **Overwrite Web Root**  | "overwritewebroot" => "",              | As with the host and protocol, ownCloud attempts to detect the webroot for generating URLs automatically.                                                                                                                       |
 +|                         |                                        | The webroot is the path used to access ownCloud relative to the domain, for instance, if                                                                                                                                        |
 +|                         |                                        | `www.example.com/owncloud <http://www.example.com/owncloud>`_                                                                                                                                                                   |
 +|                         |                                        | is the URL pointing to the ownCloud instance, the webroot would be /owncloud.                                                                                                                                                   |
 +|                         |                                        | When proxies are in use, it may be difficult for ownCloud to detect this parameter resulting in invalid URLs.                                                                                                                   |
 +|                         |                                        |                                                                                                                                                                                                                                 |
 ++-------------------------+----------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 +| **Overwrite Cond Addr** | "overwritecondaddr" => "",             |                                                                                                                                                                                                                                 |
 +|                         |                                        |                                                                                                                                                                                                                                 |
 ++-------------------------+----------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 +| **Proxy**               | "proxy" => "",                         | In the instance where a proxy is required to access the internet, the proxy should be configured in this parameter.                                                                                                             |
 +|                         |                                        | ownCloud requires access to the internet for several functions, and thus needs to have the proxy information configured to access the internet.                                                                                 |
 +|                         |                                        |                                                                                                                                                                                                                                 |
 +|                         |                                        |                                                                                                                                                                                                                                 |
 ++-------------------------+----------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 +| **Proxy User Password** | "proxyuserpwd" => "username:password", | In the event that a proxy is configured and requires authentication, the username and password would be configured in this parameter.                                                                                           |
 +|                         |                                        |                                                                                                                                                                                                                                 |
 +|                         |                                        |                                                                                                                                                                                                                                 |
 ++-------------------------+----------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 +
 +
diff --cc core/doc/admin/_sources/config/session_info.txt
index 5ad9706,0000000..5ad9706
mode 100644,000000..100644
--- a/core/doc/admin/_sources/config/session_info.txt
+++ b/core/doc/admin/_sources/config/session_info.txt
diff --cc core/doc/admin/_sources/config/user_experience.txt
index 0000000,0000000..78f0909
new file mode 100644
--- /dev/null
+++ b/core/doc/admin/_sources/config/user_experience.txt
@@@ -1,0 -1,0 +1,35 @@@
++User Experience
++===============
++
++The following parameters are those that influence the end user’s experience.
++
+++----------------------+----------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+
++| **Parameter**        | **Format**                                   | **Description**                                                                                                            |
++|                      |                                              |                                                                                                                            |
+++----------------------+----------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+
++| **Default Language** | "default_language" => "en",                  | This is the default language for the ownCloud WebUI. When configured, the default language will be the same for all users. |
++|                      |                                              | Users may then configure their own language preference in their Personal page.                                             |
++|                      |                                              | When not configured, the default language is determined form the headers sent by the web browser.                          |
++|                      |                                              | For instance, if the browser is in Spanish, ownCloud will be presented in Spanish                                          |
++|                      |                                              |                                                                                                                            |
+++----------------------+----------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+
++| **Default App**      | "defaultapp" => "files",                     | By default, when a user logs into ownCloud, they are brought to the files page.                                            |
++|                      |                                              | If, for instance, the admin desires a different page to be loaded upon login, configure that app here.                     |
++|                      |                                              | Valid values are app id’s (for example news, files, gallery).                                                              |
++|                      |                                              |                                                                                                                            |
++|                      |                                              |                                                                                                                            |
+++----------------------+----------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+
++| **Knowledge Base **  | "knowledgebaseenabled" => true,              | When enabled, default, the help menu brings up the user documentation.                                                     |
++| **Enabled**          |                                              |                                                                                                                            |
++|                      |                                              |                                                                                                                            |
+++----------------------+----------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+
++| **Enable Avatars**   | 'enable_avatars' => true,                    | Allows for the ability to use avatars.                                                                                     |
++|                      |                                              |                                                                                                                            |
++|                      |                                              |                                                                                                                            |
+++----------------------+----------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+
++| **Display Name**     | 'allow_user_to_change_display_name' => true, | Users can modify their display name in the Personal page.                                                                  |
++|                      |                                              | If this parameter is set to false, they may not change their display name.                                                 |
++|                      |                                              |                                                                                                                            |
++|                      |                                              |                                                                                                                            |
+++----------------------+----------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+
++
diff --cc core/doc/admin/_sources/config/verification.txt
index 67c1c12,0000000..4b7998c
mode 100644,000000..100644
--- a/core/doc/admin/_sources/config/verification.txt
+++ b/core/doc/admin/_sources/config/verification.txt
@@@ -1,29 -1,0 +1,30 @@@
 +Verification
 +============
 +
 +This section describes different verification checks that ownCloud may perform.
 +
 ++-----------------------------+---------------------------------------+----------------------------------------------------------------------------------------------------------------------+
 +| **Parameter**               | **Format**                            | **Description**                                                                                                      |
 +|                             |                                       |                                                                                                                      |
 ++-----------------------------+---------------------------------------+----------------------------------------------------------------------------------------------------------------------+
 +| **Update Checker**          | "updatechecker" => true,              | Provides information as to whether there is a new release of ownCloud available.                                     |
 +|                             |                                       | When enabled, default, a banner will appear on the admin’s web interface when a newer version of ownCloud exists.    |
 +|                             |                                       |                                                                                                                      |
 +|                             |                                       |                                                                                                                      |
 ++-----------------------------+---------------------------------------+----------------------------------------------------------------------------------------------------------------------+
 +| **Has Internet Connection** | "has_internet_connection" => true,    | Alerts ownCloud if there is an internet connection (true – default).                                                 |
 +|                             |                                       | If set to false, ownCloud will not be able to look for updates, display the knowledgebase, or bring up the appstore. |
 +|                             |                                       |                                                                                                                      |
 ++-----------------------------+---------------------------------------+----------------------------------------------------------------------------------------------------------------------+
 +| **Working WebDAV**          | "check_for_working_webdav" => true,   | Allows ownCloud to verify a working WebDAV connection.                                                               |
 +|                             |                                       | This is done by attempting to make a WebDAV request from PHP.                                                        |
 +|                             |                                       |                                                                                                                      |
 ++-----------------------------+---------------------------------------+----------------------------------------------------------------------------------------------------------------------+
 +| **Working .htaccess**       | "check_for_working_htaccess" => true, | Verifies whether the .htaccess file may be modified by ownCloud.                                                     |
- |                             |                                       | If set to false, this check will not be performed.                                                                   |
++|                             |                                       | If set to false, this check will not be                                                                              |
++|                             |                                       | performed.                                                                                                           |
 +|                             |                                       | If the file cannot be modified, items such as large file uploads cannot be performed.                                |
 +|                             |                                       | This check only affects Apache servers.                                                                              |
 +|                             |                                       |                                                                                                                      |
 ++-----------------------------+---------------------------------------+----------------------------------------------------------------------------------------------------------------------+
 +
diff --cc core/doc/admin/_sources/configuration/auth_ldap.txt
index d4c54e7,0000000..06af732
mode 100644,000000..100644
--- a/core/doc/admin/_sources/configuration/auth_ldap.txt
+++ b/core/doc/admin/_sources/configuration/auth_ldap.txt
@@@ -1,616 -1,0 +1,616 @@@
- User Authentication with LDAP
- =============================
++LDAP Authentication
++===================
 +
 +ownCloud ships an LDAP backend, which allows full use of ownCloud for user
 +logging in with LDAP credentials including:
 +
 +* LDAP group support
 +* File sharing with users and groups
 +* Access via WebDAV and of course ownCloud Desktop Client
 +* Versioning, external Storages and all other ownCloud goodies
 +
 +To connect to an LDAP server the configuration needs to be set up properly.
 +Once the LDAP backend is activated (Apps Sidebar→Apps, choose **LDAP user and
 +group backend**, click on **Enable**) the configuration can be found on
 +Settings→Admin. Read on for a detailed description of the configuration fields.
 +
 +Configuration
 +-------------
 +
 +The LDAP backend follows a wizard-like approach, splitted into four tabs. A
 +correctly completed first tab ("Server") is mandatory to access the other tabs.
 +Also, the other tabs need to be reviewed by the admin, however the necessary
 +settings are detected automatically. An indicator will show whether the
 +configuration is incomplete, incorrect or OK.
 +
 +The settings are changed automatically, as soon as a input element looses the
 +focus, i.e. the cursor is taken away by clicking somewhere else or pressing the
 +tabulator key.
 +
 +The other tabs can be navigated by clicking the tabs or by using the *Continue*
 +and *Back* buttons. They are located on the lower right, next to the status
 +indicator.
 +
 +Server
 +~~~~~~
 +
 +The server tab contains the basic information on the LDAP server. They make sure
 +that ownCloud will be able to connect to LDAP and be able to read data from
 +there. The admin at least needs to provide a hostname. If anonymous access is
 +not possible he will need to provide an account DN and a password, too. ownCloud
 +attempts to auto-detect the port and the base DN.
 +
 +.. figure:: ../images/ldap-wizard-1-server.png
 +
 +Server configuration:
 +  ownCloud can be configured to connect to multiple LDAP servers. Using this
 +  control you can pick a configuration you want to edit or add a new one. The
 +  button **Delete Configuration** deletes the current configuration.
 +
 +Host:
 +  The host name of the LDAP server. It can also be a **ldaps://** URI, for
 +  instance.
 +
 +  It is also possible to pass a port number, which speeds up port detection. It
 +  is especially useful, if a custom port is used. ownCloud will move the value
 +  to the port field subsequently.
 +
 +  Examples:
 +
 +  * *directory.my-company.com*
 +  * *ldaps://directory.my-company.com*
 +  * *directory.my-company.com:9876*
 +
 +Port:
 +  The port on which to connect to the LDAP server. The field is disabled in the
 +  beginning of a new configuration. The port will be detected automatically,
 +  if the LDAP server is running on a standard port. After ownCloud attempted to
 +  determine the port, the field will be enabled for user input. A successfully
 +  found port will be inserted by ownCloud, of course.
 +
 +  Example:
 +
 +  * *389*
 +
 +User DN:
 +  The name as DN of a user who is able to do searches in the LDAP
 +  directory. Leave it empty for anonymous access. It is recommended to have a
 +  special system user for ownCloud.
 +
 +  Example:
 +
 +  * *uid=owncloudsystemuser,cn=sysusers,dc=my-company,dc=com*
 +
 +Password:
 +  The password for the user given above. Empty for anonymous access.
 +
 +Base DN:
 +  The base DN of LDAP, from where all users and groups can be reached. Separated
 +  Base DNs for users and groups can be set in the Advanced tab. Nevertheless,
 +  this field is mandatory. ownCloud attempts to determine the Base DN according
 +  to the provided User DN or the provided Host.
 +
 +  Example:
 +
 +  * *dc=my-company,dc=com*
 +
 +User Filter
 +~~~~~~~~~~~
 +
 +The settings in the user filter tab determine which LDAP users will appear and
 +are allowed to log in into ownCloud. It is also possible to enter a raw LDAP
 +filter.
 +
 +.. figure:: ../images/ldap-wizard-2-user.png
 +
 +only those object classes:
 +  ownCloud will determine the object classes that are typically availalble for
 +  (ideally only) user objects in your LDAP. ownCloud will automatically select
 +  the object class that returns the highest amount of users. You can select
 +  multiple object classes.
 +
 +only from those groups:
 +  If your LDAP server supports the member-of-overlay in LDAP filters, you can
 +  define that only users from one or more certain groups are allowed to
 +  appear and log in into ownCloud. By default, no value will be selected. You
 +  can select multiple groups.
 +
 +  If your LDAP server does not support the member-of-overlay in LDAP filters,
 +  the input field is disabled. Please contact your LDAP administrator.
 +
 +Edit raw filter instead:
 +  Clicking on this text will toggle the filter mode. Instead of the assisted
 +  approach, you can enter the raw LDAP filter directly in the appearing field.
 +
 +  Example:
 +
 +  * *objectClass=inetOrgPerson*
 +
 +x users found:
 +  This is an indicator that tells you approximately how many users will be
 +  allowed to access ownCloud. The number will update after any change you do.
 +
 +Login Filter
 +~~~~~~~~~~~~
 +
 +The settings in the login filter tab determine which user detail will be
 +compared to the login value entered by the user. It is possible to allow
 +multiple user details. It is also possible to enter a raw LDAP filter.
 +
 +The user limitation as set up in the previous tab is in effect, unless you
 +manually configure the filter in raw mode.
 +
 +.. figure:: ../images/ldap-wizard-3-login.png
 +
 +LDAP Username:
 +  If this value is checked, the login value will be compared to the username in
 +  the LDAP directory. The corresponding attribute, usually *uid* or
 +  *samaccountname* will be detected automatically by ownCloud.
 +
 +LDAP Email Address:
 +  If this value is checked, the login value will be compared to an email address
 +  in the LDAP directory. The email address will be looked for in the
 +  *mailPrimaryAddress* and *mail* attributes.
 +
 +Other Attributes:
 +  This multiselect box allows you to select other attributes for the comparison.
 +  The list is generated automatically based on the attributes that a user object
 +  contains in your LDAP server.
 +
 +Edit raw filter instead:
 +  Clicking on this text will toggle the filter mode. Instead of the assisted
 +  approach, you can enter the raw LDAP filter directly in the appearing field.
 +
 +  The **%uid** placeholder will be replaced with the login name entered by the user
 +  upon login. When you enter the filter manually.
 +
 +  Examples:
 +
 +  * only username: *uid=%uid*
 +  * username or email address: *(|(uid=%uid)(mail=$uid))*
 +
 +Group Filter
 +~~~~~~~~~~~~
 +
 +The settings in the group filter tab determine which groups will be availalble
 +in ownCloud. It does not have any restrictions on logins, this has been dealed
 +with in the prior tabs.  It is also possible to enter a raw LDAP
 +filter.
 +
 +By default, no groups will be availalble in ownCloud. You actively need to
 +enable groups.
 +
 +.. figure:: ../images/ldap-wizard-4-group.png
 +
 +only those object classes:
 +  ownCloud will determine the object classes that are typically availalble for
 +  (ideally only) group objects in your LDAP. ownCloud will only list object
 +  classes that return at least one group object. You can select multiple
 +  object classes. A typical object class is "group", or "posixGroup".
 +
 +only from those groups:
 +  This setting lets you pick certain groups that shall be availalble in
 +  ownCloud. This field follows a whitelist approach. ownCloud will generate a
 +  list of available groups found in your LDAP server. You can select multiple
 +  groups.
 +
 +Edit raw filter instead:
 +  Clicking on this text will toggle the filter mode. Instead of the assisted
 +  approach, you can enter the raw LDAP filter directly in the appearing field.
 +
 +  Example:
 +
 +  * *objectClass=group*
 +  * *objectClass=posixGroup*
 +
 +y groups found:
 +  This is an indicator that tells you approximately how many groups will be
 +  available in  ownCloud. The number will update after any change you do.
 +
 +
 +Advanced Settings
 +-----------------
 +
 +In the LDAP Advanced settings section you can define options, that are less
 +common to set. They are not needed for a working connection. It can also have a
 +positive effect on the performance to specify distinguished bases for user and
 +group searches.
 +
 +The Advanced Settings are structured into three parts:
 +
 +* Connection Settings
 +* Directory Settings
 +* Special Attributes
 +
 +Connection Settings
 +~~~~~~~~~~~~~~~~~~~
 +
 +.. figure:: ../images/ldap-advanced-1-connection.png
 +
 +   LDAP Advanced Settings, section Connection Settings
 +
 +Configuration Active:
 +  Enables or Disables the current configuration. Disabled configuration will not
 +  connect to the LDAP server.
 +
 +  By default, it is turned off. It will be automatically turned on, when using
 +  the wizard and the configuration is OK and a test connection successful.
 +
 +Backup (Replica) Host:
 +  A backup server can be defined here. ownCloud tries to connect to the backup
 +  server automatically, when the main host (as specified in basic settings)
 +  cannot be reached. It is import that the backup server is a replica of the
 +  main server, because the object UUIDs must match.
 +
 +  Example:
 +
 +  * *directory2.my-company.com*
 +
 +Backup (Replica) Port:
 +  The port on which to connect to the backup LDAP server. If no port is given,
 +  but a host, then the main port (as specified above) will be used.
 +
 +  Example:
 +
 +  * *389*
 +
 +Disable Main Server:
 +  You can manually override the main server and make ownCloud only connect to
 +  the backup server. It may be handy for planned downtimes.
 +
 +Case insensitive LDAP server (Windows):
 +  Whether the LDAP server is running on a Windows Host. Usually, it is not
 +  necessary to check it, however.
 +
 +Turn off SSL certificate validation:
 +  Turns of check of valid SSL certificates. Use it – if needed –
 +  for testing, only!
 +
 +Cache Time-To-Live:
 +  A cache is introduced to avoid unnecessary LDAP traffic,
 +  for example lookups check whether the users exists on every page request or
 +  WebDAV interaction. It is also supposed to speed up the Admin → User page or
 +  list of users to share with, once it is populated. Saving the configuration
 +  empties the cache (changes are not necessary). The time is given in seconds.
 +
 +  Note that almost every PHP request would require to build up a new connection
 +  to the LDAP server. If you require a most up-to-dateness it is recommended not
 +  to totally switch off the cache, but define a minimum life time of 15s.
 +
 +  Examples:
 +
 +  * ten minutes: *600*
 +  * one hour: *3600*
 +
 +Directory Settings
 +~~~~~~~~~~~~~~~~~~~
 +
 +.. figure:: ../images/ldap-advanced-2-directory.png
 +
 +   LDAP Advanced Settings, section Directory Settings
 +
 +User Display Name Field:
 +  The attribute that should be used as display name in ownCloud.
 +
 +  *  Example: *displayName*
 +
 +Base User Tree:
 +  The base DN of LDAP, from where all users can be reached. It needs to be given
 +  completely despite to the Base DN from the Basic settings. You can specify
 +  multiple base trees, one in each line.
 +
 +  * Example:
 +
 +    | *cn=programmers,dc=my-company,dc=com*
 +    | *cn=designers,dc=my-company,dc=com*
 +
 +User Search Attributes:
 +  These attributes are used when a search for users is done. This happens, for
 +  instance, in the share dialogue. By default the user display name attribute as
 +  specified above is being used. Multiple attributes can be given, one in each
 +  line.
 +
 +  Beware that if an attribute is not available on a user object, the user will
 +  neither be listed (e.g. in the share dialogue) nor be able to login. This also
 +  affects the display name attribute as specified above. If you override the
 +  default, the display name attribute will not be taken into account, unless you
 +  specify it as well.
 +
 +  * Example:
 +
 +    | *displayName*
 +    | *mail*
 +
 +Group Display Name Field:
 +  The attribute that should be used as ownCloud group name. ownCloud allows a
 +  limited set of characters (a-zA-Z0-9.-_@), every other character will be
 +  replaced in ownCloud. Once a group name is assigned, it will not be changed,
 +  i.e. changing this value will only have effect to new LDAP groups.
 +
 +  * Example: *cn*
 +
 +Base Group Tree:
 +  The base DN of LDAP, from where all groups can be reached.
 +  It needs to be given completely despite to the Base DN from the Basic
 +  settings. You can specify multiple base trees, one in each line.
 +
 +  * Example:
 +
 +    | *cn=barcelona,dc=my-company,dc=com*
 +    | *cn=madrid,dc=my-company,dc=com*
 +
 +Group Search Attributes:
 +  These attributes are used when a search for groups is done. This happens, for
 +  instance, in the share dialogue. By default the group display name attribute
 +  as specified above is being used. Multiple attributes can be given, one in
 +  each line.
 +
 +  If you override the default, the group display name attribute will not be
 +  taken into account, unless you specify it as well.
 +
 +  * Example:
 +
 +    | *cn*
 +    | *description*
 +
 +Group Member association:
 +  The attribute that is used to indicate group memberships, i.e. the attribute
 +  used by LDAP groups to refer to their users.
 +
 +  ownCloud detects the value automatically, you should only change it, if you
 +  have a very valid reason and know what you are doing.
 +
 +  * Example: *uniquemember*
 +
 +Special Attributes
 +~~~~~~~~~~~~~~~~~~
 +
 +.. figure:: ../images/ldap-advanced-3-attributes.png
 +
 +   LDAP Advanced Settings, section Special Attributes
 +
 +Quota Field:
 +  ownCloud can read an LDAP attribute and set the user quota according to its
 +  value. Specify the attribute here, otherwise keep it empty. The attribute
 +  shall return human readable values, e.g. "2 GB".
 +
 +  * Example: *ownCloudQuota*
 +
 +Quota Default:
 +  Override ownCloud default quota for LDAP users who do not
 +  have a quota set in the attribute given above.
 +
 +  * Example: *15 GB*
 +
 +Email Field:
 +  ownCloud can read an LDAP attribute and set the user email
 +  there from. Specify the attribute here, otherwise keep it empty.
 +
 +  Although the wizard offers you to check login by email, the correct email
 +  attribute is not detected and you need to specify it manually.
 +
 +  * Example: *mail*
 +
 +User Home Folder Naming Rule:
 +  By default, the ownCloud creates the user
 +  directory, where all files and meta data are kept, according to the ownCloud
 +  user name. You may want to override this setting and name it after an
 +  attribute value. The attribute given can also return an absolute path, e.g.
 +  ``/mnt/storage43/alice``. Leave it empty for default behavior.
 +
 +  * Example: *cn*
 +
 +Expert Settings
 +---------------
 +
 +.. figure:: ../images/ldap-expert.png
 +
 +In the Expert Settings fundamental behavior can be adjusted to your needs. The
 +configuration should be done before starting production use or when testing the
 +installation.
 +
 +Internal Username:
 +  The internal username is the identifier in ownCloud for LDAP users. By default
 +  it will be created from the UUID attribute. By using the UUID attribute it is
 +  made sure that the username is unique and characters do not need to be
 +  converted. The internal username has the restriction that only these
 +  characters are allowed: [\a-\zA-\Z0-\9_. at -]. Other characters are replaced with
 +  their ASCII correspondence or are simply omitted.
 +
 +  The LDAP backend ensures that there are no duplicate internal usernames in
 +  ownCloud, i.e. that it is checking all other activated user backends
 +  (including local ownCloud users). On collisions a random number (between 1000
 +  and 9999) will be attached to the retrieved value. For example, if "alice"
 +  exists, the next username may be "alice_1337".
 +
 +  The internal username is also the default name for the user home folder in
 +  ownCloud. It is also a part of remote URLs, for instance for all \*DAV services.
 +  With this setting the default behaviour can be overridden.
 +
 +  Leave it empty for default behaviour. Changes will have effect only on newly
 +  mapped (added) LDAP users.
 +
 +  * Example: *uid*
 +
 +Override UUID detection
 +  By default, ownCloud auto-detects the UUID attribute. The UUID attribute is
 +  used to doubtlessly identify LDAP users and groups. Also, the internal
 +  username will be created based on the UUID, if not specified otherwise above.
 +
 +  You can override the setting and pass an attribute of your choice. You must
 +  make sure that the attribute of your choice can be fetched for both users and
 +  groups and it is unique. Leave it empty for default behaviour. Changes will
 +  have effect only on newly mapped (added) LDAP users and groups. It also will
 +  have effect when a user's or group's DN changes and an old UUID was cached: It
 +  will result in a new user. Because of this, the setting should be applied
 +  before putting ownCloud in production use and cleaning the bindings
 +  (see below).
 +
 +  * Example: *cn*
 +
 +Username-LDAP User Mapping
 +  ownCloud uses the usernames as key to store and assign data. In order to
 +  precisely identify and recognize users, each LDAP user will have a internal
 +  username in ownCloud. This requires a mapping from ownCloud username to LDAP
 +  user. The created username is mapped to the UUID of the LDAP user.
 +  Additionally the DN is cached as well to reduce LDAP interaction, but it is
 +  not used for identification. If the DN changes, the change will be detected by
 +  ownCloud by checking the UUID value.
 +
 +  The same is valid for groups.
 +
 +  The internal ownCloud name is used all over in ownCloud. Clearing the Mappings
 +  will have leftovers everywhere. Do never clear the mappings
 +  in a production environment. Only clear mappings in a testing or experimental
 +  stage.
 +
 +  **Clearing the Mappings is not configuration sensitive, it affects all LDAP
 +  configurations!**
 +
 +Testing the configuration
 +-------------------------
 +
 +In this version we introduced the **Test Configuration** button on the bottom
 +of the LDAP settings section. It will always check the values as currently
 +given in the input fields. You do not need to save before testing. By clicking
 +on the button, ownCloud will try to bind to the ownCloud server with the
 +settings currently given in the input fields. The response will look like this:
 +
 +.. figure:: ../images/ldap-settings-invalid-oc45.png
 +
 +   Failure
 +
 +In case the configuration fails, you can see details in ownCloud's log, which
 +is in the data directory and called **owncloud.log** or on the bottom the
 +**Settings →  Admin page**. Unfortunately it requires a reload – sorry for the
 +inconvenience.
 +
 +.. figure:: ../images/ldap-settings-valid-oc45.png
 +
 +   Success
 +
 +In this case, Save the settings. You can check if the users and groups are
 +fetched correctly on the Settings → Users page.
 +
 +ownCloud Avatar integration
 +---------------------------
 +
 +ownCloud 6 incorporates a user profile picture feature, called Avatar. If a user
 +has a photo stored in the *jpegPhoto* or, since 6.0.2, *thumbnailPhoto*
 +attribute, it will be used as Avatar. The user then is not able to change his
 +avatar in the personal settings. It must be done within LDAP. *jpegPhoto* is
 +preferred over *thumbnailPhoto*.
 +
 +.. figure:: ../images/ldap-fetched-avatar.png
 +
 +   Profile picture fetched from LDAP, Personal Settings
 +
 +If the *jpegPhoto* or *thumbnailPhoto* attribute is not set or empty, the
 +default ownCloud behaviour is active, i.e. the user will be able to set and
 +change his profile picture in the personal settings. If the user sets a profile
 +picture within ownCloud it will _not_ be stored in LDAP.
 +
 +The *jpegPhoto* or *thumbnailPhoto* attribute will be fetched once a day to make
 +sure the current photo from LDAP is used in ownCloud. If a picture is added
 +later, a possibly set profile picture will be overridden with the LDAP one. If a
 +photo stored in the *jpegPhoto* and/or *thumbnailPhoto* attribute is deleted
 +later, the last profile picture in ownCloud will still be used.
 +
 +The photo taken from LDAP will be adjusted to the requirements of the ownCloud
 +avatar automatically. I.e. it will be transformed into a square. If the photo
 +needs to be cut, it will be done equally from both affected sides. The original
 +photo stored in LDAP will stay the same, of course.
 +
 +Troubleshooting, Tips and Tricks
 +--------------------------------
 +
 +SSL Certificate Verification (LDAPS, TLS)
 +-----------------------------------------
 +
 +A common mistake with SSL certificates is that they may not be known to PHP.
 +If you have trouble with certificate validation make sure that
 +
 +* you have the certificate of the server installed on the ownCloud server
 +* the certificate is announced in the system's LDAP configuration file (usually
 +  */etc/ldap/ldap.conf* on Linux, *C:\\openldap\\sysconf\\ldap.conf* or
 +  *C:\\ldap.conf* on Windows) using a **TLS_CACERT /path/to/cert** line.
 +* Using LDAPS, also make sure that the port is correctly configured (by default
 +  686)
 +
 +Microsoft Active Directory
 +--------------------------
 +
 +Compared to earlier ownCloud versions, no further tweaks need to be done to
 +make ownCloud work with Active Directory. ownCloud will automatically find the
 +correct configuration in the wizard-like set up process.
 +
 +Duplicating Server Configurations
 +---------------------------------
 +
 +In case you have a working configuration and want to create a similar one or
 +"snapshot" configurations before modifying them you can do the following:
 +
 +#. Go to the **Server** tab
 +#. On **Server Configuration** choose *Add Server Configuration*
 +#. Answer the question *Take over settings from recent server configuration?*
 +   with *yes*.
 +#. (optional) Switch to **Advanced** tab and uncheck **Configuration Active**
 +   in the *Connection Settings*, so the new configuration is not used on Save
 +#. Click on **Save**
 +
 +Now you can modify the configuration and enable it if you wish.
 +
 +ownCloud LDAP Internals
 +-----------------------
 +
 +Some parts of how the LDAP backend works are described here. May it be helpful.
 +
 +Groups
 +------
 +
 +At the moment, only secondary groups are read. That means that only the groups
 +are retrieved, which are returned by the attribute auto-detected (or manually
 +chosen) in Group-Member association. Primary groups are not being taken into
 +account.
 +
 +User and Group Mapping
 +----------------------
 +
 +In ownCloud the user or group name is used to have all relevant information in
 +the database assigned. To work reliably a permanent internal user name and
 +group name is created and mapped to the LDAP DN and UUID. If the DN changes in
 +LDAP it will be detected, there will be no conflicts.
 +
 +Those mappings are done in the database table ldap_user_mapping and
 +ldap_group_mapping. The user name is also used for the user's folder (except
 +something else is specified in *User Home Folder Naming Rule*), which
 +contains files and meta data.
 +
 +As of ownCloud 5 internal user name and a visible display name are separated.
 +This is not the case for group names, yet, i.e. group cannot be altered.
 +
 +That means that your LDAP configuration should be good and ready before putting
 +it into production. The mapping tables are filled early, but as long as you are
 +testing, you can empty the tables any time. Do not do this in production. If you
 +want to rename a group, be very careful. Do not rename the user's internal name.
 +
 +Caching
 +-------
 +
 +For performance reasons a cache has been introduced to ownCloud. He we store
 +all users and groups, group memberships or internal userExists-requests. Since
 +ownCloud is written in PHP and each and every page request (also done by Ajax)
 +loads ownCloud and would execute one or more LDAP queries again, you do want to
 +have some of those queries cached and save those requests and traffic. It is
 +highly recommended to have the cache filled for a small amount of time, which
 +comes also very handy when using the sync client, as it is yet another request
 +for PHP.
 +
 +Handling with Backup Server
 +---------------------------
 +
 +When ownCloud is not able to contact the main server, he will be treated as
 +offline and no connection attempts will be done for the time specified in
 +**Cache Time-To-Live**. If a backup server is configured, it will be connected
 +instead. If you plan a maintained downtime, check **Disable Main Server** for
 +the time being to avoid unnecessary connection attempts every now and then.
diff --cc core/doc/admin/_sources/configuration/configuration_3rdparty.txt
index a2bceac,0000000..b7dc68b
mode 100644,000000..100644
--- a/core/doc/admin/_sources/configuration/configuration_3rdparty.txt
+++ b/core/doc/admin/_sources/configuration/configuration_3rdparty.txt
@@@ -1,20 -1,0 +1,20 @@@
- 3rd-Party Configuration
- =======================
++Find Third-Party Libraries
++==========================
 +
 +ownCloud resorts to some 3rd-party PHP components to provide its functionality.
 +These components are part of the software package and are usually shipped in
 +the **/3rdparty** folder.
 +
 +Parameters
 +----------
 +
 +If you want to change the default location of the 3rd-party folder you can use the **3rdpartyroot** parameter to define
 +the absolute file system path to the folder. The **3rdpartyurl** parameter is used to define the http web path to that
 +folder, starting at the ownCloud web root.
 +
 +.. code-block:: php
 +
 +  <?php
 +
 +  "3rdpartyroot" => OC::$SERVERROOT."/3rdparty",
 +  "3rdpartyurl"  => "/3rdparty",
diff --cc core/doc/admin/_sources/configuration/configuration_apps.txt
index 09c1649,0000000..3383938
mode 100644,000000..100644
--- a/core/doc/admin/_sources/configuration/configuration_apps.txt
+++ b/core/doc/admin/_sources/configuration/configuration_apps.txt
@@@ -1,81 -1,0 +1,82 @@@
- Apps Configuration
- ==================
++Managing Apps
++=============
++
 +After you have installed ownCloud, you might realize that it would be nice to
 +provide an additional function on top of the core functionality in your ownCloud installation.
 +
 +With ownCloud installation, you will find some apps enabled by default. To see which applications
 +are enabled, click on Apps button on the web interface navigation to go into applications page:
 +
 +.. figure:: ../images/oc_admin_app_page.png
 +Administrator application page
 +
 +In this page, you can enable or disable applications simply by clicking on their names.
 +Enabled applications will be shown in **bold** while disabled ones will be shown in normal font.
 +If the app is not developed by ownCloud, it will have the *3rd party* notice next to it. To see what an
 +application does, clicking on its name will show a description on the right side of the same page.
 +
 +To install new apps, you can use *More apps* button or check out the `ownCloud apps store <http://apps.owncloud.com/>`_.
 +There you will find a lot of ready-to-use apps provided by the ownCloud community.
 +
 +If you would like to add your own app, please use *Add your App...* button on the same page. This will redirect you to
 +our `Developer Center <http://owncloud.org/dev>`_.
 +
 +Parameters
 +----------
 +Parameters are set in the :file:`config/config.php` inside the **$CONFIG** array.
 +
 +Use custom app directories
 +~~~~~~~~~~~~~~~~~~~~~~~~~~
 +Use the **apps_paths** array to set the apps folders which should be scanned
 +for available apps and/or where user specific apps should be installed.The key
 +**path** defines the absolute file system path to the app folder. The key
 +**url** defines the http web path to that folder, starting at the ownCloud 
 +web root. The key **writable** indicates if a user can install apps in that
 +folder.
 +
 +.. note:: If you want to make sure that the default **/apps/** folder only contains apps shipped with ownCloud, you
 + should follow the example and set-up a **/apps2/** folder which will be used to store all apps downloaded by users
 +
 +.. code-block:: php
 +
 +  <?php
 +
 +    "apps_paths" => array (
 +        0 => array (
 +                "path"     => OC::$SERVERROOT."/apps",
 +                "url"      => "/apps",
 +                "writable" => false,
 +        ),
 +        1 => array (
 +                "path"     => OC::$SERVERROOT."/apps2",
 +                "url"      => "/apps2",
 +                "writable" => true,
 +        ),
 +    ),
 +
 +
 +Use your own appstore
 +~~~~~~~~~~~~~~~~~~~~~
 +If you want to allow the installation of apps from the apps store you have to
 +set **appstoreenabled** parameter, but this can only be done if at least one
 +of the configured apps directories is writable.
 +
 +The **appstoreurl** is used to set the http path to the ownCloud apps store. The appstore server has to use :abbr:`OCS (Open Collaboration Services)`.
 +
 +.. code-block:: php
 +
 +  <?php
 +
 +    "appstoreenabled" => true,
 +    "appstoreurl" => "http://api.apps.owncloud.com/v1",
 +
 +Guard against malicious 3rdparty code
 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 +Finally you can enable checks for malicious code fragments of 3rd-party apps
 +by setting the **appcodechecker** parameter.
 +
 +.. code-block:: php
 +
 +  <?php
 +
 +    "appcodechecker" => false,
diff --cc core/doc/admin/_sources/configuration/configuration_custom_clients.txt
index 88df77e,0000000..f2390fe
mode 100644,000000..100644
--- a/core/doc/admin/_sources/configuration/configuration_custom_clients.txt
+++ b/core/doc/admin/_sources/configuration/configuration_custom_clients.txt
@@@ -1,27 -1,0 +1,27 @@@
- Custom Client Configuration
- ===========================
++Customizing Client Download Links
++=================================
 +
 +If you want to access your ownCloud, you can choose between the standard Web-GUI
 +and different client sync applications. Download links which point to these
 +applications are shown at the top of the personal menu. The following sync
 +applications are currently available out of the box:
 +
 +* Desktop sync clients for Windows, Max and Linux OS
 +* Mobile sync client for Android devices
 +* Mobile sync client for iOS devices
 +
 +
 +Parameters
 +----------
 +If you want to customize the download links for the sync clients the following
 +parameters need to be modified to fulfil your requirements:
 +
 +.. code-block:: php
 +
 +  <?php
 +
 +    "customclient_desktop" => "http://owncloud.org/sync-clients/",
 +    "customclient_android" => "https://play.google.com/store/apps/details?id=com.owncloud.android",
 +    "customclient_ios"     => "https://itunes.apple.com/us/app/owncloud/id543672169?mt=8",
 +
 +This parameters can be set in the :file:`config/config.php`
diff --cc core/doc/admin/_sources/configuration/configuration_database.txt
index 3e4c247,0000000..ad42756
mode 100644,000000..100644
--- a/core/doc/admin/_sources/configuration/configuration_database.txt
+++ b/core/doc/admin/_sources/configuration/configuration_database.txt
@@@ -1,359 -1,0 +1,359 @@@
- Database Configuration
- ======================
++MySQL/Postgres/SQLite Support
++=============================
 +
 +ownCloud requires a database where administrative data will be held. Four different database types are currently
 +supported, `MySQL <http://www.mysql.com/>`_, `MariaDB <https://mariadb.org/>`_, `SQLite <http://www.sqlite.org/>`_,
 +and `PostgreSQL <http://www.postgresql.org/>`_. MySQL or MariaDB are the recommended database engines. By default
 +SQLite is chosen because it is a file based database with the least administrative overhead.
 +
 +.. note:: Because SQLite handles multiple users very badly SQLite is only recommended for single user ownCloud installations
 +
 +Requirements
 +------------
 +
 +If you decide to use MySQL, MariaDB, or PostgreSQL you need to install and set-up the
 +database first. These steps will not be covered by this description as they are easy to find elsewhere.
 +
 +Parameters
 +----------
 +
 +MySQL/MariaDB Database
 +~~~~~~~~~~~~~~~~~~~~~~
 +
 +If you decide to use a MySQL or MariaDB database make sure that you have installed and
 +enabled the MySQL extension in PHP and that the **mysql.default_socket**
 +points to the correct socket (if the database runs on same server as ownCloud).
 +
 +Please note that MariaDB is backwards compatible with MySQL, so all instructions will work for both.
 +You will not need to replace mysql with anything.
 +
 +The PHP configuration in :file:`/etc/php5/conf.d/mysql.ini` could look like this:
 +
 +.. code-block:: ini
 +
 +  # configuration for PHP MySQL module
 +  extension=pdo_mysql.so
 +  extension=mysql.so
 +
 +  [mysql]
 +  mysql.allow_local_infile=On
 +  mysql.allow_persistent=On
 +  mysql.cache_size=2000
 +  mysql.max_persistent=-1
 +  mysql.max_links=-1
 +  mysql.default_port=
 +  mysql.default_socket=/var/lib/mysql/mysql.sock  # Debian squeeze: /var/run/mysqld/mysqld.sock
 +  mysql.default_host=
 +  mysql.default_user=
 +  mysql.default_password=
 +  mysql.connect_timeout=60
 +  mysql.trace_mode=Off
 +
 +Now you need to create a database user and the database itself by using the
 +MySQL command line interface. The database tables will be created by ownCloud
 +when you login for the first time.
 +
 +To start the MySQL command line mode use::
 +
 +  mysql -uroot -p
 +
 +Then a **mysql>** or **MariaDB [root]>** prompt will appear. Now enter the following lines and confirm them with the enter key:
 +
 +.. code-block:: sql
 +
 +  CREATE USER 'username'@'localhost' IDENTIFIED BY 'password';
 +  CREATE DATABASE IF NOT EXISTS owncloud;
 +  GRANT ALL PRIVILEGES ON owncloud.* TO 'username'@'localhost' IDENTIFIED BY 'password';
 +
 +You can quit the prompt by entering::
 +
 +  quit
 +
 +In the ownCloud configuration you need to set the hostname on which the
 +database is running and a valid username and password to access it.
 +
 +.. code-block:: php
 +
 +  <?php
 +
 +    "dbtype"        => "mysql",
 +    "dbname"        => "owncloud",
 +    "dbuser"        => "username",
 +    "dbpassword"    => "password",
 +    "dbhost"        => "localhost",
 +    "dbtableprefix" => "",
 +
 +SQLite Database
 +~~~~~~~~~~~~~~~
 +
 +If you decide to use a SQLite database make sure that you have installed and
 +enabled the SQLite extension in PHP. The PHP configuration in :file:`/etc/php5/conf.d/sqlite3.ini` could look like this:
 +
 +.. code-block:: ini
 +
 +  # configuration for PHP SQLite3 module
 +  extension=pdo_sqlite.so
 +  extension=sqlite3.so
 +
 +It is not necessary to create a database and a database user in advance
 +because this will automatically be done by ownCloud when you login for the
 +first time.
 +
 +In the ownCloud configuration in :file:`config/config.php` you need to set at least the **datadirectory** parameter to
 +the directory where your data and database should be stored. Note that for the PDO SQLite driver this directory must
 +be writable (this is recommended for ownCloud anyway).  No authentication is required to access the database therefore
 +most of the default parameters could be taken as is:
 +
 +.. code-block:: php
 +
 +  <?php
 +
 +    "dbtype"        => "sqlite",
 +    "dbname"        => "owncloud",
 +    "dbuser"        => "",
 +    "dbpassword"    => "",
 +    "dbhost"        => "",
 +    "dbtableprefix" => "",
 +    "datadirectory" => "/www/htdocs/owncloud/data",
 +
 +PostgreSQL Database
 +~~~~~~~~~~~~~~~~~~~
 +
 +If you decide to use a PostgreSQL database make sure that you have installed
 +and enabled the PostgreSQL extension in PHP. The PHP configuration in :file:`/etc/php5/conf.d/pgsql.ini` could look
 +like this:
 +
 +.. code-block:: ini
 +
 +  # configuration for PHP PostgreSQL module
 +  extension=pdo_pgsql.so
 +  extension=pgsql.so
 +
 +  [PostgresSQL]
 +  pgsql.allow_persistent = On
 +  pgsql.auto_reset_persistent = Off
 +  pgsql.max_persistent = -1
 +  pgsql.max_links = -1
 +  pgsql.ignore_notice = 0
 +  pgsql.log_notice = 0
 +
 +Now you need to create a database user and the database itself by using the
 +PostgreSQL command line interface. The database tables will be created by
 +ownCloud when you login for the first time.
 +
 +To start the postgres command line mode use::
 +
 +  psql -hlocalhost -Upostgres
 +
 +Then a **postgres=#** prompt will appear. Now enter the following lines and confirm them with the enter key:
 +
 +.. code-block:: sql
 +
 +  CREATE USER username WITH PASSWORD 'password';
 +  CREATE DATABASE owncloud TEMPLATE template0 ENCODING 'UNICODE';
 +  ALTER DATABASE owncloud OWNER TO username;
 +  GRANT ALL PRIVILEGES ON DATABASE owncloud TO username;
 +
 +You can quit the prompt by entering::
 +
 +  \q
 +
 +In the ownCloud configuration you need to set the hostname on which the
 +database is running and a valid username (and sometimes a password) to
 +access it. If the database has been installed on the same server as
 +ownCloud a password is very often not required to access the database.
 +
 +.. code-block:: php
 +
 +  <?php
 +
 +    "dbtype"        => "pgsql",
 +    "dbname"        => "owncloud",
 +    "dbuser"        => "username",
 +    "dbpassword"    => "password",
 +    "dbhost"        => "localhost",
 +    "dbtableprefix" => "",
 +
 +Oracle Database
 +~~~~~~~~~~~~~~~
 +
 +If you are deploying to an Oracle database make sure that you have installed
 +and enabled the `Oracle extension <http://php.net/manual/en/book.oci8.php>`_ in PHP. The PHP configuration in
 +:file:`/etc/php5/conf.d/oci8.ini` could look like this:
 +
 +.. code-block:: ini
 +
 +  # configuration for PHP Oracle extension
 +  extension=oci8.so
 +
 +Make sure that the Oracle environment has been set up for the process trying to use the Oracle extension.
 +For a local Oracle XE installation this can be done by exporting the following environment variables
 +(eg. in :file:`/etc/apache2/envvars` for Apache)
 +
 +.. code-block:: bash
 +
 +  export ORACLE_HOME=/u01/app/oracle/product/11.2.0/xe
 +  export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$ORACLE_HOME/lib
 +
 +Installing and configuring Oracle support for PHP is way out of scope for this document.
 +The official Oracle documentation called `The Underground PHP and Oracle Manual <http://www.oracle.com/technetwork/topics/php/underground-php-oracle-manual-098250.html>`_
 +should help you through the process.
 +
 +Creating a database user for ownCloud can be done by using the sqlplus command line interface
 +or the Oracle Application Express web interface.
 +The database tables will be created by ownCloud when you login for the first time.
 +
 +To start the Oracle command line mode with a DBA account use::
 +
 +  sqlplus system AS SYSDBA
 +
 +After entering the password a **SQL>** prompt will appear. Now enter the following lines and confirm them with the enter key:
 +
 +.. code-block:: sql
 +
 +  CREATE USER owncloud IDENTIFIED BY password;
 +  ALTER USER owncloud DEFAULT TABLESPACE users
 +                      TEMPORARY TABLESPACE temp
 +                      QUOTA unlimited ON users;
 +  GRANT create session
 +      , create table
 +      , create procedure
 +      , create sequence
 +      , create trigger
 +      , create view
 +      , create synonym
 +      , alter session
 +     TO owncloud;
 +
 +.. note:: In Oracle creating a user is the same as creating a database in other RDBMs, so no ``CREATE DATABASE`` statement is necessary.
 +
 +You can quit the prompt by entering::
 +
 +  exit
 +
 +In the ownCloud configuration you need to set the hostname on which the
 +database is running and a valid username and password to
 +access it. If the database has been installed on the same server as
 +ownCloud to config file could look like this:
 +
 +.. code-block:: php
 +
 +  <?php
 +
 +    "dbtype"        => "oci",
 +    "dbname"        => "XE",
 +    "dbuser"        => "owncloud",
 +    "dbpassword"    => "password",
 +    "dbhost"        => "localhost",
 +
 +.. note:: This example assumes you are running an Oracle Express Edition on ``localhost``. The ``dbname`` is the name
 +of the Oracle instance. For Oracle Express Edition it is always ``XE``.
 +
 +Trouble Shooting
 +----------------
 +
 +How can I find out if my MySQL/PostgreSQL  server is reachable?
 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 +
 +Use the ping command to check the server availability::
 +
 +  ping db.server.dom
 +
 +::
 +
 +  PING db.server.dom (ip-address) 56(84) bytes of data.
 +  64 bytes from your-server.local.lan (192.168.1.10): icmp_req=1 ttl=64 time=3.64 ms
 +  64 bytes from your-server.local.lan (192.168.1.10): icmp_req=2 ttl=64 time=0.055 ms
 +  64 bytes from your-server.local.lan (192.168.1.10): icmp_req=3 ttl=64 time=0.062 ms
 +
 +How can I find out if a created user can access a database?
 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 +
 +The easiest way to test if a database can be accessed is by starting the
 +command line interface:
 +
 +**SQLite**::
 +
 +  sqlite3 /www/htdocs/owncloud/data/owncloud.db
 +
 +::
 +
 +  sqlite> .version
 +  SQLite 3.7.15.1 2012-12-19 20:39:10 6b85b767d0ff7975146156a99ad673f2c1a23318
 +  sqlite> .quit
 +
 +**MySQL**::
 +
 +  mysql -uUSERNAME -p
 +
 +::
 +
 +  mysql> SHOW VARIABLES LIKE "version";
 +  +---------------+--------+
 +  | Variable_name | Value  |
 +  +---------------+--------+
 +  | version       | 5.1.67 |
 +  +---------------+--------+
 +  1 row in set (0.00 sec)
 +  mysql> quit
 +
 +**PostgreSQL**::
 +
 +  psql -Uusername -downcloud
 +
 +::
 +
 +  postgres=# SELECT version();
 +  PostgreSQL 8.4.12 on i686-pc-linux-gnu, compiled by GCC gcc (GCC) 4.1.3 20080704 (prerelease), 32-bit
 +  (1 row)
 +  postgres=# \q
 +
 +**Oracle**::
 +
 +  sqlplus username
 +
 +::
 +
 +  SQL> select * from v$version;
 +
 +  BANNER
 +  --------------------------------------------------------------------------------
 +  Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64bit Production
 +  PL/SQL Release 11.2.0.2.0 - Production
 +  CORE	11.2.0.2.0	Production
 +  TNS for Linux: Version 11.2.0.2.0 - Production
 +  NLSRTL Version 11.2.0.2.0 - Production
 +
 +  SQL> exit
 +
 +Useful SQL commands
 +~~~~~~~~~~~~~~~~~~~
 +
 +**Show Database Users**::
 +
 +  SQLite    : No database user is required.
 +  MySQL     : SELECT User,Host FROM mysql.user;
 +  PostgreSQL: SELECT * FROM pg_user;
 +  Oracle    : SELECT * FROM all_users;
 +
 +**Show available Databases**::
 +
 +  SQLite    : .databases (normally one database per file!)
 +  MySQL     : SHOW DATABASES;
 +  PostgreSQL: \l
 +  Oracle    : SELECT name FROM v$database; (requires DBA privileges)
 +
 +**Show ownCloud Tables in Database**::
 +
 +  SQLite    : .tables
 +  MySQL     : USE owncloud; SHOW TABLES;
 +  PostgreSQL: \c owncloud; \d
 +  Oracle    : SELECT table_name FROM user_tables;
 +
 +**Quit Database**::
 +
 +  SQLite    : .quit
 +  MySQL     : quit
 +  PostgreSQL: \q
 +  Oracle    : quit
 +
diff --cc core/doc/admin/_sources/configuration/configuration_encryption.txt
index 754dcce,0000000..7ea3fcf
mode 100644,000000..100644
--- a/core/doc/admin/_sources/configuration/configuration_encryption.txt
+++ b/core/doc/admin/_sources/configuration/configuration_encryption.txt
@@@ -1,57 -1,0 +1,57 @@@
- Use Server-Side Encryption
- ==========================
++Using Server-Side Encryption
++============================
 +
 +ownCloud ships a encryption app, which allows to encrypt all files stored in
 +your ownCloud. Encryption and decryption always happens server-side. This
 +enables the user to continue to use all the other apps to view and edit his
 +data.
 +
 +The app uses the user's log-in password as encryption-password. This means that
 +by default the user will lose access to his files if he loses his log-in
 +password.
 +
 +It might be a good idea to make regular backups of all encryption keys. The
 +encryption keys are stored in following folders:
 +
 +* data/owncloud_private_key (recovery key, if enabled and public share key)
 +* data/public-keys (public keys from all users)
 +* data/<user>/files_encryption (users' private keys and all other keys necessary to
 +  decrypt the users' files)
 +
 +Enable File Recovery Feature
 +----------------------------
 +
 +The admin can offer the user some kind of protection against password
 +loss. Therefore you have to enable the recovery key in the admin settings and
 +provide a strong recovery key password. The admin settings also enables you to
 +change the recovery key password if you wish. But you should make sure to never
 +lose this password, because that's the only way to recover users' files.
 +
 +Once the recovery key was enabled every user can choose in his personal
 +settings to enable this feature or not.
 +
 +Recover User Files
 +------------------
 +
 +If the recovery feature was enabled the admin will see a additional input field
 +at the top of the user management settings. After entering the recovery-key
 +password the admin can change the user's log-in password which will
 +automatically recover the user's file.
 +
 +If you use a user back-end which doesn't allow you to change the log-in
 +password directly within ownCloud, e.g. the LDAP back-end, than you can follow
 +the same procedure to recover a user's files. The only difference is that
 +you need to change the log-in password additionally at your back-end. In this
 +case make sure to use both times the same password.
 +
 +LDAP and other external user back-ends
 +--------------------------------------
 +
 +if you configure a external user back-end you will be able to change the user's log-in password
 +at the back-end. Since the encryption password must be the same as the user's log-in password
 +this will result in a non-functional encryption system. If the recovery feature was enabled,
 +the administrator will be able to recover the user's files directly over the recovery feature.
 +See the description above. Otherwise the user will be informed that his log-in password and
 +his encryption password no longer matches after his next log-in. In this case the user will be
 +able to adjust his encryption password in the personal settings by providing both, his old and
 +his new log-in password.
diff --cc core/doc/admin/_sources/configuration/configuration_knowledgebase.txt
index 420cc15,0000000..9ae6d97
mode 100644,000000..100644
--- a/core/doc/admin/_sources/configuration/configuration_knowledgebase.txt
+++ b/core/doc/admin/_sources/configuration/configuration_knowledgebase.txt
@@@ -1,21 -1,0 +1,23 @@@
- Knowledge Base Configuration
- ============================
++Disable Knowledge Base
++======================
++
 +The usage of ownCloud is more or less self explaining but nevertheless a user
- might run into a problem where he needs to consult the documentation or knowledge base. To ease access to the ownCloud
- documentation and knowledge base, a help menu item is shown in the settings menu by default.
++might run into a problem where he needs to consult the documentation or
++knowledge base. To ease access to the ownCloud documentation and knowledge
++base, a help menu item is shown in the settings menu by default.
 +
 +Parameters
 +----------
 +
 +If you want to disable the ownCloud help menu item you can use the **knowledgebaseenabled** parameter inside the
 +:file:`config/config.php`. The **knowledgebaseurl** parameter is used to set the http path to the ownCloud help page.
 +The server should support :abbr:`OCS (Open Collaboration Services)`.
 +
 +.. code-block:: php
 +
 +  <?php
 +
 +    "knowledgebaseenabled" => true,
 +    "knowledgebaseurl"     => "http://api.apps.owncloud.com/v1",
 +
 +.. note:: Disabling the help menu item might increase the number of support request you have to answer in the future
diff --cc core/doc/admin/_sources/configuration/configuration_language.txt
index 386d7d8,0000000..0329141
mode 100644,000000..100644
--- a/core/doc/admin/_sources/configuration/configuration_language.txt
+++ b/core/doc/admin/_sources/configuration/configuration_language.txt
@@@ -1,24 -1,0 +1,24 @@@
- Language Configuration
- ======================
++Setting the Default Language
++============================
 +
 +In normal cases ownCloud will automatically detect the language of the Web-GUI.
 +If this doesn't work properly or you want to make sure that ownCloud always
 +starts with a given language, you can use the **default_language** parameter.
 +
 +Please keep in mind, that this will not effect a users language preference,
 +which has been configured under "personal -> language" once he has logged in.
 +
 +Please check :file:`settings/languageCodes.php` for the list of supported language
 +codes. 
 +
 +
 +Parameters
 +----------
 +
 +.. code-block:: php
 +
 +  <?php
 +
 +    "default_language" => "en",
 +
 +This parameters can be set in the :file:`config/config.php`
diff --cc core/doc/admin/_sources/configuration/configuration_logging.txt
index effe2e0,0000000..004b73a
mode 100644,000000..100644
--- a/core/doc/admin/_sources/configuration/configuration_logging.txt
+++ b/core/doc/admin/_sources/configuration/configuration_logging.txt
@@@ -1,62 -1,0 +1,63 @@@
- Logging Configuration
- =====================
++Configure Logging
++=================
++
 +To get an idea of how the current status of an ownCloud system is or to
 +solve issues log information is a good point to start with. ownCloud allows
 +to configure the way how and which depth of information should be logged.
 +
 +Parameters
 +----------
 +First you need to decide in which way logging should be done. You can
 +choose between the two options **owncloud** and **syslog**. Then you need
 +to configure the log level which directly influences how much information
 +will be logged. You can choose between:
 +
 +* **0**: DEBUG
 +* **1**: INFO
 +* **2**: WARN
 +* **3**: ERROR
 +
 +The most detailed information will be written if **0** (DEBUG) is set, the
 +least information will be written if **3** (ERROR) is set. Keep in mind that
 +it might slow down the whole system if a too detailed logging will has been
 +configured. By default the log level is set to **2** (WARN).
 +
 +This parameters can be set in the :file:`config/config.php`
 +
 +ownCloud
 +~~~~~~~~
 +All log information will be written to a separate log file which can be
 +viewed using the log menu in the admin menu of ownCloud. By default a log
 +file named **owncloud.log** will be created in the directory which has
 +been configured by the **datadirectory** parameter.
 +
 +The desired date format can optionally be defined using the **logdateformat**.
 +By default the `PHP date function`_ parameter "*c*" is used and therefore the
 +date/time is written in the format "*2013-01-10T15:20:25+02:00*". By using the
 +date format in the example the date/time format will be written in the format
 +"*January 10, 2013 15:20:25*".
 +
 +.. code-block:: php
 +
 +  <?php
 +
 +    "log_type" => "owncloud",
 +    "logfile" => "owncloud.log",
 +    "loglevel" => "3",
 +    "logdateformat" => "F d, Y H:i:s",
 +
 +syslog
 +~~~~~~
 +All log information will be send to the default syslog daemon of a system.
 +
 +.. code-block:: php
 +
 +  <?php
 +
 +    "log_type" => "syslog",
 +    "logfile" => "",
 +    "loglevel" => "3",
 +
 +
 +.. _PHP date function: http://www.php.net/manual/en/function.date.php
 +
diff --cc core/doc/admin/_sources/configuration/configuration_mail.txt
index 3ff6b62,0000000..3e7d444
mode 100644,000000..100644
--- a/core/doc/admin/_sources/configuration/configuration_mail.txt
+++ b/core/doc/admin/_sources/configuration/configuration_mail.txt
@@@ -1,322 -1,0 +1,323 @@@
- Mail Configuration
- ==================
++Sending Mail Notifications
++==========================
++
 +ownCloud does not contain a full email program but contains some parameters to
 +allow to send e.g. password reset email to the users. This function relies on
 +the `PHPMailer library <http://sourceforge.net/projects/phpmailer/>`_. To
 +take advantage of this function it needs to be configured properly.
 +
 +
 +Requirements
 +------------
 +Different requirements need to be matched, depending on the environment which
 +you are using and the way how you want to send email. You can choose between
 +**SMTP**, **PHP mail**, **Sendmail** and **qmail**.
 +
 +Parameters
 +----------
 +
 +All parameters need to be set in :file:`config/config.php`
 +
 +SMTP
 +~~~~
 +If you want to send email using a local or remote SMTP server it is necessary
 +to enter the name or ip address of the server, optionally followed by a colon
 +separated port number, e.g. **:425**. If this value is not given the default
 +port 25/tcp will be used unless you will change that by modifying the
 +**mail_smtpport** parameter. Multiple server can be entered separated by
 +semicolon:
 +
 +.. code-block:: php
 +
 +  <?php
 +
 +    "mail_smtpmode"     => "smtp",
 +    "mail_smtphost"     => "smtp-1.server.dom;smtp-2.server.dom:425",
 +    "mail_smtpport"     => 25,
 +
 +or
 +
 +.. code-block:: php
 +
 +  <?php
 +
 +    "mail_smtpmode"     => "smtp",
 +    "mail_smtphost"     => "smtp.server.dom",
 +    "mail_smtpport"     => 425,
 +
 +If a malware or SPAM scanner is running on the SMTP server it might be
 +necessary that you increase the SMTP timeout to e.g. 30s:
 +
 +.. code-block:: php
 +
 +  <?php
 +
 +    "mail_smtptimeout"  => 30,
 +
 +If the SMTP server accepts insecure connections, the default setting can be
 +used:
 +
 +.. code-block:: php
 +
 +  <?php
 +
 +  "mail_smtpsecure"   => '',
 +
 +If the SMTP server only accepts secure connections you can choose between
 +the following two variants:
 +
 +SSL
 +^^^
 +A secure connection will be initiated using the outdated SMTPS protocol
 +which uses the port 465/tcp:
 +
 +.. code-block:: php
 +
 +  <?php
 +
 +    "mail_smtphost"     => "smtp.server.dom:465",
 +    "mail_smtpsecure"   => 'ssl',
 +
 +TLS
 +^^^
 +A secure connection will be initiated using the STARTTLS protocol which
 +uses the default port 25/tcp:
 +
 +.. code-block:: php
 +
 +  <?php
 +
 +    "mail_smtphost"     => "smtp.server.dom",
 +    "mail_smtpsecure"   => 'tls',
 +
 +And finally it is necessary to configure if the SMTP server requires
 +authentication, if not, the default values can be taken as it.
 +
 +.. code-block:: php
 +
 +  <?php
 +
 +    "mail_smtpauth"     => false,
 +    "mail_smtpname"     => "",
 +    "mail_smtppassword" => "",
 +
 +If SMTP authentication is required you have to set the required username
 +and password and can optionally choose between the authentication types
 +**LOGIN** (default) or **PLAIN**.
 +
 +.. code-block:: php
 +
 +  <?php
 +
 +    "mail_smtpauth"     => true,
 +    "mail_smtpauthtype" => "LOGIN",
 +    "mail_smtpname"     => "username",
 +    "mail_smtppassword" => "password",
 +
 +PHP mail
 +~~~~~~~~
 +If you want to use PHP mail it is necessary to have an installed and working
 +email system on your server. Which program in detail is used to send email is
 +defined by the configuration settings in the **php.ini** file. (On \*nix
 +systems this will most likely be Sendmail.) ownCloud should be able to send
 +email out of the box.
 +
 +.. code-block:: php
 +
 +  <?php
 +
 +    "mail_smtpmode"     => "php",
 +    "mail_smtphost"     => "127.0.0.1",
 +    "mail_smtpport"     => 25,
 +    "mail_smtptimeout"  => 10,
 +    "mail_smtpsecure"   => "",
 +    "mail_smtpauth"     => false,
 +    "mail_smtpauthtype" => "LOGIN",
 +    "mail_smtpname"     => "",
 +    "mail_smtppassword" => "",
 +
 +Sendmail
 +~~~~~~~~
 +If you want to use the well known Sendmail program to send email, it is
 +necessary to have an installed and working email system on your \*nix server.
 +The sendmail binary (**/usr/sbin/sendmail**) is usually part of that system.
 +ownCloud should be able to send email out of the box.
 +
 +.. code-block:: php
 +
 +  <?php
 +
 +    "mail_smtpmode"     => "sendmail",
 +    "mail_smtphost"     => "127.0.0.1",
 +    "mail_smtpport"     => 25,
 +    "mail_smtptimeout"  => 10,
 +    "mail_smtpsecure"   => "",
 +    "mail_smtpauth"     => false,
 +    "mail_smtpauthtype" => "LOGIN",
 +    "mail_smtpname"     => "",
 +    "mail_smtppassword" => "",
 +
 +qmail
 +~~~~~
 +
 +If you want to use the qmail program to send email, it is necessary to have an
 +installed and working qmail email system on your server. The sendmail binary
 +(**/var/qmail/bin/sendmail**) will then be used to send email. ownCloud should
 +be able to send email out of the box.
 +
 +.. code-block:: php
 +
 +  <?php
 +
 +    "mail_smtpmode"     => "qmail",
 +    "mail_smtphost"     => "127.0.0.1",
 +    "mail_smtpport"     => 25,
 +    "mail_smtptimeout"  => 10,
 +    "mail_smtpsecure"   => "",
 +    "mail_smtpauth"     => false,
 +    "mail_smtpauthtype" => "LOGIN",
 +    "mail_smtpname"     => "",
 +    "mail_smtppassword" => "",
 +
 +Send a Test Email
 +-----------------
 +
 +The only way to test your email configuration is, to force a login failure,
 +because a function to send a test email has not be implemented yet.
 +
 +First make sure that you are using a full qualified domain and not an ip address in the ownCloud URL, like::
 +
 +  http://my-owncloud-server.domain.dom/owncloud/
 +
 +The password reset function fetches the domain name from that URL to build the
 +email sender address, e.g.::
 +
 +  john at domain.dom
 +
 +Next you need to enter your login and an *invalid* password. As soon as you
 +press the login button the login mask reappears and a **I’ve forgotten my password** link will be shown above the login
 +field. Click on that link, re-enter your login and press the **Reset password** button - that's all.
 +
 +Trouble shooting
 +----------------
 +
 +My web domain is different from my mail domain?
 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 +
 +The default domain name used for the sender address is the hostname where your ownCloud installation is served.
 +If you have a different mail domain name you can override this behavior by setting the following configuration parameter:
 +
 +.. code-block:: php
 +
 +  <?php
 +
 +    "mail_domain" => "example.com",
 +
 +Now every mail send by ownCloud e.g. password reset email, will have the domain part of the sender address look like::
 +  
 +  no-reply at example.com
 +
 +How can I find out if a SMTP server is reachable?
 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 +
 +Use the ping command to check the server availability::
 +
 +  ping smtp.server.dom
 +
 +::
 +
 +  PING smtp.server.dom (ip-address) 56(84) bytes of data.
 +  64 bytes from your-server.local.lan (192.168.1.10): icmp_req=1 ttl=64 time=3.64 ms
 +  64 bytes from your-server.local.lan (192.168.1.10): icmp_req=2 ttl=64 time=0.055 ms
 +  64 bytes from your-server.local.lan (192.168.1.10): icmp_req=3 ttl=64 time=0.062 ms
 +
 +How can I find out if the SMTP server is listening on a specific tcp port?
 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 +
 +A SMTP server is usually listening on port **25/tcp** (smtp) and/or in
 +rare circumstances is also listening on the outdated port **465/tcp** (smtps).
 +You can use the telnet command to check if a port is available::
 +
 +  telnet smtp.domain.dom 25
 +
 +::
 +
 +  Trying 192.168.1.10...
 +  Connected to smtp.domain.dom.
 +  Escape character is '^]'.
 +  220 smtp.domain.dom ESMTP Exim 4.80.1 Tue, 22 Jan 2013 22:28:14 +0100
 +
 +How can I find out if a SMTP server supports the outdated SMTPS protocol?
 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 +A good indication that a SMTP server supports the SMTPS protocol is that it
 +is listening on port **465/tcp**. How this can be checked has been described
 +previously.
 +
 +How can I find out if a SMTP server supports the TLS protocol?
 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 +A SMTP server usually announces the availability of STARTTLS right after a
 +connection has been established. This can easily been checked with the telnet command. You need to enter the marked lines to get the information displayed::
 +
 +  telnet smtp.domain.dom 25
 +
 +::
 +
 +  Trying 192.168.1.10...
 +  Connected to smtp.domain.dom.
 +  Escape character is '^]'.
 +  220 smtp.domain.dom ESMTP Exim 4.80.1 Tue, 22 Jan 2013 22:39:55 +0100
 +  EHLO your-server.local.lan                                             # <<< enter this command
 +  250-smtp.domain.dom Hello your-server.local.lan [ip-address]
 +  250-SIZE 52428800
 +  250-8BITMIME
 +  250-PIPELINING
 +  250-AUTH PLAIN LOGIN CRAM-MD5
 +  250-STARTTLS                                                           # <<< STARTTLS is supported!
 +  250 HELP
 +  QUIT                                                                   # <<< enter this command
 +  221 smtp.domain.dom closing connection
 +  Connection closed by foreign host.
 +
 +How can I find out which authentication types/methods a SMTP server supports?
 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 +A SMTP server usually announces the available authentication types/methods
 +right after a connection has been established. This can easily been checked
 +with the telnet command. You need to enter the marked lines to get the
 +information displayed::
 +
 +  telnet smtp.domain.dom 25
 +
 +::
 +
 +  Trying 192.168.1.10...
 +  Connected to smtp.domain.dom.
 +  Escape character is '^]'.
 +  220 smtp.domain.dom ESMTP Exim 4.80.1 Tue, 22 Jan 2013 22:39:55 +0100
 +  EHLO your-server.local.lan                                             # <<< enter this command
 +  250-smtp.domain.dom Hello your-server.local.lan [ip-address]
 +  250-SIZE 52428800
 +  250-8BITMIME
 +  250-PIPELINING
 +  250-AUTH PLAIN LOGIN CRAM-MD5                                          # <<< available Authentication types
 +  250-STARTTLS
 +  250 HELP
 +  QUIT                                                                   # <<< enter this command
 +  221 smtp.domain.dom closing connection
 +  Connection closed by foreign host.
 +
 +
 +Enable Debug Mode
 +~~~~~~~~~~~~~~~~~
 +
 +If you are still not able to send email it might be useful to activate
 +further debug messages by setting the following parameter. Right after
 +you have pressed the **Reset password** button, as described before, a
 +lot of **SMTP -> get_lines(): ...** messages will be written on the
 +screen.
 +
 +.. code-block:: php
 +
 +  <?php
 +
 +    "mail_smtpdebug" => true;
 +
diff --cc core/doc/admin/_sources/configuration/configuration_maintenance.txt
index 7d4ff82,0000000..c5de3d1
mode 100644,000000..100644
--- a/core/doc/admin/_sources/configuration/configuration_maintenance.txt
+++ b/core/doc/admin/_sources/configuration/configuration_maintenance.txt
@@@ -1,21 -1,0 +1,18 @@@
- Maintenance Mode Configuration
- ==============================
++Enable Maintenance Mode
++=======================
 +
 +If you want to prevent users to login to ownCloud before you start doing
 +some maintenance work, you need to set the value of the **maintenance**
 +parameter to *true*. Please keep in mind that users who are already logged-in
 +are kicked out of ownCloud instantly.
 +
- 
- 
- 
 +Parameters
 +----------
 +
 +.. code-block:: php
 +
 +  <?php
 +
 +    "maintenance" => false,
 +
 +This parameters can be set in the :file:`config/config.php`
diff --cc core/doc/admin/_sources/configuration/configuration_preview.txt
index b217109,0000000..2211fdd
mode 100644,000000..100644
--- a/core/doc/admin/_sources/configuration/configuration_preview.txt
+++ b/core/doc/admin/_sources/configuration/configuration_preview.txt
@@@ -1,124 -1,0 +1,124 @@@
- Preview Configuration
- =====================
++Enabling File Previews
++======================
++
 +ownCloud 6 introduced the new thumbnail system. It is used to generate
- thumbnails from various file types. 
- By default, it can generate previews for:
++thumbnails from various file types.  By default, it can generate previews for:
 +
 +* Images
 +* Movies
 +* Cover from mp3 files 
 +* various office files 
 +* Pdf 
 +* Svg 
 +* Text 
 +
 +Soft dependencies:
 +------------------
 +
 +imagick:
 +~~~~~~~~
 +ownCloud needs the imagick php extension to generate previews from office, pdf
 +and svg files. For further information on how to install the imagick php
 +extension on your system take a look at the `PHP documentation <http://www.php.net/manual/en/imagick.installation.php>`_.
 +If imagick is not installed, ownCloud will show file type icons instead of previews.
 +
 +LibreOffice / OpenOffice:
 +~~~~~~~~~~~~~~~~~~~~~~~~~
 +ownCloud comes with a php-only preview system for office files. But this
 +preview system has limited capabilities and is only able to create previews
 +from basic Microsoft Office files. If you need previews from advanced
 +Microsoft Office files or OpenDocument files, you have to install LibreOffice
 +or OpenOffice. To learn more about installing LibreOffice/OpenOffice consider
 +your distribution's documentation.
 +
 +avconv / ffmpeg:
 +~~~~~~~~~~~~~~~~
 +ownCloud requires avconv of ffmpeg to generate previews from movies. To learn
 +more about installing avconv or ffmpeg consider your distribution's
 +documentation.
 +
 +Parameters
 +----------
 +Disabling previews:
 +~~~~~~~~~~~~~~~~~~~
 +Under certain circumstances like a big user base or limited resources you might
 +want to consider disabling previews.
 +
 +.. code-block:: php
 +
 +  <?php
 +    'enable_previews' => true,
 +
 +There is a config option called 'enable_previews'. By default it's set to true.
 +You can disable previews by setting this option to false:
 +
 +.. code-block:: php
 +
 +  <?php
 +    'enable_previews' => false,
 +
 +Maximum preview size:
 +~~~~~~~~~~~~~~~~~~~~~
 +
 +There are two config options to set the maximum size of a preview.
 +
 +.. code-block:: php
 +
 +  <?php
 +    'preview_max_x' => null,
 +    'preview_max_y' => null,
 +
 +By default, both config options are set to null. 'Null' is equal to no limit.
 +Numeric values represent the size in pixel. The following code limits previews
 +to a maximum size of 100px by 100px:
 +
 +.. code-block:: php
 +
 +  <?php
 +    'preview_max_x' => 100,
 +    'preview_max_y' => 100,
 +
 +'preview_max_x' represents the x-axis and 'preview_max_y' represents the y-axis.
 +
 +Maximum scale factor:
 +~~~~~~~~~~~~~~~~~~~~~
 +If you have a lot of small pictures and the preview system generates blurry
 +previews, you might want to consider setting a maximum scale factor. By default,
 +ownCloud scales pictures up to 10 times the original size:
 +
 +.. code-block:: php
 +
 +  <?php
 +    'preview_max_scale_factor' => 10,
 +
 +If you want to disable scaling at all, you can set the config value to '1':
 +
 +.. code-block:: php
 +
 +  <?php
 +    'preview_max_scale_factor' => 1,
 +
 +If you want to disable the maximum scaling factor, you can set the config value to 'null':
 +
 +.. code-block:: php
 +
 +  <?php
 +    'preview_max_scale_factor' => null,
 +
 +LibreOffice / OpenOffice:
 +~~~~~~~~~~~~~~~~~~~~~~~~~
 +You can set a custom path for the LibreOffice binary. If LibreOffice is not yet
 +available on your system, you can also use OpenOffice instead.
 +
 +.. code-block:: php
 +
 +  <?php
 +    'preview_libreoffice_path' => '/usr/bin/libreoffice',
 +
 +You can set custom LibreOffice / OpenOffice command line parameters by setting
 +the preview_office_cl_parameters option.
 +
 +.. code-block:: php
 +
 +  <?php
 +    'preview_office_cl_parameters' => ' ',
diff --cc core/doc/admin/_sources/configuration/configuring_big_file_upload.txt
index 05e5d03,0000000..db82b0f
mode 100644,000000..100644
--- a/core/doc/admin/_sources/configuration/configuring_big_file_upload.txt
+++ b/core/doc/admin/_sources/configuration/configuring_big_file_upload.txt
@@@ -1,45 -1,0 +1,47 @@@
- Uploading big files > 512MB (as set by default)
- ===============================================
- It's usefull to know limiting factors, that make it impossible to exceed the values given by the ownCloud-system:
++Dealing with Big File Uploads
++=============================
++
++It's useful to know limiting factors, that make it impossible to exceed the values given by the ownCloud-system:
 +
 +Not outnumberable upload limits:
 +--------------------------------
 +* < 2GB on 32Bit OS-architecture
 +* < 2GB with Server Version 4.5 or older
 +* < 2GB with IE6 - IE8
 +* < 4GB with IE9 - IE10
 +
 +Other recommendable preconditions:
 +----------------------------------
 +
- * Make sure, that the latest version of php (at least 5.4.9) is installed
++* Make sure, that the latest version of PHP (at least 5.4.9) is installed
 +* Disable user quota. This means: set the user quota of the account, you are currently logged in, to "unlimited".
 +This is important, because you possibly could not watch otherwise, whether the desired changes take effect.
 +
 +Enabling uploading big files
- ============================
- Note: The order of the following steps is important! If you swap steps described below, the settings may fail.
++----------------------------
++
++.. note:: The order of the following steps is important! If you swap steps described below, the settings may fail.
 +
 +**Go to the admin section in the ownCloud-WebUI and do the following:**
 +
 +* Under "File handling" set the Maximum upload size to the desired value (e.g. 16GB)
 +* Click the "save"-Button
 +
 +**Open the php.ini - file**
 +
- * Under Debian or SUSE and their derivatives this file lies at /etc/php5/apache2/php.ini
- * On Windows, you can find this file within C:/Program Files (x86)/PHP/PHP.ini 
++* Under Debian or SUSE and their derivatives this file resides at ``/etc/php5/apache2/php.ini``
++* On Windows, you can find this file within ``C:\Program Files (x86)\PHP\PHP.ini``
 +
 +**Do the following:**
 +
 +* Set the following three parameters inside th php.ini to the same value as chosen inside the admin-section one step before:
- * upload_max_filesize = 16G   (e.g., to stay consistent with the example value above)
- * post_max_size = 16G   (e.g., to stay consistent with the example value above)
- * output_buffering = 16384	(e.g., to stay consistent with the example value above)
++* ``upload_max_filesize = 16G``   (e.g., to stay consistent with the example value above)
++* ``post_max_size = 16G``   (e.g., to stay consistent with the example value above)
++* ``output_buffering = 16384``	(e.g., to stay consistent with the example value above)
 +
 +whereas the "output_buffering" has to be given in MegaBytes but as a plain figure (without size-units as 'M' or 'G')
 +
 +These client configurations have been proven by testing maximum file sizes of 16 GB:
 +
 +* Linux 32 Bit: Ubuntu, Firefox => 16GB 
 +* Windows 8  64 Bit: Google Chrome => 8GB
diff --cc core/doc/admin/_sources/contents.txt
index a5646d6,0000000..1fccb2d
mode 100644,000000..100644
--- a/core/doc/admin/_sources/contents.txt
+++ b/core/doc/admin/_sources/contents.txt
@@@ -1,23 -1,0 +1,25 @@@
 +.. _contents:
 +
 +===============================
 +ownCloud documentation contents
 +===============================
 +
 +.. toctree::
 +    :hidden:
 +
 +    index
 +
 +.. toctree::
 +    :maxdepth: 3
 +
 +    installation/index
 +    configuration/index
++    apps/index
 +    maintenance/index
++    config/index
 +    issues/index
 +
 +Indices and tables
 +==================
 +
 +* :ref:`genindex`
diff --cc core/doc/admin/_sources/cron/index.txt
index 1472d8f,0000000..7c2a94e
mode 100644,000000..100644
--- a/core/doc/admin/_sources/cron/index.txt
+++ b/core/doc/admin/_sources/cron/index.txt
@@@ -1,7 -1,0 +1,37 @@@
- **ownCloud cron.php**
++========================
++Driving Events with Cron
++========================
 +
- .. toctree::
-     :maxdepth: 2
++Introduction
++============
 +
-     Introduction
-     Usage
++ownCloud is written in PHP, and because PHP is a request driven language – in
++other words it runs only when a client takes an action and calls php, and then
++it executes and ends – it does not have a built in CRON process. Instead,
++ownCloud provides ``cron.php``, which is called by the server’s CRON daemon.
++``cron.php`` is an ownCloud internal process that runs various background jobs
++on demand.  It is called by the server cron, and can be set by the
++administrator.
++
++ownCloud plug-in applications register actions with ``cron.php`` automatically to
++take care of typical housekeeping operations, such as garbage collecting of
++temporary files or checking for newly updated files using ``filescan()`` for
++externally mounted file systems.
++
++Usage
++=====
++
++The interval at which this script is executed, and thus the ownCloud registered
++actions, can depend on the size of the installation and the load of the system.
++Recommended intervals are 15 or 30 minutes.
++
++Cron.php needs to be called by the system’s cron daemon and run as the same
++user the web server runs as.
++
++As an example, on an ordinary Linux distribution, place the following in the
++webserver’s user’s crontab::
++
++    */15 * * * * /usr/bin/php -f /srv/http/owncloud/cron.php /dev/null 2>&1
++
++This will run ``cron.php`` every 15 minutes and suppress any warnings or output
++which may be generated.
diff --cc core/doc/admin/_sources/index.txt
index 62ad694,0000000..913261c
mode 100644,000000..100644
--- a/core/doc/admin/_sources/index.txt
+++ b/core/doc/admin/_sources/index.txt
@@@ -1,81 -1,0 +1,100 @@@
 +======================================
 +ownCloud |version| Admin Documentation
 +======================================
 +
 +Introduction
 +============
 +
 +This is the administrators manual for ownCloud, a flexible, open source file
 +sync and share solution. It comprises of the ownCloud server, as well as client
 +applications for Microsoft Windows, Mac OS X and Linux (Desktop Client) and
 +mobile clients for the Android and Apple iOS operating system.
 +
 +Target audience
 +---------------
 +
 +This guide is targeted towards people who want to install, administer and
 +optimize ownCloud Server. If you want to learn how to use the Web UI, or how to
 +install clients on the server, please refer to the `User Manual`_ or the `Desktop
 +Client Manual`_ respectively.
 +
 +.. _`User Manual`: http://doc.owncloud.com/
 +.. _`Desktop Client Manual`: http://doc.owncloud.com/
 +
 +Structure of this document
 +--------------------------
 +
 +The next chapters describes how to set up ownCloud Server on different platforms
 +and operating systems, as well as how to update existing installations.
 +
 +Further chapters will then detail on integrating ownCloud into your existing
 +environment, e.g. how to setup LDAP or how to mount your storage.
 +
 +
 +Installation
 +============
 +This chapter will introduce you to the installation of ownCloud in different scenarios.
 +
 +If you want to just try ownCloud in a virtual machine without any configuration, check the section
 +:doc:`installation/installation_appliance`, where you will find ready-to-use images.
 +
 +* :doc:`installation/installation_linux` (recommended)
 +* :doc:`installation/installation_windows`
 +* :doc:`installation/installation_source`
 +* :doc:`installation/installation_others`
 +* :doc:`installation/installation_ucs`
 +* :doc:`installation/installation_macos` (not supported)
 +* :doc:`installation/installation_appliance`
 +
 +Configuration
 +=============
 +This chapter covers ownCloud and web server configuration.
 +
 +* :doc:`configuration/configuration_apps`
 +* :doc:`configuration/configuration_users`
 +* :doc:`configuration/configuration_database`
 +* :doc:`configuration/auth_ldap`
 +* :doc:`configuration/custom_mount_config_gui`
 +* :doc:`configuration/custom_mount_config`
 +* :doc:`configuration/background_jobs`
 +* :doc:`configuration/configuration_mail`
 +* :doc:`configuration/configuration_automation`
 +* :doc:`configuration/configuration_encryption`
 +* :doc:`configuration/configuring_big_file_upload`
 +* :doc:`configuration/configuration_reverseproxy`
 +* :doc:`configuration/xsendfile`
 +* :doc:`configuration/configuration_3rdparty`
 +* :doc:`configuration/custom_user_backend`
 +* :doc:`configuration/configuration_custom_clients`
 +* :doc:`configuration/configuration_maintenance`
 +* :doc:`configuration/configuration_knowledgebase`
 +* :doc:`configuration/configuration_logging`
 +* :doc:`configuration/configuration_language`
 +
++Finally, the chapter :doc:`config/index` details on the switches
++in the ``config.php`` file.
++
++Apps
++====
++This chapter covers individual ownCloud apps.
++
++* :doc:`apps/activity/index`
++* :doc:`apps/admin_dependencies_chk/index`
++* :doc:`apps/files_antivirus/index`
++* :doc:`apps/files_encryption/index`
++* :doc:`apps/files_external/index`
++* :doc:`apps/files_sharing/index`
++* :doc:`apps/files_trashbin/index`
++* :doc:`apps/files_versions/index`
++* :doc:`apps/firstrunwizard/index`
++* :doc:`apps/user_ldap/index`
++* :doc:`apps/viewers/index`
++
 +Maintenance
 +===========
 +This chapter covers maintenance tasks such as updating or migrating to a new version.
 +
 +* :doc:`maintenance/migrating`
 +* :doc:`maintenance/update`
 +
 +
diff --cc core/doc/admin/_sources/installation/installation_linux.txt
index 9a779d5,0000000..2c90e5b
mode 100644,000000..100644
--- a/core/doc/admin/_sources/installation/installation_linux.txt
+++ b/core/doc/admin/_sources/installation/installation_linux.txt
@@@ -1,28 -1,0 +1,28 @@@
 +Linux Distributions
 +-------------------
 +
 +Supported Distribution Packages
 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 +
 +Ready-to-use packages are available at `openSUSE Build Service`_ for a variety of Linux distributions.
 +
 +If your distribution is not listed please follow :doc:`installation_source`.
 +
 +.. _openSUSE Build Service: http://software.opensuse.org/download.html?project=isv:ownCloud:community&package=owncloud
 +
 +
 +Additional installation guides and notes
 +****************************************
 +
 +**Fedora:** Make sure `SELinux is disabled <https://fedoraproject.org/wiki/SELinux_FAQ#How_do_I_enable_or_disable_SELinux_.3F>`_
 +or else the installation process might fail.
 +
- **Archlinux:** There are two AUR packages for ownCloud: `stable version`_ and `development version`_.
++**Archlinux:** The are two packages for ownCloud: `stable version`_ in the official community repository and `development version`_ in AUR.
 +
 +.. _stable version: https://www.archlinux.org/packages/community/any/owncloud/
 +.. _development version: http://aur.archlinux.org/packages.php?ID=38767
 +
 +
 +**PCLinuxOS:** Follow the Tutorial `ownCloud, installation and setup`_ on the PCLinuxOS web site.
 +
 +.. _ownCloud, installation and setup: http://pclinuxoshelp.com/index.php/Owncloud,_installation_and_setup
diff --cc core/doc/admin/_sources/installation/installation_source.txt
index bd2e523,0000000..ad77093
mode 100644,000000..100644
--- a/core/doc/admin/_sources/installation/installation_source.txt
+++ b/core/doc/admin/_sources/installation/installation_source.txt
@@@ -1,574 -1,0 +1,683 @@@
 +Manual Installation
 +-------------------
 +
 +If you do not want to use packages, here is how you setup ownCloud on
- from scratch using a classic :abbr:`LAMP (Linux, Apache, MySQL, PHP)` setup:
++from scratch using a classic :abbr:`LAMP (Linux, Apache, MySQL, PHP)` setup.
 +
 +This document provides a complete walk-through for installing ownCloud 
 +on Ubuntu 12.04 LTS Server with Apache and MySQL.
 +It also provides guidelines for installing it on other distributions,
 +webservers and database systems.
 +
++Although this document tries to describe all aspects of setting up ownCloud,
++a basic understanding of the Linux operating system and of server administration
++is required.
++
 +Prerequisites
 +~~~~~~~~~~~~~
 +
 +.. note:: This tutorial assumes you have terminal access to the machine you want
 +          to install owncloud on. Although this is not an absolute requirement,
 +          installation without it is highly likely to require contacting your
 +          hoster (e.g. for installing required modules).
 +
 +To run ownCloud, your web server must have the following installed:
 +
 +* PHP (>= 5.3.3 minimum, 5.4 or higher recommended)
 +* PHP module ctype
 +* PHP module dom
 +* PHP module GD
 +* PHP module iconv
 +* PHP module JSON
 +* PHP module libxml
 +* PHP module mb multibyte
 +* PHP module SimpleXML
 +* PHP module zip
 +* PHP module zlib
 +
 +Database connectors (pick at least one):
 +
- * PHP module sqlite (>= 3, usually not recommendable for performance reasons)
++* PHP module sqlite (requires sqlite >= 3.0; simple configuration, but inferior performance)
 +* PHP module mysql
 +* PHP module pgsql (requires PostgreSQL >= 9.0)
 +
 +*Recommended* packages:
 +
 +* PHP module curl (highly recommended, some functionality, e.g. http user
 +  authentication, depends on this)
 +* PHP module fileinfo (highly recommended, enhances file analysis performance)
 +* PHP module bz2 (recommended, required for extraction of apps)
 +* PHP module intl (increases language translation performance)
 +* PHP module mcrypt (increases file encryption performance)
 +* PHP module openssl (required for accessing HTTPS resources)
 +
 +Required for specific apps (if you use the mentioned app, you must install that
 +package):
 +
 +* PHP module ldap (for ldap integration)
 +* smbclient (for SMB storage)
 +* PHP module ftp (for FTP storage)
 +
 +Recommended for specific apps (*optional*):
 +
 +* PHP module exif (for image rotation in pictures app)
 +
 +For enhanced performance (*optional* / select only one of the following):
 +
 +* PHP module apc
 +* PHP module apcu
 +* PHP module xcache
 +
 +For preview generation (*optional*):
 +
 +* PHP module imagick
 +* avconv or ffmpeg
 +* OpenOffice or libreOffice
 +
 +**Remarks:**
 +
 +* Please check your distribution, operating system or hosting partner documentation
 +  on how to install/enable these modules.
 +
 +* Make sure your distribution's php version fulfils the version requirements
-   specified above. If it doesn't, there might be custom repositories you can use.
-   If you are e.g. running Ubuntu 10.04 LTS, you can update your
-   PHP using a custom `PHP PPA`_:
-   ::
++  specified above. If it doesn't, there might be custom repositories you can
++  use. If you are e.g. running Ubuntu 10.04 LTS, you can update your PHP using
++  a custom `PHP PPA`_: ::
 +
 +	sudo add-apt-repository ppa:ondrej/php5
 +	sudo apt-get update
 +	sudo apt-get install php5
 +
 +* You don’t need any WebDAV support module for your web server (i.e. Apache’s
 +  mod_webdav) to access your ownCloud data via WebDAV. ownCloud has a built-in
 +  WebDAV server of its own.
 +  
- Example installation on Ubuntu 12.04.4 LTS Server
- *************************************************
++Installation of packages on Ubuntu 12.04.4 LTS Server
++*****************************************************
++
 +On a machine running a pristine Ubuntu 12.04.4 LTS server, you would install the
 +required and recommended modules for a typical ownCloud installation, using
- Apache and MySQL by issuing the following commands in a terminal:
- ::
++Apache and MySQL by issuing the following commands in a terminal::
 +
 +	sudo apt-get install apache2 mysql-server libapache2-mod-php5
 +	sudo apt-get install php5-gd php5-json php5-mysql php5-curl
 +	sudo apt-get install php5-intl php5-mcrypt php5-imagick
 +
 +**Remarks:**
 +
- * If you want to use any other combination of distribution, webserver or database,
-   please consult the respective documentation.
++* This installs the packages for the ownCloud core system. If you are planning on
++  running additional apps, keep in mind that they might require additional packages.
++  See the list above for details.
 +
 +* At the execution of each of the above commands you might be prompted whether you
 +  want to continue; press "Y" for Yes (that is if your system language is English.
 +  You might have to press a different key if you have a different system language).
 +
 +* At the installation of the MySQL server, you will be prompted for a root password.
-   Be sure to remember that password for later use.
- 
- * This installs the packages for the ownCloud core system. If you are planning on
-   running additional apps, keep in mind that they might require additional packages.
-   See the list above for details.
++  Be sure to remember the password you enter there for later use (you will need it
++  during ownCloud database setup).
 +
 +Download, extract and copy ownCloud to Your Web Server
 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 +
 +First, download the archive of the latest ownCloud version:
 +
- * Navigate to `http://owncloud.org/install`
++* Navigate to the `ownCloud Installation Page`_
 +* Click "Tar or Zip file"
 +* In the opening dialog, chose the "Linux" link.
 +* This will start the download of a file named owncloud-x.y.z.tar.bz2 (where
 +  x.y.z is the version number of the current latest version).
 +* Save this file on the machine you want to install ownCloud on.
- * If that's a different machine than the one you are currently working on, use
++  If that's a different machine than the one you are currently working on, use
 +  e.g. FTP to transfer the downloaded archive file there.
- * Note down the directory where you put the file.
- * Extract the archive contents. Open a terminal on the machine
-   you plan to run ownCloud on, and run:
-   ::
++* Extract the archive contents. Open a terminal and run::
 +
 +	cd path/to/downloaded/archive
 +	tar -xjf owncloud-x.y.z.tar.bz2
 +
-   where :code:`path/to/downloaded/archive` is to be replaced by the path where you
++  where ``path/to/downloaded/archive`` is to be replaced by the path where you
 +  put the downloaded archive, and x.y.z of course has to be replaced by the actual
 +  version number as in the file you have downloaded.
 +  
 +* Copy the ownCloud files to their final destination in the document root of your
 +  webserver (you can skip this step if you already downloaded and extracted the
-   files there):
-   ::
++  files there)::
 +
- 	sudo cp -r owncloud /path/to/your/webserver/document-root
++	sudo cp -r owncloud /path/to/your/webservers/document-root
 +
++  where ``/path/to/your/webservers/document-root``, needs to be replaced by the
++  actual path where the document root of your webserver is configured to be.
 +
-   * If you don't know where your webserver's document root is located, consult its
-     documentation. For Apache on Ubuntu 12.04 LTS for example, this would usually be
-     :code:`/var/www`. So above command should look like this:
-     ::
++  * If you don't know where your webserver's document root is located, consult
++    its documentation. For Apache on Ubuntu 12.04 LTS for example, this would
++    usually be ``/var/www``. So the concrete command to run would be::
 +
 +	sudo cp -r owncloud /var/www
 +
 +  * The above assumes you want to install ownCloud into a subdirectory "owncloud"
 +    on your webserver. For installing it anywhere else, you'll have to adapt the
-     above command accordingly.
++    above command (and also the commands in the following section) accordingly.
 +
 +Set the Directory Permissions
 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 +
- The user running your web server must own at least the apps/, data/ and config/
- directories in your ownCloud installation folder.
- The following command will change the ownership of the whole folder to that user.
++The user running your web server must own at least the config/, data/ and apps/ 
++directories in your ownCloud installation folder so that you can configure ownCloud,
++create/modify and delete your data files through ownCloud and install apps through
++the web interface. If you are planning on also using the automatic updater app for
++updating, the whole ``owncloud`` folder must be owned by (or at least be writable to)
++the user running php on your system.
 +
- * For Debian-based distributions (like Ubuntu, Debian or Linux Mint) and Gentoo, run:
-   ::
++.. note:: When using an NFS mount for the data directory, do not change ownership as above.
++          The simple act of mounting the drive will set proper permissions for ownCloud to
++          write to the directory. Changing ownership as above could result in some issues
++          if the NFS mount is lost.
 +
- 	sudo chown -R www-data:www-data /path/to/your/owncloud
-   
- * Continuing the example from above, for Ubuntu 12.04 LTS, where the install location
-   was :code:`/var/www`, you would run:
-   ::
++The following command will change the ownership of the whole ownCloud folder to
++that user.
 +
- 	sudo chown -R www-data:www-data /var/www/owncloud
++* The generic command to run is::
 +
- * For ArchLinux should run (as root):
-   ::
++	sudo chown -R <php-user>:<php-user> /path/to/your/webservers/document-root/owncloud
 +
- 	chown -R http:http /path/to/your/owncloud
++  where ``<php-user>`` is to be replaced by the user running php scripts, and
++  ``/path/to/your/webservers/document-root/owncloud`` by the folder where the
++  extracted ownCloud files are located.
 +
- * Fedora users should run (as root):
-   ::
++* For Ubuntu 12.04 LTS server, where the ``owncloud`` folder was copied into the
++  Apache document root at ``/var/www``, and the user running Apache and php
++  scripts is called ``www-data``, this would mean you need to run::
 +
- 	chown -R apache:apache /path/to/your/owncloud
++	sudo chown -R www-data:www-data /var/www/owncloud
 +
- When using an NFS mount for the data directory, do not change ownership as above.
- The simple act of mounting the drive will set proper permissions for ownCloud to
- write to the directory. Changing ownership as above could result in some issues
- if the NFS mount is lost.
++* For all Debian-based distributions (like Ubuntu, Debian or Linux Mint) and Gentoo,
++  use ``www-data`` user
++* On ArchLinux, use ``http`` user.
++* On Fedora, use ``apache`` user.
++* When you had extracted ownCloud as user ``root``, you should adjust file and directory
++  permission to avoid world writeable files and folder::
++
++	find /path/to/your/webservers/document-root/owncloud -type d -exec chmod 750 {} \;
++	find /path/to/your/webservers/document-root/owncloud -type f -exec chmod 640 {} \;
++
++  Running this in combination with the above ``chown`` command will give a secure
++  set-up.
 +
 +Web Server Configuration
 +~~~~~~~~~~~~~~~~~~~~~~~~
 +
 +.. note:: You can use ownCloud over plain http, but we strongly encourage you to
 +          use SSL/TLS. If you don't use it, and you for example access your
 +          ownCloud over an unsecured WiFi, everyone in the same WiFi can grab
 +          your authentication data or the content of files synchronized while you
 +          are on the WiFi.
 +
 +Apache is the recommended web server.
 +
 +Apache Configuration
 +********************
 +
 +Enabling SSL
 +............
 +
 +An Apache installed under Ubuntu comes already set-up with a simple
 +self-signed certificate. All you have to do is to enable the ssl module and
- the according site. Open a terminal and run
- ::
++the according site. Open a terminal and run::
 +
 +	sudo a2enmod ssl
 +	sudo a2ensite default-ssl
 +	sudo service apache2 reload
 +
 +If you are using a different distribution, check their documentation on how to
 +enable SSL.
 +
 +.. note:: Self-signed certificates have their drawbacks - especially when you
 +          plan to make your ownCloud server publicly accessible. You might want
 +          to consider getting a certificate signed by an official signing
-           authority. If you're looking for a free certificate, you can consult
-           e.g. this article:
-           `https://www.sslshopper.com/article-free-ssl-certificates-from-a-free-certificate-authority.html`
++          authority. SSLShopper for example has an article on your
++          `options for free SSL certificates`_.
 +
 +Configuring ownCloud
 +....................
 +
 +Since there was a change in the way versions 2.2 and 2.4 are configured,
 +you'll have to find out which Apache version you are using.
 +
- Usually you can do this by running one of the following commands:
- ::
++Usually you can do this by running one of the following commands::
 +
 +	sudo apachectl -v
 +	apache2 -v
 +
- Example output:
- ::
++Example output::
 +
 +	Server version: Apache/2.2.22 (Ubuntu)
 +	Server built:   Jul 12 2013 13:37:10
 +
 +This indicates an Apache of the 2.2 version branch (as e.g. you will find on
 +Ubuntu 12.04 LTS).
 +
 +Example config for Apache 2.2:
 +
 +.. code-block:: xml
 +
 +    <Directory /path/to/your/owncloud/install>
 +        Options Indexes FollowSymLinks MultiViews
 +        AllowOverride All
 +        Order allow,deny
 +        allow from all
 +    </Directory>
 +
- 
 +Example config for Apache 2.4:
 +
 +.. code-block:: xml
 +
 +    <Directory /path/to/your/owncloud/install>
 +        Options Indexes FollowSymLinks MultiViews
 +        AllowOverride All
 +        Require all granted
 +    </Directory>
 +
 +* This config entry needs to go into the configuration file of the "site" you want
 +  to use.
- * On a Ubuntu system, this typically is the "default-ssl" site (to be found at
-   :code:`/etc/apache2/sites-available/default-ssl`).
++* On a Ubuntu system, this typically is the "default-ssl" site (to be found in
++  the :file:`/etc/apache2/sites-available/default-ssl`).
 +* Edit the site file with your favorite editor (note that you'll need root
 +  permissions to modify that file). For Ubuntu 12.04 LTS, you could for example run
-   the following command in a Terminal:
-   ::
++  the following command in a Terminal::
 +
 +	sudo nano /etc/apache2/sites-available/default-ssl
 +
- * Add the entry shown above immediately before the line containing
-   ::
++* Add the entry shown above immediately before the line containing::
 +
 +	</VirtualHost>
 +
 +  (this should be one of the last lines in the file).
 +
- * For ownCloud to work correctly, we need the module mod_rewrite. Enable it by running::
- 
- 	sudo a2enmod rewrite
- 
- * In distributions that do not come with a2enmod the module needs to be enabled
-   manually by editing the config Apache files, usually :file:`/etc/httpd/httpd.conf`.
-   consult the Apache documentation or your distributions documentation.
- 
- * Then restart Apache.
- 
-   * For Ubuntu systems (or distributions using upstartd), run::
- 
- 	sudo service apache2 restart
- 
-   * For systemd systems (Fedora, ArchLinux, OpenSUSE), run::
- 
- 	systemctl restart httpd.service
- 
- * In order for the maximum upload size to be configurable, the .htaccess file in the
-   ownCloud folder needs to be made writable by the server (this should already be done,
-   see section `Set the Directory Permissions`_).
- 
- * You should make sure that any built-in WebDAV module of your web server is disabled
-   (at least for the ownCloud directory), as it will interfere with ownCloud's
-   built-in WebDAV support.
- 
-   If you need the WebDAV support in the rest of your configuration, you can turn it off
-   specifically for the ownCloud entry by adding the following line in the
-   configuration of your ownCloud. In above "<Directory ..." code, add the following line
-   directly after the "allow from all" / "Require all granted" line):
-   ::
- 
- 	Dav Off
- 
- * Furthermore, you need to disable any server-configured authentication for ownCloud, as
-   it's internally using Basic authentication for its \*DAV services.
-   If you have turned on authentication on a parent folder (via e.g. an "AuthType Basic"
-   directive), you can turn off the authentication specifically for the ownCloud entry;
-   to do so, in above "<Directory ..." code, add the following line directly after the
-   "allow from all" / "Require all granted" line):
-   ::
- 
- 	Satisfy Any
- 
- A minimal site configuration on Ubuntu 12.04 might look like this:
++* A minimal site configuration file on Ubuntu 12.04 might look like this:
 +
 +.. code-block:: xml
 +
 +	<IfModule mod_ssl.c>
 +	<VirtualHost _default_:443>
 +		ServerName YourServerName
 +		ServerAdmin webmaster at localhost
 +		DocumentRoot /var/www
 +		<Directory />
 +			Options FollowSymLinks
 +			AllowOverride None
 +		</Directory>
 +		<Directory /var/www/>
 +			Options Indexes FollowSymLinks MultiViews
 +			AllowOverride None
 +			Order allow,deny
 +			allow from all
 +		</Directory>
 +		ErrorLog ${APACHE_LOG_DIR}/error.log
 +		LogLevel warn
 +		CustomLog ${APACHE_LOG_DIR}/ssl_access.log combined
 +		SSLEngine on
 +		SSLCertificateFile    /etc/ssl/certs/ssl-cert-snakeoil.pem
 +		SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key
 +		<FilesMatch "\.(cgi|shtml|phtml|php)$">
 +			SSLOptions +StdEnvVars
 +		</FilesMatch>
 +		<Directory /usr/lib/cgi-bin>
 +			SSLOptions +StdEnvVars
 +		</Directory>
 +		BrowserMatch "MSIE [2-6]" \
 +			nokeepalive ssl-unclean-shutdown \
 +			downgrade-1.0 force-response-1.0
 +		BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown
 +		<Directory /var/www/owncloud>
 +			Options Indexes FollowSymLinks MultiViews
 +			AllowOverride All
 +			Order allow,deny
 +			Allow from all
 +			# add any possibly required additional directives here
- 			# e.g. the Satisfy directive:
++			# e.g. the Satisfy directive (see below for details):
 +			Satisfy Any
 +		</Directory>
 +	</VirtualHost>
 +	</IfModule>
 +
- When using ssl, take special note on the ServerName. You should specify one in the
- server configuration, as well as in the CommonName field of the certificate. If you want
- your ownCloud to be reachable via the internet, then set both these to the domain you
- want to reach your ownCloud under.
++* For ownCloud to work correctly, we need the module mod_rewrite. Enable it by running::
++
++	sudo a2enmod rewrite
++
++* In distributions that do not come with ``a2enmod``, the module needs to be
++  enabled manually by editing the Apache config files, usually :file:`/etc/httpd/httpd.conf`.
++  consult the Apache documentation or your distributions documentation.
++
++* In order for the maximum upload size to be configurable, the
++  :file:`.htaccess` in the ownCloud folder needs to be made writable by the
++  server (this should already be done, see section `Set the Directory Permissions`_).
++
++* You should make sure that any built-in WebDAV module of your web server is disabled
++  (at least for the ownCloud directory), as it will interfere with ownCloud's
++  built-in WebDAV support.
++
++  If you need the WebDAV support in the rest of your configuration, you can turn it off
++  specifically for the ownCloud entry by adding the following line in the
++  configuration of your ownCloud. In above "<Directory ..." code, add the following line
++  directly after the ``allow from all`` / ``Require all granted`` line): ::
++
++	Dav Off
++
++* Furthermore, you need to disable any server-configured authentication for ownCloud, as
++  it's internally using Basic authentication for its \*DAV services.
++  If you have turned on authentication on a parent folder (via e.g. an ``AuthType Basic``
++  directive), you can turn off the authentication specifically for the ownCloud entry;
++  to do so, in above "<Directory ..." code, add the following line directly after the
++  ``allow from all`` / ``Require all granted`` line): ::
++
++	Satisfy Any
++
++* When using ssl, take special note on the ServerName. You should specify one in the
++  server configuration, as well as in the CommonName field of the certificate. If you want
++  your ownCloud to be reachable via the internet, then set both these to the domain you
++  want to reach your ownCloud under.
++
++.. note:: By default, the certificates' CommonName will get set to the host
++          name at the time when the ssl-cert package was installed.
++
++* Finally, restart Apache.
++
++  * For Ubuntu systems (or distributions using upstartd), run::
++
++	sudo service apache2 restart
 +
- .. note:: By default, the certificates' CommonName will get set to the host name at the time
-           when the ssl-cert package was installed.
++  * For systemd systems (Fedora, ArchLinux, OpenSUSE), run::
++
++	systemctl restart httpd.service
 +
 +Nginx Configuration
 +*******************
 +
- -  You need to insert the following code into **your nginx config file.**
- -  Adjust **server_name**, **root**, **ssl_certificate** and **ssl_certificate_key** to suit your needs.
- -  Make sure your SSL certificates are readable by the server (see `http://wiki.nginx.org/HttpSslModule`_).
++- You need to insert the following code into **your nginx config file.**
++- Adjust **server_name**, **root**, **ssl_certificate** and **ssl_certificate_key** to suit your needs.
++- Make sure your SSL certificates are readable by the server (see the
++   `Nginx HTTP SSL Module documentation`_).
 +
 +.. code-block:: python
 +
 +    upstream php-handler {
 +            server 127.0.0.1:9000; 
 +            #server unix:/var/run/php5-fpm.sock;
 +    }
 +
 +    server {
 +            listen 80;
 +            server_name cloud.example.com;
 +            return 301 https://$server_name$request_uri;  # enforce https
 +    }
 +
 +    server {
 +            listen 443 ssl;
 +            server_name cloud.example.com;
 +
 +            ssl_certificate /etc/ssl/nginx/cloud.example.com.crt;
 +            ssl_certificate_key /etc/ssl/nginx/cloud.example.com.key;
 +
 +            # Path to the root of your installation
 +            root /var/www/;
 +
 +            client_max_body_size 10G; # set max upload size
 +            fastcgi_buffers 64 4K;
 +
 +            rewrite ^/caldav(.*)$ /remote.php/caldav$1 redirect;
 +            rewrite ^/carddav(.*)$ /remote.php/carddav$1 redirect;
 +            rewrite ^/webdav(.*)$ /remote.php/webdav$1 redirect;
 +
 +            index index.php;
 +            error_page 403 /core/templates/403.php;
 +            error_page 404 /core/templates/404.php;
 +
 +            location = /robots.txt {
 +                allow all;
 +                log_not_found off;
 +                access_log off;
 +            }
 +
 +            location ~ ^/(data|config|\.ht|db_structure\.xml|README) {
 +                    deny all;
 +            }
 +
 +            location / {
 +                    # The following 2 rules are only needed with webfinger
 +                    rewrite ^/.well-known/host-meta /public.php?service=host-meta last;
 +                    rewrite ^/.well-known/host-meta.json /public.php?service=host-meta-json last;
 +
 +                    rewrite ^/.well-known/carddav /remote.php/carddav/ redirect;
 +                    rewrite ^/.well-known/caldav /remote.php/caldav/ redirect;
 +
 +                    rewrite ^(/core/doc/[^\/]+/)$ $1/index.html;
 +
 +                    try_files $uri $uri/ index.php;
 +            }
 +
 +            location ~ ^(.+?\.php)(/.*)?$ {
-                     try_files $1 = 404;
++                    try_files $1 =404;
 +
 +                    include fastcgi_params;
 +                    fastcgi_param SCRIPT_FILENAME $document_root$1;
 +                    fastcgi_param PATH_INFO $2;
 +                    fastcgi_param HTTPS on;
 +                    fastcgi_pass php-handler;
 +            }
 +
 +            # Optional: set long EXPIRES header on static assets
 +            location ~* ^.+\.(jpg|jpeg|gif|bmp|ico|png|css|js|swf)$ {
 +                    expires 30d;
 +                    # Optional: Don't log access to assets
 +                    access_log off;
 +            }
 +
 +    }
 +
 +To enable SSL support:
 +-  Remove the server block containing the redirect
 +-  Change **listen 443 ssl** to **listen 80;**
 +-  Remove **ssl_certificate** and **ssl_certificate_key**.
 +-  Remove **fastcgi_params HTTPS on;**
 +
 +.. note:: If you want to effectively increase maximum upload size you will also
 +          have to modify your **php-fpm configuration** (**usually at
 +          /etc/php5/fpm/php.ini**) and increase **upload_max_filesize** and
 +          **post_max_size** values. You’ll need to restart php5-fpm and nginx
 +	  services in order these changes to be applied.
 +
 +Lighttpd Configuration
 +**********************
 +
 +This assumes that you are familiar with installing PHP application on
 +lighttpd.
 +
- It is important to note that the **.htaccess** files used by ownCloud to protect the **data** folder are ignored by
- lighttpd, so you have to secure it by yourself, otherwise your **owncloud.db** database and user data are publicly
- readable even if directory listing is off. You need to add two snippets to your lighttpd configuration file:
++It is important to note that the :file:`.htaccess` used by ownCloud to
++protect the :file:`data` folder are ignored by lighttpd, so you have to secure
++it by yourself, otherwise your :file:`owncloud.db` database and user data are
++publicly readable even if directory listing is off. You need to add two
++snippets to your lighttpd configuration file:
 +
 +Disable access to data folder::
 +
-     $HTTP["url"] =~ "^/owncloud/data/" {
-          url.access-deny = ("")
-        }
++	$HTTP["url"] =~ "^/owncloud/data/" {
++		url.access-deny = ("")
++	}
 +
 +Disable directory listing::
 +
-     $HTTP["url"] =~ "^/owncloud($|/)" {
-          dir-listing.activate = "disable"
-        }
++	$HTTP["url"] =~ "^/owncloud($|/)" {
++		dir-listing.activate = "disable"
++	}
++       
++**Note for Lighttpd users on Debian stable (wheezy):**
++
++Recent versions of ownCloud make use of the **HTTP PATCH** feature, which was added to Lighttpd at version 1.4.32 while Debian stable only ships 1.4.31. The patch is simple, however, and easy to integrate if you're willing to build your own package.
++
++Download the patch from http://redmine.lighttpd.net/attachments/download/1370/patch.patch
++
++Make sure you have the build tools you need::
++
++    apt-get build-dep lighttpd
++    apt-get install quilt patch devscripts
++    
++Patch the package source::
++
++    apt-get source lighttpd
++    cd lighttpd-1.4.31
++    export QUILT_PATCHES=debian/patches # This tells quilt to put the patch in the right spot
++    quilt new http-patch.patch
++    quilt add src/connections.c src/keyvalue.c src/keyvalue.h # Make quilt watch the files we'll be changing
++    patch -p1 -i /patch/to/downloaded/patch.patch
++    quilt refresh
++
++Increment the package version with ``dch -i``. This will open the changelog with a new entry. You can save as-is or add info to it. The important bit is that the version is bumped so apt will not try to "upgrade" back to Debian's version.
++
++Then build with ``debuild`` and install the .debs for any Lighttpd packages you already have installed.
 +
 +Yaws Configuration
 +******************
 +
 +This should be in your **yaws_server.conf**. In the configuration file, the
 +**dir_listings = false** is important and also the redirect from **/data**
 +to somewhere else, because files will be saved in this directory and it
 +should not be accessible from the outside. A configuration file would look
 +like this
 +
 +.. code-block:: xml
 +
 +    <server owncloud.myserver.com/>
 +            port = 80
 +            listen = 0.0.0.0
 +            docroot = /var/www/owncloud/src
 +            allowed_scripts = php
 +            php_handler = <cgi, /usr/local/bin/php-cgi>
 +            errormod_404 = yaws_404_to_index_php
 +            access_log = false
 +            dir_listings = false
 +            <redirect>
 +                    /data == /
 +            </redirect>
 +    </server>
 +
- 
- The Apache **.htaccess** file that comes with ownCloud is configured to
++The Apache :file:`.htaccess` that comes with ownCloud is configured to
 +redirect requests to nonexistent pages. To emulate that behaviour, you
- need a custom error handler for yaws. See this `github gist for further instructions`_ on how to create and compile that error handler.
++need a custom error handler for yaws. See this
++`github gist for further instructions`_ on how to create and compile that error
++handler.
 +
 +Hiawatha Configuration
 +**********************
 +
- Add **WebDAVapp = yes** to the ownCloud virtual host. Users accessing
- WebDAV from MacOS will also need to add **AllowDotFiles = yes**.
++Add ``WebDAVapp = yes`` to the ownCloud virtual host. Users accessing
++WebDAV from MacOS will also need to add ``AllowDotFiles = yes``.
 +
 +Disable access to data folder::
 +
 +    UrlToolkit {
 +        ToolkitID = denyData
 +        Match ^/data DenyAccess
 +    }
 +
- 
- 
 +Microsoft Internet Information Server (IIS)
 +*******************************************
 +
 +See :doc:`installation_windows` for further instructions.
 +
++
 +Follow the Install Wizard
 +~~~~~~~~~~~~~~~~~~~~~~~~~
- Open your web browser and navigate to your ownCloud instance. If you are
- installing ownCloud on the same machine as you will access the install wizard
- from, the url will be: http://localhost/ (or http://localhost/owncloud).
++* Open your web browser
++* Navigate to your ownCloud instance.
++
++  * If you are installing ownCloud on the same machine as you are accessing the
++    install wizard from, the url will be https://localhost/owncloud
++  * If you are installing ownCloud on a different machine, you'll have to access
++    it by its hostname or IP address, e.g. https://example.com/owncloud
++  * If you are using a self-signed certificate, you will be presented with a
++    security warning about the issuer of the certificate not being trusted which
++    you can ignore.
++
++* You will be presented with the setup screen
++* Enter username and password for the administrative user account
++* Expand Advanced options to choose a data folder and the database system
++
++* If you are not using Apache as the web server, please set the data directory
++  to a location outside of the document root.
++
++* If following the Ubuntu-Apache-MySQL walk-through:
++
++  * choose MySQL as Database backend (you might not be presented with any other
++    choice if you haven't installed any other database systems).
++  * As Database host, enter ``localhost``.
++  * As Database user enter ``root``.
++  * As Database password, enter the password you entered during installation of
++    the MySQL server package.
++  * As Database name, enter an arbitrary name as you see fit
++
++    * Beware that there are restrictions as to what characters a database name
++      may or may not contain, see the
++      `MySQL Schema Object Names documentation`_ for details);
++    * Make sure to choose a name under which no database exists yet
++  * ownCloud will use the provided credentials and create its own user with
++    permissions only on its own database.
++
++* In general, you have the following choices regarding the database:
++
++  * For basic installs we recommend SQLite as it is easy to setup (ownCloud will do
++    it for you). The performance when using sqlite is however inferior to the two
++    other options.
++  * For larger installs you should use MySQL or PostgreSQL.
++  * Note that you will only be able to choose among the php database connectors
++    which are actually installed on the system (see package requirements above).
++  * Further, it is not easily possible to migrate to another database system
++    once you have set up your ownCloud to use a specific one. So make sure to
++    carefully consider which database system to use.
++  * When using MySQL or PostgreSQL you have two options  regarding the database
++    name and user account you specify:
++
++    * You can specify either an admin/root user, and the name of a database
++      which does not yet exist. This lets ownCloud create its own database; it
++      will also create a database user account with restricted rights (with the
++      same username as you specified for the administrative user, plus an
++      ``oc_`` prefix) and will use that for all subsequent database access.
++    * You can enter the name of an existing database and the username/password
++      of a user with restricted permissions
++
++      * You can create such a user yourself e.g. via phpmyadmin.
++      * This user shouldn't have permission to create a database.
++      * It should have full permissions on the (existing) database with the
++        name you specify.
++
++* Press "Finish Setup"
++* ownCloud will set up your cloud according to the given settings
++* When its finished, it will log you in as administrative user and present the
++  "Welcome to ownCloud" screen.
++
++Note
++~~~~
++When the initial ownCloud configuration is performed, ownCloud will take the URL used to access it and insert that 
++the config.php file under the ‘trusted_domains’ header.  
++
++Users will only be able to log into ownCloud when the addressed URL is as stated in the ‘trusted_domans’  header 
++in the config.php file.  
++
++In the event that a load balancer is in place, as long as it sends the correct X-Forwarded-Host header, there will
++be no issues.  
++
++It should be noted that the loopback address, 127.0.0.1, is white labeled and therefore users on the ownCloud 
++server who access ownCloud with the loopback will successfully login.
++In the event that an improper URL is used, the following error will appear:
++
++.. image:: images/untrusted-domain.png
++
++For configuration examples, refer to the config.php document.
 +
- For basic installs we recommend SQLite as it is easy to setup (ownCloud will do it for you). For larger installs you
- should use MySQL or PostgreSQL. Click on the Advanced options to show the configuration options. You may enter admin
- credentials and let ownCloud create its own database user, or enter a preconfigured user.  If you are not using Apache
- as the web server, please set the data directory to a location outside of the document root. See the advanced
- install settings.
 +
 +
 +.. _PHP PPA: https://launchpad.net/~ondrej/+archive/php5
++.. _ownCloud Installation Page: http://owncloud.org/install
++.. _options for free SSL certificates: https://www.sslshopper.com/article-free-ssl-certificates-from-a-free-certificate-authority.html
 +.. _github gist for further instructions: https://gist.github.com/2200407
- .. _`http://wiki.nginx.org/HttpSslModule`: http://wiki.nginx.org/HttpSslModule
++.. _Nginx HTTP SSL Module documentation: http://wiki.nginx.org/HttpSslModule
++.. _MySQL Schema Object Names documentation: http://dev.mysql.com/doc/refman/5.5/en/identifiers.html
diff --cc core/doc/admin/_sources/issues/index.txt
index 486f78a,0000000..c5712bc
mode 100644,000000..100644
--- a/core/doc/admin/_sources/issues/index.txt
+++ b/core/doc/admin/_sources/issues/index.txt
@@@ -1,19 -1,0 +1,19 @@@
- ===========
++======
 +Issues
- ===========
++======
 +
 +If you think you have found a bug in ownCloud, please:
 +
 +* Search for a solution
 +* Double check your configuration
 +
 +If you can't find a solution, please file an issue:
 +
 +* If the issue is with the ownCloud server, report it to the `GitHub core repository <https://github.com/owncloud/core>`_
 +* If the issue is with the ownCloud client, report it to the `GitHub mirall repository <https://github.com/owncloud/mirall>`_
 +* If the issue with with an ownCloud app, report it to where that app is developed
 +
 +  * If the app is listed `here <https://github.com/owncloud>`_ report it to the correct repository
 +  * If the app is listed `here <https://github.com/owncloud/apps>`_ report it to the apps repository
 +
 +Please note that the mailing list should not be used for bug reports, as it is hard to track them there.
diff --cc core/doc/admin/_sources/maintenance/update.txt
index b1e0f72,0000000..43095cc
mode 100644,000000..100644
--- a/core/doc/admin/_sources/maintenance/update.txt
+++ b/core/doc/admin/_sources/maintenance/update.txt
@@@ -1,53 -1,0 +1,51 @@@
 +Updating ownCloud
 +=================
 +
 +.. note:: If you have installed ownCloud from a repository, your package management should take care of it. Probably
 +   you will need to look for compatible third party applications yourself. **Always do backups anyway.**
 +
 +Update
 +------
- Updating means updating ownCloud to the latest *point release*, e.g. ownCloud 5.0.13 → 5.0.14a. This procedure uses the
++Updating means updating ownCloud to the latest *point release*, e.g. ownCloud 6.0.0a → 6.0.2. This procedure uses the
 +ownCloud updater plugin called "Updater": it's an internal application already present in your ownCloud installation.
 +
 +To update ownCloud, follow those steps:
 +
 +#. Make a backup of the ownCloud folder and the database.
 +#. Make sure that updater plugin is enabled.
 +#. Navigate to the 'Admin' page.
 +#. Click 'Update'.
 +#. Refresh the page with Ctrl+F5.
 +
 +If this procedure doesn't work (for example, ownCloud 5.0.10 doesn't show new any new version) you could try to perform
 +a full upgrade to update to the latest point release (see below).
 +
 +Upgrade
 +-------
 +Upgrade is to bring an ownCloud instance to a new *major release*, e.g.
 +ownCloud 5.0.14a → 6.0.2. Always do backups anyway.
 +
 +To upgrade ownCloud, follow those steps:
 +
 +#. Make sure that you ran the latest point release of the major ownCloud
 +   version, e.g. 5.0.14a in the 5.0 series. If not, update to that version first
 +   (see above).
 +#. Make a backup of the ownCloud folder and the database.
 +#. Download the latest version to the working directory::
 +    
 +    wget http://download.owncloud.org/community/owncloud-latest.tar.bz2
 +
 +#. Deactivate all third party applications.
 +#. Delete everything from your ownCloud installation directory, except data and
-    config. Assuming that it's your working directory, you could execute this command::
-     
-     ls | grep -v 'data\|config' | xargs rm -r
++   config.
 +
 +#. Unpack the release tarball in the ownCloud directory (or copy the
 +   files thereto). Assuming that your installation directory is called 'owncloud' and that it's inside your working
 +   directory, you could execute this command::
 +   
 +    tar xfj owncloud-latest.tar.bz2
 +
 +#. Set the permissions properly   
 +#. With the next page request the update procedures will run.
 +#. If you had 3rd party applications, check if they provide versions compatible
 +   with the new release. If so, install and enable them, update procedures will run if needed. 
diff --cc core/doc/admin/_sources/quota/index.txt
index a7501a8,0000000..95cffd5
mode 100644,000000..100644
--- a/core/doc/admin/_sources/quota/index.txt
+++ b/core/doc/admin/_sources/quota/index.txt
@@@ -1,10 -1,0 +1,113 @@@
- **ownCloud Quota Calculations**
++=================
++Quota Calculation
++=================
 +
- .. toctree::
-     :maxdepth: 2
++Introduction
++============
++
++ownCloud allows the admin to specify a storage quota for users.
++This quota is the maximum space a user is allowed to utilize for files located in their home storage.
++
++The users quota is set in the Users page within ownCloud when creating a user.
++
++|10000000000003DF000000D953A456B6_png|
++
++Each user can have a different quota (shown above in the Storage column).
++In addition, there is a default quota should a user not have a quota specified.
++
++It is important to note that when setting a quota, the administrator needs to be aware that it applies only to the actual files and not the metadata.
++This means when allocating a quota, the admin should make sure at least 10% more space is available for each user.
++
++
++.. |10000000000003DF000000D953A456B6_png| image:: images/10000000000003DF000000D953A456B6.png
++    :width: 6.5in
++    :height: 1.4228in
++
++Checking available space
++========================
++
++A user can check their available space on the Personal page.
++
++|10000000000003A800000039364066E4_png|
++
++The available space for a given user is calculated using the following formula:
++
++|10000000000002BB000000266DB6AD1A_png|
++
++Where disk_free_space is the space available on the partition where the user’s home storage is located on the server.
++
++.. |10000000000003A800000039364066E4_png| image:: images/10000000000003A800000039364066E4.png
++    :width: 6.5in
++    :height: 0.3957in
++
++
++.. |10000000000002BB000000266DB6AD1A_png| image:: images/10000000000002BB000000266DB6AD1A.png
++    :width: 6.5in
++    :height: 0.3535in
++
++Sharing
++=======
++
++Shared files or directories are counted against the owner’s quota and not the “shared-to” user’s quota.
++
++Shared Files
++------------
++
++When user A shares a file with user B, the size of the file will be counted against user A’s quota.
++This is the case even if the file is modified by user B or if user B increases the file size.
++
++Shared Directories
++------------------
++
++When user A shares a directory with User B, all files uploaded to that directory by user B will count against user A’s quota.
++Likewise, files within that directory which are modified by user B will count against user A’s quota.
++
++Resharing
++---------
++
++If user A shares a file with user B who then reshares a file to user C, the space occupied by that file is counted against user A’s quota.
++
++Public sharing with upload permission
++-------------------------------------
++
++If user A publicly shares a directory via a link and enables “public upload” permission, files uploaded to that directory from the outside are counted against user A’s quota.
++Excluded from quota
++===================
++
++The following sections describe information which is not counted in a user’s quota.
++
++Metadata and cache
++------------------
++
++Application metadata and cached information are excluded from total used space.
++Examples of such data are thumbnails (icon previews, pictures app), temporary files, and encryption keys.
++
++Deleted Files
++-------------
++
++Files which have been moved to the trash bin do not count against a user’s quota.
++Deleted items are permanently deleted, oldest to newest, should the user run out of space to make room for new files.
++
++For example, if the user has a 10GB quota, and has used 4GB of space and 5GB in the trash bin, the user will still have 6GB available space.
++If, however, the user uploads 6GB, ownCloud will permanently delete files from the trash bin in order to make room for the new files.
++
++Version Control
++---------------
++
++Older versions do not count against the user’s quota.
++The versions app will delete old versions, oldest to newest, should the user run out of space to make room for new files.
++
++For example, if the user has a 10GB quota, and has used 4GB and 5GB is used on older versions, the user will still have 6GB available space.
++If, however, the user uploads 6GB, ownCloud will discard older versions to make room for the new files.
++
++Encryption
++----------
++
++Encrypted files are slightly larger than their unencrypted equivalents.
++The unencrypted file size is used to determine the quota.
++
++External Storage
++----------------
++
++External storage, mounted by either a user or the admin, is not taken into consideration when calculating the user’s storage.
 +
-     Table_of_Contents
-     Introduction
-     Checking_available_space
-     Sharing
-     Excluded_from_quota
diff --cc core/doc/admin/_sources/sharing_api/create_a_new_share.txt
index f92a83d,0000000..7426475
mode 100644,000000..100644
--- a/core/doc/admin/_sources/sharing_api/create_a_new_share.txt
+++ b/core/doc/admin/_sources/sharing_api/create_a_new_share.txt
@@@ -1,261 -1,0 +1,250 @@@
 +Create a new Share
 +==================
 +
 +To create a new share the following may be used.
 +This allows sharing with a user or group or as a link.
 +
 ++--------------------+-----------------------------------------------+---------+---------------------------------------------------------------------+
 +| Syntax             | <Base URL>                                    |         |                                                                     |
 +|                    |                                               |         |                                                                     |
 ++--------------------+-----------------------------------------------+---------+---------------------------------------------------------------------+
 +| Method             | POST                                          |         |                                                                     |
 +|                    |                                               |         |                                                                     |
 ++--------------------+-----------------------------------------------+---------+---------------------------------------------------------------------+
 +| Mandatory Argument | path                                          | string  | Full path of the file/folder being shared                           |
 +|                    |                                               |         |                                                                     |
 ++--------------------+-----------------------------------------------+---------+---------------------------------------------------------------------+
 +| Mandatory Argument | shareType                                     | int     | ‘0’ = user, ‘1’ = group, ‘3’ = Public link                          |
 +|                    |                                               |         |                                                                     |
 ++--------------------+-----------------------------------------------+---------+---------------------------------------------------------------------+
 +| Argument           | shareWith                                     | string  | User/group ID with who the file should be shared.                   |
 +|                    |                                               |         | This is mandatory for shareType of 0 or 1                           |
 +|                    |                                               |         |                                                                     |
 ++--------------------+-----------------------------------------------+---------+---------------------------------------------------------------------+
 +| Argument           | publicUpload                                  | boolean | If ‘false’ (default) public cannot upload to a public shared folder |
 +|                    |                                               |         |                                                                     |
 +|                    |                                               |         | If ‘true’ public can upload to a shared folder                      |
 +|                    |                                               |         |                                                                     |
 +|                    |                                               |         | Only available for public link shares                               |
 +|                    |                                               |         |                                                                     |
 ++--------------------+-----------------------------------------------+---------+---------------------------------------------------------------------+
 +| Argument           | password                                      | string  | Password to protect a public link share                             |
 +|                    |                                               |         |                                                                     |
 +|                    |                                               |         | Only available for public link shares                               |
 +|                    |                                               |         |                                                                     |
 ++--------------------+-----------------------------------------------+---------+---------------------------------------------------------------------+
 +| Argument           | permissions                                   | int     | From table in section 2.2 for user or group shares                  |
 +|                    |                                               |         |                                                                     |
 ++--------------------+-----------------------------------------------+---------+---------------------------------------------------------------------+
 +| Result             | XML Code with share ID of newly created share |         |                                                                     |
 +|                    |                                               |         |                                                                     |
 ++--------------------+-----------------------------------------------+---------+---------------------------------------------------------------------+
 +
 +The following is a list of returned status codes:
 +
 ++------------------+---------------------------------+
 +| HTTP Status Code | Description                     |
 +|                  |                                 |
 ++------------------+---------------------------------+
 +| 100              | Successful                      |
 +|                  |                                 |
 ++------------------+---------------------------------+
 +| 400              | Unknown Share type              |
 +|                  |                                 |
 ++------------------+---------------------------------+
 +| 403              | Public Upload disabled by admin |
 +|                  |                                 |
 ++------------------+---------------------------------+
 +| 404              | File couldn’t be shared         |
 +|                  |                                 |
 ++------------------+---------------------------------+
 +
 +
 +Poster – Share as a link
 +------------------------
 +
 +The following example shares the file “test/Lab.txt” as a public link
 +
 ++---------------+---------------------------------------------+
 +| Field         | Value                                       |
 +|               |                                             |
 ++---------------+---------------------------------------------+
 +| **URL**       | Base URL for the API of the ownCloud server |
 +|               |                                             |
 ++---------------+---------------------------------------------+
 +| **User Auth** | User ID of the file owner                   |
 +|               |                                             |
 ++---------------+---------------------------------------------+
 +| **Password**  | User’s Password                             |
 +|               |                                             |
 ++---------------+---------------------------------------------+
 +| **Name**      | Argument being passed                       |
 +|               |                                             |
 ++---------------+---------------------------------------------+
 +| **Value**     | Full path of file/folder shared             |
 +|               |                                             |
 ++---------------+---------------------------------------------+
 +
 +
 +|1000000000000298000001874D3CA506_png|
 +
 +Navigate to the “Content to Send” tab and select “Body from Parameters”
 +
 +|1000000000000298000001870B0581FA_png|
 +
 +Select POST.
 +
 +
 +Curl – Share as link
 +--------------------
 +
- #curl http://<ip>/ocs/v1.php/apps/files_sharing/api/v1/shares -k -u user:password -X POST –data “path=<file>&shareType=3”
- 
- #curl
- `http://192.168.1.63/owncloud/ocs/v1.php/apps/files_sharing/api/v1/shares <http://192.168.1.63/owncloud/ocs/v1.php/apps/files_sharing/api/v1/shares>`_
- 
- -k -u ser72_oc6:Password01 -X POST –data “path=test/Lab.txt&shareType=3”
++$ curl \http://<ip>/ocs/v1.php/apps/files_sharing/api/v1/shares -k -u user:password -X POST –data “path=<file>&shareType=3”
 +
 +
 +Output
 +------
 +
 ++-------------------------------------------------------------------------------------------------------------+--------------------------------+
 +| <?xml version="1.0"?>                                                                                       |                                |
 +|                                                                                                             |                                |
 ++-------------------------------------------------------------------------------------------------------------+--------------------------------+
 +| <ocs>                                                                                                       |                                |
 +|                                                                                                             |                                |
 ++-------------------------------------------------------------------------------------------------------------+--------------------------------+
 +| <meta>                                                                                                      |                                |
 +|                                                                                                             |                                |
 ++-------------------------------------------------------------------------------------------------------------+--------------------------------+
 +| <status>ok</status>                                                                                         |                                |
 +|                                                                                                             |                                |
 ++-------------------------------------------------------------------------------------------------------------+--------------------------------+
 +| <statuscode>100</statuscode>                                                                                | Status = 100: successful       |
 +|                                                                                                             |                                |
 ++-------------------------------------------------------------------------------------------------------------+--------------------------------+
 +| <message/>                                                                                                  |                                |
 +|                                                                                                             |                                |
 ++-------------------------------------------------------------------------------------------------------------+--------------------------------+
 +| </meta>                                                                                                     |                                |
 +|                                                                                                             |                                |
 ++-------------------------------------------------------------------------------------------------------------+--------------------------------+
 +| <data>                                                                                                      |                                |
 +|                                                                                                             |                                |
 ++-------------------------------------------------------------------------------------------------------------+--------------------------------+
 +| <id>9</id>                                                                                                  | Share ID = 9                   |
 +|                                                                                                             |                                |
 ++-------------------------------------------------------------------------------------------------------------+--------------------------------+
 +| <url>http://192.168.1.63/owncloud6RC3/public.php?service=files&t=e1947aaeaa2b88a69cc1e90bf27ddfe2</url> | Share Link.                    |
 +|                                                                                                             | Send this to the desired users |
 +|                                                                                                             |                                |
 ++-------------------------------------------------------------------------------------------------------------+--------------------------------+
 +| <token>e1947aaeaa2b88a69cc1e90bf27ddfe2</token>                                                             |                                |
 +|                                                                                                             |                                |
 ++-------------------------------------------------------------------------------------------------------------+--------------------------------+
 +| </data>                                                                                                     |                                |
 +|                                                                                                             |                                |
 ++-------------------------------------------------------------------------------------------------------------+--------------------------------+
 +| **</ocs>**                                                                                                  |                                |
 +|                                                                                                             |                                |
 ++-------------------------------------------------------------------------------------------------------------+--------------------------------+
 +
 +
 +Poster – Share with user
 +------------------------
 +
 +The following example shares a file called “test/Lab.txt” with user “ser72”
 +
 ++---------------+---------------------------------------------+
 +| Field         | Value                                       |
 +|               |                                             |
 ++---------------+---------------------------------------------+
 +| **URL**       | Base URL for the API of the ownCloud server |
 +|               |                                             |
 ++---------------+---------------------------------------------+
 +| **User Auth** | User ID of the file owner                   |
 +|               |                                             |
 ++---------------+---------------------------------------------+
 +| **Password**  | User’s Password                             |
 +|               |                                             |
 ++---------------+---------------------------------------------+
 +| **Name**      | Argument being passed                       |
 +|               |                                             |
 ++---------------+---------------------------------------------+
 +| **Value**     | Full path of file/folder shared             |
 +|               |                                             |
 ++---------------+---------------------------------------------+
 +
 +
 +|1000000000000289000001A9D7F3941F_png|
 +
 +
 +Navigate to the “Content to Send Tab” and select “Body from Parameters”
 +
 +|10000000000002950000019EF5732E36_png|
 +
 +
 +
 +Select POST.
 +
 +Curl – Share with User
 +----------------------
 +
- #curl http://<ip>/ocs/v1.php/apps/files_sharing/api/v1/shares -k -u user:password -X POST –data “path=<file>&shareType=0&shareWith=<user>”
- 
- #curl
- `http://192.168.1.63/owncloud/ocs/v1.php/apps/files_sharing/api/v1/shares <http://192.168.1.63/owncloud/ocs/v1.php/apps/files_sharing/api/v1/shares>`_
++$ curl \http://<ip>/ocs/v1.php/apps/files_sharing/api/v1/shares -k -u user:password -X POST –data "path=<file>&shareType=0&shareWith=<user>"
 +
- -k -u ser72_oc6:Password01 -X POST –data “path=test/Lab.txt&shareType=0&shareWith=ser72”
 +
- 
- output
++Output
 +------
 +
 ++------------------------------+-------------------------+
 +| <?xml version="1.0"?>        |                         |
 +|                              |                         |
 ++------------------------------+-------------------------+
 +| <ocs>                        |                         |
 +|                              |                         |
 ++------------------------------+-------------------------+
 +| <meta>                       |                         |
 +|                              |                         |
 ++------------------------------+-------------------------+
 +| <status>ok</status>          |                         |
 +|                              |                         |
 ++------------------------------+-------------------------+
 +| <statuscode>100</statuscode> | Status: 100: Successful |
 +|                              |                         |
 ++------------------------------+-------------------------+
 +| <message/>                   |                         |
 +|                              |                         |
 ++------------------------------+-------------------------+
 +| </meta>                      |                         |
 +|                              |                         |
 ++------------------------------+-------------------------+
 +| <data>                       |                         |
 +|                              |                         |
 ++------------------------------+-------------------------+
 +| <id>10</id>                  | Share ID = 10           |
 +|                              |                         |
 ++------------------------------+-------------------------+
 +| </data>                      |                         |
 +|                              |                         |
 ++------------------------------+-------------------------+
 +| </ocs>                       |                         |
 +|                              |                         |
 ++------------------------------+-------------------------+
 +
 +
 +
 +.. |10000000000002950000019EF5732E36_png| image:: images/10000000000002950000019EF5732E36.png
 +    :width: 6.5in
 +    :height: 4.0701in
 +
 +
 +.. |1000000000000289000001A9D7F3941F_png| image:: images/1000000000000289000001A9D7F3941F.png
 +    :width: 6.5in
 +    :height: 4.2563in
 +
 +
 +.. |1000000000000298000001874D3CA506_png| image:: images/1000000000000298000001874D3CA506.png
 +    :width: 6.5in
 +    :height: 3.828in
 +
 +
 +.. |1000000000000298000001870B0581FA_png| image:: images/1000000000000298000001870B0581FA.png
 +    :width: 6.5in
 +    :height: 3.828in
- 
diff --cc core/doc/admin/_sources/sharing_api/delete_share.txt
index a5110a0,0000000..7d6d97d
mode 100644,000000..100644
--- a/core/doc/admin/_sources/sharing_api/delete_share.txt
+++ b/core/doc/admin/_sources/sharing_api/delete_share.txt
@@@ -1,89 -1,0 +1,85 @@@
 +Delete Share
 +============
 +
 +The following method should be used in the event that a file share should be removed.
 +
 +Note: the share ID can be obtained from the output of any of the previous Share API calls or the creation of a new share.
 +
 ++----------+-----------------------+
 +| Syntax   | <Base URL>/<share id> |
 +|          |                       |
 ++----------+-----------------------+
 +| Method   | DELETE                |
 +|          |                       |
 ++----------+-----------------------+
 +| Argument | Share ID (int)        |
 +|          |                       |
 ++----------+-----------------------+
 +
 +
 +The following is a list of returned status codes:
 +
 ++------------------+--------------------------+
 +| HTTP Status Code | Description              |
 +|                  |                          |
 ++------------------+--------------------------+
 +| 100              | Successful               |
 +|                  |                          |
 ++------------------+--------------------------+
 +| 404              | File couldn’t be deleted |
 +|                  |                          |
 ++------------------+--------------------------+
 +
 +Poster
 +------
 +
 +To remove the share identified by ID 10, use the following method.
 +
 +|10000000000002910000018B31D51F03_png|
 +
 +Press DELETE
 +
 +
 +Curl
 +----
 +
- #curl –X “DELETE” http://<user>:<password>@<ip>/ocs/v1.php/apps/files_sharing/api/v1/files/<share_id>
++$ curl –X "DELETE" \http://<user>:<password>@<ip>/ocs/v1.php/apps/files_sharing/api/v1/files/<share_id>
 +
- #curl –X “DELETE”
- `http://ser72_oc6:Password01@192.168.1.63/owncloud/ocs/v1.php/apps/files_sharing/api/v1/shares/10 <http://ser72_oc6:Password01@192.168.1.63/owncloud/ocs/v1.php/apps/files_sharing/api/v1/shares/10>`_
 +
- 
- output
++Output
 +------
 +
 ++------------------------------+------------------------+
 +| <?xml version="1.0"?>        |                        |
 +|                              |                        |
 ++------------------------------+------------------------+
 +| <ocs>                        |                        |
 +|                              |                        |
 ++------------------------------+------------------------+
 +| <meta>                       |                        |
 +|                              |                        |
 ++------------------------------+------------------------+
 +| <status>ok</status>          |                        |
 +|                              |                        |
 ++------------------------------+------------------------+
 +| <statuscode>100</statuscode> | Status=100: Successful |
 +|                              |                        |
 ++------------------------------+------------------------+
 +| <message/>                   |                        |
 +|                              |                        |
 ++------------------------------+------------------------+
 +| </meta>                      |                        |
 +|                              |                        |
 ++------------------------------+------------------------+
 +| <data/>                      |                        |
 +|                              |                        |
 ++------------------------------+------------------------+
 +| </ocs>                       |                        |
 +|                              |                        |
 ++------------------------------+------------------------+
 +
 +
 +
 +.. |10000000000002910000018B31D51F03_png| image:: images/10000000000002910000018B31D51F03.png
 +    :width: 6.5in
 +    :height: 3.9075in
- 
diff --cc core/doc/admin/_sources/sharing_api/get_all_shares.txt
index 2f0b45a,0000000..1b2a3ea
mode 100644,000000..100644
--- a/core/doc/admin/_sources/sharing_api/get_all_shares.txt
+++ b/core/doc/admin/_sources/sharing_api/get_all_shares.txt
@@@ -1,155 -1,0 +1,151 @@@
 +Get All Shares
 +==============
 +
 +To obtain a list of all files shared by a user, the following can be used.
 +
 ++--------+--------------------------------------+
 +| Syntax | <Base URL>                           |
 +|        |                                      |
 ++--------+--------------------------------------+
 +| Method | GET                                  |
 +|        |                                      |
 ++--------+--------------------------------------+
 +| Result | XML code with all shares by the user |
 +|        |                                      |
 ++--------+--------------------------------------+
 +
 +
 +The following is a list of returned status codes:
 +
 ++------------------+---------------------+
 +| HTTP Status Code | Description         |
 +|                  |                     |
 ++------------------+---------------------+
 +| 100              | Successful          |
 +|                  |                     |
 ++------------------+---------------------+
 +| 404              | Couldn’t get shares |
 +|                  |                     |
 ++------------------+---------------------+
 +
 +
- Poster:
- -------
++Poster
++------
 +
 ++---------------+---------------------------------------------+
 +| Field         | Value                                       |
 +|               |                                             |
 ++---------------+---------------------------------------------+
 +| **URL**       | Base URL for the API of the ownCloud server |
 +|               |                                             |
 ++---------------+---------------------------------------------+
 +| **User Auth** | User ID performing the Share                |
 +|               |                                             |
 ++---------------+---------------------------------------------+
 +| **Password**  | User’s Password                             |
 +|               |                                             |
 ++---------------+---------------------------------------------+
 +
 +
 +|10000201000002FC000001DC2DDAD2F1_png|
 +
 +
 +Select “GET”
 +
 +
 +Curl
 +----
 +
 +The user is the id of the user who shares the files.
 +The password belongs to that user as well.
 +
- #curl http://<user>:<password>@<ip>/ocs/v1.php/apps/files_sharing/api/v1/shares
- 
- #curl
- `http://ser72_oc6:Password01@192.168.1.63/owncloud/ocs/v1.php/appsi/files_sharing/api/v1/shares <http://ser72_oc6:Password01@192.168.1.63/owncloud/ocs/v1.php/appsi/files_sharing/api/v1/shares>`_
++$ curl \http://<user>:<password>@<ip>/ocs/v1.php/apps/files_sharing/api/v1/shares
 +
 +
- output
++Output
 +------
 +
 ++--------------------------------------------------------+---------------------------------------------+
 +| <?xml version="1.0"?>                                  |                                             |
 +|                                                        |                                             |
 ++--------------------------------------------------------+---------------------------------------------+
 +| <ocs>                                                  |                                             |
 +|                                                        |                                             |
 ++--------------------------------------------------------+---------------------------------------------+
 +| <meta>                                                 |                                             |
 +|                                                        |                                             |
 ++--------------------------------------------------------+---------------------------------------------+
 +| <status>ok</status>                                    |                                             |
 +|                                                        |                                             |
 ++--------------------------------------------------------+---------------------------------------------+
 +| <statuscode>100</statuscode>                           | Status = 100: Successful                    |
 +|                                                        |                                             |
 ++--------------------------------------------------------+---------------------------------------------+
 +| <message/>                                             |                                             |
 +|                                                        |                                             |
 ++--------------------------------------------------------+---------------------------------------------+
 +| </meta>                                                |                                             |
 +|                                                        |                                             |
 ++--------------------------------------------------------+---------------------------------------------+
 +| <data>                                                 |                                             |
 +|                                                        |                                             |
 ++--------------------------------------------------------+---------------------------------------------+
 +| <element>                                              |                                             |
 +|                                                        |                                             |
 ++--------------------------------------------------------+---------------------------------------------+
 +| <id>6</id>                                             | Share ID = 6                                |
 +|                                                        |                                             |
 ++--------------------------------------------------------+---------------------------------------------+
 +| <item_type>file</item_type>                            |                                             |
 +|                                                        |                                             |
 ++--------------------------------------------------------+---------------------------------------------+
 +| <item_source>138</item_source>                         |                                             |
 +|                                                        |                                             |
 ++--------------------------------------------------------+---------------------------------------------+
 +| <parent/>                                              |                                             |
 +|                                                        |                                             |
 ++--------------------------------------------------------+---------------------------------------------+
 +| <share_type>0</share_type>                             | Share Type = 0: User share                  |
 +|                                                        |                                             |
 ++--------------------------------------------------------+---------------------------------------------+
 +| <share_with>ser72</share_with>                         | File shared with user ser72                 |
 +|                                                        |                                             |
 ++--------------------------------------------------------+---------------------------------------------+
 +| <file_source>138</file_source>                         |                                             |
 +|                                                        |                                             |
 ++--------------------------------------------------------+---------------------------------------------+
 +| <path>/Lab.txt</path>                                  | File name /Lab.txt                          |
 +|                                                        |                                             |
 ++--------------------------------------------------------+---------------------------------------------+
 +| <permissions>27</permissions>                          | Permissions: Re-share, Read, Delete, Update |
 +|                                                        |                                             |
 ++--------------------------------------------------------+---------------------------------------------+
 +| <stime>1386697532</stime>                              |                                             |
 +|                                                        |                                             |
 ++--------------------------------------------------------+---------------------------------------------+
 +| <expiration/>                                          |                                             |
 +|                                                        |                                             |
 ++--------------------------------------------------------+---------------------------------------------+
 +| <token/>                                               |                                             |
 +|                                                        |                                             |
 ++--------------------------------------------------------+---------------------------------------------+
 +| <storage>4</storage>                                   |                                             |
 +|                                                        |                                             |
 ++--------------------------------------------------------+---------------------------------------------+
 +| <mail_send>0</mail_send>                               | Do not send email alerting of the share     |
 +|                                                        |                                             |
 ++--------------------------------------------------------+---------------------------------------------+
 +| <share_with_displayname>ser72</share_with_displayname> |                                             |
 +|                                                        |                                             |
 ++--------------------------------------------------------+---------------------------------------------+
 +| </element>                                             |                                             |
 +|                                                        |                                             |
 ++--------------------------------------------------------+---------------------------------------------+
 +| </data>                                                |                                             |
 +|                                                        |                                             |
 ++--------------------------------------------------------+---------------------------------------------+
 +| </ocs>                                                 |                                             |
 +|                                                        |                                             |
 ++--------------------------------------------------------+---------------------------------------------+
 +
 +.. |10000201000002FC000001DC2DDAD2F1_png| image:: images/10000201000002FC000001DC2DDAD2F1.png
- 
diff --cc core/doc/admin/_sources/sharing_api/get_information_about_a_known_share.txt
index f472268,0000000..a8f7d6f
mode 100644,000000..100644
--- a/core/doc/admin/_sources/sharing_api/get_information_about_a_known_share.txt
+++ b/core/doc/admin/_sources/sharing_api/get_information_about_a_known_share.txt
@@@ -1,160 -1,0 +1,157 @@@
 +Get Information about a known share
 +===================================
 +
 +To get information about a share when the share ID is known, use the following.
 +
 +Note: the share ID can be obtained from the output of any of the previous Share API calls or the creation of a new share.
 +
 ++-----------+---------------------------------+
 +| Syntax    | <Base URL>/<share id>           |
 +|           |                                 |
 ++-----------+---------------------------------+
 +| Method    | GET                             |
 +|           |                                 |
 ++-----------+---------------------------------+
 +| Arguments | Share id (int)                  |
 +|           |                                 |
 ++-----------+---------------------------------+
 +| Result    | XML code with share information |
 +|           |                                 |
 ++-----------+---------------------------------+
 +|           |                                 |
 ++-----------+---------------------------------+
 +
 +
 +The following is a list of returned status codes:
 +
 ++------------------+---------------------+
 +| HTTP Status Code | Description         |
 +|                  |                     |
 ++------------------+---------------------+
 +| 100              | Successful          |
 +|                  |                     |
 ++------------------+---------------------+
 +| 404              | Share doesn’t exist |
 +|                  |                     |
 ++------------------+---------------------+
 +
 +
 +Poster
 +------
 +
 +This example shows the output of share information for share ID “7”
 +
 ++---------------+--------------------------------------------------------+
 +| Field         | Value                                                  |
 +|               |                                                        |
 ++---------------+--------------------------------------------------------+
 +| **URL**       | Base URL for the API of the ownCloud server/<share id> |
 +|               |                                                        |
 ++---------------+--------------------------------------------------------+
 +| **User Auth** | User ID of the file owner                              |
 +|               |                                                        |
 ++---------------+--------------------------------------------------------+
 +| **Password**  | User’s Password                                        |
 +|               |                                                        |
 ++---------------+--------------------------------------------------------+
 +
 +
 +
 +|1000000000000288000001A1D5BE4881_png|
 +
 +
 +Curl
 +----
 +
- #curl http://<user>:<passowrd>@<ip>/ocs/v1.php/apps/files_sharing/api/v1/shares/<share_id>
++$ curl \http://<user>:<passowrd>@<ip>/ocs/v1.php/apps/files_sharing/api/v1/shares/<share_id>
 +
- #curl http://ser72_oc6:Password01@192.168.1.63/owncloud/ocs/v1.php/apps/files_sharing/api/v1/shares/7
 +
- 
- output
++Output
 +------
 +
 ++--------------------------------------------------------+------------------------+
 +| <?xml version="1.0"?>                                  |                        |
 +|                                                        |                        |
 ++--------------------------------------------------------+------------------------+
 +| <ocs>                                                  |                        |
 +|                                                        |                        |
 ++--------------------------------------------------------+------------------------+
 +| <meta>                                                 |                        |
 +|                                                        |                        |
 ++--------------------------------------------------------+------------------------+
 +| <status>ok</status>                                    | Status=100: successful |
 +|                                                        |                        |
 ++--------------------------------------------------------+------------------------+
 +| <statuscode>100</statuscode>                           |                        |
 +|                                                        |                        |
 ++--------------------------------------------------------+------------------------+
 +| <message/>                                             |                        |
 +|                                                        |                        |
 ++--------------------------------------------------------+------------------------+
 +| </meta>                                                |                        |
 +|                                                        |                        |
 ++--------------------------------------------------------+------------------------+
 +| <data>                                                 |                        |
 +|                                                        |                        |
 ++--------------------------------------------------------+------------------------+
 +| <element>                                              |                        |
 +|                                                        |                        |
 ++--------------------------------------------------------+------------------------+
 +| <id>7</id>                                             | Share ID = 7           |
 +|                                                        |                        |
 ++--------------------------------------------------------+------------------------+
 +| <item_type>file</item_type>                            |                        |
 +|                                                        |                        |
 ++--------------------------------------------------------+------------------------+
 +| <item_source>675</item_source>                         |                        |
 +|                                                        |                        |
 ++--------------------------------------------------------+------------------------+
 +| <parent/>                                              |                        |
 +|                                                        |                        |
 ++--------------------------------------------------------+------------------------+
 +| <share_type>0</share_type>                             | Share type = 0: user   |
 +|                                                        |                        |
 ++--------------------------------------------------------+------------------------+
 +| <share_with>ser72</share_with>                         | Share with user ser72  |
 +|                                                        |                        |
 ++--------------------------------------------------------+------------------------+
 +| <file_source>675</file_source>                         |                        |
 +|                                                        |                        |
 ++--------------------------------------------------------+------------------------+
 +| <path>/test share api/ieee.txt</path>                  |                        |
 +|                                                        |                        |
 ++--------------------------------------------------------+------------------------+
 +| <permissions>27</permissions>                          |                        |
 +|                                                        |                        |
 ++--------------------------------------------------------+------------------------+
 +| <stime>1386698116</stime>                              |                        |
 +|                                                        |                        |
 ++--------------------------------------------------------+------------------------+
 +| <expiration/>                                          |                        |
 +|                                                        |                        |
 ++--------------------------------------------------------+------------------------+
 +| <token/>                                               |                        |
 +|                                                        |                        |
 ++--------------------------------------------------------+------------------------+
 +| <storage>4</storage>                                   |                        |
 +|                                                        |                        |
 ++--------------------------------------------------------+------------------------+
 +| <mail_send>0</mail_send>                               |                        |
 +|                                                        |                        |
 ++--------------------------------------------------------+------------------------+
 +| <share_with_displayname>ser72</share_with_displayname> |                        |
 +|                                                        |                        |
 ++--------------------------------------------------------+------------------------+
 +| </element>                                             |                        |
 +|                                                        |                        |
 ++--------------------------------------------------------+------------------------+
 +| </data>                                                |                        |
 +|                                                        |                        |
 ++--------------------------------------------------------+------------------------+
 +| </ocs>                                                 |                        |
 +|                                                        |                        |
 ++--------------------------------------------------------+------------------------+
 +
 +.. |1000000000000288000001A1D5BE4881_png| image:: images/1000000000000288000001A1D5BE4881.png
 +    :width: 6.5in
 +    :height: 4.1819in
- 
diff --cc core/doc/admin/_sources/sharing_api/get_shares_from_a_specific_file_or_folder.txt
index a9251c3,0000000..fa35b6f
mode 100644,000000..100644
--- a/core/doc/admin/_sources/sharing_api/get_shares_from_a_specific_file_or_folder.txt
+++ b/core/doc/admin/_sources/sharing_api/get_shares_from_a_specific_file_or_folder.txt
@@@ -1,364 -1,0 +1,359 @@@
 +Get Shares from a Specific File or Folder
 +=========================================
 +
 +The following will provide a list shares for a specific file.
 +The input is the full path of the desired file.
 +The output is a list of everyone who has the file shared with them.
 +
 ++------------------------+----------------------+---------+-----------------------------------------------------------------------------+
 +| **Syntax**             | <Base URL>           |         |                                                                             |
 +|                        |                      |         |                                                                             |
 ++------------------------+----------------------+---------+-----------------------------------------------------------------------------+
 +| **Method**             | GET                  |         |                                                                             |
 +|                        |                      |         |                                                                             |
 ++------------------------+----------------------+---------+-----------------------------------------------------------------------------+
 +| **Mandatory Argument** | Path                 | string  | Path to file or folder                                                      |
 +|                        |                      |         |                                                                             |
 ++------------------------+----------------------+---------+-----------------------------------------------------------------------------+
 +| **Argument**           | Reshares             | boolean | If set to ‘false’ (default), only shares from the current user are returned |
 +|                        |                      |         |                                                                             |
 +|                        |                      |         | If set to ‘true’, all shares from the given file are returned               |
 +|                        |                      |         |                                                                             |
 ++------------------------+----------------------+---------+-----------------------------------------------------------------------------+
 +| **Argument**           | Subfiles             | boolean | If set to ‘false’ (default), lists only the folder being shared             |
 +|                        |                      |         |                                                                             |
 +|                        |                      |         | If set to ‘true’, all shared files within the folder are returned.          |
 +|                        |                      |         |                                                                             |
 ++------------------------+----------------------+---------+-----------------------------------------------------------------------------+
 +| **Result**             | XML code with shares |         |                                                                             |
 +|                        |                      |         |                                                                             |
 ++------------------------+----------------------+---------+-----------------------------------------------------------------------------+
 +
 +
 +The following is a list of returned status codes:
 +
 ++------------------+------------------------------------------------------+
 +| HTTP Status Code | Description                                          |
 +|                  |                                                      |
 ++------------------+------------------------------------------------------+
 +| 100              | Successful                                           |
 +|                  |                                                      |
 ++------------------+------------------------------------------------------+
 +| 400              | Not a directory (if the ‘subfile’ argument was used) |
 +|                  |                                                      |
 ++------------------+------------------------------------------------------+
 +| 404              | File does not exist                                  |
 +|                  |                                                      |
 ++------------------+------------------------------------------------------+
 +
 +
- Poster - Default arguments
++Poster – Default arguments
 +--------------------------
 +
 +This example shows the output of share information for “test share api/ieee.txt”
 +
 ++---------------+---------------------------------------------+
 +| Field         | Value                                       |
 +|               |                                             |
 ++---------------+---------------------------------------------+
 +| **URL**       | Base URL for the API of the ownCloud server |
 +|               |                                             |
 ++---------------+---------------------------------------------+
 +| **User Auth** | User ID of the file owner                   |
 +|               |                                             |
 ++---------------+---------------------------------------------+
 +| **Password**  | User’s Password                             |
 +|               |                                             |
 ++---------------+---------------------------------------------+
 +| **Name**      | Argument being passed                       |
 +|               |                                             |
 ++---------------+---------------------------------------------+
 +| **Value**     | Full path of file/folder shared             |
 +|               |                                             |
 ++---------------+---------------------------------------------+
 +
 +
 +Navigate to the “Parameters” tab and input the Name and value.
 +
 +|10000000000002720000013FB6EDA793_png|
 +
 +
 +
 +Navigate to the “Content to Send” tab and select “Body from Parameters” to move the required parameters to the query.
 +
 +
 +|1000000000000291000001951B69B9A6_png|
 +
 +
 +Select GET.
 +
- Curl – default configuration:
- -----------------------------
++Curl – Default configuration
++----------------------------
 +
- #curl –G –data “path=test_share_api/ieee.txt” http://<userid>:<password>@<ip>/ocs/v1.php/apps/files_sharing/api/v1/shares
++$ curl –G –data "path=test_share_api/ieee.txt" \http://<userid>:<password>@<ip>/ocs/v1.php/apps/files_sharing/api/v1/shares
 +
- #curl –G –data “path=test_share_api/ieee.txt”
- `http://ser72_oc6:Password01@192.168.1.63/owncloud/ocs/v1.php/apps/files_sharing/api/v1/shares <http://ser72_oc6:Password01@192.168.1.63/owncloud/ocs/v1.php/apps/files_sharing/api/v1/shares>`_
 +
- output
++Output
 +------
 +
 ++--------------------------------------------------------+-------------------------------+
 +| <?xml version="1.0"?>                                  |                               |
 +|                                                        |                               |
 ++--------------------------------------------------------+-------------------------------+
 +| <ocs>                                                  |                               |
 +|                                                        |                               |
 ++--------------------------------------------------------+-------------------------------+
 +| <meta>                                                 |                               |
 +|                                                        |                               |
 ++--------------------------------------------------------+-------------------------------+
 +| <status>ok</status>                                    |                               |
 +|                                                        |                               |
 ++--------------------------------------------------------+-------------------------------+
 +| <statuscode>100</statuscode>                           | Status=100: Successful        |
 +|                                                        |                               |
 ++--------------------------------------------------------+-------------------------------+
 +| <message/>                                             |                               |
 +|                                                        |                               |
 ++--------------------------------------------------------+-------------------------------+
 +| </meta>                                                |                               |
 +|                                                        |                               |
 ++--------------------------------------------------------+-------------------------------+
 +| <data>                                                 |                               |
 +|                                                        |                               |
 ++--------------------------------------------------------+-------------------------------+
 +| <element>                                              |                               |
 +|                                                        |                               |
 ++--------------------------------------------------------+-------------------------------+
 +| <id>7</id>                                             | Share ID=7                    |
 +|                                                        |                               |
 ++--------------------------------------------------------+-------------------------------+
 +| <item_type>file</item_type>                            |                               |
 +|                                                        |                               |
 ++--------------------------------------------------------+-------------------------------+
 +| <item_source>675</item_source>                         |                               |
 +|                                                        |                               |
 ++--------------------------------------------------------+-------------------------------+
 +| <parent/>                                              |                               |
 +|                                                        |                               |
 ++--------------------------------------------------------+-------------------------------+
 +| <share_type>0</share_type>                             | Share Type=0: user            |
 +|                                                        |                               |
 ++--------------------------------------------------------+-------------------------------+
 +| <share_with>ser72</share_with>                         | Share with user ser72         |
 +|                                                        |                               |
 ++--------------------------------------------------------+-------------------------------+
 +| <file_source>675</file_source>                         |                               |
 +|                                                        |                               |
 ++--------------------------------------------------------+-------------------------------+
 +| <path>/test share api/ieee.txt</path>                  | File /test share api/ieee.txt |
 +|                                                        |                               |
 ++--------------------------------------------------------+-------------------------------+
 +| <permissions>27</permissions>                          | Permissions 27                |
 +|                                                        |                               |
 ++--------------------------------------------------------+-------------------------------+
 +| <stime>1386698116</stime>                              |                               |
 +|                                                        |                               |
 ++--------------------------------------------------------+-------------------------------+
 +| <expiration/>                                          |                               |
 +|                                                        |                               |
 ++--------------------------------------------------------+-------------------------------+
 +| <token/>                                               |                               |
 +|                                                        |                               |
 ++--------------------------------------------------------+-------------------------------+
 +| <storage>4</storage>                                   |                               |
 +|                                                        |                               |
 ++--------------------------------------------------------+-------------------------------+
 +| <mail_send>0</mail_send>                               |                               |
 +|                                                        |                               |
 ++--------------------------------------------------------+-------------------------------+
 +| <share_with_displayname>ser72</share_with_displayname> |                               |
 +|                                                        |                               |
 ++--------------------------------------------------------+-------------------------------+
 +| </element>                                             |                               |
 +|                                                        |                               |
 ++--------------------------------------------------------+-------------------------------+
 +| </data>                                                |                               |
 +|                                                        |                               |
 ++--------------------------------------------------------+-------------------------------+
 +| </ocs>                                                 |                               |
 +|                                                        |                               |
 ++--------------------------------------------------------+-------------------------------+
 +
 +
- Poster - To add another argument, such as re-shares:
- ----------------------------------------------------
++Poster – To add another argument, such as re-shares
++---------------------------------------------------
 +
 +This example shows the output of share information for “test share api/ieee.txt”.
 +reshares is set to true which will show output if the file is re-shared by another user.
 +
 +
 +|1000000000000304000001B964698779_png|
 +
 +
 +Navigate to the “Content to Send” tab and select “Body from Parameters”
 +
 +|100000000000029B0000018885B5282E_png|
 +
 +
 +Select Get
 +
 +
 +
 +Curl – To add another argument, such as re-shares
 +-------------------------------------------------
 +
- #curl –G –data “path=test_share_api/ieee.tx&reshares=true” http://<userid>:<password>@<ip>/ocs/v1.php/apps/files_sharing/api/v1/shares
++$ curl –G –data "path=test_share_api/ieee.tx&reshares=true" \http://<userid>:<password>@<ip>/ocs/v1.php/apps/files_sharing/api/v1/shares
 +
- #curl –G –data “path=test_share_api/ieee.tx&reshares=true”
- `http://ser72_oc6:Password01@192.168.1.63/owncloud/ocs/v1.php/apps/files_sharing/api/v1/shares <http://ser72_oc6:Password01@192.168.1.63/owncloud/ocs/v1.php/apps/files_sharing/api/v1/shares>`_
 +
- output
++Output
 +------
 +
 ++--------------------------------------------------------+--------------------------------------+
 +| <?xml version="1.0"?>                                  |                                      |
 +|                                                        |                                      |
 ++--------------------------------------------------------+--------------------------------------+
 +| <ocs>                                                  |                                      |
 +|                                                        |                                      |
 ++--------------------------------------------------------+--------------------------------------+
 +| <meta>                                                 |                                      |
 +|                                                        |                                      |
 ++--------------------------------------------------------+--------------------------------------+
 +| <status>ok</status>                                    |                                      |
 +|                                                        |                                      |
 ++--------------------------------------------------------+--------------------------------------+
 +| <statuscode>100</statuscode>                           | Status=100: Successful               |
 +|                                                        |                                      |
 ++--------------------------------------------------------+--------------------------------------+
 +| <message/>                                             |                                      |
 +|                                                        |                                      |
 ++--------------------------------------------------------+--------------------------------------+
 +| </meta>                                                |                                      |
 +|                                                        |                                      |
 ++--------------------------------------------------------+--------------------------------------+
 +| <data>                                                 |                                      |
 +|                                                        |                                      |
 ++--------------------------------------------------------+--------------------------------------+
 +| <element>                                              |                                      |
 +|                                                        |                                      |
 ++--------------------------------------------------------+--------------------------------------+
 +| <id>7</id>                                             | Share id = 7                         |
 +|                                                        |                                      |
 ++--------------------------------------------------------+--------------------------------------+
 +| <item_type>file</item_type>                            |                                      |
 +|                                                        |                                      |
 ++--------------------------------------------------------+--------------------------------------+
 +| <item_source>675</item_source>                         |                                      |
 +|                                                        |                                      |
 ++--------------------------------------------------------+--------------------------------------+
 +| <parent/>                                              |                                      |
 +|                                                        |                                      |
 ++--------------------------------------------------------+--------------------------------------+
 +| <share_type>0</share_type>                             | Share Type=0: User                   |
 +|                                                        |                                      |
 ++--------------------------------------------------------+--------------------------------------+
 +| <share_with>ser72</share_with>                         | Share with user ser72                |
 +|                                                        |                                      |
 ++--------------------------------------------------------+--------------------------------------+
 +| <file_source>675</file_source>                         |                                      |
 +|                                                        |                                      |
 ++--------------------------------------------------------+--------------------------------------+
 +| <path>/test share api/ieee.txt</path>                  |                                      |
 +|                                                        |                                      |
 ++--------------------------------------------------------+--------------------------------------+
 +| <permissions>27</permissions>                          | Permissions 27                       |
 +|                                                        |                                      |
 ++--------------------------------------------------------+--------------------------------------+
 +| <stime>1386698116</stime>                              |                                      |
 +|                                                        |                                      |
 ++--------------------------------------------------------+--------------------------------------+
 +| <expiration/>                                          |                                      |
 +|                                                        |                                      |
 ++--------------------------------------------------------+--------------------------------------+
 +| <token/>                                               |                                      |
 +|                                                        |                                      |
 ++--------------------------------------------------------+--------------------------------------+
 +| <storage>4</storage>                                   |                                      |
 +|                                                        |                                      |
 ++--------------------------------------------------------+--------------------------------------+
 +| <mail_send>0</mail_send>                               |                                      |
 +|                                                        |                                      |
 ++--------------------------------------------------------+--------------------------------------+
 +| <share_with_displayname>ser72</share_with_displayname> |                                      |
 +|                                                        |                                      |
 ++--------------------------------------------------------+--------------------------------------+
 +| </element>                                             |                                      |
 +|                                                        |                                      |
 ++--------------------------------------------------------+--------------------------------------+
 +| <element>                                              |                                      |
 +|                                                        |                                      |
 ++--------------------------------------------------------+--------------------------------------+
 +| <id>8</id>                                             | Share id 8                           |
 +|                                                        |                                      |
 ++--------------------------------------------------------+--------------------------------------+
 +| <item_type>file</item_type>                            |                                      |
 +|                                                        |                                      |
 ++--------------------------------------------------------+--------------------------------------+
 +| <parent>7</parent>                                     |                                      |
 +|                                                        |                                      |
 ++--------------------------------------------------------+--------------------------------------+
 +| <share_type>0</share_type>                             | Parent share id = 7                  |
 +|                                                        |                                      |
 ++--------------------------------------------------------+--------------------------------------+
 +| <share_with>ser73</share_with>                         | Share with ser73                     |
 +|                                                        |                                      |
 ++--------------------------------------------------------+--------------------------------------+
 +| <file_source>675</file_source>                         |                                      |
 +|                                                        |                                      |
 ++--------------------------------------------------------+--------------------------------------+
 +| <path>/test share api/ieee.txt</path>                  | Share file /test share api/ieee.txt  |
 +|                                                        |                                      |
 ++--------------------------------------------------------+--------------------------------------+
 +| <permissions>19</permissions>                          | Permissions 19 – read, update, share |
 +|                                                        |                                      |
 ++--------------------------------------------------------+--------------------------------------+
 +| <stime>1386698465</stime>                              |                                      |
 +|                                                        |                                      |
 ++--------------------------------------------------------+--------------------------------------+
 +| <expiration/>                                          |                                      |
 +|                                                        |                                      |
 ++--------------------------------------------------------+--------------------------------------+
 +| <token/>                                               |                                      |
 +|                                                        |                                      |
 ++--------------------------------------------------------+--------------------------------------+
 +| <storage>4</storage>                                   |                                      |
 +|                                                        |                                      |
 ++--------------------------------------------------------+--------------------------------------+
 +| <mail_send>0</mail_send>                               |                                      |
 +|                                                        |                                      |
 ++--------------------------------------------------------+--------------------------------------+
 +| <share_with_displayname>ser73</share_with_displayname> |                                      |
 +|                                                        |                                      |
 ++--------------------------------------------------------+--------------------------------------+
 +| </element>                                             |                                      |
 +|                                                        |                                      |
 ++--------------------------------------------------------+--------------------------------------+
 +| </data>                                                |                                      |
 +|                                                        |                                      |
 ++--------------------------------------------------------+--------------------------------------+
 +| </ocs>                                                 |                                      |
 +|                                                        |                                      |
 ++--------------------------------------------------------+--------------------------------------+
 +
 +.. |10000000000002720000013FB6EDA793_png| image:: images/10000000000002720000013FB6EDA793.png
 +    :width: 6.5in
 +    :height: 3.3126in
 +
 +
 +.. |1000000000000304000001B964698779_png| image:: images/1000000000000304000001B964698779.png
 +    :width: 6.5in
 +    :height: 3.7134in
 +
 +
 +.. |100000000000029B0000018885B5282E_png| image:: images/100000000000029B0000018885B5282E.png
 +    :width: 6.5in
 +    :height: 3.8201in
 +
 +
 +.. |1000000000000291000001951B69B9A6_png| image:: images/1000000000000291000001951B69B9A6.png
 +    :width: 6.5in
 +    :height: 4.0071in
- 
diff --cc core/doc/admin/_sources/sharing_api/index.txt
index 9e01679,0000000..c9870e6
mode 100644,000000..100644
--- a/core/doc/admin/_sources/sharing_api/index.txt
+++ b/core/doc/admin/_sources/sharing_api/index.txt
@@@ -1,13 -1,0 +1,62 @@@
- **ownCloud Sharing API**
- 
++===========
++Sharing API
++===========
 +
 +.. toctree::
 +    :maxdepth: 2
++    :hidden:
++
++    get_all_shares
++    get_shares_from_a_specific_file_or_folder
++    get_information_about_a_known_share
++    create_a_new_share
++    delete_share
++
++Introduction
++============
++
++This document will describe how to use the ownCloud Sharing API.
++The sharing API allows for the creation of new shares, obtaining a list of shares, and deleting shares.
++In addition, information such a lists of files shared to users can be obtained.
++
++In order to utilize this API, all user ID’s involved in the share, as well as full path names of files is required to be known.
++
++Two methods will be shown:
++Firefox Plugin “Poster” and Curl via the command line.
++
++The base URL for all calls to the share API is:
++owncloud_base_url>/ocs/v1.php/apps/files_sharing/api/v1/shares
++
++Permissions
++-----------
++
++The following table describes the Permissions of a share.
++The Permissions are contained in the XML code output of the command.
++
+++--------+------------------------------------------+
++| Value  | Permissions                              |
++|        |                                          |
+++--------+------------------------------------------+
++| **1**  | Read only – Default for “public” shares  |
++|        |                                          |
+++--------+------------------------------------------+
++| **2**  | Update                                   |
++|        |                                          |
+++--------+------------------------------------------+
++| **4**  | Create                                   |
++|        |                                          |
+++--------+------------------------------------------+
++| **8**  | Delete                                   |
++|        |                                          |
+++--------+------------------------------------------+
++| **16** | Re-share                                 |
++|        |                                          |
+++--------+------------------------------------------+
++| **31** | All above – Default for “private” shares |
++|        |                                          |
+++--------+------------------------------------------+
++
++
++To obtain combinations, add the desired values together.
++For instance, for “Re-Share”, “delete”, “read”, “update”, add 16+8+2+1 = 27.
 +
-     Contents
-     Introduction
-     Get_All_Shares
-     Get_Shares_from_a_Specific_File_or_Folder
-     Get_Information_about_a_known_share
-     Create_a_new_Share
-     Delete_Share
diff --cc core/doc/admin/apps/activity/index.html
index b049953,0000000..9aaa67f
mode 100644,000000..100644
--- a/core/doc/admin/apps/activity/index.html
+++ b/core/doc/admin/apps/activity/index.html
@@@ -1,154 -1,0 +1,245 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
-     <title><no title> — ownCloud Administrators Manual 6.0 documentation</title>
++    <title>Activity — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../../index.html" />
++    <link rel="up" title="Apps" href="../index.html" />
++    <link rel="next" title="Finding Deployment Dependencies" href="../admin_dependencies_chk/index.html" />
++    <link rel="prev" title="Apps" href="../index.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
- <ul>
++<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../../installation/index.html">Installation</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../../configuration/index.html">Configuration</a></li>
++<li class="toctree-l1 current"><a class="reference internal" href="../index.html">Apps</a><ul class="current">
++<li class="toctree-l2 current"><a class="current reference internal" href="">Activity</a><ul>
++<li class="toctree-l3"><a class="reference internal" href="#configuration">Configuration</a></li>
++<li class="toctree-l3"><a class="reference internal" href="#utilization">Utilization</a></li>
++<li class="toctree-l3"><a class="reference internal" href="#rss-feed">RSS Feed</a></li>
++</ul>
++</li>
++<li class="toctree-l2"><a class="reference internal" href="../admin_dependencies_chk/index.html">Finding Deployment Dependencies</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../files_antivirus/index.html">File Antivirus Engine</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../files_encryption/index.html">Encryption</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../files_external/index.html">External storage support</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../files_sharing/index.html">Sharing</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../files_trashbin/index.html">Deleted Files</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../files_versions/index.html">Versions</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../firstrunwizard/index.html">First Run Wizard</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../user_ldap/index.html">LDAP user and group backend</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../viewers/index.html">File Viewers</a></li>
++</ul>
++</li>
 +<li class="toctree-l1"><a class="reference internal" href="../../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../../config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
-   <p><strong>ownCloud Activity</strong></p>
- <div class="toctree-wrapper compound">
- <ul>
- <li class="toctree-l1"><a class="reference internal" href="Table_of_Contents.html">Table of Contents</a></li>
- <li class="toctree-l1"><a class="reference internal" href="Introduction.html">Introduction</a></li>
- <li class="toctree-l1"><a class="reference internal" href="Configuration.html">Configuration</a></li>
- <li class="toctree-l1"><a class="reference internal" href="Utilization.html">Utilization</a><ul>
- <li class="toctree-l2"><a class="reference internal" href="Utilization.html#sample-activities">Sample Activities</a></li>
- </ul>
- </li>
- <li class="toctree-l1"><a class="reference internal" href="RSS_Feed.html">RSS Feed</a></li>
++  <div class="section" id="activity">
++<h1>Activity<a class="headerlink" href="#activity" title="Permalink to this headline">¶</a></h1>
++<p>The ownCloud Activity app shows an activity feed where users can see what they did in the past and what happened to
++their files and what others did with their shared files.</p>
++<p>The Activity Stream introduces a central interface where all events that happen in a user’s ownCloud instance are shown.</p>
++<p>The following can be seen in the new interface:</p>
++<ul class="simple">
++<li>Creation, edit or deletion of files along with a thumbnail and date and path</li>
++<li>If someone shared a file with you</li>
++<li>If someone created, edited or deleted something in a folder you shared to them.</li>
 +</ul>
++<p>All the events are presented with endless scrolling and also in an RSS feed which a user can subscribe to.</p>
++<div class="section" id="configuration">
++<h2>Configuration<a class="headerlink" href="#configuration" title="Permalink to this headline">¶</a></h2>
++<p>The Activity App is enabled by default.  To verify or to disable, navigate to the APPS page and search for <tt class="docutils literal"><span class="pre">Activity</span></tt>.</p>
++<img alt="../../_images/10000000000002F3000000926CA65D02.png" src="../../_images/10000000000002F3000000926CA65D02.png" style="width: 6.5in; height: 1.2571in;" />
++</div>
++<div class="section" id="utilization">
++<h2>Utilization<a class="headerlink" href="#utilization" title="Permalink to this headline">¶</a></h2>
++<p>The Activities can be viewed by selecting
++Activity
++in the App bar on the left side of the ownCloud browser interface</p>
++<p><img alt="1000000000000050000000DB83B8FA5B_png" src="../../_images/1000000000000050000000DB83B8FA5B.png" style="width: 0.8335in; height: 2.2811in;" /></p>
++<p>This will bring up the Activity interface showing all the activities which occurred for this user’s instance.</p>
++<div class="section" id="sample-activities">
++<h3>Sample Activities<a class="headerlink" href="#sample-activities" title="Permalink to this headline">¶</a></h3>
++<p>This section will show how the different activities may appear within this interface</p>
++<div class="section" id="create-file">
++<h4>Create file<a class="headerlink" href="#create-file" title="Permalink to this headline">¶</a></h4>
++<p>The following shows a file entitled
++DeleteMe.txt
++being created 3 days ago.</p>
++<p><img alt="10000000000000F300000068AF0ECD53_png" src="../../_images/10000000000000F300000068AF0ECD53.png" style="width: 2.5311in; height: 1.0835in;" /></p>
++</div>
++<div class="section" id="delete-file">
++<h4>Delete File<a class="headerlink" href="#delete-file" title="Permalink to this headline">¶</a></h4>
++<p>The following shows a file entitled <tt class="docutils literal"><span class="pre">DeleteMe.txt</span></tt> being deleted 3 days ago.</p>
++<p><img alt="10000000000000F5000000675DC5F68C_png" src="../../_images/10000000000000F5000000675DC5F68C.png" style="width: 2.552in; height: 1.0728in;" /></p>
++</div>
++<div class="section" id="edit-a-file">
++<h4>Edit a file<a class="headerlink" href="#edit-a-file" title="Permalink to this headline">¶</a></h4>
++<p>The following shows a file <tt class="docutils literal"><span class="pre">Shared/test.txt</span></tt> being edited mere seconds ago.</p>
++<p><img alt="10000000000000F1000000F6704F46D3_png" src="../../_images/10000000000000F1000000F6704F46D3.png" style="width: 2.5102in; height: 2.5626in;" /></p>
++</div>
++<div class="section" id="share-a-file-with-a-user">
++<h4>Share a file with a user<a class="headerlink" href="#share-a-file-with-a-user" title="Permalink to this headline">¶</a></h4>
++<p>The following shows the file <tt class="docutils literal"><span class="pre">shareMe</span></tt> being shared with another user.</p>
++<p><img alt="10000000000000F1000000F56125BDBA_png" src="../../_images/10000000000000F1000000F56125BDBA.png" style="width: 2.5102in; height: 2.552in;" /></p>
++</div>
++<div class="section" id="file-shared-to-user">
++<h4>File shared to user<a class="headerlink" href="#file-shared-to-user" title="Permalink to this headline">¶</a></h4>
++<p>The following shows the file <tt class="docutils literal"><span class="pre">Shared/test.txt</span></tt> being shared with this user almost an hour ago.</p>
++<p><img alt="10000000000000F60000006754ED2A1E_png" src="../../_images/10000000000000F60000006754ED2A1E.png" style="width: 2.5626in; height: 1.0728in;" /></p>
++</div>
++<div class="section" id="file-created-by-another-user-in-shared-folder">
++<h4>File created by another user in Shared folder<a class="headerlink" href="#file-created-by-another-user-in-shared-folder" title="Permalink to this headline">¶</a></h4>
++<p>The following is shown when another user creates a file in your shared folder.</p>
++<p><img alt="10000000000000F500000067A8845EF8_png" src="../../_images/10000000000000F500000067A8845EF8.png" style="width: 2.552in; height: 1.0728in;" /></p>
++</div>
++<div class="section" id="shared-file-modified">
++<h4>Shared file modified<a class="headerlink" href="#shared-file-modified" title="Permalink to this headline">¶</a></h4>
++<p>The following shows a file <tt class="docutils literal"><span class="pre">BoB/test.txt</span></tt> modified by a user who this file was shared to.</p>
++<p><img alt="10000000000000F6000000685DFB3767_png" src="../../_images/10000000000000F6000000685DFB3767.png" style="width: 2.5626in; height: 1.0835in;" /></p>
++</div>
++<div class="section" id="combined-activities">
++<h4>Combined activities<a class="headerlink" href="#combined-activities" title="Permalink to this headline">¶</a></h4>
++<p>The following shows what “combined” activities may look like on the activity interface.</p>
++<p><img alt="10000000000000F40000019A110DD159_png" src="../../_images/10000000000000F40000019A110DD159.png" style="width: 2.5417in; height: 4.2701in;" /></p>
++</div>
++</div>
++</div>
++<div class="section" id="rss-feed">
++<h2>RSS Feed<a class="headerlink" href="#rss-feed" title="Permalink to this headline">¶</a></h2>
++<p>To subscribe to the RSS Feed, navigate to the <tt class="docutils literal"><span class="pre">Activity</span></tt> page and select <tt class="docutils literal"><span class="pre">RSS</span> <span class="pre">feed</span></tt> in the upper right of the
++browser.</p>
++<p><img alt="10000000000001440000005A2989832F_png" src="../../_images/10000000000001440000005A2989832F.png" style="width: 3.3752in; height: 0.9374in;" /></p>
++<p>The resulting page will look something like this:</p>
++<p><img alt="10000000000002B1000002258C08D304_png" src="../../_images/10000000000002B1000002258C08D304.png" style="width: 6.5in; height: 5.1791in;" /></p>
++<p>To subscribe, select the <tt class="docutils literal"><span class="pre">Subscribe</span> <span class="pre">Now</span></tt> button.  The RSS Feed may be viewed via the browser’s capabilities.</p>
++</div>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/apps/admin_dependencies_chk/index.html
index 0a8b50a,0000000..1f36e9e
mode 100644,000000..100644
--- a/core/doc/admin/apps/admin_dependencies_chk/index.html
+++ b/core/doc/admin/apps/admin_dependencies_chk/index.html
@@@ -1,150 -1,0 +1,184 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
-     <title><no title> — ownCloud Administrators Manual 6.0 documentation</title>
++    <title>Finding Deployment Dependencies — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../../index.html" />
++    <link rel="up" title="Apps" href="../index.html" />
++    <link rel="next" title="File Antivirus Engine" href="../files_antivirus/index.html" />
++    <link rel="prev" title="Activity" href="../activity/index.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
- <ul>
++<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../../installation/index.html">Installation</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../../configuration/index.html">Configuration</a></li>
++<li class="toctree-l1 current"><a class="reference internal" href="../index.html">Apps</a><ul class="current">
++<li class="toctree-l2"><a class="reference internal" href="../activity/index.html">Activity</a></li>
++<li class="toctree-l2 current"><a class="current reference internal" href="">Finding Deployment Dependencies</a><ul>
++<li class="toctree-l3"><a class="reference internal" href="#configuration">Configuration</a></li>
++<li class="toctree-l3"><a class="reference internal" href="#utilization">Utilization</a></li>
++</ul>
++</li>
++<li class="toctree-l2"><a class="reference internal" href="../files_antivirus/index.html">File Antivirus Engine</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../files_encryption/index.html">Encryption</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../files_external/index.html">External storage support</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../files_sharing/index.html">Sharing</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../files_trashbin/index.html">Deleted Files</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../files_versions/index.html">Versions</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../firstrunwizard/index.html">First Run Wizard</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../user_ldap/index.html">LDAP user and group backend</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../viewers/index.html">File Viewers</a></li>
++</ul>
++</li>
 +<li class="toctree-l1"><a class="reference internal" href="../../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../../config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
-   <p><strong>ownCloud Dependencies</strong></p>
- <div class="toctree-wrapper compound">
- <ul>
- <li class="toctree-l1"><a class="reference internal" href="Table_of_Contents.html">Table of Contents</a></li>
- <li class="toctree-l1"><a class="reference internal" href="Introduction.html">Introduction</a></li>
- <li class="toctree-l1"><a class="reference internal" href="Configuration.html">Configuration</a></li>
- <li class="toctree-l1"><a class="reference internal" href="Utilization.html">Utilization</a></li>
- </ul>
++  <div class="section" id="finding-deployment-dependencies">
++<h1>Finding Deployment Dependencies<a class="headerlink" href="#finding-deployment-dependencies" title="Permalink to this headline">¶</a></h1>
++<p>The ownCloud Dependencies App provides a list of modules required to run the current setup of ownCloud.
++All of the modules listed should be installed on the base operating system prior to using ownCloud.</p>
++<div class="section" id="configuration">
++<h2>Configuration<a class="headerlink" href="#configuration" title="Permalink to this headline">¶</a></h2>
++<p>By default, the ownCloud Dependencies App is disabled.
++To enable, navigate to the Apps page and select “ownCloud dependencies info” and enable.</p>
++<img alt="../../_images/10000000000001C9000000AF9C1CE57F.png" src="../../_images/10000000000001C9000000AF9C1CE57F.png" style="width: 4.7602in; height: 1.8228in;" />
++</div>
++<div class="section" id="utilization">
++<h2>Utilization<a class="headerlink" href="#utilization" title="Permalink to this headline">¶</a></h2>
++<p>Once this app is enabled, navigate to the Admin page and scroll to “Dependencies status”.
++This section will show a list of all modules required to execute this ownCloud
++setup as well as what part of ownCloud uses the given module.</p>
++<img alt="../../_images/100000000000013C0000017D4FC6CEF5.png" src="../../_images/100000000000013C0000017D4FC6CEF5.png" style="width: 3.2917in; height: 3.9689in;" />
++<p>Modules in green are required and have been installed.  Modules in red are
++required yet have not been installed.  It is recommended to install these
++modules prior to using ownCloud.</p>
++</div>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/apps/files_antivirus/index.html
index 353f65b,0000000..e20a037
mode 100644,000000..100644
--- a/core/doc/admin/apps/files_antivirus/index.html
+++ b/core/doc/admin/apps/files_antivirus/index.html
@@@ -1,157 -1,0 +1,253 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
-     <title><no title> — ownCloud Administrators Manual 6.0 documentation</title>
++    <title>File Antivirus Engine — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../../index.html" />
++    <link rel="up" title="Apps" href="../index.html" />
++    <link rel="next" title="Encryption" href="../files_encryption/index.html" />
++    <link rel="prev" title="Finding Deployment Dependencies" href="../admin_dependencies_chk/index.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
- <ul>
++<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../../installation/index.html">Installation</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../../configuration/index.html">Configuration</a></li>
++<li class="toctree-l1 current"><a class="reference internal" href="../index.html">Apps</a><ul class="current">
++<li class="toctree-l2"><a class="reference internal" href="../activity/index.html">Activity</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../admin_dependencies_chk/index.html">Finding Deployment Dependencies</a></li>
++<li class="toctree-l2 current"><a class="current reference internal" href="">File Antivirus Engine</a><ul>
++<li class="toctree-l3"><a class="reference internal" href="#configuration">Configuration</a></li>
++</ul>
++</li>
++<li class="toctree-l2"><a class="reference internal" href="../files_encryption/index.html">Encryption</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../files_external/index.html">External storage support</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../files_sharing/index.html">Sharing</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../files_trashbin/index.html">Deleted Files</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../files_versions/index.html">Versions</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../firstrunwizard/index.html">First Run Wizard</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../user_ldap/index.html">LDAP user and group backend</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../viewers/index.html">File Viewers</a></li>
++</ul>
++</li>
 +<li class="toctree-l1"><a class="reference internal" href="../../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../../config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
-   <p><strong>ownCloud Antivirus</strong></p>
- <div class="toctree-wrapper compound">
- <ul>
- <li class="toctree-l1"><a class="reference internal" href="Table_of_Contents.html">Table of Contents</a></li>
- <li class="toctree-l1"><a class="reference internal" href="Introduction.html">Introduction</a></li>
- <li class="toctree-l1"><a class="reference internal" href="Configuration.html">Configuration</a><ul>
- <li class="toctree-l2"><a class="reference internal" href="Configuration.html#enable-the-app">Enable The app</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Configuration.html#install-clamav">Install ClamAV</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Configuration.html#configure-logging">Configure Logging</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Configuration.html#executable-mode">Executable Mode</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Configuration.html#daemon-mode">Daemon Mode</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Configuration.html#daemon-socket-mode">Daemon Socket mode</a></li>
++  <div class="section" id="file-antivirus-engine">
++<h1>File Antivirus Engine<a class="headerlink" href="#file-antivirus-engine" title="Permalink to this headline">¶</a></h1>
++<p>ownCloud integrates with ClamAV, an open source (GPL) antivirus engine, to provide an antivirus solution for files which are uploaded to the ownCloud server.
++Via this method, ownCloud/ClamAV can detect Trojans, viruses, malware and other malicious threats.
++Files are scanned for virus upon initial upload to the ownCloud server.</p>
++<p>The ownCloud antivirus app is supported on ownCloud instances which are installed on a Linux operating system.</p>
++<p>The antivirus app can run in one of three modes:</p>
++<ul class="simple">
++<li>Executable – ClamAV is running on the same server as the ownCloud instance.
++For executable mode, the ClamAV process is started and stopped with each file upload.</li>
++<li>Daemon – ClamAV is running on a different server from the ownCloud instance</li>
++<li>Daemon (Socket) – ClamAV is running on the same server as the ownCloud instance. In this mode, the ClamAV process is running in the background at all times.
++It is a bit quicker for scanning than executable mode, but requires system administrator skills and root access.</li>
 +</ul>
- </li>
++<p>In addition, there are two possible actions which may occur when an infected file is found:</p>
++<ul class="simple">
++<li>Only Log – A log entry is created when an infected file is found.</li>
++<li>Delete File – The infected file is deleted.</li>
 +</ul>
++<div class="section" id="configuration">
++<h2>Configuration<a class="headerlink" href="#configuration" title="Permalink to this headline">¶</a></h2>
++<div class="section" id="enable-the-app">
++<h3>Enable The app<a class="headerlink" href="#enable-the-app" title="Permalink to this headline">¶</a></h3>
++<p>To enable the Antivirus App, navigate to the Apps page and select “Antivirus App for Files” and enable.</p>
++<p><img alt="10000000000001800000009A9494E037_png" src="../../_images/10000000000001800000009A9494E037.png" style="width: 4in; height: 1.6043in;" /></p>
++</div>
++<div class="section" id="install-clamav">
++<h3>Install ClamAV<a class="headerlink" href="#install-clamav" title="Permalink to this headline">¶</a></h3>
++<p>ClamAV must be installed on the server (either the local for Executable or Daemon Socket mode or a remote server for Daemon mode).</p>
++<p>To install, use the repository’s installation method to install “clamav”.
++For example:</p>
++<div class="highlight-python"><pre>apt-get install clamav</pre>
++</div>
++<p>For daemon mode, the ClamAV daemon must also be installed (either on the local machine for Daemon Socket or the remote machine for daemon mode):</p>
++<div class="highlight-python"><pre>apt-get install clamav-daemon</pre>
++</div>
++</div>
++<div class="section" id="configure-logging">
++<h3>Configure Logging<a class="headerlink" href="#configure-logging" title="Permalink to this headline">¶</a></h3>
++<p>Set log level to Everything in the Admin page.</p>
++<p><img alt="10000000000001AC000000477C76808F_png" src="../../_images/10000000000001AC000000477C76808F.png" style="width: 4.4583in; height: 0.7398in;" /></p>
++</div>
++<div class="section" id="executable-mode">
++<h3>Executable Mode<a class="headerlink" href="#executable-mode" title="Permalink to this headline">¶</a></h3>
++<p>To run in executable mode, ClamAV must be installed on the local server.
++From the Admin page, configure Antivirus as follows:</p>
++<p><img alt="1000000000000165000000D3FF2168AB_png" src="../../_images/1000000000000165000000D3FF2168AB.png" style="width: 3.7189in; height: 2.198in;" /></p>
++<p>The Stream Length is defined as the ClamAV StreamMaxLengeth Size.
++The default value, according to the ClamAV web site is 10M which equates to 10485760 bytes as shown in the above example.</p>
++<p>The Path to clamscan is the path for the executable clamscan file.
++By default it installs in /usr/bin/clamscan.</p>
++<p>When files are uploaded, they will be scanned and, if clean, the following logs will appear:</p>
++<div class="highlight-python"><div class="highlight"><pre><span class="p">{</span><span class="s">"app"</span><span class="p">:</span><span class="s">"files_antivirus"</span><span class="p">,</span><span class="s">"message"</span><span class="p">:</span><span class="s">"Scanning file : \/Lab.txt"</span><span class="p">,</span><span class="s">"level"</span><span class="p">:</span><span class="mi">0</span><span class="p">,</span><span clas [...]
++<span class="p">{</span><span class="s">"app"</span><span class="p">:</span><span class="s">"files_antivirus"</span><span class="p">,</span><span class="s">"message"</span><span class="p">:</span><span class="s">"Exec scan: \/Lab.txt"</span><span class="p">,</span><span class="s">"level"</span><span class="p">:</span><span class="mi">0</span><span class="p">,</span><span class="s">"time"</span><span class="p">:</span><span clas [...]
++<span class="p">{</span><span class="s">"app"</span><span class="p">:</span><span class="s">"files_antivirus"</span><span class="p">,</span><span class="s">"message"</span><span class="p">:</span><span class="s">"Result CLEAN!"</span><span class="p">,</span><span class="s">"level"</span><span class="p">:</span><span class="mi">0</span><span class="p">,</span><span class="s">"time"</span><span class="p">:</span><span class="s">& [...]
++</pre></div>
++</div>
++</div>
++<div class="section" id="daemon-mode">
++<h3>Daemon Mode<a class="headerlink" href="#daemon-mode" title="Permalink to this headline">¶</a></h3>
++<p>When running in Daemon Mode, install ClamAV and clamAV-Daemon on a remote server.</p>
++<p>The port, upon which ClamAV listens must be configured.
++To do this, add the following line in <tt class="docutils literal"><span class="pre">/etc/clamav/clamd.conf</span></tt>:</p>
++<div class="highlight-python"><pre>TCPSocket 3310</pre>
++</div>
++<p>Then restart the Clamd service:</p>
++<div class="highlight-python"><pre>/etc/init.d/clamav-daemon restart</pre>
++</div>
++<p>Back on the ownCloud server, navigate to the Admin page and configure the Antivirus Configuration as follows:</p>
++<p><img alt="1000000000000194000000FAD39BC0D8_png" src="../../_images/1000000000000194000000FAD39BC0D8.png" style="width: 4.2083in; height: 2.6043in;" /></p>
++<p>Where the host is the IP of the server running the ClamAV Daemon and the Port is what was configured in the above step.</p>
++<p>Upon upload of files to the ownCloud server, the following logs will appear indicating the files are clean:</p>
++<div class="highlight-python"><div class="highlight"><pre><span class="p">{</span><span class="s">"app"</span><span class="p">:</span><span class="s">"files_antivirus"</span><span class="p">,</span><span class="s">"message"</span><span class="p">:</span><span class="s">"Scanning file : \/Lab.txt"</span><span class="p">,</span><span class="s">"level"</span><span class="p">:</span><span class="mi">0</span><span class="p">,</span><span clas [...]
++<span class="p">{</span><span class="s">"app"</span><span class="p">:</span><span class="s">"files_antivirus"</span><span class="p">,</span><span class="s">"message"</span><span class="p">:</span><span class="s">"Response :: stream: OK</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="s">"level"</span><span class="p">:</span><span class="mi">0</span><span class="p">,</span><span class="s">" [...]
++</pre></div>
++</div>
++</div>
++<div class="section" id="daemon-socket-mode">
++<h3>Daemon Socket mode<a class="headerlink" href="#daemon-socket-mode" title="Permalink to this headline">¶</a></h3>
++<p>To run in Daemon socket mode, install clamav and clamav-daemon on the ownCloud server.</p>
++<p>Configure the Admin page as such:</p>
++<p><img alt="1000000000000160000000DBB2FB0223_png" src="../../_images/1000000000000160000000DBB2FB0223.png" style="width: 3.6665in; height: 2.2811in;" /></p>
++<p>Where Socket is the location of the Clamd executable.</p>
++<p>Upon upload of a clean file to the ownCloud server, the following logs will appear:</p>
++<div class="highlight-python"><div class="highlight"><pre><span class="p">{</span><span class="s">"app"</span><span class="p">:</span><span class="s">"files_antivirus"</span><span class="p">,</span><span class="s">"message"</span><span class="p">:</span><span class="s">"Scanning file : \/Lab.txt"</span><span class="p">,</span><span class="s">"level"</span><span class="p">:</span><span class="mi">0</span><span class="p">,</span><span clas [...]
++<span class="p">{</span><span class="s">"app"</span><span class="p">:</span><span class="s">"files_antivirus"</span><span class="p">,</span><span class="s">"message"</span><span class="p">:</span><span class="s">"Response :: stream: OK</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="s">"level"</span><span class="p">:</span><span class="mi">0</span><span class="p">,</span><span class="s">" [...]
++</pre></div>
++</div>
++</div>
++</div>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/apps/files_encryption/index.html
index 58c088a,0000000..daf3929
mode 100644,000000..100644
--- a/core/doc/admin/apps/files_encryption/index.html
+++ b/core/doc/admin/apps/files_encryption/index.html
@@@ -1,157 -1,0 +1,291 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
-     <title><no title> — ownCloud Administrators Manual 6.0 documentation</title>
++    <title>Encryption — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../../index.html" />
++    <link rel="up" title="Apps" href="../index.html" />
++    <link rel="next" title="External storage support" href="../files_external/index.html" />
++    <link rel="prev" title="File Antivirus Engine" href="../files_antivirus/index.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
- <ul>
++<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../../installation/index.html">Installation</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../../configuration/index.html">Configuration</a></li>
++<li class="toctree-l1 current"><a class="reference internal" href="../index.html">Apps</a><ul class="current">
++<li class="toctree-l2"><a class="reference internal" href="../activity/index.html">Activity</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../admin_dependencies_chk/index.html">Finding Deployment Dependencies</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../files_antivirus/index.html">File Antivirus Engine</a></li>
++<li class="toctree-l2 current"><a class="current reference internal" href="">Encryption</a><ul>
++<li class="toctree-l3"><a class="reference internal" href="#what-gets-encrypted">What gets encrypted?</a></li>
++<li class="toctree-l3"><a class="reference internal" href="#decrypting-the-data">Decrypting the data</a></li>
++<li class="toctree-l3"><a class="reference internal" href="#configuration">Configuration</a></li>
++<li class="toctree-l3"><a class="reference internal" href="#file-systems">File Systems</a></li>
++</ul>
++</li>
++<li class="toctree-l2"><a class="reference internal" href="../files_external/index.html">External storage support</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../files_sharing/index.html">Sharing</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../files_trashbin/index.html">Deleted Files</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../files_versions/index.html">Versions</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../firstrunwizard/index.html">First Run Wizard</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../user_ldap/index.html">LDAP user and group backend</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../viewers/index.html">File Viewers</a></li>
++</ul>
++</li>
 +<li class="toctree-l1"><a class="reference internal" href="../../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../../config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
-   <p><strong>ownCloud Enctryption</strong></p>
- <div class="toctree-wrapper compound">
- <ul>
- <li class="toctree-l1"><a class="reference internal" href="Table_of_Contents.html">Table of Contents</a></li>
- <li class="toctree-l1"><a class="reference internal" href="Introduction.html">Introduction</a><ul>
- <li class="toctree-l2"><a class="reference internal" href="Introduction.html#what-gets-encrypted">What gets encrypted?</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Introduction.html#decrypting-the-data">Decrypting the data</a></li>
- </ul>
- </li>
- <li class="toctree-l1"><a class="reference internal" href="Configuration.html">Configuration</a><ul>
- <li class="toctree-l2"><a class="reference internal" href="Configuration.html#recovery-key">Recovery Key</a></li>
++  <div class="section" id="encryption">
++<h1>Encryption<a class="headerlink" href="#encryption" title="Permalink to this headline">¶</a></h1>
++<p>ownCloud contains an encryption app which, when enabled, encrypts all files stored in ownCloud.
++The encryption is done automatically once the admin enables the app.
++All encryption and decryption occur on the ownCloud server, which allows the
++user to continue to use other apps to view and edit the data.</p>
++<p>The user’s password is used as the key to decrypt their data.
++This means that if the user loses their login password, data will be lost.
++To protect against password loss, the recovery key may be used as described in a later section.</p>
++<div class="section" id="what-gets-encrypted">
++<h2>What gets encrypted?<a class="headerlink" href="#what-gets-encrypted" title="Permalink to this headline">¶</a></h2>
++<p>All files stored in ownCloud will be encrypted with the following exceptions:</p>
++<ul class="simple">
++<li>Old versions (versions created prior to enabling the encryption app)</li>
++<li>Old files in the trash bin (files deleted prior to enabling the encryption app)</li>
++<li>Existing files on external storage.
++Only new files placed on the external storage mount after encryption was enabled are encrypted.</li>
++<li>Image thumbnails from the gallery app</li>
++<li>Search index form the full text search app.</li>
 +</ul>
- </li>
- <li class="toctree-l1"><a class="reference internal" href="File_Systems.html">File Systems</a></li>
++</div>
++<div class="section" id="decrypting-the-data">
++<h2>Decrypting the data<a class="headerlink" href="#decrypting-the-data" title="Permalink to this headline">¶</a></h2>
++<p>If the encryption app is disable, users will get the following message alerting
++them how to decrypt their files.</p>
++<img alt="../../_images/100000000000023B000000125381F51B.png" src="../../_images/100000000000023B000000125381F51B.png" style="width: 5.948in; height: 0.1874in;" />
++<p>Navigating to the Personal settings page, the user can enter their password and
++decrypt all files.</p>
++<img alt="../../_images/100000000000018B000000A090F31164.png" src="../../_images/100000000000018B000000A090F31164.png" style="width: 4.1146in; height: 1.6665in;" />
++</div>
++<div class="section" id="configuration">
++<h2>Configuration<a class="headerlink" href="#configuration" title="Permalink to this headline">¶</a></h2>
++<p>To enable the encryption app, navigate to the Apps page and select Encryption, then enable.</p>
++<img alt="../../_images/10000000000001A3000000AAFE82893A.png" src="../../_images/10000000000001A3000000AAFE82893A.png" />
++<p>Once the app is enabled, the following message will appear for all users
++currently logged into the web browser as they navigate to a new page within the
++ownCloud web browser</p>
++<img alt="../../_images/10000000000001BF00000012349EAE2F.png" src="../../_images/10000000000001BF00000012349EAE2F.png" />
++<p>It is necessary to logout of ownCloud and re-login to initialize the encryption keys.</p>
++<div class="section" id="recovery-key">
++<h3>Recovery Key<a class="headerlink" href="#recovery-key" title="Permalink to this headline">¶</a></h3>
++<p>Enabling the recovery key globally is done by the admin.
++Each user then has the option as to whether they wish to do so for their own account.
++If enabled, the admin will be able to reset the user’s encryption password
++using a predefined recovery password.  This allows for the recovery of a user’s
++files in the event of a password loss.  If recovery key is not enabled, there
++is no way to restore files if the login password is lost.</p>
++<div class="section" id="admin-level">
++<h4>Admin level<a class="headerlink" href="#admin-level" title="Permalink to this headline">¶</a></h4>
++<p>To enable the recovery key, the Admin must first enable this feature in the Admin page.</p>
++<img alt="../../_images/100000000000018E000000C4BA62B2A3.png" src="../../_images/100000000000018E000000C4BA62B2A3.png" />
++<p>Once enabled, the Admin may change the recovery key password at any time.</p>
++<img alt="../../_images/1000000000000193000001AE9AB8B0A2.png" src="../../_images/1000000000000193000001AE9AB8B0A2.png" />
++</div>
++<div class="section" id="user-level">
++<h4>User level<a class="headerlink" href="#user-level" title="Permalink to this headline">¶</a></h4>
++<p>The user can then navigate to the Personal page and enable password recovery.</p>
++<img alt="../../_images/1000000000000227000000935D9B1EF6.png" src="../../_images/1000000000000227000000935D9B1EF6.png" />
++</div>
++<div class="section" id="recovery">
++<h4>Recovery<a class="headerlink" href="#recovery" title="Permalink to this headline">¶</a></h4>
++<p>In order for the admin to recover the user’s files in the event of a lost
++password, the admin should navigate to the “Users” tab and enter the Recovery
++Key Password into the “Admin Recovery Password” field at the top of the page.</p>
++<img alt="../../_images/10000000000003730000002B6865E951.png" src="../../_images/10000000000003730000002B6865E951.png" />
++<p>This will allow the admin to generate a new encryption password for the user.</p>
++<ul class="simple">
++<li>For local user management, this will generate both a new log-in password as well
++as a new encryption password for the data.</li>
++<li>If LDAP authentication is in use, the admin would need to set the new log-in password
++in the LDAP server, and then enter the same password in the user management page for
++the encryption key. It is important that both the password in the LDAP server and the
++password entered in the user management page are identical.</li>
 +</ul>
 +</div>
++</div>
++</div>
++<div class="section" id="file-systems">
++<h2>File Systems<a class="headerlink" href="#file-systems" title="Permalink to this headline">¶</a></h2>
++<p>Once enabled, all files within ownCloud are encrypted, with the exceptions mentioned above.
++This includes files in local storage, as well as files contained within external storage mounts.</p>
++<p>The encryption app creates several key files/folders when enabled.
++<tt class="docutils literal"><span class="pre">~/data/public-keys</span></tt> contains the public keys for all users, and
++<tt class="docutils literal"><span class="pre">~/data/owncloud_private_keys</span></tt> contains system wide private keys utilized for
++public link shares as well as the recovery key.</p>
++<div class="highlight-console"><div class="highlight"><pre><span class="gp">root at server:/var/www/owncloud/data#</span> ls
++<span class="go">files_encryption/  mount.json  owncloud.log           public-keys/ yogi/</span>
++<span class="go">index.html         oc6admin/   owncloud_private_key/  user1/</span>
++</pre></div>
++</div>
++<p>The encryption app stores key information in the <tt class="docutils literal"><span class="pre">~/data/<user>/files_encryption</span></tt> directory.</p>
++<div class="highlight-console"><div class="highlight"><pre><span class="gp">root at server:/var/www/owncloud/data/user1/encryption#</span> ls
++<span class="go">keyfiles/ user1.private.key share-keys/</span>
++</pre></div>
++</div>
++<p>As mentioned previously, the private key is generated from the user’s password.</p>
++<p>Each file that the user owns will have a corresponding keyfile maintained in the keyfiles directory.</p>
++<div class="highlight-console"><div class="highlight"><pre><span class="gp">root at server:/var/www/owncloud/data/user1/files_encryption/keyfiles#</span> ls
++<span class="go">documents/ ownCloud undelete.docx.key photos/</span>
++<span class="go">music/     ownCloudUserManual.pdf.key test encryption.txt.key</span>
++</pre></div>
++</div>
++<p>In addition a share key will be generated for each file in the event that there
++is an external storage mount by the admin for multiple users or groups.</p>
++<div class="highlight-console"><div class="highlight"><pre><span class="gp">root at server:/var/www/owncloud/data/user1/files_encryption/share-keys#</span> ls
++<span class="go">documents/</span>
++<span class="go">music/</span>
++<span class="go">ownCloud undelete.docx.recovery_5dcce10a.shareKey</span>
++<span class="go">ownCloud undelete.docx.user1.shareKey</span>
++<span class="go">ownCloudUserManual.pdf.recovery_5dcce10a.shareKey</span>
++<span class="go">ownCloudUserManual.pdf.user1.shareKey</span>
++<span class="go">photos/</span>
++<span class="go">test encryption.txt.recovery_5dcce10a.shareKey</span>
++<span class="go">test encryption.txt.user1.shareKey</span>
++<span class="go">...</span>
++</pre></div>
++</div>
++<p>When viewing a file directly on the ownCloud data directory, it will show up as encrypted.</p>
++<div class="highlight-console"><div class="highlight"><pre><span class="gp">root at server:/var/www/owncloud/data/user1/files#</span> more <span class="nb">test</span><span class="se">\ </span>encryption.txt
++<span class="go">2JnmDdDh//8FVcDhLrnD1WH0JjhrzKpFKV6V61pAfUCu9IJX00iv007Yw3Tf/QBbtJFpQFxx</span>
++</pre></div>
++</div>
++<p>However, viewing the same file via the browser, the actual contents of the file are displayed.</p>
++<img alt="../../_images/edit_encrypted_file.png" src="../../_images/edit_encrypted_file.png" />
++</div>
++</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/apps/files_external/index.html
index 59cb0f3,0000000..e2882d9
mode 100644,000000..100644
--- a/core/doc/admin/apps/files_external/index.html
+++ b/core/doc/admin/apps/files_external/index.html
@@@ -1,157 -1,0 +1,491 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
-     <title><no title> — ownCloud Administrators Manual 6.0 documentation</title>
++    <title>External storage support — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../../index.html" />
++    <link rel="up" title="Apps" href="../index.html" />
++    <link rel="next" title="Sharing" href="../files_sharing/index.html" />
++    <link rel="prev" title="Encryption" href="../files_encryption/index.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
- <ul>
++<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../../installation/index.html">Installation</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../../configuration/index.html">Configuration</a></li>
++<li class="toctree-l1 current"><a class="reference internal" href="../index.html">Apps</a><ul class="current">
++<li class="toctree-l2"><a class="reference internal" href="../activity/index.html">Activity</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../admin_dependencies_chk/index.html">Finding Deployment Dependencies</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../files_antivirus/index.html">File Antivirus Engine</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../files_encryption/index.html">Encryption</a></li>
++<li class="toctree-l2 current"><a class="current reference internal" href="">External storage support</a><ul>
++<li class="toctree-l3"><a class="reference internal" href="#supported-mounts">Supported mounts</a></li>
++<li class="toctree-l3"><a class="reference internal" href="#configuration">Configuration</a></li>
++</ul>
++</li>
++<li class="toctree-l2"><a class="reference internal" href="../files_sharing/index.html">Sharing</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../files_trashbin/index.html">Deleted Files</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../files_versions/index.html">Versions</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../firstrunwizard/index.html">First Run Wizard</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../user_ldap/index.html">LDAP user and group backend</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../viewers/index.html">File Viewers</a></li>
++</ul>
++</li>
 +<li class="toctree-l1"><a class="reference internal" href="../../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../../config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
-   <p><strong>External Storage Mounts</strong></p>
- <div class="toctree-wrapper compound">
- <ul>
- <li class="toctree-l1"><a class="reference internal" href="Table_of_Contents.html">Table of Contents</a></li>
- <li class="toctree-l1"><a class="reference internal" href="Introduction.html">Introduction</a><ul>
- <li class="toctree-l2"><a class="reference internal" href="Introduction.html#supported-mounts">Supported mounts</a></li>
++  <div class="section" id="external-storage-support">
++<h1>External storage support<a class="headerlink" href="#external-storage-support" title="Permalink to this headline">¶</a></h1>
++<p>ownCloud provides the ability to mount an external storage device.
++The external storage devices serves as a secondary storage device within ownCloud.</p>
++<p>The ownCloud Admin has the ability to create such a mount.
++In addition, the ownCloud Admin may decide to provide the end user the ability to create the mount.
++The mounts may be created on a per-user, per group, or all user basis.</p>
++<div class="section" id="supported-mounts">
++<h2>Supported mounts<a class="headerlink" href="#supported-mounts" title="Permalink to this headline">¶</a></h2>
++<p>The following lists the supported storage types.</p>
++<ul class="simple">
++<li>Local</li>
++<li>Amazon S3</li>
++<li>Dropbox</li>
++<li>FTP</li>
++<li>Google Drive</li>
++<li>OpenStack Object Storage</li>
++<li>SMB/CIFS</li>
++<li>ownCloud/WebDAV</li>
++<li>SFTP</li>
++<li>iRODS</li>
 +</ul>
- </li>
- <li class="toctree-l1"><a class="reference internal" href="Configuration.html">Configuration</a><ul>
- <li class="toctree-l2"><a class="reference internal" href="Configuration.html#enable-the-app">Enable the app</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Configuration.html#configure-mounts">Configure mounts</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Configuration.html#configuration-file">Configuration File</a></li>
++</div>
++<div class="section" id="configuration">
++<h2>Configuration<a class="headerlink" href="#configuration" title="Permalink to this headline">¶</a></h2>
++<div class="section" id="enable-the-app">
++<h3>Enable the app<a class="headerlink" href="#enable-the-app" title="Permalink to this headline">¶</a></h3>
++<p>From the <tt class="docutils literal"><span class="pre">APPs</span></tt> Page within ownCloud, select <tt class="docutils literal"><span class="pre">External</span> <span class="pre">Storage</span> <span class="pre">Support</span></tt> and enable.</p>
++<p><img alt="10000000000001980000009271BE0D26_png" src="../../_images/10000000000001980000009271BE0D26.png" style="width: 4.25in; height: 1.5201in;" /></p>
++</div>
++<div class="section" id="configure-mounts">
++<h3>Configure mounts<a class="headerlink" href="#configure-mounts" title="Permalink to this headline">¶</a></h3>
++<p>As stated previously, the Admin has the ability to configure these mounts, as
++well as decide whether an end user can configure mounts for themselves.  For
++the Admin, the configuration is performed in the <tt class="docutils literal"><span class="pre">Admin</span></tt> page.  For end
++users, the configuration is performed in the <tt class="docutils literal"><span class="pre">Personal</span></tt> Page.  This document
++will discuss how the Admin configures the mounts, however, the configuration is
++the same for the end user.</p>
++<p>On the <tt class="docutils literal"><span class="pre">Admin</span></tt> page, scroll to External Storage:</p>
++<p><img alt="1000000000000631000000E19D116AA0_png" src="../../_images/1000000000000631000000E19D116AA0.png" style="width: 6.5in; height: 0.9228in;" /></p>
++<div class="section" id="enable-users-to-mount-their-own-devices">
++<h4>Enable users to mount their own devices<a class="headerlink" href="#enable-users-to-mount-their-own-devices" title="Permalink to this headline">¶</a></h4>
++<p>In order to allow end users to mount their own devices, select the radio button next to
++Enable User External Storage.</p>
++</div>
++<div class="section" id="local-storage">
++<h4>Local Storage<a class="headerlink" href="#local-storage" title="Permalink to this headline">¶</a></h4>
++<p>This is used to mount storage that is outside ownCloud’s data directory</p>
++<p><img alt="10000000000006060000006A0106CA0C_png" src="../../_images/10000000000006060000006A0106CA0C.png" style="width: 6.5in; height: 0.4465in;" /></p>
++<ul class="simple">
++<li>Location – The directory to mount</li>
++<li>Applicable – A list users of who can see this mount</li>
 +</ul>
- </li>
++<p><img alt="10000000000003DF00000071A41D8A1F_png" src="../../_images/10000000000003DF00000071A41D8A1F.png" style="width: 6.5in; height: 0.7409in;" /></p>
++<p>Note: When configured correctly, a <em>Green Light</em> will appear next to the Folder Name.
++If misconfigured, a <em>Red Light</em> will appear.</p>
++<p><img alt="10000000000004770000008AAF3CFFDB_png" src="../../_images/10000000000004770000008AAF3CFFDB.png" style="width: 6.5in; height: 0.7846in;" /></p>
++</div>
++<div class="section" id="amazon-s3">
++<h4>Amazon S3<a class="headerlink" href="#amazon-s3" title="Permalink to this headline">¶</a></h4>
++<p>This is used to mount to an S3 server</p>
++<p><img alt="100000000000061D0000007047877972_png" src="../../_images/100000000000061D0000007047877972.png" style="width: 6.5in; height: 0.4654in;" /></p>
++<ul class="simple">
++<li>Access Key – The access key provided by the S3 storage provider</li>
++<li>Secret Key – The secret key provided by the S3 storage provider</li>
++<li>Bucket – The bucket created within the S3 storage server</li>
++<li>Hostname (optional) – The host of the s3 storage server</li>
++<li>Port (optional) – The port to communicate to the host on</li>
++<li>Region (optional) – The region where the storage exists</li>
++<li>Applicable – A list of users who can see this mount</li>
++</ul>
++<p><img alt="10000000000005BB0000007C1DF71FA7_png" src="../../_images/10000000000005BB0000007C1DF71FA7.png" style="width: 6.5in; height: 0.5492in;" /></p>
++<div class="admonition note">
++<p class="first admonition-title">Note</p>
++<p class="last">When configured correctly, a Green Light will appear next to the Folder Name.
++If misconfigured, a Red Light will appear.</p>
++</div>
++<p><img alt="100000000000063F00000090AAE1FA4A_png" src="../../_images/100000000000063F00000090AAE1FA4A.png" style="width: 6.5in; height: 0.5846in;" /></p>
++</div>
++<div class="section" id="dropbox">
++<h4>Dropbox<a class="headerlink" href="#dropbox" title="Permalink to this headline">¶</a></h4>
++<p>Mounts a dropbox in the Dropbox cloud into the virtual file system.</p>
++<div class="section" id="configure-dropbox">
++<h5>Configure DropBox<a class="headerlink" href="#configure-dropbox" title="Permalink to this headline">¶</a></h5>
++<p>Log onto the <a class="reference external" href="http://www.dropbox.com/developers">Dropbox Developers page</a>:</p>
++<p>Select App Console:</p>
++<p><img alt="10000000000000A800000073F49785A6_png" src="../../_images/10000000000000A800000073F49785A6.png" style="width: 1.75in; height: 1.198in;" /></p>
++<p>This will ask you to accept terms and conditions.</p>
++<p>Select Dropbox API and configure down the page as follows:</p>
++<p><img alt="1000000000000372000002AF943ADDA0_png" src="../../_images/1000000000000372000002AF943ADDA0.png" style="width: 6.5in; height: 5.0634in;" /></p>
++<p>The name can be any unique name desired.</p>
++<p>Select Create App</p>
++<p><img alt="10000000000000950000004412998BE7_png" src="../../_images/10000000000000950000004412998BE7.png" style="width: 1.552in; height: 0.7083in;" /></p>
++<p>Enter the OAuth redirect URI as follows:</p>
++<div class="highlight-python"><pre>http://<ownCloud instance>/index.php/settings/personal
++http://<ownCloud instance>/index.php/settings/admin</pre>
++</div>
++<p><img alt="10000000000003A6000002A9C7A660BE_png" src="../../_images/10000000000003A6000002A9C7A660BE.png" style="width: 6.5in; height: 4.7398in;" /></p>
++<p>Take note of the App Key and App Secret and enter into ownCloud.</p>
++</div>
++<div class="section" id="owncloud-configuration">
++<h5>ownCloud Configuration<a class="headerlink" href="#owncloud-configuration" title="Permalink to this headline">¶</a></h5>
++<p><img alt="100000000000060300000065DF96536B_png" src="../../_images/100000000000060300000065DF96536B.png" style="width: 6.5in; height: 0.4264in;" /></p>
++<ul class="simple">
++<li>App key – The app key to login to your Dropbox</li>
++<li>App secret – The app secret to login to your Dropbox</li>
++<li>Applicable – A list users of who can see this mount</li>
++</ul>
++<p><img alt="10000000000005EC00000073E678DFEC_png" src="../../_images/10000000000005EC00000073E678DFEC.png" style="width: 6.5in; height: 0.4929in;" /></p>
++<p>Select “Grant Access” and the following appears</p>
++<p><img alt="10000000000002950000021E245F6883_png" src="../../_images/10000000000002950000021E245F6883.png" style="width: 6.5in; height: 5.3299in;" /></p>
++<p>Note if you are not logged into Dropbox, you will first be prompted to login.
++Select Allow.</p>
++<p><img alt="10000000000005E6000000676902E040_png" src="../../_images/10000000000005E6000000676902E040.png" style="width: 6.5in; height: 0.4429in;" /></p>
++<div class="admonition note">
++<p class="first admonition-title">Note</p>
++<p class="last">When configured correctly, a Green Light will appear next to the Folder Name.
++If misconfigured, a Red Light will appear.</p>
++</div>
++<p><img alt="100000000000061A0000006FC014C3A4_png" src="../../_images/100000000000061A0000006FC014C3A4.png" style="width: 6.5in; height: 0.461in;" /></p>
++</div>
++</div>
++<div class="section" id="ftp">
++<h4>FTP<a class="headerlink" href="#ftp" title="Permalink to this headline">¶</a></h4>
++<p>Mounts a folder on a remote FTP or FTPS server</p>
++<p><img alt="100000000000061E0000006BCF9ECC0B_png" src="../../_images/100000000000061E0000006BCF9ECC0B.png" style="width: 6.5in; height: 0.4437in;" /></p>
++<ul class="simple">
++<li>URL – The hostname of the FTP/FTPS server</li>
++<li>Username – The username to login to the FTP/FTPS server</li>
++<li>Password – The password to login to the FTP/FTPS esrver</li>
++<li>Root – The folder inside the FTP/FTPS server to mount (optional – defaults to ‘/’)</li>
++<li>Secure <tt class="docutils literal"><span class="pre">ftps://</span></tt> – Whether to use ftps:// to connect to the FTP server instead of <tt class="docutils literal"><span class="pre">ftp://</span></tt></li>
++<li>Applicable – A list users of who can see this mount</li>
++</ul>
++<p><img alt="10000000000005AF00000074604B1A67_png" src="../../_images/10000000000005AF00000074604B1A67.png" style="width: 6.5in; height: 0.5181in;" /></p>
++<div class="admonition note">
++<p class="first admonition-title">Note</p>
++<p class="last">When configured correctly, a Green Light will appear next to the
++Folder Name.  If misconfigured, a Red Light will appear.</p>
++</div>
++<p><img alt="10000000000005D50000009458C5EE48_png" src="../../_images/10000000000005D50000009458C5EE48.png" style="width: 6.5in; height: 0.6437in;" /></p>
++</div>
++<div class="section" id="googledrive">
++<h4>GoogleDrive<a class="headerlink" href="#googledrive" title="Permalink to this headline">¶</a></h4>
++<p>Mounts a share in the Google cloud.</p>
++<div class="section" id="configure-googledrive">
++<h5>Configure GoogleDrive<a class="headerlink" href="#configure-googledrive" title="Permalink to this headline">¶</a></h5>
++<p>All applications that access a Google API must be registered through the “Google Cloud Console”.
++This can be accessed at the following URL:</p>
++<p><a class="reference external" href="https://cloud.google.com">https://cloud.google.com</a></p>
++<p>Once logged into Google, create a project by selecting
++Create Project</p>
++<p><img alt="1000000000000247000000A77440E4D3_png" src="../../_images/1000000000000247000000A77440E4D3.png" style="width: 6.0728in; height: 1.7398in;" /></p>
++<p>Enter a Project name and either keep or enter a new Project ID
++<img alt="100000000000027B0000011D10F70F88_png" src="../../_images/100000000000027B0000011D10F70F88.png" style="width: 6.5in; height: 2.9173in;" /></p>
++<p>Select the project and choose the APIs & auth menu entry
++<img alt="10000000000000B600000120706C3C75_png" src="../../_images/10000000000000B600000120706C3C75.png" style="width: 1.8957in; height: 3in;" /></p>
++<p>Enable <tt class="docutils literal"><span class="pre">Drive</span> <span class="pre">API</span></tt> and <tt class="docutils literal"><span class="pre">Drive</span> <span class="pre">SDK</span></tt> and then select the</p>
++<p><img alt="100000000000003800000018D49F1CE7_png" src="../../_images/100000000000003800000018D49F1CE7.png" style="width: 0.5835in; height: 0.25in;" /></p>
++<p>next to either <tt class="docutils literal"><span class="pre">Drive</span> <span class="pre">API</span></tt> or <tt class="docutils literal"><span class="pre">Drive</span> <span class="pre">SDK</span></tt></p>
++<p><img alt="10000000000004100000005657010336_png" src="../../_images/10000000000004100000005657010336.png" style="width: 6.5in; height: 0.5374in;" /></p>
++<p>Select <tt class="docutils literal"><span class="pre">API</span> <span class="pre">Access</span></tt> on the menu</p>
++<p><img alt="10000000000000CD000000ECA8DE7780_png" src="../../_images/10000000000000CD000000ECA8DE7780.png" style="width: 2.1346in; height: 2.4583in;" /></p>
++<p>Select <tt class="docutils literal"><span class="pre">REGISTER</span> <span class="pre">APP</span></tt></p>
++<p><img alt="10000000000001FD000000DF8D2D7546_png" src="../../_images/10000000000001FD000000DF8D2D7546.png" style="width: 5.302in; height: 2.3228in;" /></p>
++<p>Enter a name and select <tt class="docutils literal"><span class="pre">Web</span> <span class="pre">Application</span></tt></p>
++<p><img alt="10000000000002840000016729388B7F_png" src="../../_images/10000000000002840000016729388B7F.png" style="width: 6.5in; height: 3.6228in;" /></p>
++<p>Expand <tt class="docutils literal"><span class="pre">OAuth</span> <span class="pre">2.0</span> <span class="pre">Client</span> <span class="pre">ID</span></tt>
++Enter the following in the <tt class="docutils literal"><span class="pre">REDIRECT</span> <span class="pre">URI</span></tt> field:</p>
++<div class="highlight-python"><pre>http://<ownCloud instance>/index.php/settings/personal
++http://<ownCloud instance>/index.php/settings/admin</pre>
++</div>
++<div class="admonition note">
++<p class="first admonition-title">Note</p>
++<p class="last">The <tt class="docutils literal"><span class="pre"><ownCloud</span> <span class="pre">instance></span></tt> must be a Fully Qualified Domain Name.  It cannot be an IP address!</p>
++</div>
++<p>Select <tt class="docutils literal"><span class="pre">Generate</span></tt></p>
++<p><img alt="10000000000003B30000021B5EE5D338_png" src="../../_images/10000000000003B30000021B5EE5D338.png" style="width: 6.5in; height: 3.6992in;" /></p>
++<p>Verify that the required email addresses are in the Permissions tab</p>
++<p><img alt="10000000000003A60000011E274A1A28_png" src="../../_images/10000000000003A60000011E274A1A28.png" style="width: 6.5in; height: 1.9902in;" /></p>
++</div>
++<div class="section" id="configure-owncloud">
++<h5>Configure ownCloud<a class="headerlink" href="#configure-owncloud" title="Permalink to this headline">¶</a></h5>
++<p>Prior to configuring the mount, an E-mail address needs to be configured in the <tt class="docutils literal"><span class="pre">Personal</span></tt> tab</p>
++<p><img alt="10000000000001880000007EA4444400_png" src="../../_images/10000000000001880000007EA4444400.png" style="width: 4.0835in; height: 1.3126in;" /></p>
++<p><img alt="10000000000006000000005EDA7B96BE_png" src="../../_images/10000000000006000000005EDA7B96BE.png" style="width: 6.5in; height: 0.398in;" /></p>
++<ul class="simple">
++<li>Client ID – The client id to login to the Google Drive from <tt class="docutils literal"><span class="pre">OAuth</span> <span class="pre">2.0</span> <span class="pre">Client</span> <span class="pre">ID</span></tt> above</li>
++<li>Client secret – The client secret to login to the Google Drive from <tt class="docutils literal"><span class="pre">OAuth</span> <span class="pre">2.0</span> <span class="pre">Client</span> <span class="pre">ID</span></tt> above</li>
++<li>Applicable – A list users of who can see this mount</li>
++</ul>
++<p>Once the required fields are filled in, a <tt class="docutils literal"><span class="pre">Grant</span> <span class="pre">access</span></tt> button appears.  Select this button.</p>
++<p><img alt="10000000000005F70000007E43DB8026_png" src="../../_images/10000000000005F70000007E43DB8026.png" style="width: 6.5in; height: 0.5362in;" /></p>
++<p>The following screen appears. Select <tt class="docutils literal"><span class="pre">Accept</span></tt></p>
++<p><img alt="10000000000001D30000014DC251C948_png" src="../../_images/10000000000001D30000014DC251C948.png" style="width: 4.8646in; height: 3.4689in;" /></p>
++<p><img alt="10000000000004C0000000795BB2C146_png" src="../../_images/10000000000004C0000000795BB2C146.png" style="width: 6.5in; height: 0.6465in;" /></p>
++<p><img alt="1000000000000552000000BF22E90239_png" src="../../_images/1000000000000552000000BF22E90239.png" style="width: 6.5in; height: 0.911in;" /></p>
++<div class="admonition note">
++<p class="first admonition-title">Note</p>
++<p class="last">When configured correctly, a Green Light will appear next to the
++Folder Name.  If misconfigured, a Red Light will appear.</p>
++</div>
++</div>
++</div>
++<div class="section" id="openstack-object-storage">
++<h4>OpenStack Object Storage<a class="headerlink" href="#openstack-object-storage" title="Permalink to this headline">¶</a></h4>
++<p>Mounts a container on an OpenStack Object Storage server.</p>
++<p><img alt="100000000000053A00000067708C8F53_png" src="../../_images/100000000000053A00000067708C8F53.png" style="width: 6.5in; height: 0.5008in;" /></p>
++<p><img alt="10000000000002170000004A27056037_png" src="../../_images/10000000000002170000004A27056037.png" style="width: 5.5728in; height: 0.7701in;" /></p>
++<ul class="simple">
++<li>Username</li>
++<li>Bucket</li>
++<li>Region</li>
++<li>API Key</li>
++<li>Tenantname</li>
++<li>Password</li>
++<li>Service Name</li>
++<li>URL of identity Endpoint</li>
++<li>Timeout of HTTP request</li>
++<li>Applicable – A list users of who can see this mount</li>
++</ul>
++<div class="admonition note">
++<p class="first admonition-title">Note</p>
++<p class="last">When configured correctly, a Green Light will appear next to the
++Folder Name.  If misconfigured, a Red Light will appear.</p>
++</div>
++</div>
++<div class="section" id="smb-cifs">
++<h4>SMB/CIFS<a class="headerlink" href="#smb-cifs" title="Permalink to this headline">¶</a></h4>
++<p>Mounts a folder on a remote Samba server, NAS appliance, or Windows machine.</p>
++<p><img alt="10000000000005FA0000005CE8491B77_png" src="../../_images/10000000000005FA0000005CE8491B77.png" style="width: 6.5in; height: 0.3909in;" /></p>
++<ul class="simple">
++<li>URL – The host name of the Samba server.</li>
++<li>Username – The user name used to login to the Samba server.</li>
++<li>Password – The password to login to the Samba server.</li>
++<li>Share – The share on the Samba server to mount.</li>
++<li>Root – The folder inside the Samba share to mount (optional, defaults to ‘/’)</li>
++<li>Applicable – A list users of who can see this mount</li>
++</ul>
++<p><img alt="10000000000005C30000006CAFFAAD61_png" src="../../_images/10000000000005C30000006CAFFAAD61.png" style="width: 6.5in; height: 0.4756in;" /></p>
++<div class="admonition note">
++<p class="first admonition-title">Note</p>
++<p class="last">When configured correctly, a Green Light will appear next to the
++Folder Name.  If misconfigured, a Red Light will appear.</p>
++</div>
++<div class="admonition note">
++<p class="first admonition-title">Note</p>
++<p class="last">The SMB backend requires <tt class="docutils literal"><span class="pre">smbclient</span></tt> to be installed on the server.</p>
++</div>
++<p><img alt="10000000000005D00000003B29340A7A_png" src="../../_images/10000000000005D00000003B29340A7A.png" style="width: 6.5in; height: 0.2575in;" /></p>
++</div>
++<div class="section" id="owncloud-webdav">
++<h4>ownCloud/WebDAV<a class="headerlink" href="#owncloud-webdav" title="Permalink to this headline">¶</a></h4>
++<p>Mounts a folder on a WebDAV server (or another ownCloud instance via WebDAV).</p>
++<p><img alt="10000000000005F70000005F0912E904_png" src="../../_images/10000000000005F70000005F0912E904.png" style="width: 6.5in; height: 0.4043in;" /></p>
++<ul class="simple">
++<li>URL – The hostname of the WebDAV server.</li>
++<li>Username – The username used to login to the WebDAV server.</li>
++<li>Password – The password used to login to the WebDAV server.</li>
++<li>Root – The folder inside the WebDav server to mount (optional, defaults to ‘/’)</li>
++<li>Secure <tt class="docutils literal"><span class="pre">https://</span></tt> - Whether to use <tt class="docutils literal"><span class="pre">https://</span></tt> to connect to the WebDav server instead of <tt class="docutils literal"><span class="pre">http://</span></tt></li>
++<li>Applicable – A list users of who can see this mount</li>
 +</ul>
++<p><img alt="10000000000005B90000007866D92D14_png" src="../../_images/10000000000005B90000007866D92D14.png" style="width: 6.5in; height: 0.5319in;" /></p>
++<div class="admonition note">
++<p class="first admonition-title">Note</p>
++<p class="last">When configured correctly, a Green Light will appear next to the
++Folder Name.  If misconfigured, a Red Light will appear.</p>
++</div>
++<p><img alt="10000000000005E20000009B1BA5A8CF_png" src="../../_images/10000000000005E20000009B1BA5A8CF.png" style="width: 6.5in; height: 0.6689in;" /></p>
++</div>
++<div class="section" id="sftp">
++<h4>SFTP<a class="headerlink" href="#sftp" title="Permalink to this headline">¶</a></h4>
++<p>Mounts a folder on a remote SSH server.</p>
++<p><img alt="10000000000005FF0000005F35710398_png" src="../../_images/10000000000005FF0000005F35710398.png" style="width: 6.5in; height: 0.402in;" /></p>
++<ul class="simple">
++<li>URL – The hostname of the SSH server.</li>
++<li>Username – The username used to login to the SSH server.</li>
++<li>Password – The password used to login to the SSH server.</li>
++<li>Root – The folder inside the SSH server to mount (optional, defaults to ‘/’)</li>
++<li>Applicable – A list users of who can see this mount</li>
++</ul>
++<p><img alt="10000000000005970000006AE23997C9_png" src="../../_images/10000000000005970000006AE23997C9.png" style="width: 6.5in; height: 0.4811in;" /></p>
++<div class="admonition note">
++<p class="first admonition-title">Note</p>
++<p class="last">When configured correctly, a Green Light will appear next to the
++Folder Name.  If misconfigured, a Red Light will appear.</p>
++</div>
++<p><img alt="10000000000005EB000000A68BA73E2D_png" src="../../_images/10000000000005EB000000A68BA73E2D.png" style="width: 6.5in; height: 0.7126in;" /></p>
++</div>
++<div class="section" id="irods">
++<h4>iRODS<a class="headerlink" href="#irods" title="Permalink to this headline">¶</a></h4>
++<p>Mounts a folder on a iRODS server.</p>
++<p><img alt="100000000000062A0000005F61A18950_png" src="../../_images/100000000000062A0000005F61A18950.png" style="width: 6.5in; height: 0.3909in;" /></p>
++<ul class="simple">
++<li>Host</li>
++<li>Port</li>
++<li>Use ownCloud login</li>
++<li>Username</li>
++<li>Password</li>
++<li>Authentication Mode</li>
++<li>Zone</li>
++<li>Applicable – A list users of who can see this mount</li>
++</ul>
++<div class="admonition note">
++<p class="first admonition-title">Note</p>
++<p class="last">When configured correctly, a Green Light will appear next to the
++Folder Name.  If misconfigured, a Red Light will appear.</p>
++</div>
++</div>
++</div>
++<div class="section" id="configuration-file">
++<h3>Configuration File<a class="headerlink" href="#configuration-file" title="Permalink to this headline">¶</a></h3>
++<p>The configuration of mounts created within the External Storage App are stored in the
++<tt class="docutils literal"><span class="pre">data/mount.json</span></tt> file.
++This file contains all settings in JSON (JavaScript Object Notation) format.
++Two different types of entries exist:</p>
++<ul class="simple">
++<li>Group mounts -
++Each entry configures a mount for each user in group</li>
++<li>User mount – Each entry configures a mount for a single user or all users.</li>
++</ul>
++<p>For each type, there is a JSON array with the user/group name as key and an array of configuration values as the value.
++Each entry consist of the class name of the storage backend and an array of backend specific options (described above) and will be replaced by the user login.</p>
++<p>Although configuration may be done by making modifications to the mount.json file, it is recommended to use the Web-GUI in the administrator panel (as described in the above section) to add, remove, or modify mount options in order to prevent any problems.</p>
++</div>
++</div>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/apps/files_sharing/index.html
index ee56d2f,0000000..d3c8ee1
mode 100644,000000..100644
--- a/core/doc/admin/apps/files_sharing/index.html
+++ b/core/doc/admin/apps/files_sharing/index.html
@@@ -1,165 -1,0 +1,258 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
-     <title><no title> — ownCloud Administrators Manual 6.0 documentation</title>
++    <title>Sharing — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../../index.html" />
++    <link rel="up" title="Apps" href="../index.html" />
++    <link rel="next" title="Deleted Files" href="../files_trashbin/index.html" />
++    <link rel="prev" title="External storage support" href="../files_external/index.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
- <ul>
++<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../../installation/index.html">Installation</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../../configuration/index.html">Configuration</a></li>
++<li class="toctree-l1 current"><a class="reference internal" href="../index.html">Apps</a><ul class="current">
++<li class="toctree-l2"><a class="reference internal" href="../activity/index.html">Activity</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../admin_dependencies_chk/index.html">Finding Deployment Dependencies</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../files_antivirus/index.html">File Antivirus Engine</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../files_encryption/index.html">Encryption</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../files_external/index.html">External storage support</a></li>
++<li class="toctree-l2 current"><a class="current reference internal" href="">Sharing</a><ul>
++<li class="toctree-l3"><a class="reference internal" href="#configuration">Configuration</a></li>
++<li class="toctree-l3"><a class="reference internal" href="#utilization">Utilization</a></li>
++<li class="toctree-l3"><a class="reference internal" href="#retrieving-shared-data">Retrieving shared data</a></li>
++</ul>
++</li>
++<li class="toctree-l2"><a class="reference internal" href="../files_trashbin/index.html">Deleted Files</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../files_versions/index.html">Versions</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../firstrunwizard/index.html">First Run Wizard</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../user_ldap/index.html">LDAP user and group backend</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../viewers/index.html">File Viewers</a></li>
++</ul>
++</li>
 +<li class="toctree-l1"><a class="reference internal" href="../../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../../config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
-   <p><strong>ownCloud Sharing App</strong></p>
- <div class="toctree-wrapper compound">
- <ul>
- <li class="toctree-l1"><a class="reference internal" href="Table_of_Contents.html">Table of Contents</a></li>
- <li class="toctree-l1"><a class="reference internal" href="Introduction.html">Introduction</a></li>
- <li class="toctree-l1"><a class="reference internal" href="Configuration.html">Configuration</a><ul>
- <li class="toctree-l2"><a class="reference internal" href="Configuration.html#enable-the-app">Enable the app</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Configuration.html#configuring-the-permitted-functionality">Configuring the permitted functionality</a></li>
- </ul>
- </li>
- <li class="toctree-l1"><a class="reference internal" href="Utilization.html">Utilization</a><ul>
- <li class="toctree-l2"><a class="reference internal" href="Utilization.html#share-with-another-owncloud-user">Share with another ownCloud user</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Utilization.html#setting-permissions-on-the-share">Setting Permissions on the share</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Utilization.html#share-as-a-link">Share as a link</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Utilization.html#setting-expiration-date">Setting Expiration Date</a></li>
- </ul>
- </li>
- <li class="toctree-l1"><a class="reference internal" href="Retrieving_shared_data.html">Retrieving shared data</a><ul>
- <li class="toctree-l2"><a class="reference internal" href="Retrieving_shared_data.html#user-group-shares">User/group shares</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Retrieving_shared_data.html#share-as-link">Share as link</a></li>
- </ul>
- </li>
- </ul>
++  <div class="section" id="sharing">
++<h1>Sharing<a class="headerlink" href="#sharing" title="Permalink to this headline">¶</a></h1>
++<p>ownCloud allows users to share files and folders with both other ownCloud
++users, as well as publicly via a link.  Sharing may be done either via the web
++interface or via the Sharing API.  This document will discuss the web interface
++and sharing. For information on the Sharing API, please refer to that document.</p>
++<div class="section" id="configuration">
++<h2>Configuration<a class="headerlink" href="#configuration" title="Permalink to this headline">¶</a></h2>
++<div class="section" id="enable-the-app">
++<h3>Enable the app<a class="headerlink" href="#enable-the-app" title="Permalink to this headline">¶</a></h3>
++<p>The Share Files app is enabled by default. To verify this and/or disable this functionality,
++navigate to the APPS page in the web interface and select “Share Files”</p>
++<p><img alt="1000000000000167000000B43E4BF478_png" src="../../_images/1000000000000167000000B43E4BF478.png" style="width: 3.7398in; height: 1.8752in;" /></p>
++</div>
++<div class="section" id="configuring-the-permitted-functionality">
++<h3>Configuring the permitted functionality<a class="headerlink" href="#configuring-the-permitted-functionality" title="Permalink to this headline">¶</a></h3>
++<p>There are several functions which may be enabled or disabled at the admin’s discretion.
++To configure these functions, navigate to the Admin page in the web interface and scroll to the “Sharing” section.</p>
++<p><img alt="10000000000001CF00000176B0BE1EBC_png" src="../../_images/10000000000001CF00000176B0BE1EBC.png" style="width: 4.8228in; height: 3.8957in;" /></p>
++<p>The above parameters are self-explanatory and may be enabled or disabled as required.</p>
++</div>
++</div>
++<div class="section" id="utilization">
++<h2>Utilization<a class="headerlink" href="#utilization" title="Permalink to this headline">¶</a></h2>
++<p>An ownCloud user may share files or entire folders with other individuals.
++The method of sharing is the same.</p>
++<div class="section" id="share-with-another-owncloud-user">
++<h3>Share with another ownCloud user<a class="headerlink" href="#share-with-another-owncloud-user" title="Permalink to this headline">¶</a></h3>
++<p>Hover over the line containing the file or folder to be shared.
++And then select Share.
++The following dialog appears.</p>
++<p><img alt="10000000000003EC000000AB60616FA7_png" src="../../_images/10000000000003EC000000AB60616FA7.png" style="width: 6.5in; height: 1.1071in;" /></p>
++<p>In the “share with user or group” text box, enter the user to share with, or the group to share with.
++Note, as letters are typed, the users and groups who match the typed string will appear.
++As a short cut, simply select the desired user/group</p>
++</div>
++<div class="section" id="setting-permissions-on-the-share">
++<h3>Setting Permissions on the share<a class="headerlink" href="#setting-permissions-on-the-share" title="Permalink to this headline">¶</a></h3>
++<p>When a file or folder is shared, the permissions may be modified stating what the other user may do with the file/folder.
++Once the share with user or group has been entered, the dialog will expand as follows.</p>
++<p><img alt="1000000000000404000000FCFC13E732_png" src="../../_images/1000000000000404000000FCFC13E732.png" style="width: 6.5in; height: 1.5929in;" /></p>
++<p>If the shared with user has an email address configured, the sharing user may choose to notify the shared with user of the share.
++To do this, select the checkbox next to “notify by email”.
++It is important to note, this checkbox appears whether or not the shared with user has email configured.</p>
++<p>When sharing a file/folder, it is obvious that the file may be viewed or downloaded.
++However, if the shared with user is allowed to modify the file in any way, the “can edit” box should be checked.
++The sharing user may allow the shared with user to update, delete, or re-share the file.
++Note, by default, all permissions are set.</p>
++<p>It should be noted that when sharing a folder, an additional permission, “create” is available.
++When enabled, the shared to users can create new files and folders within the shared folder.</p>
++</div>
++<div class="section" id="share-as-a-link">
++<h3>Share as a link<a class="headerlink" href="#share-as-a-link" title="Permalink to this headline">¶</a></h3>
++<p>In the event that an ownCloud user desires to share a file with a non-ownCloud user, the file may be shared as a link.
++To share as a link, hover over the line containing the file and select Share.
++Then select the check box next to “Share link”</p>
++<p><img alt="10000000000003E8000001524A147A04_png" src="../../_images/10000000000003E8000001524A147A04.png" style="width: 6.5in; height: 2.1965in;" /></p>
++<p>The link is then shown in the text box.
++The link may be copied and pasted into an email and sent to the other user.
++Alternatively, if email is setup within ownCloud, the sharing user may input the shared with user’s email address in the text box and select send.
++The shared user will then receive an email from the ownCloud server with the link.</p>
++<p>There may be circumstances where the file owner wants some security on the link so it cannot be accessed by anyone other than the desired person.
++To do this, the link may be Password Protected by selecting the “Password Protect” checkbox and entering a desired password.</p>
++<p><img alt="1000000000000403000001632F0B76F6_png" src="../../_images/1000000000000403000001632F0B76F6.png" style="width: 6.5in; height: 2.2465in;" /></p>
++</div>
++<div class="section" id="setting-expiration-date">
++<h3>Setting Expiration Date<a class="headerlink" href="#setting-expiration-date" title="Permalink to this headline">¶</a></h3>
++<p>ownCloud allows the sharing user to expire a file or folder share at a given date.
++This expiration applies to all shares within the folder as well.
++So, if a user expires a folder share, all files within the folder will no longer be shared.</p>
++<p>To set an expiration, select the Set expiration date checkbox and then select the expiration date.
++(The calendar will appear when the mouse is clicked in the Expiration date text box.</p>
++<p><img alt="10000000000004010000017E4A6552BC_png" src="../../_images/10000000000004010000017E4A6552BC.png" style="width: 6.5in; height: 2.422in;" /></p>
++</div>
++</div>
++<div class="section" id="retrieving-shared-data">
++<h2>Retrieving shared data<a class="headerlink" href="#retrieving-shared-data" title="Permalink to this headline">¶</a></h2>
++<div class="section" id="user-group-shares">
++<h3>User/group shares<a class="headerlink" href="#user-group-shares" title="Permalink to this headline">¶</a></h3>
++<p>When the shared with user logs into their ownCloud instance they will see a “Shared” folder.</p>
++<p><img alt="100000000000046C000000C2D3E5CF30_png" src="../../_images/100000000000046C000000C2D3E5CF30.png" style="width: 6.5in; height: 1.1138in;" /></p>
++<p>Within that Shared folder are all files and folders which have been shared to that user by any other ownCloud user.</p>
++<p><img alt="1000000000000462000000D44541CF9A_png" src="../../_images/1000000000000462000000D44541CF9A.png" style="width: 6.5in; height: 1.2283in;" /></p>
++</div>
++<div class="section" id="share-as-link">
++<h3>Share as link<a class="headerlink" href="#share-as-link" title="Permalink to this headline">¶</a></h3>
++<p>To view a file/folder which was shared as a link, simply enter the link into the browser.</p>
++<p><img alt="10000000000004CA000002B52116BE0C_png" src="../../_images/10000000000004CA000002B52116BE0C.png" style="width: 6.5in; height: 3.6744in;" /></p>
++<p>To download the file/folder select the Download button on the upper right of the page.
++If this link was password protected, the user will be prompted with a password prior to this page appearing.</p>
++<p><img alt="100000000000045800000197FE462F2B_png" src="../../_images/100000000000045800000197FE462F2B.png" style="width: 6.5in; height: 2.3791in;" /></p>
++</div>
++</div>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/apps/files_trashbin/index.html
index b81d195,0000000..a4b93e3
mode 100644,000000..100644
--- a/core/doc/admin/apps/files_trashbin/index.html
+++ b/core/doc/admin/apps/files_trashbin/index.html
@@@ -1,166 -1,0 +1,277 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
-     <title><no title> — ownCloud Administrators Manual 6.0 documentation</title>
++    <title>Deleted Files — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../../index.html" />
++    <link rel="up" title="Apps" href="../index.html" />
++    <link rel="next" title="Versions" href="../files_versions/index.html" />
++    <link rel="prev" title="Sharing" href="../files_sharing/index.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
- <ul>
++<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../../installation/index.html">Installation</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../../configuration/index.html">Configuration</a></li>
++<li class="toctree-l1 current"><a class="reference internal" href="../index.html">Apps</a><ul class="current">
++<li class="toctree-l2"><a class="reference internal" href="../activity/index.html">Activity</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../admin_dependencies_chk/index.html">Finding Deployment Dependencies</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../files_antivirus/index.html">File Antivirus Engine</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../files_encryption/index.html">Encryption</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../files_external/index.html">External storage support</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../files_sharing/index.html">Sharing</a></li>
++<li class="toctree-l2 current"><a class="current reference internal" href="">Deleted Files</a><ul>
++<li class="toctree-l3"><a class="reference internal" href="#expiry-of-deleted-files">Expiry of deleted files</a></li>
++<li class="toctree-l3"><a class="reference internal" href="#configuration-and-storage">Configuration and storage</a></li>
++<li class="toctree-l3"><a class="reference internal" href="#utilization">Utilization</a></li>
++</ul>
++</li>
++<li class="toctree-l2"><a class="reference internal" href="../files_versions/index.html">Versions</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../firstrunwizard/index.html">First Run Wizard</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../user_ldap/index.html">LDAP user and group backend</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../viewers/index.html">File Viewers</a></li>
++</ul>
++</li>
 +<li class="toctree-l1"><a class="reference internal" href="../../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../../config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
-   <p><strong>ownCloud Deleted Files</strong></p>
- <div class="toctree-wrapper compound">
- <ul>
- <li class="toctree-l1"><a class="reference internal" href="Table_of_Contents.html">Table of Contents</a></li>
- <li class="toctree-l1"><a class="reference internal" href="Introduction.html">Introduction</a><ul>
- <li class="toctree-l2"><a class="reference internal" href="Introduction.html#expiry-of-deleted-files">Expiry of deleted files</a></li>
- </ul>
- </li>
- <li class="toctree-l1"><a class="reference internal" href="Configuration_and_storage_.html">Configuration and storage</a><ul>
- <li class="toctree-l2"><a class="reference internal" href="Configuration_and_storage_.html#configuration">Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Configuration_and_storage_.html#storage">Storage</a></li>
- </ul>
- </li>
- <li class="toctree-l1"><a class="reference internal" href="Utilization.html">Utilization</a><ul>
- <li class="toctree-l2"><a class="reference internal" href="Utilization.html#delete-a-file">Delete a file</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Utilization.html#view-deleted-files">View Deleted Files</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Utilization.html#restore-files">Restore files</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Utilization.html#permanently-delete-files">Permanently Delete Files</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Utilization.html#nested-files-and-restore">Nested files and restore</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Utilization.html#shared-files-and-restore">Shared files and restore</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Utilization.html#restore-files-with-versions">Restore files with Versions</a></li>
- </ul>
- </li>
- </ul>
++  <div class="section" id="deleted-files">
++<h1>Deleted Files<a class="headerlink" href="#deleted-files" title="Permalink to this headline">¶</a></h1>
++<p>The ownCloud server stores deleted files in a temporary area in the event that the file was inadvertently deleted and/or needs to be restored.</p>
++<div class="section" id="expiry-of-deleted-files">
++<h2>Expiry of deleted files<a class="headerlink" href="#expiry-of-deleted-files" title="Permalink to this headline">¶</a></h2>
++<p>There are two instances in which ownCloud will automatically permanently remove a deleted file.</p>
++<div class="section" id="disk-utilization">
++<h3>Disk Utilization<a class="headerlink" href="#disk-utilization" title="Permalink to this headline">¶</a></h3>
++<p>To prevent a user from running out of disk space, the ownCloud deleted files app will not utilize more than 50% of the currently available free space for deleted files.
++If the deleted files exceed this limit, ownCloud deletes the oldest files until it gets below this limit.</p>
++</div>
++<div class="section" id="age">
++<h3>Age<a class="headerlink" href="#age" title="Permalink to this headline">¶</a></h3>
++<p>By default, deleted files remain in the trash bin for 30 days.
++This can be configured using the trashbin_retention_obligation parameter
++in the <tt class="docutils literal"><span class="pre">config.php</span></tt> file.
++Files older than the configured value (or default 30 days) will be permanently deleted.
++ownCloud checks the age of the files each time a new file is moved to the deleted files bin.</p>
++</div>
++</div>
++<div class="section" id="configuration-and-storage">
++<h2>Configuration and storage<a class="headerlink" href="#configuration-and-storage" title="Permalink to this headline">¶</a></h2>
++<div class="section" id="configuration">
++<h3>Configuration<a class="headerlink" href="#configuration" title="Permalink to this headline">¶</a></h3>
++<p>By default, the ownCloud deleted files app is enabled.
++To verify or disable, navigate to the apps
++page and select Deleted Files.</p>
++<p><img alt="100000000000042F000000CC3EDDE79E_png" src="../../_images/100000000000042F000000CC3EDDE79E.png" style="width: 6.5in; height: 1.2382in;" /></p>
++</div>
++<div class="section" id="storage">
++<h3>Storage<a class="headerlink" href="#storage" title="Permalink to this headline">¶</a></h3>
++<p>Once a file has been deleted by the user, it is moved to the <tt class="docutils literal"><span class="pre">~/data/<user>/files_trashbin/files</span></tt> folder.</p>
++<p><img alt="10000000000002B3000000365E1CD00D_png" src="../../_images/10000000000002B3000000365E1CD00D.png" style="width: 6.5in; height: 0.5075in;" /></p>
++<p>The remaining directories retain information on encryption key files, and versions.</p>
++</div>
++</div>
++<div class="section" id="utilization">
++<h2>Utilization<a class="headerlink" href="#utilization" title="Permalink to this headline">¶</a></h2>
++<p>The deleted files app, when enabled, automatically moves deleted files to the Deleted Files folder and leaves them available for restore or permanent deletion</p>
++<div class="section" id="delete-a-file">
++<h3>Delete a file<a class="headerlink" href="#delete-a-file" title="Permalink to this headline">¶</a></h3>
++<p>To delete a file, either select the file check box and select Delete
++on the upper right of the screen, or the “x” to the right of the file.</p>
++<p><img alt="1000000000000530000001410CF0028A_png" src="../../_images/1000000000000530000001410CF0028A.png" style="width: 6.5in; height: 1.5701in;" /></p>
++<p>To delete multiple files simultaneously, select the check box on all the desired files, then select Delete
++on the upper right of the screen.</p>
++</div>
++<div class="section" id="view-deleted-files">
++<h3>View Deleted Files<a class="headerlink" href="#view-deleted-files" title="Permalink to this headline">¶</a></h3>
++<p>To view a list of the deleted files, select the Deleted files
++button on the upper right of the browser.</p>
++<p><img alt="1000000000000532000000285DDBBF37_png" src="../../_images/1000000000000532000000285DDBBF37.png" style="width: 6.5in; height: 0.1957in;" /></p>
++<p>Once selected, a list of all deleted files will appear.</p>
++</div>
++<div class="section" id="restore-files">
++<h3>Restore files<a class="headerlink" href="#restore-files" title="Permalink to this headline">¶</a></h3>
++<p>As with deleting files, there are two ways to restore a file.
++Either select the check box next to the file (or for bulk restore – files) and select restore
++on the upper right.
++Or hover over the file and select restore
++.</p>
++<p><img alt="1000000000000527000000A7AB409FE0_png" src="../../_images/1000000000000527000000A7AB409FE0.png" style="width: 6.5in; height: 0.8228in;" />
++<img alt="100000000000052500000088DBB95005_png" src="../../_images/100000000000052500000088DBB95005.png" style="width: 6.5in; height: 0.6717in;" /></p>
++</div>
++<div class="section" id="permanently-delete-files">
++<h3>Permanently Delete Files<a class="headerlink" href="#permanently-delete-files" title="Permalink to this headline">¶</a></h3>
++<p>Files in the Deleted Files
++folder can be permanently deleted.
++To do this, either select the check box next to the file (or for bulk deletion – files) and select Delete in the upper right corner.
++Or hover over the file and select the “x”.</p>
++</div>
++<div class="section" id="nested-files-and-restore">
++<h3>Nested files and restore<a class="headerlink" href="#nested-files-and-restore" title="Permalink to this headline">¶</a></h3>
++<p>If, for instance, the directory structure within ownCloud is
++<em>~/public/support/documentation/ownCloud undelete</em>
++.</p>
++<p><img alt="1000000000000525000000BE30CF0423_png" src="../../_images/1000000000000525000000BE30CF0423.png" style="width: 6.5in; height: 0.9374in;" /></p>
++<div class="section" id="delete-entire-directory-structure">
++<h4>Delete entire directory structure<a class="headerlink" href="#delete-entire-directory-structure" title="Permalink to this headline">¶</a></h4>
++<p>When the public folder is deleted, all child folders/files will also be deleted.</p>
++<p><img alt="100000000000052F000000C2867B7294_png" src="../../_images/100000000000052F000000C2867B7294.png" style="width: 6.5in; height: 0.95in;" /></p>
++<p>Suppose the file “ownCloud undelete.docx” was still required.
++A restore of the file will place it in the ‘root’ directory of the Files folder.</p>
++</div>
++<div class="section" id="delete-only-the-file">
++<h4>Delete only the file<a class="headerlink" href="#delete-only-the-file" title="Permalink to this headline">¶</a></h4>
++<p>If the file “ownCloud undelete.docx”
++was accidentally deleted, it may be restored following the steps described in section
++.
++The restore will place the file back into the directory structure from where it came.</p>
++</div>
++<div class="section" id="delete-the-file-then-the-directory-structure">
++<h4>Delete the file then the directory structure<a class="headerlink" href="#delete-the-file-then-the-directory-structure" title="Permalink to this headline">¶</a></h4>
++<p>If the file “ownCloud undelete.docs”
++is deleted, then the entire directory structure is deleted, the file will appear in the ‘root’ of the Deleted Files folder.</p>
++<p><img alt="1000000000000523000000C6F786381C_png" src="../../_images/1000000000000523000000C6F786381C.png" style="width: 6.5in; height: 0.9783in;" /></p>
++<p>A restore of “ownCloud undelete.docx”
++will place it in the user’s ownCloud root directory.</p>
++<p><img alt="100000000000053100000142D9A4C916_png" src="../../_images/100000000000053100000142D9A4C916.png" style="width: 6.5in; height: 1.5752in;" /></p>
++</div>
++</div>
++<div class="section" id="shared-files-and-restore">
++<h3>Shared files and restore<a class="headerlink" href="#shared-files-and-restore" title="Permalink to this headline">¶</a></h3>
++<p>When a
++shared file is deleted, the file will be deleted from the shared to user as well.
++Upon restore of the file by the file owner, the file is no longer shared.</p>
++</div>
++<div class="section" id="restore-files-with-versions">
++<h3>Restore files with Versions<a class="headerlink" href="#restore-files-with-versions" title="Permalink to this headline">¶</a></h3>
++<p>When a file which has versions has been deleted, and then restored, the versions will exist upon restoration.</p>
++</div>
++</div>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/apps/files_versions/index.html
index 7ec7d8b,0000000..c829273
mode 100644,000000..100644
--- a/core/doc/admin/apps/files_versions/index.html
+++ b/core/doc/admin/apps/files_versions/index.html
@@@ -1,169 -1,0 +1,271 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
-     <title><no title> — ownCloud Administrators Manual 6.0 documentation</title>
++    <title>Versions — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../../index.html" />
++    <link rel="up" title="Apps" href="../index.html" />
++    <link rel="next" title="First Run Wizard" href="../firstrunwizard/index.html" />
++    <link rel="prev" title="Deleted Files" href="../files_trashbin/index.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
- <ul>
++<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../../installation/index.html">Installation</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../../configuration/index.html">Configuration</a></li>
++<li class="toctree-l1 current"><a class="reference internal" href="../index.html">Apps</a><ul class="current">
++<li class="toctree-l2"><a class="reference internal" href="../activity/index.html">Activity</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../admin_dependencies_chk/index.html">Finding Deployment Dependencies</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../files_antivirus/index.html">File Antivirus Engine</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../files_encryption/index.html">Encryption</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../files_external/index.html">External storage support</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../files_sharing/index.html">Sharing</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../files_trashbin/index.html">Deleted Files</a></li>
++<li class="toctree-l2 current"><a class="current reference internal" href="">Versions</a><ul>
++<li class="toctree-l3"><a class="reference internal" href="#expiry-of-versions">Expiry of versions</a></li>
++<li class="toctree-l3"><a class="reference internal" href="#space-limitations">Space limitations</a></li>
++<li class="toctree-l3"><a class="reference internal" href="#configuration-and-storage">Configuration and storage</a></li>
++<li class="toctree-l3"><a class="reference internal" href="#utilization">Utilization</a></li>
++</ul>
++</li>
++<li class="toctree-l2"><a class="reference internal" href="../firstrunwizard/index.html">First Run Wizard</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../user_ldap/index.html">LDAP user and group backend</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../viewers/index.html">File Viewers</a></li>
++</ul>
++</li>
 +<li class="toctree-l1"><a class="reference internal" href="../../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../../config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
-   <p><strong>ownCloud Versioning</strong></p>
- <p>Table of Contents</p>
- <p>` <#_Toc374004001>`_</p>
- <p>Reviewers</p>
- <p>Allen Gigler 12/4/2013</p>
- <div class="toctree-wrapper compound">
- <ul>
- <li class="toctree-l1"><a class="reference internal" href="Introduction.html">Introduction</a><ul>
- <li class="toctree-l2"><a class="reference internal" href="Introduction.html#expiry-of-versions">Expiry of versions</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Introduction.html#space-limitations">Space limitations</a></li>
- </ul>
- </li>
- <li class="toctree-l1"><a class="reference internal" href="Configuration_and_storage.html">Configuration and storage</a><ul>
- <li class="toctree-l2"><a class="reference internal" href="Configuration_and_storage.html#configuration">Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Configuration_and_storage.html#storage">Storage</a></li>
- </ul>
- </li>
- <li class="toctree-l1"><a class="reference internal" href="Utilization.html">Utilization</a><ul>
- <li class="toctree-l2"><a class="reference internal" href="Utilization.html#initial-file-creation">Initial File creation</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Utilization.html#edit-the-file">Edit the file</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Utilization.html#create-version">Create version</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Utilization.html#accessing-versions">Accessing Versions</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Utilization.html#reverting-to-a-different-version">Reverting to a different version</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Utilization.html#sharing-and-versions">Sharing and Versions</a></li>
- </ul>
- </li>
++  <div class="section" id="versions">
++<h1>Versions<a class="headerlink" href="#versions" title="Permalink to this headline">¶</a></h1>
++<p>The ownCloud Versions app maintains older versions of a file which have been
++modified by an ownCloud user.</p>
++<div class="section" id="expiry-of-versions">
++<h2>Expiry of versions<a class="headerlink" href="#expiry-of-versions" title="Permalink to this headline">¶</a></h2>
++<p>The versions app expires old versions automatically to make certain that the
++user doesn’t run out of space.  The following algorithm is used to delete old
++versions:</p>
++<ul class="simple">
++<li>ownCloud keeps one new version every 2 seconds for the first 10 seconds</li>
++<li>ownCloud keeps one new version every minute for the first hour</li>
++<li>ownCloud keeps one new version every hour for the first 24 hours</li>
++<li>ownCloud keeps one new version every day for the first 30 days</li>
++<li>ownCloud keeps one new version every week thereafter.</li>
 +</ul>
++<p>The versions are adjusted along this algorithm every time a new version is created.</p>
++</div>
++<div class="section" id="space-limitations">
++<h2>Space limitations<a class="headerlink" href="#space-limitations" title="Permalink to this headline">¶</a></h2>
++<p>In addition to the expiry of versions, ownCloud’s versions app makes certain
++never to use more than 50% of the user’s currently available free space.  If
++stored versions exceed this limit, ownCloud will delete the oldest versions
++first until it meets this limit.</p>
++</div>
++<div class="section" id="configuration-and-storage">
++<h2>Configuration and storage<a class="headerlink" href="#configuration-and-storage" title="Permalink to this headline">¶</a></h2>
++<div class="section" id="configuration">
++<h3>Configuration<a class="headerlink" href="#configuration" title="Permalink to this headline">¶</a></h3>
++<p>By default, the ownCloud versions app is enabled.
++To verify or disable, navigate to the apps
++page and select Versions.</p>
++<p><img alt="1000000000000336000000F38C3FAF84_png" src="../../_images/1000000000000336000000F38C3FAF84.png" style="width: 6.5in; height: 1.9217in;" /></p>
++</div>
++<div class="section" id="storage">
++<h3>Storage<a class="headerlink" href="#storage" title="Permalink to this headline">¶</a></h3>
++<p>Previous versions of files are stored in the <tt class="docutils literal"><span class="pre">data/<user>/files_versions</span></tt> folder.</p>
++<p><img alt="100000000000021C0000004CACBF786C_png" src="../../_images/100000000000021C0000004CACBF786C.png" style="width: 5.6252in; height: 0.7917in;" /></p>
++<p>This directory is automatically created when the first file version is created.</p>
++<p>The naming convention of the files in this directory are:</p>
++<div class="highlight-python"><pre><file_name>.v<unix_timestamp></pre>
++</div>
++<p><img alt="10000000000002210000002DE3BE7515_png" src="../../_images/10000000000002210000002DE3BE7515.png" style="width: 5.6772in; height: 0.4689in;" /></p>
++</div>
++</div>
++<div class="section" id="utilization">
++<h2>Utilization<a class="headerlink" href="#utilization" title="Permalink to this headline">¶</a></h2>
++<p>The versions app, when enabled, automatically creates a new version each time an existing, non-empty file is saved.</p>
++<div class="section" id="initial-file-creation">
++<h3>Initial File creation<a class="headerlink" href="#initial-file-creation" title="Permalink to this headline">¶</a></h3>
++<p>Create a file on the ownCloud server – either directly via the browser, an upload, or a file sync from the client.
++In this example, the file versionText.txt was created via the web browser.</p>
++<p><img alt="1000000000000427000000324F58266D_png" src="../../_images/1000000000000427000000324F58266D.png" style="width: 6.5in; height: 0.3055in;" /></p>
++<div class="section" id="note">
++<h4>Note<a class="headerlink" href="#note" title="Permalink to this headline">¶</a></h4>
++<p>Since this file was initially created via the web browser, it is an empty file.</p>
++</div>
++</div>
++<div class="section" id="edit-the-file">
++<h3>Edit the file<a class="headerlink" href="#edit-the-file" title="Permalink to this headline">¶</a></h3>
++<p>Edit the file through the web browser.</p>
++<p><img alt="100000000000019E0000004CD2A0F407_png" src="../../_images/100000000000019E0000004CD2A0F407.png" style="width: 4.3126in; height: 0.7917in;" /></p>
++<p>And save.</p>
++<div class="section" id="notes">
++<h4>Notes<a class="headerlink" href="#notes" title="Permalink to this headline">¶</a></h4>
++<p>Editing an empty file, as in this instance, for the first time, does not create a new version.</p>
++</div>
++</div>
++<div class="section" id="create-version">
++<h3>Create version<a class="headerlink" href="#create-version" title="Permalink to this headline">¶</a></h3>
++<p>Edit the non-zero byte file either via the web browser, via the sync client or via an upload.</p>
++<p><img alt="1000000000000194000000498325A766_png" src="../../_images/1000000000000194000000498325A766.png" style="width: 4.2083in; height: 0.7602in;" /></p>
++<p>And save.</p>
++<div class="section" id="id1">
++<h4>Notes<a class="headerlink" href="#id1" title="Permalink to this headline">¶</a></h4>
++<p>When performing an upload of a file which already exists on the server, a dialog box appears asking whether to keep the existing file or the new file.</p>
++<p><img alt="10000000000001C1000000FE663748B2_png" src="../../_images/10000000000001C1000000FE663748B2.png" style="width: 4.6772in; height: 2.6457in;" /></p>
++<p>In order to create a version, the New File must be selected.
++If the Existing File is selected, the file is not replaced hence no new version is created.</p>
++</div>
++</div>
++<div class="section" id="accessing-versions">
++<h3>Accessing Versions<a class="headerlink" href="#accessing-versions" title="Permalink to this headline">¶</a></h3>
++<p>In order to view what versions exist for a given file, hover over the line containing the file and select Versions
++on the right side.</p>
++<p><img alt="1000000000000430000000AF9D6E724E_png" src="../../_images/1000000000000430000000AF9D6E724E.png" style="width: 6.5in; height: 1.061in;" /></p>
++<p>In this case, there are two previous versions of versionTest.txt
++.
++The thumbnail and creation time can be used to identify what was in the file in that version.</p>
++</div>
++<div class="section" id="reverting-to-a-different-version">
++<h3>Reverting to a different version<a class="headerlink" href="#reverting-to-a-different-version" title="Permalink to this headline">¶</a></h3>
++<p>To revert to a previous version, simply select the restore next to the version as seen in
++.</p>
++<div class="section" id="id2">
++<h4>Notes<a class="headerlink" href="#id2" title="Permalink to this headline">¶</a></h4>
++<p>In the instance where a file is reverted to another version, the “existing” version of the file is versioned and can be reverted at a later date.</p>
++</div>
++</div>
++<div class="section" id="sharing-and-versions">
++<h3>Sharing and Versions<a class="headerlink" href="#sharing-and-versions" title="Permalink to this headline">¶</a></h3>
++<p>If user-A shares a file with user-B, user-B may revert the file to any previous version.
++If user-B modifies the file, a new version is created.</p>
++</div>
++</div>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/apps/firstrunwizard/index.html
index 34fe1e3,0000000..e7a371e
mode 100644,000000..100644
--- a/core/doc/admin/apps/firstrunwizard/index.html
+++ b/core/doc/admin/apps/firstrunwizard/index.html
@@@ -1,157 -1,0 +1,206 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
-     <title><no title> — ownCloud Administrators Manual 6.0 documentation</title>
++    <title>First Run Wizard — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../../index.html" />
++    <link rel="up" title="Apps" href="../index.html" />
++    <link rel="next" title="LDAP user and group backend" href="../user_ldap/index.html" />
++    <link rel="prev" title="Versions" href="../files_versions/index.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
- <ul>
++<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../../installation/index.html">Installation</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../../configuration/index.html">Configuration</a></li>
++<li class="toctree-l1 current"><a class="reference internal" href="../index.html">Apps</a><ul class="current">
++<li class="toctree-l2"><a class="reference internal" href="../activity/index.html">Activity</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../admin_dependencies_chk/index.html">Finding Deployment Dependencies</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../files_antivirus/index.html">File Antivirus Engine</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../files_encryption/index.html">Encryption</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../files_external/index.html">External storage support</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../files_sharing/index.html">Sharing</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../files_trashbin/index.html">Deleted Files</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../files_versions/index.html">Versions</a></li>
++<li class="toctree-l2 current"><a class="current reference internal" href="">First Run Wizard</a><ul>
++<li class="toctree-l3"><a class="reference internal" href="#configuration">Configuration</a></li>
++<li class="toctree-l3"><a class="reference internal" href="#usage">Usage</a></li>
++<li class="toctree-l3"><a class="reference internal" href="#links">Links</a></li>
++</ul>
++</li>
++<li class="toctree-l2"><a class="reference internal" href="../user_ldap/index.html">LDAP user and group backend</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../viewers/index.html">File Viewers</a></li>
++</ul>
++</li>
 +<li class="toctree-l1"><a class="reference internal" href="../../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../../config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
-   <p><strong>ownCloud First Run Wizard</strong></p>
- <div class="toctree-wrapper compound">
- <ul>
- <li class="toctree-l1"><a class="reference internal" href="Table_of_Contents.html">Table of Contents</a></li>
- <li class="toctree-l1"><a class="reference internal" href="Introduction.html">Introduction</a></li>
- <li class="toctree-l1"><a class="reference internal" href="Configuration.html">Configuration</a></li>
- <li class="toctree-l1"><a class="reference internal" href="Usage.html">Usage</a></li>
- <li class="toctree-l1"><a class="reference internal" href="Links.html">Links</a><ul>
- <li class="toctree-l2"><a class="reference internal" href="Links.html#desktop-app">Desktop App</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Links.html#android-app">Android App</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Links.html#ios-app">iOS App</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Links.html#access-files-via-webdav">Access files via WebDAV</a></li>
- </ul>
- </li>
- </ul>
++  <div class="section" id="first-run-wizard">
++<h1>First Run Wizard<a class="headerlink" href="#first-run-wizard" title="Permalink to this headline">¶</a></h1>
++<p>The ownCloud First Run Wizard is a welcome screen which links users to the various ownCloud utilities such as the Sync Client, Mobile Apps, and WebDav</p>
++<div class="section" id="configuration">
++<h2>Configuration<a class="headerlink" href="#configuration" title="Permalink to this headline">¶</a></h2>
++<p>The First Run Wizard app is enabled by default.
++To verify or disable this app, navigate to the apps page and select “First Run Wizard”</p>
++<p><img alt="1000000000000200000000BCCCC35DEB_png" src="../../_images/1000000000000200000000BCCCC35DEB.png" style="width: 5.3335in; height: 1.9583in;" /></p>
++</div>
++<div class="section" id="usage">
++<h2>Usage<a class="headerlink" href="#usage" title="Permalink to this headline">¶</a></h2>
++<p>When enabled, a user entering the ownCloud web browser for the first time will have the Welcome screen popup.</p>
++<p><img alt="10000000000004920000028D9C8DC2CB_png" src="../../_images/10000000000004920000028D9C8DC2CB.png" style="width: 6.5in; height: 3.628in;" /></p>
++<p>To close the window, select the ‘x’ in the upper right corner.
++If the user would like to bring up this window at a later time, they may do so by navigating to the Personal menu selection and select “Show First Run Wizard again”</p>
++<p><img alt="10000000000002A6000000BFBE298238_png" src="../../_images/10000000000002A6000000BFBE298238.png" style="width: 6.5in; height: 1.8311in;" /></p>
++</div>
++<div class="section" id="links">
++<h2>Links<a class="headerlink" href="#links" title="Permalink to this headline">¶</a></h2>
++<p>The wizard contains links for the Desktop app, Android App on Google Play, and iOS on the App store, as well as how to access files via WebDav.</p>
++<div class="section" id="desktop-app">
++<h3>Desktop App<a class="headerlink" href="#desktop-app" title="Permalink to this headline">¶</a></h3>
++<p>Selecting the Desktop App link will bring the user to ownCloud’s web site to download the client.</p>
++<p><img alt="1000000000000557000002E148BAB6D4_png" src="../../_images/1000000000000557000002E148BAB6D4.png" style="width: 6.5in; height: 3.5043in;" /></p>
++</div>
++<div class="section" id="android-app">
++<h3>Android App<a class="headerlink" href="#android-app" title="Permalink to this headline">¶</a></h3>
++<p>Selecting the Android App will load the web page to purchase the android client from the Google Play store.</p>
++<p><img alt="1000000000000668000002D29EAD9899_png" src="../../_images/1000000000000668000002D29EAD9899.png" style="width: 6.5in; height: 2.861in;" /></p>
++</div>
++<div class="section" id="ios-app">
++<h3>iOS App<a class="headerlink" href="#ios-app" title="Permalink to this headline">¶</a></h3>
++<p>Selecting the iOS App loads the itunes web page to obtain the ownCloud iOS mobile client.</p>
++<p><img alt="10000000000005F30000030F1372448D_png" src="../../_images/10000000000005F30000030F1372448D.png" style="width: 6.5in; height: 3.3417in;" /></p>
++</div>
++<div class="section" id="access-files-via-webdav">
++<h3>Access files via WebDAV<a class="headerlink" href="#access-files-via-webdav" title="Permalink to this headline">¶</a></h3>
++<p>This link brings up a link with documentation on how to access files on the ownCloud server using WebDAV.</p>
++<p><img alt="100000000000066D000001AAD8CE8256_png" src="../../_images/100000000000066D000001AAD8CE8256.png" style="width: 6.5in; height: 1.6835in;" /></p>
++</div>
++</div>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/apps/index.html
index 17bb1c8,0000000..14908bd
mode 100644,000000..100644
--- a/core/doc/admin/apps/index.html
+++ b/core/doc/admin/apps/index.html
@@@ -1,163 -1,0 +1,176 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
-     <title><no title> — ownCloud Administrators Manual 6.0 documentation</title>
++    <title>Apps — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
++    <link rel="next" title="Activity" href="activity/index.html" />
++    <link rel="prev" title="Serving static files via web server" href="../configuration/xsendfile.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
- <ul>
++<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../installation/index.html">Installation</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../configuration/index.html">Configuration</a></li>
++<li class="toctree-l1 current"><a class="current reference internal" href="">Apps</a><ul>
++<li class="toctree-l2"><a class="reference internal" href="activity/index.html">Activity</a></li>
++<li class="toctree-l2"><a class="reference internal" href="admin_dependencies_chk/index.html">Finding Deployment Dependencies</a></li>
++<li class="toctree-l2"><a class="reference internal" href="files_antivirus/index.html">File Antivirus Engine</a></li>
++<li class="toctree-l2"><a class="reference internal" href="files_encryption/index.html">Encryption</a></li>
++<li class="toctree-l2"><a class="reference internal" href="files_external/index.html">External storage support</a></li>
++<li class="toctree-l2"><a class="reference internal" href="files_sharing/index.html">Sharing</a></li>
++<li class="toctree-l2"><a class="reference internal" href="files_trashbin/index.html">Deleted Files</a></li>
++<li class="toctree-l2"><a class="reference internal" href="files_versions/index.html">Versions</a></li>
++<li class="toctree-l2"><a class="reference internal" href="firstrunwizard/index.html">First Run Wizard</a></li>
++<li class="toctree-l2"><a class="reference internal" href="user_ldap/index.html">LDAP user and group backend</a></li>
++<li class="toctree-l2"><a class="reference internal" href="viewers/index.html">File Viewers</a></li>
++</ul>
++</li>
 +<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
-   <p><strong>ownCloud Sync Client</strong></p>
++  <div class="section" id="apps">
++<h1>Apps<a class="headerlink" href="#apps" title="Permalink to this headline">¶</a></h1>
 +<div class="toctree-wrapper compound">
 +<ul>
- <li class="toctree-l1"><a class="reference internal" href="Table_of_Contents.html">Table of Contents</a></li>
- <li class="toctree-l1"><a class="reference internal" href="Introduction.html">Introduction</a></li>
- <li class="toctree-l1"><a class="reference internal" href="Obtaining_the_Client.html">Obtaining the Client</a></li>
- <li class="toctree-l1"><a class="reference internal" href="Setting_up_an_Account.html">Setting up an Account</a></li>
- <li class="toctree-l1"><a class="reference internal" href="Visual_Tour.html">Visual Tour</a><ul>
- <li class="toctree-l2"><a class="reference internal" href="Visual_Tour.html#icon">Icon</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Visual_Tour.html#menu">Menu</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Visual_Tour.html#settings">Settings</a></li>
- </ul>
- </li>
- <li class="toctree-l1"><a class="reference internal" href="Advanced_Usage.html">Advanced Usage</a><ul>
- <li class="toctree-l2"><a class="reference internal" href="Advanced_Usage.html#options">Options</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Advanced_Usage.html#config-file">Config file</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Advanced_Usage.html#comparison-and-conflicts">Comparison and Conflicts</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Advanced_Usage.html#ignored-files">Ignored Files</a></li>
- </ul>
- </li>
++<li class="toctree-l1"><a class="reference internal" href="activity/index.html">Activity</a></li>
++<li class="toctree-l1"><a class="reference internal" href="admin_dependencies_chk/index.html">Finding Deployment Dependencies</a></li>
++<li class="toctree-l1"><a class="reference internal" href="files_antivirus/index.html">File Antivirus Engine</a></li>
++<li class="toctree-l1"><a class="reference internal" href="files_encryption/index.html">Encryption</a></li>
++<li class="toctree-l1"><a class="reference internal" href="files_external/index.html">External storage support</a></li>
++<li class="toctree-l1"><a class="reference internal" href="files_sharing/index.html">Sharing</a></li>
++<li class="toctree-l1"><a class="reference internal" href="files_trashbin/index.html">Deleted Files</a></li>
++<li class="toctree-l1"><a class="reference internal" href="files_versions/index.html">Versions</a></li>
++<li class="toctree-l1"><a class="reference internal" href="firstrunwizard/index.html">First Run Wizard</a></li>
++<li class="toctree-l1"><a class="reference internal" href="user_ldap/index.html">LDAP user and group backend</a></li>
++<li class="toctree-l1"><a class="reference internal" href="viewers/index.html">File Viewers</a></li>
 +</ul>
 +</div>
++</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/apps/user_ldap/index.html
index c0c7654,0000000..f092bf6
mode 100644,000000..100644
--- a/core/doc/admin/apps/user_ldap/index.html
+++ b/core/doc/admin/apps/user_ldap/index.html
@@@ -1,154 -1,0 +1,541 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
-     <title><no title> — ownCloud Administrators Manual 6.0 documentation</title>
++    <title>LDAP user and group backend — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../../index.html" />
++    <link rel="up" title="Apps" href="../index.html" />
++    <link rel="next" title="File Viewers" href="../viewers/index.html" />
++    <link rel="prev" title="First Run Wizard" href="../firstrunwizard/index.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
- <ul>
++<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../../installation/index.html">Installation</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../../configuration/index.html">Configuration</a></li>
++<li class="toctree-l1 current"><a class="reference internal" href="../index.html">Apps</a><ul class="current">
++<li class="toctree-l2"><a class="reference internal" href="../activity/index.html">Activity</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../admin_dependencies_chk/index.html">Finding Deployment Dependencies</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../files_antivirus/index.html">File Antivirus Engine</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../files_encryption/index.html">Encryption</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../files_external/index.html">External storage support</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../files_sharing/index.html">Sharing</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../files_trashbin/index.html">Deleted Files</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../files_versions/index.html">Versions</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../firstrunwizard/index.html">First Run Wizard</a></li>
++<li class="toctree-l2 current"><a class="current reference internal" href="">LDAP user and group backend</a><ul>
++<li class="toctree-l3"><a class="reference internal" href="#configuration">Configuration</a></li>
++</ul>
++</li>
++<li class="toctree-l2"><a class="reference internal" href="../viewers/index.html">File Viewers</a></li>
++</ul>
++</li>
 +<li class="toctree-l1"><a class="reference internal" href="../../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../../config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
-   <p><strong>LDAP Active Directory Integration</strong></p>
- <div class="toctree-wrapper compound">
- <ul>
- <li class="toctree-l1"><a class="reference internal" href="Table_of_Contents.html">Table of Contents</a></li>
- <li class="toctree-l1"><a class="reference internal" href="Introduction.html">Introduction</a></li>
- <li class="toctree-l1"><a class="reference internal" href="CONFIGURATION.html">CONFIGURATION</a><ul>
- <li class="toctree-l2"><a class="reference internal" href="CONFIGURATION.html#enable-ldap-app">Enable LDAP app</a></li>
- <li class="toctree-l2"><a class="reference internal" href="CONFIGURATION.html#configuring-ldap">Configuring LDAP</a></li>
- <li class="toctree-l2"><a class="reference internal" href="CONFIGURATION.html#expert-tab">Expert Tab</a></li>
++  <div class="section" id="ldap-user-and-group-backend">
++<h1>LDAP user and group backend<a class="headerlink" href="#ldap-user-and-group-backend" title="Permalink to this headline">¶</a></h1>
++<p>ownCloud ships an LDAP backend, which allows full use of ownCloud for user logging with LDAP credentials including:</p>
++<ul class="simple">
++<li>LDAP group support</li>
++<li>File sharing with users and groups</li>
++<li>Access via WebDAV and of course ownCloud Desktop Client</li>
++<li>Versioning, external Storages and all other ownCloud features.</li>
 +</ul>
++<div class="section" id="configuration">
++<h2>Configuration<a class="headerlink" href="#configuration" title="Permalink to this headline">¶</a></h2>
++<div class="section" id="enable-ldap-app">
++<h3>Enable LDAP app<a class="headerlink" href="#enable-ldap-app" title="Permalink to this headline">¶</a></h3>
++<p>From the APPs page, select “LDAP user and group backend” and select enable</p>
++<p><img alt="1000020100000359000000A8B848DE68_png" src="../../_images/1000020100000359000000A8B848DE68.png" /></p>
++</div>
++<div class="section" id="configuring-ldap">
++<h3>Configuring LDAP<a class="headerlink" href="#configuring-ldap" title="Permalink to this headline">¶</a></h3>
++<p>The configuration of the LDAP feature is performed on the Admin page of the ownCloud web browser.
++The configuration follows a wizard-like approach split into four tabs.
++The first tab must be completed correctly to allow access to subsequent tabs.
++Although the configuration in the remaining tabs is detected automatically, it should be reviewed by the admin to verify correctness.
++An indicator exists on the all pages
++to show whether the configuration is valid, incomplete, or incorrect.</p>
++<p>Configuration settings are saved automatically when the cursor is no longer focused on the input element.</p>
++<div class="section" id="server-tab">
++<h4>Server Tab<a class="headerlink" href="#server-tab" title="Permalink to this headline">¶</a></h4>
++<p>The server tab contains basic information on the LDAP server.
++It makes certain that ownCloud can connect to the desired LDAP and read data from it.
++At a minimum, the admin must provide a hostname for the LDAP server.
++If anonymous access to the LDAP server is not allowed, the admin will be required to enter an account Distinguished Name (DN) and password.
++ownCloud will auto-detect the port and base DN.</p>
++<div class="section" id="server">
++<h5>Server<a class="headerlink" href="#server" title="Permalink to this headline">¶</a></h5>
++<p>ownCloud can be configured to connect to multiple LDAP servers.
++Using this control you can pick a configuration you want to edit or to add a new one.
++The button
++Delete Configuration deletes the current configuration.</p>
++</div>
++<div class="section" id="host">
++<h5>Host<a class="headerlink" href="#host" title="Permalink to this headline">¶</a></h5>
++<p>The hostname of the LDAP server.
++It can also be a <tt class="docutils literal"><span class="pre">ldaps://</span></tt> URI.
++It is possible to pass a port number which will speed up port detection.
++This is especially useful if a custom port is used.
++ownCloud will subsequently move the port value to the port field.</p>
++<p>Examples:</p>
++<div class="highlight-python"><pre>directory.my-company.com
++ldaps://directory.my-company.com
++directory.my-company.com:9876</pre>
++</div>
++</div>
++<div class="section" id="port">
++<h5>Port<a class="headerlink" href="#port" title="Permalink to this headline">¶</a></h5>
++<p>This is the port which ownCloud should utilize to connect to the LDAP server.
++Upon initial configuration, this field is disabled.
++ownCloud will auto-detect the port if it is running on a standard port (389).
++After ownCloud detects the port, the field will be enabled for admin input.
++A successfully discovered port will be inserted by ownCloud.</p>
++</div>
++<div class="section" id="user-dn">
++<h5>User DN<a class="headerlink" href="#user-dn" title="Permalink to this headline">¶</a></h5>
++<p>The name as DN of a user who is able to do searches in the LDAP directory.
++For anonymous access, leave this field blank.
++It is recommended to have a special system user for ownCloud.
++This information is provided by the LDAP admin.</p>
++</div>
++<div class="section" id="password">
++<h5>Password<a class="headerlink" href="#password" title="Permalink to this headline">¶</a></h5>
++<p>The password for the user given above.
++For anonymous access, leave this blank.
++This information is provided by the LDAP admin.</p>
++</div>
++<div class="section" id="base-dn">
++<h5>Base DN<a class="headerlink" href="#base-dn" title="Permalink to this headline">¶</a></h5>
++<p>The base DM of the LDAP from where all users and groups can be reached.
++It is possible to provide separated base DN’s for users and groups in the advanced tab.
++This is a mandatory field.
++ownCloud will attempt to determine the proper value of this field based on the provided User DN or Host values.</p>
++<p><img alt="100000000000043200000169BCD20493_png" src="../../_images/100000000000043200000169BCD20493.png" style="width: 6.5in; height: 2.1846in;" /></p>
++</div>
++</div>
++<div class="section" id="user-filter">
++<h4>User Filter<a class="headerlink" href="#user-filter" title="Permalink to this headline">¶</a></h4>
++<p>The settings in the User Filter tab determine which LDAP users will appear and will be able to log into ownCloud.
++This may be configured using the wizard or entered via a raw LDAP filter.</p>
++<div class="section" id="only-those-object-classes">
++<h5>Only those object classes<a class="headerlink" href="#only-those-object-classes" title="Permalink to this headline">¶</a></h5>
++<p>ownCloud will determine the available object classes.
++ownCloud will automatically select the object that contains the highest number of users.
++It is possible to select multiple object classes.</p>
++</div>
++<div class="section" id="only-from-those-groups">
++<h5>Only from those groups<a class="headerlink" href="#only-from-those-groups" title="Permalink to this headline">¶</a></h5>
++<p>This is used if the LDAP server supports the member-of-overlay in LDAP filters.
++It allows the admin to define the users from one or more certain groups that are allowed to appear and log into ownCloud.
++No value is selected by default.
++It is possible to select multiple groups.</p>
++<p>If the LDAP server does not support member-of-overlay in LDAP filters, the field is disabled.</p>
++</div>
++<div class="section" id="edit-raw-filter-instead">
++<h5>Edit raw filter instead<a class="headerlink" href="#edit-raw-filter-instead" title="Permalink to this headline">¶</a></h5>
++<p>Selecting this text will toggle the filter mode.
++Instead of the wizard’s assistance, the admin may enter the raw LDAP filter in this field.</p>
++<p>Example:</p>
++<div class="highlight-python"><div class="highlight"><pre><span class="n">objectClass</span><span class="o">=</span><span class="n">inetOrgPerson</span>
++</pre></div>
++</div>
++</div>
++<div class="section" id="x-users-found">
++<h5>x users found<a class="headerlink" href="#x-users-found" title="Permalink to this headline">¶</a></h5>
++<p>Indicates the approximate number of users allowed to access ownCloud.
++This number will update after any changes made to the LDAP configuration.</p>
++<p><img alt="100000000000042500000163D2B339D5_png" src="../../_images/100000000000042500000163D2B339D5.png" style="width: 6.5in; height: 2.1752in;" /></p>
++</div>
++</div>
++<div class="section" id="login-filter">
++<h4>Login Filter<a class="headerlink" href="#login-filter" title="Permalink to this headline">¶</a></h4>
++<p>The settings in the login filter tab determine which user information will be compared to login credentials entered by the user.
++It is possible to allow multiple user details.
++It is also possible to enter a raw LDAP filter.</p>
++<div class="section" id="ldap-username">
++<h5>LDAP Username<a class="headerlink" href="#ldap-username" title="Permalink to this headline">¶</a></h5>
++<p>If checked, the login credentials will be compared to the username in the LDAP directory.
++The corresponding attribute, usually <tt class="docutils literal"><span class="pre">uid</span></tt> or <tt class="docutils literal"><span class="pre">samaccountname</span></tt> will be automatically detected by ownCloud.</p>
++</div>
++<div class="section" id="ldap-email-address">
++<h5>LDAP Email Address<a class="headerlink" href="#ldap-email-address" title="Permalink to this headline">¶</a></h5>
++<p>If checked, the login credentials will be compared to an email address in the LDAP directory.
++ownCloud will exmaine the <tt class="docutils literal"><span class="pre">mailPrimaryAddress</span></tt> and <tt class="docutils literal"><span class="pre">mail</span></tt> attributes in the LDAP for the email address.</p>
++</div>
++<div class="section" id="other-attributes">
++<h5>Other attributes<a class="headerlink" href="#other-attributes" title="Permalink to this headline">¶</a></h5>
++<p>This field allows the admin to select additional attributes for comparison.
++The list is generated automatically based on the attributes contained in the user object of the LDAP server.</p>
++</div>
++<div class="section" id="enter-raw-filter-instead">
++<h5>Enter raw filter instead<a class="headerlink" href="#enter-raw-filter-instead" title="Permalink to this headline">¶</a></h5>
++<p>Selecting this text will toggle the filter mode.
++Instead of the wizard’s assistance, the admin may enter the raw LDAP filter in this field.</p>
++<p>The <tt class="docutils literal"><span class="pre">%uid</span></tt> placeholder will be replaced with the login name entered by the user upon login.</p>
++<p>Examples:</p>
++<ul>
++<li><p class="first">Username only:</p>
++<div class="highlight-python"><pre>uid=%iud</pre>
++</div>
 +</li>
++<li><p class="first">Username or email address:</p>
++<div class="highlight-python"><pre>(|(uid=%uid)(mail=%uid))</pre>
++</div>
++</li>
++</ul>
++<p><img alt="10000000000004170000016ACB5E15AE_png" src="../../_images/10000000000004170000016ACB5E15AE.png" style="width: 6.5in; height: 2.2465in;" /></p>
++</div>
++</div>
++<div class="section" id="group-filter">
++<h4>Group Filter<a class="headerlink" href="#group-filter" title="Permalink to this headline">¶</a></h4>
++<p>The settings in this tab determine which groups will be available in ownCloud.
++This tab does not restrict logins in any manner as that was handled in the prior tabs.
++It is possible to enter a raw LDAP filter as well.</p>
++<p>By default, there are no groups available in ownCloud.
++The admin must enable this manually.</p>
++<div class="section" id="id1">
++<h5>Only those object classes<a class="headerlink" href="#id1" title="Permalink to this headline">¶</a></h5>
++<p>ownCloud will automatically determine which object classes are available in the LDAP.
++ownCloud will only list object classes that return at least one group object.
++It is possible to enter multiple object classes.</p>
++</div>
++<div class="section" id="id2">
++<h5>Only from those groups<a class="headerlink" href="#id2" title="Permalink to this headline">¶</a></h5>
++<p>This setting allows the admin to select which groups are available within ownCloud.
++ownCloud will generate a list of available groups found in the LDAP server for the admin to select.
++It is possible to enter multiple groups.</p>
++</div>
++<div class="section" id="id3">
++<h5>Edit raw filter instead<a class="headerlink" href="#id3" title="Permalink to this headline">¶</a></h5>
++<p>Selecting this text will toggle the filter mode.
++Instead of the wizard’s assistance, the admin may enter the raw LDAP filter in this field</p>
++</div>
++<div class="section" id="y-groups-found">
++<h5>Y groups found<a class="headerlink" href="#y-groups-found" title="Permalink to this headline">¶</a></h5>
++<p>Indicates the approximate number of groups available in ownCloud.
++This number will update after any changes made to the LDAP configuration.</p>
++<p><img alt="100000000000043000000164DA0CE8C9_png" src="../../_images/100000000000043000000164DA0CE8C9.png" style="width: 6.5in; height: 2.1583in;" /></p>
++</div>
++</div>
++<div class="section" id="advanced-tab">
++<h4>Advanced Tab<a class="headerlink" href="#advanced-tab" title="Permalink to this headline">¶</a></h4>
++<p>The LDAP Advanced settings section allows the admin to define less common
++options.  These options are not required for a working connection however, they
++can have a positive effect on the performance.</p>
++<p>The Advanced Settings tab has three sections</p>
++<ul class="simple">
++<li>Connection settings</li>
++<li>Directory settings</li>
++<li>Special attributes</li>
 +</ul>
++<div class="section" id="connection-settings">
++<h5>Connection Settings<a class="headerlink" href="#connection-settings" title="Permalink to this headline">¶</a></h5>
++<div class="section" id="configuration-active">
++<h6>Configuration Active<a class="headerlink" href="#configuration-active" title="Permalink to this headline">¶</a></h6>
++<p>Allows the admin to enable or disable the current configuration.
++A disabled configuration will not connect to the LDAP server.</p>
++<p>By default, this is disabled.
++It is enabled automatically, when using the wizard and configuration is valid and tests successfully.</p>
++</div>
++<div class="section" id="backup-replica-host">
++<h6>Backup (Replica) Host<a class="headerlink" href="#backup-replica-host" title="Permalink to this headline">¶</a></h6>
++<p>This is used to define a backup LDAP server.  ownCloud automatically attempts
++to connect to the backup server when the primary server cannot be accessed.  It
++is important that the backup server is an exact replica of the primary server
++as all the object UUIDs must match.</p>
++</div>
++<div class="section" id="backup-replica-port">
++<h6>Backup (Replica) Port<a class="headerlink" href="#backup-replica-port" title="Permalink to this headline">¶</a></h6>
++<p>This identifies the port on which ownCloud will connect to the backup LDAP server.
++If no port is provided, ownCloud will utilize the same port as the primary LDAP server.</p>
++</div>
++<div class="section" id="disable-main-server">
++<h6>Disable Main Server<a class="headerlink" href="#disable-main-server" title="Permalink to this headline">¶</a></h6>
++<p>This is used to disable the primary LDAP server so ownCloud will connect only to the backup server.
++This can be useful for planned maintenance on the primary server.</p>
++</div>
++<div class="section" id="case-insensitive-ldap-server-windows">
++<h6>Case insensitive LDAP server (Windows)<a class="headerlink" href="#case-insensitive-ldap-server-windows" title="Permalink to this headline">¶</a></h6>
++<p>Check this if the LDAP server is running on a windows host.
++Not usually necessary.</p>
++</div>
++<div class="section" id="turn-off-ssl-certificate-validation">
++<h6>Turn off SSL certificate validation<a class="headerlink" href="#turn-off-ssl-certificate-validation" title="Permalink to this headline">¶</a></h6>
++<p>Disables the check for a valid SSL certificate.
++It is recommended to use for testing only if needed, but not use in production.</p>
++</div>
++<div class="section" id="cache-time-to-live">
++<h6>Cache Time-To-Live<a class="headerlink" href="#cache-time-to-live" title="Permalink to this headline">¶</a></h6>
++<p>ownCloud caches the information it receives from the LDAP server.  This is
++necessary as the ownCloud server attempts to validate the user with every page
++request or WebDAV interaction.  This time is in seconds.</p>
++<p>Note if it is required to have the most up-to-date information from the LDAP,
++it is recommended not to turn off the cache totally, however, to define a
++lifetime of a small duration (15 seconds)</p>
++<p><img alt="100000000000042E000001D3EEB9978B_png" src="../../_images/100000000000042E000001D3EEB9978B.png" style="width: 6.5in; height: 2.8366in;" /></p>
++</div>
++</div>
++<div class="section" id="directory-settings">
++<h5>Directory Settings<a class="headerlink" href="#directory-settings" title="Permalink to this headline">¶</a></h5>
++<div class="section" id="user-display-name-field">
++<h6>User Display Name Field<a class="headerlink" href="#user-display-name-field" title="Permalink to this headline">¶</a></h6>
++<p>The attribute that should be used as display name in ownCloud.</p>
++</div>
++<div class="section" id="base-user-tree">
++<h6>Base User Tree<a class="headerlink" href="#base-user-tree" title="Permalink to this headline">¶</a></h6>
++<p>The Base DN of LDAP, from where all users can be reached.
++It needs to be given completely despite to the Base DN from the Basic Settings.
++You can specify multiple base trees, one in each line.</p>
++</div>
++<div class="section" id="user-search-attributes">
++<h6>User Search Attributes<a class="headerlink" href="#user-search-attributes" title="Permalink to this headline">¶</a></h6>
++<p>These attributes are used when a search for users with a search string is done.
++This happens in the share dialogue.
++By default the user display name attribute as specified above is used.
++Multiple attributes can be given, one in each line.</p>
++<p>Note: if an attribute is not available for a given user object, the user will neither be listed nor able to login.</p>
++</div>
++<div class="section" id="group-display-name-field">
++<h6>Group Display Name Field<a class="headerlink" href="#group-display-name-field" title="Permalink to this headline">¶</a></h6>
++<p>The attribute that should be used as an ownCloud group name.
++ownCloud allows a limited set of characters (regex notation):</p>
++<div class="highlight-python"><pre>[a-zA_Z0-9,-_@]</pre>
++</div>
++<p>Every other character will be replaced in ownCloud.
++Once a group bane is assigned, it will not be changed.</p>
++</div>
++<div class="section" id="base-group-tree">
++<h6>Base Group Tree<a class="headerlink" href="#base-group-tree" title="Permalink to this headline">¶</a></h6>
++<p>The base DN of LDAP from where all groups can be reached.
++It needs to be given completely despite to the Base DN from the Basic Settings.
++You can specify multiple base trees, one in each line.</p>
++</div>
++<div class="section" id="group-search-attributes">
++<h6>Group Search Attributes<a class="headerlink" href="#group-search-attributes" title="Permalink to this headline">¶</a></h6>
++<p>These attributes are used when a search for groups with a search string is done.
++This happens in the share dialogue for instance.
++By default the group display name attribute as specified above is being used.
++Multiple attributes can be given, one in each line.</p>
++</div>
++<div class="section" id="group-member-association">
++<h6>Group Member association<a class="headerlink" href="#group-member-association" title="Permalink to this headline">¶</a></h6>
++<p>The attribute that is used to indicate group memberships.</p>
++<p><img alt="10000201000005F90000029D8BA200FB_png" src="../../_images/10000201000005F90000029D8BA200FB.png" /></p>
++</div>
++</div>
++<div class="section" id="special-attributes">
++<h5>Special Attributes<a class="headerlink" href="#special-attributes" title="Permalink to this headline">¶</a></h5>
++<div class="section" id="quota-field">
++<h6>Quota Field<a class="headerlink" href="#quota-field" title="Permalink to this headline">¶</a></h6>
++<p>This field is used to set a LDAP attribute to define the user quota.
++The attribute should retain a readable value, for example:</p>
++<div class="highlight-python"><pre>2 GB</pre>
++</div>
++</div>
++<div class="section" id="quota-default">
++<h6>Quota Default<a class="headerlink" href="#quota-default" title="Permalink to this headline">¶</a></h6>
++<p>This is used to override the ownCloud default quota for LDAP users who do not have an attribute set in the above parameter.</p>
++<p>Example:</p>
++<div class="highlight-python"><pre>15GB</pre>
++</div>
++</div>
++<div class="section" id="email-field">
++<h6>Email Field<a class="headerlink" href="#email-field" title="Permalink to this headline">¶</a></h6>
++<p>ownCloud will read the attribute configured here and configure the user’s email.</p>
++</div>
++<div class="section" id="user-home-folder-naming-rule">
++<h6>User Home Folder Naming Rule<a class="headerlink" href="#user-home-folder-naming-rule" title="Permalink to this headline">¶</a></h6>
++<p>By default, ownCloud creates a user directory which contains all files and meta data based on the ownCloud user name.
++To override this setting and name it after a different attribute, configure that attribute here.
++The attribute can also return an absolute path (such as <tt class="docutils literal"><span class="pre">/mnt/storage43/alice</span></tt>).</p>
++<p><img alt="100000000000041D0000017D8D1BC4D9_png" src="../../_images/100000000000041D0000017D8D1BC4D9.png" style="width: 6.5in; height: 2.352in;" /></p>
++</div>
++</div>
++</div>
++</div>
++<div class="section" id="expert-tab">
++<h3>Expert Tab<a class="headerlink" href="#expert-tab" title="Permalink to this headline">¶</a></h3>
++<div class="section" id="internal-username">
++<h4>Internal Username<a class="headerlink" href="#internal-username" title="Permalink to this headline">¶</a></h4>
++<p>The internal username is the identifier in ownCloud for LDAP users.
++By default it will be created from the UUID attribute.  By using the UUID
++attribute it is made sure that the username is unique and characters do not
++need to be converted.  The internal username has the restriction that only
++these characters are allowed (regex notation):</p>
++<div class="highlight-python"><pre>[a-zA-Z0-0_. at -]</pre>
++</div>
++<p>Other characters are replaced with their ASCII correspondence or are simply
++omitted</p>
++<p>The LDAP backend ensures that there are no duplicate internal usernames in
++ownCloud, i.e. that it is checking all other activated user back ends
++(including local ownCloud users). On collisions a random number (between 1000
++and 9999) will be attached to the retrieved value. For example, if <tt class="docutils literal"><span class="pre">alice</span></tt>
++exists, the next username may be <tt class="docutils literal"><span class="pre">alice_1337</span></tt>.</p>
++<p>The internal username is also the default name for the user home folder in
++ownCloud. It is also a part of remote URLs, for instance for all *DAV
++services. With this setting the default behavior can be overridden.</p>
++<p>Leave it empty for default behavior. Changes will have effect only on newly
++mapped (added) LDAP users.</p>
++</div>
++<div class="section" id="override-uuid-detection">
++<h4>Override UUID detection<a class="headerlink" href="#override-uuid-detection" title="Permalink to this headline">¶</a></h4>
++<p>By default ownCloud auto-detects the UUID attribute.
++The UUID attribute is used to doubtlessly identify LDAP users and groups.
++Also, the internal username will be created based on the UUID, if not specified from above.</p>
++<p>You can override the setting and pass an attribute of your choice. You must
++make sure that the attribute of your choice can be fetched for both users and
++groups and it is unique. Leave it empty for default behavior. Changes will have
++effect only on newly mapped (added) LDAP users and groups. It also will have
++effect when a user’s or group’s DN changes and an old UUID was cached: It will
++result in a new user.</p>
++<p>Because of this, the setting should be applied before putting ownCloud in
++production use and cleaning the bindings (see below).</p>
++</div>
++<div class="section" id="username-ldap-user-mapping">
++<h4>Username-LDAP User Mapping<a class="headerlink" href="#username-ldap-user-mapping" title="Permalink to this headline">¶</a></h4>
++<p>ownCloud uses the usernames as key to store and assign data.  In order to
++precisely identify and recognize users, each LDAP user will have an internal
++username in ownCloud.  This requires a mapping from ownCloud username to LDAP
++user.  The created username is mapped to the UUID of the LDAP user.
++Additionally the DN is cached as well to reduce LDAP interaction, but is not
++used for identification.  If the DN changes, the change will be detected by
++ownCloud by checking the UUID value.</p>
++<p>The same is valid for groups.</p>
++<p>The internal ownCloud name is used all over in ownCloud.
++Clearing the mappings will have leftovers everywhere.
++Never clear the mappings in a production environment.
++Only clear mappings in a test or experimental stage.</p>
++<p><img alt="10000000000003FB000002359BAFB40E_png" src="../../_images/10000000000003FB000002359BAFB40E.png" style="width: 6.5in; height: 3.6043in;" /></p>
++</div>
++</div>
++</div>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/apps/viewers/index.html
index 780bd11,0000000..7f8d00c
mode 100644,000000..100644
--- a/core/doc/admin/apps/viewers/index.html
+++ b/core/doc/admin/apps/viewers/index.html
@@@ -1,155 -1,0 +1,190 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
-     <title><no title> — ownCloud Administrators Manual 6.0 documentation</title>
++    <title>File Viewers — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../../index.html" />
++    <link rel="up" title="Apps" href="../index.html" />
++    <link rel="next" title="Maintenance" href="../../maintenance/index.html" />
++    <link rel="prev" title="LDAP user and group backend" href="../user_ldap/index.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
- <ul>
++<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../../installation/index.html">Installation</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../../configuration/index.html">Configuration</a></li>
++<li class="toctree-l1 current"><a class="reference internal" href="../index.html">Apps</a><ul class="current">
++<li class="toctree-l2"><a class="reference internal" href="../activity/index.html">Activity</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../admin_dependencies_chk/index.html">Finding Deployment Dependencies</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../files_antivirus/index.html">File Antivirus Engine</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../files_encryption/index.html">Encryption</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../files_external/index.html">External storage support</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../files_sharing/index.html">Sharing</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../files_trashbin/index.html">Deleted Files</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../files_versions/index.html">Versions</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../firstrunwizard/index.html">First Run Wizard</a></li>
++<li class="toctree-l2"><a class="reference internal" href="../user_ldap/index.html">LDAP user and group backend</a></li>
++<li class="toctree-l2 current"><a class="current reference internal" href="">File Viewers</a><ul>
++<li class="toctree-l3"><a class="reference internal" href="#configuration">Configuration</a></li>
++<li class="toctree-l3"><a class="reference internal" href="#utilization">Utilization</a></li>
++</ul>
++</li>
++</ul>
++</li>
 +<li class="toctree-l1"><a class="reference internal" href="../../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../../config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
-   <p><strong>ownCloud Viewers</strong></p>
- <p>Table of Contents</p>
- <p>` <#_Toc376421150>`_</p>
- <div class="toctree-wrapper compound">
- <ul>
- <li class="toctree-l1"><a class="reference internal" href="Introduction.html">Introduction</a></li>
- <li class="toctree-l1"><a class="reference internal" href="Configuration.html">Configuration</a><ul>
- <li class="toctree-l2"><a class="reference internal" href="Configuration.html#text-editor">Text Editor</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Configuration.html#image-viewer">Image Viewer</a></li>
- </ul>
- </li>
- <li class="toctree-l1"><a class="reference internal" href="Utilization.html">Utilization</a></li>
- </ul>
++  <div class="section" id="file-viewers">
++<h1>File Viewers<a class="headerlink" href="#file-viewers" title="Permalink to this headline">¶</a></h1>
++<p>ownCloud provides apps which allow users to view/edit
++text files and view images which exist on the ownCloud server.</p>
++<div class="section" id="configuration">
++<h2>Configuration<a class="headerlink" href="#configuration" title="Permalink to this headline">¶</a></h2>
++<div class="section" id="text-editor">
++<h3>Text Editor<a class="headerlink" href="#text-editor" title="Permalink to this headline">¶</a></h3>
++<p>The Text Editor App allows users to view and edit text files.
++To enable this app, navigate to the Apps page and select “Text Editor” then Enable.</p>
++<p><img alt="100000000000012C0000009C444B4720_png" src="../../_images/100000000000012C0000009C444B4720.png" style="width: 3.1252in; height: 1.6252in;" /></p>
++</div>
++<div class="section" id="image-viewer">
++<h3>Image Viewer<a class="headerlink" href="#image-viewer" title="Permalink to this headline">¶</a></h3>
++<p>The image viewer app allows users to preview image files within the ownCloud web interface.
++To enable, navigate to the Apps page and select “Image Viewer” then enable.</p>
++<p><img alt="10000000000001400000008A557EF7E3_png" src="../../_images/10000000000001400000008A557EF7E3.png" style="width: 3.3335in; height: 1.4374in;" /></p>
++</div>
++</div>
++<div class="section" id="utilization">
++<h2>Utilization<a class="headerlink" href="#utilization" title="Permalink to this headline">¶</a></h2>
++<p>When the apps are enabled, select the file name on the web interface Files tab and either the text editor or the image will appear.</p>
++<p><img alt="10000000000001E50000006E3ECDC427_png" src="../../_images/10000000000001E50000006E3ECDC427.png" style="width: 5.052in; height: 1.1457in;" /></p>
++<p><img alt="100000000000044C000002B0B421E27E_png" src="../../_images/100000000000044C000002B0B421E27E.png" style="width: 6.5in; height: 4.0654in;" /></p>
++<p>When the apps are disabled, selecting the file name on the web interface will prompt the user to download the specified file.</p>
++</div>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/config/apps.html
index 6aae1aa,0000000..653fbad
mode 100644,000000..100644
--- a/core/doc/admin/config/apps.html
+++ b/core/doc/admin/config/apps.html
@@@ -1,192 -1,0 +1,212 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
 +    <title>APPS — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
++    <link rel="up" title="The Configuration File" href="index.html" />
++    <link rel="next" title="Previews" href="previews.html" />
++    <link rel="prev" title="Code Locations" href="code_locations.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
- <ul>
++<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../installation/index.html">Installation</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../configuration/index.html">Configuration</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1 current"><a class="reference internal" href="index.html">The Configuration File</a><ul class="current">
++<li class="toctree-l2"><a class="reference internal" href="default_parameters.html">Default Parameters</a></li>
++<li class="toctree-l2"><a class="reference internal" href="reverse_proxy_configurations.html">Reverse Proxy Configurations</a></li>
++<li class="toctree-l2"><a class="reference internal" href="user_experience.html">User Experience</a></li>
++<li class="toctree-l2"><a class="reference internal" href="mail_parameters.html">Mail Parameters</a></li>
++<li class="toctree-l2"><a class="reference internal" href="deleted_items.html">Deleted Items</a></li>
++<li class="toctree-l2"><a class="reference internal" href="verification.html">Verification</a></li>
++<li class="toctree-l2"><a class="reference internal" href="logging.html">Logging</a></li>
++<li class="toctree-l2"><a class="reference internal" href="session_info.html">Session Info</a></li>
++<li class="toctree-l2"><a class="reference internal" href="code_locations.html">Code Locations</a></li>
++<li class="toctree-l2 current"><a class="current reference internal" href="">APPS</a></li>
++<li class="toctree-l2"><a class="reference internal" href="previews.html">Previews</a></li>
++<li class="toctree-l2"><a class="reference internal" href="maintenance.html">Maintenance</a></li>
++<li class="toctree-l2"><a class="reference internal" href="miscellaneous.html">Miscellaneous</a></li>
++</ul>
++</li>
 +<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
 +  <div class="section" id="apps">
 +<h1>APPS<a class="headerlink" href="#apps" title="Permalink to this headline">¶</a></h1>
 +<p>The following parameters are used for ownCloud apps.</p>
 +<table border="1" class="docutils">
 +<colgroup>
 +<col width="10%" />
 +<col width="23%" />
 +<col width="67%" />
 +</colgroup>
 +<tbody valign="top">
 +<tr class="row-odd"><td><strong>Parameter</strong></td>
 +<td><strong>Format</strong></td>
 +<td><strong>Description</strong></td>
 +</tr>
 +<tr class="row-even"><td><strong>Apps Paths</strong></td>
 +<td><p class="first">“apps_paths” => array(</p>
 +<p>0 => array(</p>
 +<p>‘path’=> ‘/var/www/owncloud/apps’,</p>
 +<p>‘url’ => ‘/apps’,</p>
 +<p>‘writable’ => true,</p>
 +<p>),</p>
 +<p>1 => array (</p>
 +<p>‘path’ =>
 +‘/var/www/owncloud/apps2’,</p>
 +<p>‘url’ => ‘/apps2’,</p>
 +<p>Writable => false,</p>
 +<p>),</p>
 +<p class="last">),</p>
 +</td>
 +<td>Use this parameter to set the location of the apps folder which should be scanned for available apps and/or where user specific apps should be installed.
 +The path defines the absolute file system path to the app folder.
- The key url defines the http web path to that folder starting at the ownCloud web root.
++The key url defines the http web path to that folder starting at the owncloud web root.
 +The key writable indicates if a user can install apps in that folder.</td>
 +</tr>
 +<tr class="row-odd"><td><strong>App Store Enabled</strong></td>
 +<td>“appstoreenabled” => true,</td>
 +<td>When enabled, admins may install apps from the ownCloud app store.</td>
 +</tr>
 +<tr class="row-even"><td><strong>App Store URL</strong></td>
 +<td>“appstoreurl” => “<a class="reference external" href="http://api.apps.owncloud.com/v1">http://api.apps.owncloud.com/v1</a>”,</td>
 +<td>The URL of the appstore.</td>
 +</tr>
 +<tr class="row-odd"><td><strong>App Code Checker</strong></td>
 +<td>“appcodechecker” => “”,</td>
 +<td>Checks for malicious code fragments of 3
 +rd
 +party apps.</td>
 +</tr>
 +</tbody>
 +</table>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/config/code_locations.html
index f149048,0000000..1370ee6
mode 100644,000000..100644
--- a/core/doc/admin/config/code_locations.html
+++ b/core/doc/admin/config/code_locations.html
@@@ -1,191 -1,0 +1,211 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
 +    <title>Code Locations — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
++    <link rel="up" title="The Configuration File" href="index.html" />
++    <link rel="next" title="APPS" href="apps.html" />
++    <link rel="prev" title="Session Info" href="session_info.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
- <ul>
++<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../installation/index.html">Installation</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../configuration/index.html">Configuration</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1 current"><a class="reference internal" href="index.html">The Configuration File</a><ul class="current">
++<li class="toctree-l2"><a class="reference internal" href="default_parameters.html">Default Parameters</a></li>
++<li class="toctree-l2"><a class="reference internal" href="reverse_proxy_configurations.html">Reverse Proxy Configurations</a></li>
++<li class="toctree-l2"><a class="reference internal" href="user_experience.html">User Experience</a></li>
++<li class="toctree-l2"><a class="reference internal" href="mail_parameters.html">Mail Parameters</a></li>
++<li class="toctree-l2"><a class="reference internal" href="deleted_items.html">Deleted Items</a></li>
++<li class="toctree-l2"><a class="reference internal" href="verification.html">Verification</a></li>
++<li class="toctree-l2"><a class="reference internal" href="logging.html">Logging</a></li>
++<li class="toctree-l2"><a class="reference internal" href="session_info.html">Session Info</a></li>
++<li class="toctree-l2 current"><a class="current reference internal" href="">Code Locations</a></li>
++<li class="toctree-l2"><a class="reference internal" href="apps.html">APPS</a></li>
++<li class="toctree-l2"><a class="reference internal" href="previews.html">Previews</a></li>
++<li class="toctree-l2"><a class="reference internal" href="maintenance.html">Maintenance</a></li>
++<li class="toctree-l2"><a class="reference internal" href="miscellaneous.html">Miscellaneous</a></li>
++</ul>
++</li>
 +<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
 +  <div class="section" id="code-locations">
 +<h1>Code Locations<a class="headerlink" href="#code-locations" title="Permalink to this headline">¶</a></h1>
 +<p>ownCloud has the ability to find parts of its code in non-standard locations.
 +This section describes how to configure ownCloud for that functionality.</p>
 +<table border="1" class="docutils">
 +<colgroup>
 +<col width="7%" />
 +<col width="34%" />
 +<col width="59%" />
 +</colgroup>
 +<tbody valign="top">
 +<tr class="row-odd"><td><strong>Parameter</strong></td>
 +<td><strong>Format</strong></td>
 +<td><strong>Description</strong></td>
 +</tr>
 +<tr class="row-even"><td><strong>Theme</strong></td>
 +<td>“theme” => “”,</td>
 +<td>If the instance of ownCloud is themed, the name of the theme should be configured here.
 +For more information on this parameter, see the document on Theming.</td>
 +</tr>
 +<tr class="row-odd"><td><strong>3</strong>
 +rd
 +** Party Root**</td>
 +<td>“3rdpartyroot” => “”,</td>
 +<td>ownCloud uses some 3
 +rd
 +party PHP components to provide certain functionality.
 +These components are shipped as part of the software package and reside in
 +~/owncloud/3rdparty.
 +However, if this folder resides elsewhere, the location can be configured here.
 +For example /srv/http/path/to/3rdparty.</td>
 +</tr>
 +<tr class="row-even"><td><strong>3</strong>
 +rd
 +** Party URL**</td>
 +<td>“3rdpartyurl” => “”,</td>
 +<td>In the event that the 3rdpartyroot is configured, this parameter should be configured as well to show the http web path to the 3rdpartyroot starting at the owncloud web root.
 +For instance /path/to/3rdparty.</td>
 +</tr>
 +<tr class="row-odd"><td><strong>Custome Client</strong></td>
 +<td><p class="first">‘customclient_desktop’ => ‘’, //<a class="reference external" href="http://owncloud.org/sync-clients/">http://owncloud.org/sync-clients/</a></p>
 +<p>‘customclient_android’ => ‘’, //<a class="reference external" href="https://play.google.com/store/apps/details?id=com.owncloud.android">https://play.google.com/store/apps/details?id=com.owncloud.android</a></p>
 +<p class="last">‘customclient_ios’ => ‘’, //<a class="reference external" href="https://itunes.apple.com/us/app/owncloud/id543672169?mt=8">https://itunes.apple.com/us/app/owncloud/id543672169?mt=8</a></p>
 +</td>
 +<td>The location where ownCloud will bring the user to download clients.
 +The link is in the first run wizard or the Personal page.</td>
 +</tr>
 +</tbody>
 +</table>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/config/default_parameters.html
index 47b68de,0000000..e841938
mode 100644,000000..100644
--- a/core/doc/admin/config/default_parameters.html
+++ b/core/doc/admin/config/default_parameters.html
@@@ -1,219 -1,0 +1,251 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
 +    <title>Default Parameters — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
++    <link rel="up" title="The Configuration File" href="index.html" />
++    <link rel="next" title="Reverse Proxy Configurations" href="reverse_proxy_configurations.html" />
++    <link rel="prev" title="The Configuration File" href="index.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
- <ul>
++<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../installation/index.html">Installation</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../configuration/index.html">Configuration</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1 current"><a class="reference internal" href="index.html">The Configuration File</a><ul class="current">
++<li class="toctree-l2 current"><a class="current reference internal" href="">Default Parameters</a></li>
++<li class="toctree-l2"><a class="reference internal" href="reverse_proxy_configurations.html">Reverse Proxy Configurations</a></li>
++<li class="toctree-l2"><a class="reference internal" href="user_experience.html">User Experience</a></li>
++<li class="toctree-l2"><a class="reference internal" href="mail_parameters.html">Mail Parameters</a></li>
++<li class="toctree-l2"><a class="reference internal" href="deleted_items.html">Deleted Items</a></li>
++<li class="toctree-l2"><a class="reference internal" href="verification.html">Verification</a></li>
++<li class="toctree-l2"><a class="reference internal" href="logging.html">Logging</a></li>
++<li class="toctree-l2"><a class="reference internal" href="session_info.html">Session Info</a></li>
++<li class="toctree-l2"><a class="reference internal" href="code_locations.html">Code Locations</a></li>
++<li class="toctree-l2"><a class="reference internal" href="apps.html">APPS</a></li>
++<li class="toctree-l2"><a class="reference internal" href="previews.html">Previews</a></li>
++<li class="toctree-l2"><a class="reference internal" href="maintenance.html">Maintenance</a></li>
++<li class="toctree-l2"><a class="reference internal" href="miscellaneous.html">Miscellaneous</a></li>
++</ul>
++</li>
 +<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
 +  <div class="section" id="default-parameters">
 +<h1>Default Parameters<a class="headerlink" href="#default-parameters" title="Permalink to this headline">¶</a></h1>
 +<p>The following parameters are automatically configured by ownCloud upon the initial admin login.
 +These parameters are mandatory for the ownCloud instance to operate properly.</p>
 +<table border="1" class="docutils">
 +<colgroup>
 +<col width="9%" />
 +<col width="12%" />
 +<col width="79%" />
 +</colgroup>
 +<tbody valign="top">
 +<tr class="row-odd"><td><strong>Parameter</strong></td>
 +<td><strong>Format</strong></td>
 +<td><strong>Description</strong></td>
 +</tr>
 +<tr class="row-even"><td><strong>Debug</strong></td>
 +<td>define(“DEBUG”, true);</td>
 +<td>When set to true, additional information is written to the logs.
 +This is to be used only for local development and not in a production environment.</td>
 +</tr>
 +<tr class="row-odd"><td><strong>Installed</strong></td>
 +<td>“installed” => false,</td>
 +<td>This flag indicates whether the ownCloud instance was installed successfully.
 +When set to true, the install was successful.
 +When set to false the instance is not properly installed.</td>
 +</tr>
 +<tr class="row-even"><td><strong>DB Type</strong></td>
 +<td>“dbtype” => “sqlite”,</td>
 +<td>The dbtype indicates what type of database is being used with this install.</td>
 +</tr>
 +<tr class="row-odd"><td><strong>DB Name</strong></td>
 +<td>“dbname” => “owncloud”,</td>
 +<td>The ownCloud database within the SQL instance.
 +ownCloud database configuration guides use “owncloud” in the instructions, it is the default for this field.
 +This may be set to any valid table name.
 +If the table doesn’t exist, the setup will attempt to create it, provided it has proper permissions.</td>
 +</tr>
 +<tr class="row-even"><td><strong>DB User</strong></td>
 +<td>“dbuser” => “”,</td>
 +<td>This is the user that ownCloud uses to write to the databse.
 +This must be unique across ownCloud instances using the same SQL database.
 +The user will be created when the install wizard is complete.
 +Since the database user in the initial login screen has admin privileges (root), ownCloud creates a new user to ensure ownCloud does not run with unnecessary database permissions.
 +ownCloud prefixes “<a href="#id1"><span class="problematic" id="id2">oc_</span></a>” to the userid to prevent a collision between the ownCloud admin user and any existing database users.
 +This is generated at the time of the initial login and is the Admin User as entered by the ownCloud admin.</td>
 +</tr>
 +<tr class="row-odd"><td><strong>DB Password</strong></td>
 +<td>“dbpassword” => “”,</td>
 +<td>When a new database user is created for ownCloud, a password for the database is generated by hashing the admin user password.
 +This hash is stored in this parameter.</td>
 +</tr>
 +<tr class="row-even"><td><strong>DB Host</strong></td>
 +<td>“dbhost” => “”,</td>
 +<td>This parameter shows the location of the database.
 +Can be an IP pointing to the database server, a Fully Qualified Domain Name (FQDN) or localhost.</td>
 +</tr>
 +<tr class="row-odd"><td><strong>DB Table Prefix</strong></td>
 +<td>“dbtableprefix” => “<a href="#id3"><span class="problematic" id="id4">oc_</span></a>”,</td>
 +<td>All tables in the database will begin with this prefix.
 +By default the prefix is “<a href="#id5"><span class="problematic" id="id6">oc_</span></a>”.
 +If this prefix is changed in the config file, the tables in the database will need to be manually renamed.
 +ownCloud will not detect a change to this option so changing this prefix without manually renaming the tables will break the instance of ownCloud.</td>
 +</tr>
 +<tr class="row-even"><td><strong>Password Salt</strong></td>
 +<td>“passwordsalt” => “”,</td>
 +<td>This is the salt used to hash passwords within the ownCloud instance.
 +It is important not to remove or lose this password.
 +If lost, all passwords within the ownCloud instance will be lost.</td>
 +</tr>
 +<tr class="row-odd"><td><strong>Data Directory</strong></td>
 +<td>“datadirectory” => “”,</td>
 +<td>This parameter tells ownCloud where the default data directory is located.
 +It is configured in the installation wizard.
 +If using SQLITE, the database is stored in this data directory as well.</td>
 +</tr>
++<tr class="row-even"><td><strong>Trusted Domains</strong></td>
++<td><p class="first">  ‘trusted_domains’ =></p>
++<p>  array (</p>
++<p>    0 => ‘A.B.C.D
++‘,</p>
++<p class="last">  ),</p>
++</td>
++<td>This parameter identifies trusted URL for ownCloud which users may log into.
++The initial entry ‘0’ is automatic.
++If it is desired to have additional entries, these may be added manually.
++This is used to mitigate Header Post Poisoning attacks.</td>
++</tr>
 +</tbody>
 +</table>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/config/deleted_items.html
index 534f996,0000000..26521fc
mode 100644,000000..100644
--- a/core/doc/admin/config/deleted_items.html
+++ b/core/doc/admin/config/deleted_items.html
@@@ -1,167 -1,0 +1,187 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
 +    <title>Deleted Items — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
++    <link rel="up" title="The Configuration File" href="index.html" />
++    <link rel="next" title="Verification" href="verification.html" />
++    <link rel="prev" title="Mail Parameters" href="mail_parameters.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
- <ul>
++<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../installation/index.html">Installation</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../configuration/index.html">Configuration</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1 current"><a class="reference internal" href="index.html">The Configuration File</a><ul class="current">
++<li class="toctree-l2"><a class="reference internal" href="default_parameters.html">Default Parameters</a></li>
++<li class="toctree-l2"><a class="reference internal" href="reverse_proxy_configurations.html">Reverse Proxy Configurations</a></li>
++<li class="toctree-l2"><a class="reference internal" href="user_experience.html">User Experience</a></li>
++<li class="toctree-l2"><a class="reference internal" href="mail_parameters.html">Mail Parameters</a></li>
++<li class="toctree-l2 current"><a class="current reference internal" href="">Deleted Items</a></li>
++<li class="toctree-l2"><a class="reference internal" href="verification.html">Verification</a></li>
++<li class="toctree-l2"><a class="reference internal" href="logging.html">Logging</a></li>
++<li class="toctree-l2"><a class="reference internal" href="session_info.html">Session Info</a></li>
++<li class="toctree-l2"><a class="reference internal" href="code_locations.html">Code Locations</a></li>
++<li class="toctree-l2"><a class="reference internal" href="apps.html">APPS</a></li>
++<li class="toctree-l2"><a class="reference internal" href="previews.html">Previews</a></li>
++<li class="toctree-l2"><a class="reference internal" href="maintenance.html">Maintenance</a></li>
++<li class="toctree-l2"><a class="reference internal" href="miscellaneous.html">Miscellaneous</a></li>
++</ul>
++</li>
 +<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
 +  <div class="section" id="deleted-items">
 +<h1>Deleted Items<a class="headerlink" href="#deleted-items" title="Permalink to this headline">¶</a></h1>
 +<p>These parameters are related to the deleted files app.</p>
 +<table border="1" class="docutils">
 +<colgroup>
 +<col width="15%" />
 +<col width="23%" />
 +<col width="62%" />
 +</colgroup>
 +<tbody valign="top">
 +<tr class="row-odd"><td><strong>Parameter</strong></td>
 +<td><strong>Format</strong></td>
 +<td><strong>Description</strong></td>
 +</tr>
 +<tr class="row-even"><td><strong>Trash Bin Rentention</strong></td>
 +<td>‘trashbin_retention_obligation’ => 30,</td>
 +<td>When the delete app is enabled (default), this is the amount of days a file will be kept in the trash bin.
 +Default is 30 days.</td>
 +</tr>
 +<tr class="row-odd"><td><strong>Trash Bin Auto Expire</strong></td>
 +<td>‘trashbin_auto_expire’ => true,</td>
 +<td> </td>
 +</tr>
 +</tbody>
 +</table>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/config/index.html
index f186da8,0000000..df93651
mode 100644,000000..100644
--- a/core/doc/admin/config/index.html
+++ b/core/doc/admin/config/index.html
@@@ -1,161 -1,0 +1,171 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
-     <title><no title> — ownCloud Administrators Manual 6.0 documentation</title>
++    <title>The Configuration File — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
++    <link rel="next" title="Default Parameters" href="default_parameters.html" />
++    <link rel="prev" title="Migrating ownCloud Installations" href="../maintenance/migrating.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
- <ul>
++<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../installation/index.html">Installation</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../configuration/index.html">Configuration</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1 current"><a class="current reference internal" href="">The Configuration File</a><ul>
++<li class="toctree-l2"><a class="reference internal" href="default_parameters.html">Default Parameters</a></li>
++<li class="toctree-l2"><a class="reference internal" href="reverse_proxy_configurations.html">Reverse Proxy Configurations</a></li>
++<li class="toctree-l2"><a class="reference internal" href="user_experience.html">User Experience</a></li>
++<li class="toctree-l2"><a class="reference internal" href="mail_parameters.html">Mail Parameters</a></li>
++<li class="toctree-l2"><a class="reference internal" href="deleted_items.html">Deleted Items</a></li>
++<li class="toctree-l2"><a class="reference internal" href="verification.html">Verification</a></li>
++<li class="toctree-l2"><a class="reference internal" href="logging.html">Logging</a></li>
++<li class="toctree-l2"><a class="reference internal" href="session_info.html">Session Info</a></li>
++<li class="toctree-l2"><a class="reference internal" href="code_locations.html">Code Locations</a></li>
++<li class="toctree-l2"><a class="reference internal" href="apps.html">APPS</a></li>
++<li class="toctree-l2"><a class="reference internal" href="previews.html">Previews</a></li>
++<li class="toctree-l2"><a class="reference internal" href="maintenance.html">Maintenance</a></li>
++<li class="toctree-l2"><a class="reference internal" href="miscellaneous.html">Miscellaneous</a></li>
++</ul>
++</li>
 +<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
-   <p><strong>ownCloud config.php</strong></p>
++  <div class="section" id="the-configuration-file">
++<h1>The Configuration File<a class="headerlink" href="#the-configuration-file" title="Permalink to this headline">¶</a></h1>
 +<div class="toctree-wrapper compound">
- <ul>
- <li class="toctree-l1"><a class="reference internal" href="Table_of_Contents.html">Table of Contents</a></li>
- <li class="toctree-l1"><a class="reference internal" href="Introduction.html">Introduction</a></li>
- <li class="toctree-l1"><a class="reference internal" href="Default_Parameters.html">Default Parameters</a></li>
- <li class="toctree-l1"><a class="reference internal" href="Reverse_Proxy_Configurations.html">Reverse Proxy Configurations</a></li>
- <li class="toctree-l1"><a class="reference internal" href="User_Experience.html">User Experience</a></li>
- <li class="toctree-l1"><a class="reference internal" href="Mail_Parameters.html">Mail Parameters</a></li>
- <li class="toctree-l1"><a class="reference internal" href="Deleted_Items.html">Deleted Items</a></li>
- <li class="toctree-l1"><a class="reference internal" href="Verification.html">Verification</a></li>
- <li class="toctree-l1"><a class="reference internal" href="Logging.html">Logging</a></li>
- <li class="toctree-l1"><a class="reference internal" href="Session_Info.html">Session Info</a></li>
- <li class="toctree-l1"><a class="reference internal" href="Code_Locations.html">Code Locations</a></li>
- <li class="toctree-l1"><a class="reference internal" href="APPS.html">APPS</a></li>
- <li class="toctree-l1"><a class="reference internal" href="Previews.html">Previews</a></li>
- <li class="toctree-l1"><a class="reference internal" href="Maintenance.html">Maintenance</a></li>
- <li class="toctree-l1"><a class="reference internal" href="Miscellaneous.html">Miscellaneous</a></li>
- </ul>
++</div>
++<p>ownCloud uses a configuration file to set certain parameters.  The
++configuration file is entitled <cite>config.php</cite> and resides in the <cite>config</cite>
++directory of the ownCloud installation. Also residing in that directory is a
++sample configuration file entitled <cite>config.sample.php</cite>.  This file lists all
++the configurable parameters within ownCloud along with a brief description.
++This document will provide more details as to what each parameter is used for.</p>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/config/logging.html
index a7710c9,0000000..1c37616
mode 100644,000000..100644
--- a/core/doc/admin/config/logging.html
+++ b/core/doc/admin/config/logging.html
@@@ -1,207 -1,0 +1,227 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
 +    <title>Logging — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
++    <link rel="up" title="The Configuration File" href="index.html" />
++    <link rel="next" title="Session Info" href="session_info.html" />
++    <link rel="prev" title="Verification" href="verification.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
- <ul>
++<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../installation/index.html">Installation</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../configuration/index.html">Configuration</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1 current"><a class="reference internal" href="index.html">The Configuration File</a><ul class="current">
++<li class="toctree-l2"><a class="reference internal" href="default_parameters.html">Default Parameters</a></li>
++<li class="toctree-l2"><a class="reference internal" href="reverse_proxy_configurations.html">Reverse Proxy Configurations</a></li>
++<li class="toctree-l2"><a class="reference internal" href="user_experience.html">User Experience</a></li>
++<li class="toctree-l2"><a class="reference internal" href="mail_parameters.html">Mail Parameters</a></li>
++<li class="toctree-l2"><a class="reference internal" href="deleted_items.html">Deleted Items</a></li>
++<li class="toctree-l2"><a class="reference internal" href="verification.html">Verification</a></li>
++<li class="toctree-l2 current"><a class="current reference internal" href="">Logging</a></li>
++<li class="toctree-l2"><a class="reference internal" href="session_info.html">Session Info</a></li>
++<li class="toctree-l2"><a class="reference internal" href="code_locations.html">Code Locations</a></li>
++<li class="toctree-l2"><a class="reference internal" href="apps.html">APPS</a></li>
++<li class="toctree-l2"><a class="reference internal" href="previews.html">Previews</a></li>
++<li class="toctree-l2"><a class="reference internal" href="maintenance.html">Maintenance</a></li>
++<li class="toctree-l2"><a class="reference internal" href="miscellaneous.html">Miscellaneous</a></li>
++</ul>
++</li>
 +<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
 +  <div class="section" id="logging">
 +<h1>Logging<a class="headerlink" href="#logging" title="Permalink to this headline">¶</a></h1>
 +<p>This section describes parameters associated with ownCloud’s logging abilities.</p>
 +<table border="1" class="docutils">
 +<colgroup>
 +<col width="10%" />
 +<col width="25%" />
 +<col width="65%" />
 +</colgroup>
 +<tbody valign="top">
 +<tr class="row-odd"><td><strong>Parameter</strong></td>
 +<td><strong>Format</strong></td>
 +<td><strong>Description</strong></td>
 +</tr>
 +<tr class="row-even"><td><strong>Log Type</strong></td>
 +<td>“log_type” => “owncloud”,</td>
 +<td>By default the ownCloud logs are sent to the owncloud.log file within the default data directory.
 +If syslogging is desired, set this parameter to syslog.</td>
 +</tr>
 +<tr class="row-odd"><td><strong>Log File</strong></td>
 +<td>“logfile” => “”,</td>
 +<td>The log file, by default, is owncloud.log and stored in the default data directory.
 +Use this parameter to change the name to something other than owncloud.log.</td>
 +</tr>
 +<tr class="row-even"><td><strong>Log Level</strong></td>
 +<td>“loglevel” => “”,</td>
 +<td>ownCloud has several levels of logging.
 +This may be set on the Admin page of the webUI or directly in the configuration file using this parameter.
 +Valid values are: 0=Debug, 1=Info, 2=Warning, 3=Error.
 +The default value is Warning</td>
 +</tr>
 +<tr class="row-odd"><td><strong>Log Date Format</strong></td>
 +<td>‘logdateformat’ => ‘F d, Y H:i:s’,</td>
 +<td>ownCloud allows the admin to specify the format of the time and date within the log file.
 +Valid values may be found at the following website:
 +<a class="reference external" href="http://www.php.net/manual/en/function.date.php">http://www.php.net/manual/en/function.date.php</a>
 +.</td>
 +</tr>
 +<tr class="row-even"><td><strong>Log Time Zone</strong></td>
 +<td>‘logtimezone’ => ‘Europe/Berlin’,</td>
 +<td>By default, the time zone displayed in the ownCloud logs is UTC.
 +To change the displayed time zone to the local time zone, use this parameter.
 +For a list of valid values, see the following website:
 +<a class="reference external" href="http://php.net/manual/en/timezones.php">http://php.net/manual/en/timezones.php</a>
 +.</td>
 +</tr>
 +<tr class="row-odd"><td><strong>Log Query</strong></td>
 +<td>“log_query” => false,</td>
 +<td>When set to “true”, all SQL queries performed by ownCloud will be written to the log file.
 +Default is false.
 +It is not recommended to run with this enabled as it will fill up the log file.
 +Use only for debugging purposes.</td>
 +</tr>
 +<tr class="row-even"><td><strong>Log Auth Fail IP</strong></td>
 +<td>“log_authfailip” => false,</td>
 +<td>When set to true, the IP addresses of failed login attempts will be logged.</td>
 +</tr>
 +<tr class="row-odd"><td><strong>Log Rotate Size</strong></td>
 +<td>‘log_rotate_size’ => false, // 104857600, // 100 MiB</td>
 +<td>Since ownCloud log files can get large in size, this parameter may be used to rotate to a new log file once it reaches the specified size.
 +This should be configured in bytes.
 +Default is false, or 0, which will not rotate the file.</td>
 +</tr>
 +</tbody>
 +</table>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/config/mail_parameters.html
index 0000000,0000000..8868fa7
new file mode 100644
--- /dev/null
+++ b/core/doc/admin/config/mail_parameters.html
@@@ -1,0 -1,0 +1,239 @@@
++
++<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
++  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
++
++
++<html xmlns="http://www.w3.org/1999/xhtml">
++  <head>
++    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
++    
++    <title>Mail Parameters — ownCloud Administrators Manual 6.0 documentation</title>
++    
++    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
++    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
++    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
++    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
++    
++    <script type="text/javascript">
++      var DOCUMENTATION_OPTIONS = {
++        URL_ROOT:    '../',
++        VERSION:     '6.0',
++        COLLAPSE_INDEX: false,
++        FILE_SUFFIX: '.html',
++        HAS_SOURCE:  true
++      };
++    </script>
++    <script type="text/javascript" src="../_static/jquery.js"></script>
++    <script type="text/javascript" src="../_static/underscore.js"></script>
++    <script type="text/javascript" src="../_static/doctools.js"></script>
++    <script type="text/javascript" src="../_static/bootstrap.js"></script>
++    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
++    <link rel="up" title="The Configuration File" href="index.html" />
++    <link rel="next" title="Deleted Items" href="deleted_items.html" />
++    <link rel="prev" title="User Experience" href="user_experience.html" />
++<script type="text/javascript">
++(function () {
++  /**
++   * Patch TOC list.
++   *
++   * Will mutate the underlying span to have a correct ul for nav.
++   *
++   * @param $span: Span containing nested UL's to mutate.
++   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
++   */
++  var patchToc = function ($ul, minLevel) {
++    var findA;
++
++    // Find all a "internal" tags, traversing recursively.
++    findA = function ($elem, level) {
++      var level = level || 0,
++        $items = $elem.find("> li > a.internal, > ul, > li > ul");
++
++      // Iterate everything in order.
++      $items.each(function (index, item) {
++        var $item = $(item),
++          tag = item.tagName.toLowerCase(),
++          pad = 15 + ((level - minLevel) * 10);
++
++        if (tag === 'a' && level >= minLevel) {
++          // Add to existing padding.
++          $item.css('padding-left', pad + "px");
++          console.log(level, $item, 'padding-left', pad + "px");
++        } else if (tag === 'ul') {
++          // Recurse.
++          findA($item, level + 1);
++        }
++      });
++    };
++
++    console.log("HERE");
++    findA($ul);
++  };
++
++  $(document).ready(function () {
++    // Add styling, structure to TOC's.
++    $(".dropdown-menu").each(function () {
++      $(this).find("ul").each(function (index, item){
++        var $item = $(item);
++        $item.addClass('unstyled');
++      });
++      $(this).find("li").each(function () {
++        $(this).parent().append(this);
++      });
++    });
++
++    // Patch in level.
++    patchToc($("ul.globaltoc"), 2);
++    patchToc($("ul.localtoc"), 2);
++
++    // Enable dropdown.
++    $('.dropdown-toggle').dropdown();
++  });
++}());
++</script>
++
++  </head>
++  <body>
++  
++
++<div class="container">
++  <div class="content">
++    <div class="page-header">
++      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
++
++    </div>
++    
++			<div class="row">
++				<div class="span3">
++					<div class="sidebar">
++						<div class="well">
++							<div class="menu-support-container">
++								<ul id="menu-support" class="menu">
++									<ul>
++										<li><a href="../contents.html">Overview</a></li>
++									</ul>
++                  <ul>
++<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
++</ul>
++<ul class="current">
++<li class="toctree-l1"><a class="reference internal" href="../installation/index.html">Installation</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../configuration/index.html">Configuration</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1 current"><a class="reference internal" href="index.html">The Configuration File</a><ul class="current">
++<li class="toctree-l2"><a class="reference internal" href="default_parameters.html">Default Parameters</a></li>
++<li class="toctree-l2"><a class="reference internal" href="reverse_proxy_configurations.html">Reverse Proxy Configurations</a></li>
++<li class="toctree-l2"><a class="reference internal" href="user_experience.html">User Experience</a></li>
++<li class="toctree-l2 current"><a class="current reference internal" href="">Mail Parameters</a></li>
++<li class="toctree-l2"><a class="reference internal" href="deleted_items.html">Deleted Items</a></li>
++<li class="toctree-l2"><a class="reference internal" href="verification.html">Verification</a></li>
++<li class="toctree-l2"><a class="reference internal" href="logging.html">Logging</a></li>
++<li class="toctree-l2"><a class="reference internal" href="session_info.html">Session Info</a></li>
++<li class="toctree-l2"><a class="reference internal" href="code_locations.html">Code Locations</a></li>
++<li class="toctree-l2"><a class="reference internal" href="apps.html">APPS</a></li>
++<li class="toctree-l2"><a class="reference internal" href="previews.html">Previews</a></li>
++<li class="toctree-l2"><a class="reference internal" href="maintenance.html">Maintenance</a></li>
++<li class="toctree-l2"><a class="reference internal" href="miscellaneous.html">Miscellaneous</a></li>
++</ul>
++</li>
++<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
++</ul>
++
++								</ul>
++							</div>
++						</div>
++					</div>
++				</div>
++        
++
++				<div class="span9">
++					<div class="page-content">
++						
++  <div class="section" id="mail-parameters">
++<h1>Mail Parameters<a class="headerlink" href="#mail-parameters" title="Permalink to this headline">¶</a></h1>
++<p>These parameters are related to ownCloud’s ability to send emails for lost passwords or file shares.</p>
++<table border="1" class="docutils">
++<colgroup>
++<col width="13%" />
++<col width="19%" />
++<col width="68%" />
++</colgroup>
++<tbody valign="top">
++<tr class="row-odd"><td><strong>Parameter</strong></td>
++<td><strong>Format</strong></td>
++<td><strong>Description</strong></td>
++</tr>
++<tr class="row-even"><td><strong>Mail Domain</strong></td>
++<td>“mail_domain” => “example.com”,</td>
++<td>The domain to use when ownCloud sends emails.
++Emails can be sent in such instances as to share a public link, share notification or lost password.</td>
++</tr>
++<tr class="row-odd"><td><strong>Mail SMTP Debug</strong></td>
++<td>“mail_smtpdebug” => false,</td>
++<td> </td>
++</tr>
++<tr class="row-even"><td><strong>Mail SMTP Mode</strong></td>
++<td>“mail_smtpmode” => “sendmail”,</td>
++<td><p class="first">The method used to send mail.
++Valid values are smtp, php, sendmail and qmail.</p>
++<p>If using local or remote SMTP, set to smtp.</p>
++<p>If using PHP mail it is necessary to have an installed and working email system on the server.
++The program used to send email is defined in the PHP.ini file.</p>
++<p>If using sendmail, it is necessary to have an installed and working email system on the server.
++The sendmail binary is /usr/sbin/sendmail and should be installed on your <a href="#id1"><span class="problematic" id="id2">*</span></a>nix system.</p>
++<p class="last">If using qmail to send email, the binary is /var/qmail/bin/sendmail and should be installed in your <a href="#id3"><span class="problematic" id="id4">*</span></a>nix system.</p>
++</td>
++</tr>
++<tr class="row-odd"><td><strong>Mail SMTP Host</strong></td>
++<td>“mail_smtphost” => “127.0.0.1”,</td>
++<td>Mail server host.
++May contain multiple hosts separated by a semi colon.
++Also possible is to set the port used a particular host by following the host with a colon then the port number.</td>
++</tr>
++<tr class="row-even"><td><strong>Mail SMTP Port</strong></td>
++<td>“mail_smtpport” => 25,</td>
++<td>Port used to communicate with the mail server.</td>
++</tr>
++<tr class="row-odd"><td><strong>Mail SMTP TIMEOUT</strong></td>
++<td>“mail_smtptimeout” => 10,</td>
++<td>In the event that a malware or SPAM scanner is running on the SMTP server, it could be necessary to increase the SMTP timeout.
++That can be done using this parameter.</td>
++</tr>
++<tr class="row-even"><td><strong>Mail SMTP **
++**Secure</strong></td>
++<td>“mail_smtpsecure” => “”,</td>
++<td>Default value is no security.
++May be ssl or tls depending
++on the required level of security.</td>
++</tr>
++<tr class="row-odd"><td><strong>MAIL SMPT AUTH</strong></td>
++<td>“mail_smtpauth” => false,</td>
++<td>Determine if the mail server requires authentication.
++Default is false.
++If true, the following parameters should be configured as well.</td>
++</tr>
++<tr class="row-even"><td><strong>Mail SMTP Auth Type</strong></td>
++<td>“mail_smtpauthtype” => “LOGIN”,</td>
++<td>If SMTP authentication is required, choose the authentication type as login (default) or plain.</td>
++</tr>
++<tr class="row-odd"><td><strong>Mail SMTP Name</strong></td>
++<td>“mail_smtpname” => “username”,</td>
++<td>The username to use when authentication is enabled.</td>
++</tr>
++<tr class="row-even"><td><strong>Mail SMTP Password</strong></td>
++<td>“mail_smtppassword” => “password”,</td>
++<td>The password to use when authentication is enabled.</td>
++</tr>
++</tbody>
++</table>
++</div>
++
++
++					</div>
++				</div>
++			</div>
++    
++  </div>
++</div>
++  </body>
++</html>
diff --cc core/doc/admin/config/maintenance.html
index 71634bd,0000000..e3d4395
mode 100644,000000..100644
--- a/core/doc/admin/config/maintenance.html
+++ b/core/doc/admin/config/maintenance.html
@@@ -1,169 -1,0 +1,189 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
 +    <title>Maintenance — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
++    <link rel="up" title="The Configuration File" href="index.html" />
++    <link rel="next" title="Miscellaneous" href="miscellaneous.html" />
++    <link rel="prev" title="Previews" href="previews.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
- <ul>
++<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../installation/index.html">Installation</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../configuration/index.html">Configuration</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1 current"><a class="reference internal" href="index.html">The Configuration File</a><ul class="current">
++<li class="toctree-l2"><a class="reference internal" href="default_parameters.html">Default Parameters</a></li>
++<li class="toctree-l2"><a class="reference internal" href="reverse_proxy_configurations.html">Reverse Proxy Configurations</a></li>
++<li class="toctree-l2"><a class="reference internal" href="user_experience.html">User Experience</a></li>
++<li class="toctree-l2"><a class="reference internal" href="mail_parameters.html">Mail Parameters</a></li>
++<li class="toctree-l2"><a class="reference internal" href="deleted_items.html">Deleted Items</a></li>
++<li class="toctree-l2"><a class="reference internal" href="verification.html">Verification</a></li>
++<li class="toctree-l2"><a class="reference internal" href="logging.html">Logging</a></li>
++<li class="toctree-l2"><a class="reference internal" href="session_info.html">Session Info</a></li>
++<li class="toctree-l2"><a class="reference internal" href="code_locations.html">Code Locations</a></li>
++<li class="toctree-l2"><a class="reference internal" href="apps.html">APPS</a></li>
++<li class="toctree-l2"><a class="reference internal" href="previews.html">Previews</a></li>
++<li class="toctree-l2 current"><a class="current reference internal" href="">Maintenance</a></li>
++<li class="toctree-l2"><a class="reference internal" href="miscellaneous.html">Miscellaneous</a></li>
++</ul>
++</li>
 +<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
 +  <div class="section" id="maintenance">
 +<h1>Maintenance<a class="headerlink" href="#maintenance" title="Permalink to this headline">¶</a></h1>
 +<p>This section discusses the different stages of maintenance.</p>
 +<table border="1" class="docutils">
 +<colgroup>
 +<col width="12%" />
 +<col width="18%" />
 +<col width="70%" />
 +</colgroup>
 +<tbody valign="top">
 +<tr class="row-odd"><td><strong>Parameter</strong></td>
 +<td><strong>Format</strong></td>
 +<td><strong>Description</strong></td>
 +</tr>
 +<tr class="row-even"><td><strong>Single User</strong></td>
 +<td>‘singleuser’ => false,</td>
 +<td>When set to true, the ownCloud instance will be unavailable for all users not in the admin group.
 +This is useful when performing maintenance.</td>
 +</tr>
 +<tr class="row-odd"><td><strong>Maintenance</strong></td>
 +<td>“maintenance” => false,</td>
 +<td>Enable maintenance mode to disable ownCloud.
 +When performing upgrades, ownCloud automatically enters maintenance mode.
 +When enabled, users who are already logged-in are kicked out of ownCloud instantly.</td>
 +</tr>
 +</tbody>
 +</table>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/config/miscellaneous.html
index 0000000,0000000..fd03865
new file mode 100644
--- /dev/null
+++ b/core/doc/admin/config/miscellaneous.html
@@@ -1,0 -1,0 +1,224 @@@
++
++<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
++  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
++
++
++<html xmlns="http://www.w3.org/1999/xhtml">
++  <head>
++    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
++    
++    <title>Miscellaneous — ownCloud Administrators Manual 6.0 documentation</title>
++    
++    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
++    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
++    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
++    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
++    
++    <script type="text/javascript">
++      var DOCUMENTATION_OPTIONS = {
++        URL_ROOT:    '../',
++        VERSION:     '6.0',
++        COLLAPSE_INDEX: false,
++        FILE_SUFFIX: '.html',
++        HAS_SOURCE:  true
++      };
++    </script>
++    <script type="text/javascript" src="../_static/jquery.js"></script>
++    <script type="text/javascript" src="../_static/underscore.js"></script>
++    <script type="text/javascript" src="../_static/doctools.js"></script>
++    <script type="text/javascript" src="../_static/bootstrap.js"></script>
++    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
++    <link rel="up" title="The Configuration File" href="index.html" />
++    <link rel="next" title="Issues" href="../issues/index.html" />
++    <link rel="prev" title="Maintenance" href="maintenance.html" />
++<script type="text/javascript">
++(function () {
++  /**
++   * Patch TOC list.
++   *
++   * Will mutate the underlying span to have a correct ul for nav.
++   *
++   * @param $span: Span containing nested UL's to mutate.
++   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
++   */
++  var patchToc = function ($ul, minLevel) {
++    var findA;
++
++    // Find all a "internal" tags, traversing recursively.
++    findA = function ($elem, level) {
++      var level = level || 0,
++        $items = $elem.find("> li > a.internal, > ul, > li > ul");
++
++      // Iterate everything in order.
++      $items.each(function (index, item) {
++        var $item = $(item),
++          tag = item.tagName.toLowerCase(),
++          pad = 15 + ((level - minLevel) * 10);
++
++        if (tag === 'a' && level >= minLevel) {
++          // Add to existing padding.
++          $item.css('padding-left', pad + "px");
++          console.log(level, $item, 'padding-left', pad + "px");
++        } else if (tag === 'ul') {
++          // Recurse.
++          findA($item, level + 1);
++        }
++      });
++    };
++
++    console.log("HERE");
++    findA($ul);
++  };
++
++  $(document).ready(function () {
++    // Add styling, structure to TOC's.
++    $(".dropdown-menu").each(function () {
++      $(this).find("ul").each(function (index, item){
++        var $item = $(item);
++        $item.addClass('unstyled');
++      });
++      $(this).find("li").each(function () {
++        $(this).parent().append(this);
++      });
++    });
++
++    // Patch in level.
++    patchToc($("ul.globaltoc"), 2);
++    patchToc($("ul.localtoc"), 2);
++
++    // Enable dropdown.
++    $('.dropdown-toggle').dropdown();
++  });
++}());
++</script>
++
++  </head>
++  <body>
++  
++
++<div class="container">
++  <div class="content">
++    <div class="page-header">
++      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
++
++    </div>
++    
++			<div class="row">
++				<div class="span3">
++					<div class="sidebar">
++						<div class="well">
++							<div class="menu-support-container">
++								<ul id="menu-support" class="menu">
++									<ul>
++										<li><a href="../contents.html">Overview</a></li>
++									</ul>
++                  <ul>
++<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
++</ul>
++<ul class="current">
++<li class="toctree-l1"><a class="reference internal" href="../installation/index.html">Installation</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../configuration/index.html">Configuration</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1 current"><a class="reference internal" href="index.html">The Configuration File</a><ul class="current">
++<li class="toctree-l2"><a class="reference internal" href="default_parameters.html">Default Parameters</a></li>
++<li class="toctree-l2"><a class="reference internal" href="reverse_proxy_configurations.html">Reverse Proxy Configurations</a></li>
++<li class="toctree-l2"><a class="reference internal" href="user_experience.html">User Experience</a></li>
++<li class="toctree-l2"><a class="reference internal" href="mail_parameters.html">Mail Parameters</a></li>
++<li class="toctree-l2"><a class="reference internal" href="deleted_items.html">Deleted Items</a></li>
++<li class="toctree-l2"><a class="reference internal" href="verification.html">Verification</a></li>
++<li class="toctree-l2"><a class="reference internal" href="logging.html">Logging</a></li>
++<li class="toctree-l2"><a class="reference internal" href="session_info.html">Session Info</a></li>
++<li class="toctree-l2"><a class="reference internal" href="code_locations.html">Code Locations</a></li>
++<li class="toctree-l2"><a class="reference internal" href="apps.html">APPS</a></li>
++<li class="toctree-l2"><a class="reference internal" href="previews.html">Previews</a></li>
++<li class="toctree-l2"><a class="reference internal" href="maintenance.html">Maintenance</a></li>
++<li class="toctree-l2 current"><a class="current reference internal" href="">Miscellaneous</a></li>
++</ul>
++</li>
++<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
++</ul>
++
++								</ul>
++							</div>
++						</div>
++					</div>
++				</div>
++        
++
++				<div class="span9">
++					<div class="page-content">
++						
++  <div class="section" id="miscellaneous">
++<h1>Miscellaneous<a class="headerlink" href="#miscellaneous" title="Permalink to this headline">¶</a></h1>
++<p>The remaining parameters are listed below.</p>
++<table border="1" class="docutils">
++<colgroup>
++<col width="5%" />
++<col width="47%" />
++<col width="48%" />
++</colgroup>
++<tbody valign="top">
++<tr class="row-odd"><td><strong>Parameter</strong></td>
++<td><strong>Format</strong></td>
++<td><strong>Description</strong></td>
++</tr>
++<tr class="row-even"><td><strong>Open SSL</strong></td>
++<td><p class="first">‘openssl’ => array(</p>
++<p>//’config’ => ‘/absolute/location/of/openssl.cnf’,</p>
++<p class="last">),</p>
++</td>
++<td> </td>
++</tr>
++<tr class="row-odd"><td><strong>User Backends</strong></td>
++<td><p class="first">‘user_backends’=>array(</p>
++<p>array(</p>
++<p>‘class’=>’OC_User_IMAP’,</p>
++<p>‘arguments’=>array(‘{imap.gmail.com:993/imap/ssl}INBOX’),</p>
++<p>),</p>
++<p class="last">),</p>
++</td>
++<td>It is possible to configure additional user backends in ownCloud.
++The “External user Support” (user_external) app provides the following backends: IMAP (OC_User_IMAP), SMB (OC_User_SMB), FTP (OC_User_FTP).</td>
++</tr>
++<tr class="row-even"><td><strong>CSP Policy</strong></td>
++<td>“custom_csp_policy” => “default-src ‘self’; script-src ‘self’ ‘unsafe-eval’; style-src ‘self’ ‘unsafe-inline’; frame-src <a href="#id1"><span class="problematic" id="id2">*</span></a>; img-src <a href="#id3"><span class="problematic" id="id4">*</span></a>; font-src ‘self’ data:; media-src <a href="#id5"><span class="problematic" id="id6">*</span></a>”,</td>
++<td> </td>
++</tr>
++<tr class="row-odd"><td><strong>X Frame</strong></td>
++<td>“xframe_restriction” => true,</td>
++<td>XFrame-restriction is a header which
++prevents browsers from showing the site inside an iframe.
++This may be used to prevent clickjacking.</td>
++</tr>
++<tr class="row-even"><td><strong>Mem Cache</strong></td>
++<td>“memcached_server” => array(‘localhost’, 11211),</td>
++<td>Server details for one or more memcached servers to use for memory caching.
++Memcache is only used if other memory cache options (xcache, apc, apcu) are not available.</td>
++</tr>
++<tr class="row-odd"><td><strong>Force SSL</strong></td>
++<td>“forcessl” => false,</td>
++<td>If the admin checks “Enforce HTTPS” in the Admin page of the ownCloud WebUI. This will be set to true indicating that only HTTPS may be used to access this instance of ownCloud.
++HTTP requests will be denied.</td>
++</tr>
++<tr class="row-even"><td><strong>Black List</strong></td>
++<td>“blacklisted_files” => array(‘.htaccess’),</td>
++<td>Files listed in this array will not be uploaded to ownCloud.
++It should be noted that wildcards are not supported in this array.
++The configured must be exact file names to be blocked.
++If wildcards are
++required, use the ownCloud firewall.</td>
++</tr>
++</tbody>
++</table>
++</div>
++
++
++					</div>
++				</div>
++			</div>
++    
++  </div>
++</div>
++  </body>
++</html>
diff --cc core/doc/admin/config/previews.html
index 7d2ec1a,0000000..17a007b
mode 100644,000000..100644
--- a/core/doc/admin/config/previews.html
+++ b/core/doc/admin/config/previews.html
@@@ -1,188 -1,0 +1,208 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
 +    <title>Previews — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
++    <link rel="up" title="The Configuration File" href="index.html" />
++    <link rel="next" title="Maintenance" href="maintenance.html" />
++    <link rel="prev" title="APPS" href="apps.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
- <ul>
++<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../installation/index.html">Installation</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../configuration/index.html">Configuration</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1 current"><a class="reference internal" href="index.html">The Configuration File</a><ul class="current">
++<li class="toctree-l2"><a class="reference internal" href="default_parameters.html">Default Parameters</a></li>
++<li class="toctree-l2"><a class="reference internal" href="reverse_proxy_configurations.html">Reverse Proxy Configurations</a></li>
++<li class="toctree-l2"><a class="reference internal" href="user_experience.html">User Experience</a></li>
++<li class="toctree-l2"><a class="reference internal" href="mail_parameters.html">Mail Parameters</a></li>
++<li class="toctree-l2"><a class="reference internal" href="deleted_items.html">Deleted Items</a></li>
++<li class="toctree-l2"><a class="reference internal" href="verification.html">Verification</a></li>
++<li class="toctree-l2"><a class="reference internal" href="logging.html">Logging</a></li>
++<li class="toctree-l2"><a class="reference internal" href="session_info.html">Session Info</a></li>
++<li class="toctree-l2"><a class="reference internal" href="code_locations.html">Code Locations</a></li>
++<li class="toctree-l2"><a class="reference internal" href="apps.html">APPS</a></li>
++<li class="toctree-l2 current"><a class="current reference internal" href="">Previews</a></li>
++<li class="toctree-l2"><a class="reference internal" href="maintenance.html">Maintenance</a></li>
++<li class="toctree-l2"><a class="reference internal" href="miscellaneous.html">Miscellaneous</a></li>
++</ul>
++</li>
 +<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
 +  <div class="section" id="previews">
 +<h1>Previews<a class="headerlink" href="#previews" title="Permalink to this headline">¶</a></h1>
 +<p>ownCloud allows for thumbnail previews of files.
 +This section contains the different configuration parameters available for that functionality.</p>
 +<table border="1" class="docutils">
 +<colgroup>
 +<col width="18%" />
 +<col width="36%" />
 +<col width="46%" />
 +</colgroup>
 +<tbody valign="top">
 +<tr class="row-odd"><td><strong>Parameter</strong></td>
 +<td><strong>Format</strong></td>
 +<td><strong>Description</strong></td>
 +</tr>
 +<tr class="row-even"><td><strong>Enable Previews</strong></td>
 +<td>‘enable_previews’ => true,</td>
 +<td>When enabled, default, the user will have file thumbnails visible.
 +Disable to remove thumbnails.</td>
 +</tr>
 +<tr class="row-odd"><td><strong>Preview Width</strong></td>
 +<td>‘preview_max_x’ => null,</td>
 +<td>Maximum width of the thumbnail.
 +Default is null meaning no limit.</td>
 +</tr>
 +<tr class="row-even"><td><strong>Preview Height</strong></td>
 +<td>‘preview_max_y’ => null,</td>
 +<td>The maximum height of the thumbnail.
 +Default is set to null meaning no limit.</td>
 +</tr>
 +<tr class="row-odd"><td><strong>Scale Factor</strong></td>
 +<td>‘preview_max_scale_factor’ => 10,</td>
 +<td>Scale the thumbnail by this factor.
 +Default is 10.</td>
 +</tr>
 +<tr class="row-even"><td><strong>Libreoffice Path</strong></td>
 +<td>‘preview_libreoffice_path’ => ‘/usr/bin/libreoffice’,</td>
 +<td>ownCloud uses Libre Office for previews.
 +This parameter indicates the location of the Libre Office executable.</td>
 +</tr>
 +<tr class="row-odd"><td><strong>Libreoffice Parameters</strong></td>
 +<td>‘preview_office_cl_parameters’ => ‘’,</td>
 +<td>Use this if Libre Office requires additional arguments</td>
 +</tr>
 +</tbody>
 +</table>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/config/reverse_proxy_configurations.html
index 1ddec1a,0000000..b8e5143
mode 100644,000000..100644
--- a/core/doc/admin/config/reverse_proxy_configurations.html
+++ b/core/doc/admin/config/reverse_proxy_configurations.html
@@@ -1,199 -1,0 +1,218 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
 +    <title>Reverse Proxy Configurations — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
++    <link rel="up" title="The Configuration File" href="index.html" />
++    <link rel="next" title="User Experience" href="user_experience.html" />
++    <link rel="prev" title="Default Parameters" href="default_parameters.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
- <ul>
++<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../installation/index.html">Installation</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../configuration/index.html">Configuration</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1 current"><a class="reference internal" href="index.html">The Configuration File</a><ul class="current">
++<li class="toctree-l2"><a class="reference internal" href="default_parameters.html">Default Parameters</a></li>
++<li class="toctree-l2 current"><a class="current reference internal" href="">Reverse Proxy Configurations</a></li>
++<li class="toctree-l2"><a class="reference internal" href="user_experience.html">User Experience</a></li>
++<li class="toctree-l2"><a class="reference internal" href="mail_parameters.html">Mail Parameters</a></li>
++<li class="toctree-l2"><a class="reference internal" href="deleted_items.html">Deleted Items</a></li>
++<li class="toctree-l2"><a class="reference internal" href="verification.html">Verification</a></li>
++<li class="toctree-l2"><a class="reference internal" href="logging.html">Logging</a></li>
++<li class="toctree-l2"><a class="reference internal" href="session_info.html">Session Info</a></li>
++<li class="toctree-l2"><a class="reference internal" href="code_locations.html">Code Locations</a></li>
++<li class="toctree-l2"><a class="reference internal" href="apps.html">APPS</a></li>
++<li class="toctree-l2"><a class="reference internal" href="previews.html">Previews</a></li>
++<li class="toctree-l2"><a class="reference internal" href="maintenance.html">Maintenance</a></li>
++<li class="toctree-l2"><a class="reference internal" href="miscellaneous.html">Miscellaneous</a></li>
++</ul>
++</li>
 +<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
 +  <div class="section" id="reverse-proxy-configurations">
 +<h1>Reverse Proxy Configurations<a class="headerlink" href="#reverse-proxy-configurations" title="Permalink to this headline">¶</a></h1>
 +<p>The following parameters are used in the instance that Proxies are being used within the network.</p>
 +<table border="1" class="docutils">
 +<colgroup>
 +<col width="9%" />
 +<col width="14%" />
 +<col width="78%" />
 +</colgroup>
 +<tbody valign="top">
 +<tr class="row-odd"><td><strong>Parameter</strong></td>
 +<td><strong>Format</strong></td>
 +<td><strong>Description</strong></td>
 +</tr>
 +<tr class="row-even"><td><strong>Overwrite Host</strong></td>
 +<td>“overwritehost” => “”,</td>
- <td><p class="first">By default, ownCloud attempts to detect what outside host can access the instance (www.example.com
- ) for generating URLs.
++<td><p class="first">By default, ownCloud attempts to detect what outside host can access the instance (www.example.com) for generating URLs.
 +However, due to some reverse proxies, the automatically detected value may be incorrect (www.example.com:88) which would lead to incorrect URLs being generated.
 +Use this field to enter the proper URL.</p>
 +<p>If set as follows: “overwritehost” => “<a class="reference external" href="http://www.example.com:88">http://www.example.com:88</a>”,</p>
 +<p class="last">When logging into ownCloud, the browser will point to port 88.</p>
 +</td>
 +</tr>
 +<tr class="row-odd"><td><strong>Overwrite Protocol</strong></td>
 +<td>“overwriteprotocol” => “”,</td>
 +<td><p class="first">When generating URLs, ownCloud attempts to detect whether the server is accessed via https or http.
 +However, if ownCloud is behind a proxy and the proxy handles the https calls, thereby leaving ownCloud running without SSL, ownCloud would not realize that ssl is in use which would result in incorrect URLs being generated.
 +Valid values are “http” and “https”.</p>
 +<p>If set as follows:</p>
 +<p>“overwriteprotocol” => “https”,</p>
 +<p class="last">ownCloud will generate all URLs as HTTPS rather than HTTP.</p>
 +</td>
 +</tr>
 +<tr class="row-even"><td><strong>Overwrite Web Root</strong></td>
 +<td>“overwritewebroot” => “”,</td>
 +<td>As with the host and protocol, ownCloud attempts to detect the webroot for generating URLs automatically.
 +The webroot is the path used to access ownCloud relative to the domain, for instance, if
 +<a class="reference external" href="http://www.example.com/owncloud">www.example.com/owncloud</a>
 +is the URL pointing to the ownCloud instance, the webroot would be /owncloud.
 +When proxies are in use, it may be difficult for ownCloud to detect this parameter resulting in invalid URLs.</td>
 +</tr>
 +<tr class="row-odd"><td><strong>Overwrite Cond Addr</strong></td>
 +<td>“overwritecondaddr” => “”,</td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td><strong>Proxy</strong></td>
 +<td>“proxy” => “”,</td>
 +<td>In the instance where a proxy is required to access the internet, the proxy should be configured in this parameter.
 +ownCloud requires access to the internet for several functions, and thus needs to have the proxy information configured to access the internet.</td>
 +</tr>
 +<tr class="row-odd"><td><strong>Proxy User Password</strong></td>
 +<td>“proxyuserpwd” => “username:password”,</td>
 +<td>In the event that a proxy is configured and requires authentication, the username and password would be configured in this parameter.</td>
 +</tr>
 +</tbody>
 +</table>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/config/session_info.html
index b53dac1,0000000..e71c323
mode 100644,000000..100644
--- a/core/doc/admin/config/session_info.html
+++ b/core/doc/admin/config/session_info.html
@@@ -1,172 -1,0 +1,192 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
 +    <title>Session Info — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
++    <link rel="up" title="The Configuration File" href="index.html" />
++    <link rel="next" title="Code Locations" href="code_locations.html" />
++    <link rel="prev" title="Logging" href="logging.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
- <ul>
++<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../installation/index.html">Installation</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../configuration/index.html">Configuration</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1 current"><a class="reference internal" href="index.html">The Configuration File</a><ul class="current">
++<li class="toctree-l2"><a class="reference internal" href="default_parameters.html">Default Parameters</a></li>
++<li class="toctree-l2"><a class="reference internal" href="reverse_proxy_configurations.html">Reverse Proxy Configurations</a></li>
++<li class="toctree-l2"><a class="reference internal" href="user_experience.html">User Experience</a></li>
++<li class="toctree-l2"><a class="reference internal" href="mail_parameters.html">Mail Parameters</a></li>
++<li class="toctree-l2"><a class="reference internal" href="deleted_items.html">Deleted Items</a></li>
++<li class="toctree-l2"><a class="reference internal" href="verification.html">Verification</a></li>
++<li class="toctree-l2"><a class="reference internal" href="logging.html">Logging</a></li>
++<li class="toctree-l2 current"><a class="current reference internal" href="">Session Info</a></li>
++<li class="toctree-l2"><a class="reference internal" href="code_locations.html">Code Locations</a></li>
++<li class="toctree-l2"><a class="reference internal" href="apps.html">APPS</a></li>
++<li class="toctree-l2"><a class="reference internal" href="previews.html">Previews</a></li>
++<li class="toctree-l2"><a class="reference internal" href="maintenance.html">Maintenance</a></li>
++<li class="toctree-l2"><a class="reference internal" href="miscellaneous.html">Miscellaneous</a></li>
++</ul>
++</li>
 +<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
 +  <div class="section" id="session-info">
 +<h1>Session Info<a class="headerlink" href="#session-info" title="Permalink to this headline">¶</a></h1>
 +<p>The following parameters are related to sessions within ownCloud.</p>
 +<table border="1" class="docutils">
 +<colgroup>
 +<col width="13%" />
 +<col width="22%" />
 +<col width="65%" />
 +</colgroup>
 +<tbody valign="top">
 +<tr class="row-odd"><td><strong>Parameter</strong></td>
 +<td><strong>Format</strong></td>
 +<td><strong>Description</strong></td>
 +</tr>
 +<tr class="row-even"><td><strong>Remember Cookie Lifetime</strong></td>
 +<td>“remember_login_cookie_lifetime” => 60*60*24*15,</td>
 +<td>ownCloud provides the user the option of remembering their login credentials (this option appears as the “remember” checkbox on the login screen).
 +This parameter allows the admin to configure the length of time which ownCloud will remember that user.
 +Default is 15 days.
 +The configuration is in seconds.</td>
 +</tr>
 +<tr class="row-odd"><td><strong>Session Lifetime</strong></td>
 +<td>“session_lifetime” => 60 * 60 * 24,</td>
 +<td>ownCloud will automatically logout a user after a period of inactivity.
 +The default is 1 day.
 +This parameter can be used to modify that time.
 +Configuration is in seconds.</td>
 +</tr>
 +</tbody>
 +</table>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/config/user_experience.html
index 16bab55,0000000..790e72d
mode 100644,000000..100644
--- a/core/doc/admin/config/user_experience.html
+++ b/core/doc/admin/config/user_experience.html
@@@ -1,185 -1,0 +1,205 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
 +    <title>User Experience — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
++    <link rel="up" title="The Configuration File" href="index.html" />
++    <link rel="next" title="Mail Parameters" href="mail_parameters.html" />
++    <link rel="prev" title="Reverse Proxy Configurations" href="reverse_proxy_configurations.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
- <ul>
++<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../installation/index.html">Installation</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../configuration/index.html">Configuration</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1 current"><a class="reference internal" href="index.html">The Configuration File</a><ul class="current">
++<li class="toctree-l2"><a class="reference internal" href="default_parameters.html">Default Parameters</a></li>
++<li class="toctree-l2"><a class="reference internal" href="reverse_proxy_configurations.html">Reverse Proxy Configurations</a></li>
++<li class="toctree-l2 current"><a class="current reference internal" href="">User Experience</a></li>
++<li class="toctree-l2"><a class="reference internal" href="mail_parameters.html">Mail Parameters</a></li>
++<li class="toctree-l2"><a class="reference internal" href="deleted_items.html">Deleted Items</a></li>
++<li class="toctree-l2"><a class="reference internal" href="verification.html">Verification</a></li>
++<li class="toctree-l2"><a class="reference internal" href="logging.html">Logging</a></li>
++<li class="toctree-l2"><a class="reference internal" href="session_info.html">Session Info</a></li>
++<li class="toctree-l2"><a class="reference internal" href="code_locations.html">Code Locations</a></li>
++<li class="toctree-l2"><a class="reference internal" href="apps.html">APPS</a></li>
++<li class="toctree-l2"><a class="reference internal" href="previews.html">Previews</a></li>
++<li class="toctree-l2"><a class="reference internal" href="maintenance.html">Maintenance</a></li>
++<li class="toctree-l2"><a class="reference internal" href="miscellaneous.html">Miscellaneous</a></li>
++</ul>
++</li>
 +<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
 +  <div class="section" id="user-experience">
 +<h1>User Experience<a class="headerlink" href="#user-experience" title="Permalink to this headline">¶</a></h1>
 +<p>The following parameters are those that influence the end user’s experience.</p>
 +<table border="1" class="docutils">
 +<colgroup>
- <col width="14%" />
- <col width="23%" />
- <col width="63%" />
++<col width="11%" />
++<col width="24%" />
++<col width="65%" />
 +</colgroup>
 +<tbody valign="top">
 +<tr class="row-odd"><td><strong>Parameter</strong></td>
 +<td><strong>Format</strong></td>
 +<td><strong>Description</strong></td>
 +</tr>
 +<tr class="row-even"><td><strong>Default Language</strong></td>
 +<td>“default_language” => “en”,</td>
 +<td>This is the default language for the ownCloud WebUI. When configured, the default language will be the same for all users.
 +Users may then configure their own language preference in their Personal page.
 +When not configured, the default language is determined form the headers sent by the web browser.
 +For instance, if the browser is in Spanish, ownCloud will be presented in Spanish</td>
 +</tr>
 +<tr class="row-odd"><td><strong>Default App</strong></td>
 +<td>“defaultapp” => “files”,</td>
 +<td>By default, when a user logs into ownCloud, they are brought to the files page.
 +If, for instance, the admin desires a different page to be loaded upon login, configure that app here.
 +Valid values are app id’s (for example news, files, gallery).</td>
 +</tr>
- <tr class="row-even"><td><strong>Knowledge Base Enabled</strong></td>
++<tr class="row-even"><td><strong>Knowledge Base **
++**Enabled</strong></td>
 +<td>“knowledgebaseenabled” => true,</td>
 +<td>When enabled, default, the help menu brings up the user documentation.</td>
 +</tr>
 +<tr class="row-odd"><td><strong>Enable Avatars</strong></td>
 +<td>‘enable_avatars’ => true,</td>
 +<td>Allows for the ability to use avatars.</td>
 +</tr>
 +<tr class="row-even"><td><strong>Display Name</strong></td>
 +<td>‘allow_user_to_change_display_name’ => true,</td>
 +<td>Users can modify their display name in the Personal page.
- If this parameter is set to false, they may not change their display
- name.</td>
++If this parameter is set to false, they may not change their display name.</td>
 +</tr>
 +</tbody>
 +</table>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/config/verification.html
index 0354f78,0000000..355ace4
mode 100644,000000..100644
--- a/core/doc/admin/config/verification.html
+++ b/core/doc/admin/config/verification.html
@@@ -1,180 -1,0 +1,201 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
 +    <title>Verification — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
++    <link rel="up" title="The Configuration File" href="index.html" />
++    <link rel="next" title="Logging" href="logging.html" />
++    <link rel="prev" title="Deleted Items" href="deleted_items.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
- <ul>
++<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../installation/index.html">Installation</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../configuration/index.html">Configuration</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1 current"><a class="reference internal" href="index.html">The Configuration File</a><ul class="current">
++<li class="toctree-l2"><a class="reference internal" href="default_parameters.html">Default Parameters</a></li>
++<li class="toctree-l2"><a class="reference internal" href="reverse_proxy_configurations.html">Reverse Proxy Configurations</a></li>
++<li class="toctree-l2"><a class="reference internal" href="user_experience.html">User Experience</a></li>
++<li class="toctree-l2"><a class="reference internal" href="mail_parameters.html">Mail Parameters</a></li>
++<li class="toctree-l2"><a class="reference internal" href="deleted_items.html">Deleted Items</a></li>
++<li class="toctree-l2 current"><a class="current reference internal" href="">Verification</a></li>
++<li class="toctree-l2"><a class="reference internal" href="logging.html">Logging</a></li>
++<li class="toctree-l2"><a class="reference internal" href="session_info.html">Session Info</a></li>
++<li class="toctree-l2"><a class="reference internal" href="code_locations.html">Code Locations</a></li>
++<li class="toctree-l2"><a class="reference internal" href="apps.html">APPS</a></li>
++<li class="toctree-l2"><a class="reference internal" href="previews.html">Previews</a></li>
++<li class="toctree-l2"><a class="reference internal" href="maintenance.html">Maintenance</a></li>
++<li class="toctree-l2"><a class="reference internal" href="miscellaneous.html">Miscellaneous</a></li>
++</ul>
++</li>
 +<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
 +  <div class="section" id="verification">
 +<h1>Verification<a class="headerlink" href="#verification" title="Permalink to this headline">¶</a></h1>
 +<p>This section describes different verification checks that ownCloud may perform.</p>
 +<table border="1" class="docutils">
 +<colgroup>
 +<col width="16%" />
 +<col width="21%" />
 +<col width="63%" />
 +</colgroup>
 +<tbody valign="top">
 +<tr class="row-odd"><td><strong>Parameter</strong></td>
 +<td><strong>Format</strong></td>
 +<td><strong>Description</strong></td>
 +</tr>
 +<tr class="row-even"><td><strong>Update Checker</strong></td>
 +<td>“updatechecker” => true,</td>
 +<td>Provides information as to whether there is a new release of ownCloud available.
 +When enabled, default, a banner will appear on the admin’s web interface when a newer version of ownCloud exists.</td>
 +</tr>
 +<tr class="row-odd"><td><strong>Has Internet Connection</strong></td>
 +<td>“has_internet_connection” => true,</td>
 +<td>Alerts ownCloud if there is an internet connection (true – default).
 +If set to false, ownCloud will not be able to look for updates, display the knowledgebase, or bring up the appstore.</td>
 +</tr>
 +<tr class="row-even"><td><strong>Working WebDAV</strong></td>
 +<td>“check_for_working_webdav” => true,</td>
 +<td>Allows ownCloud to verify a working WebDAV connection.
 +This is done by attempting to make a WebDAV request from PHP.</td>
 +</tr>
 +<tr class="row-odd"><td><strong>Working .htaccess</strong></td>
 +<td>“check_for_working_htaccess” => true,</td>
 +<td>Verifies whether the .htaccess file may be modified by ownCloud.
- If set to false, this check will not be performed.
++If set to false, this check will not be
++performed.
 +If the file cannot be modified, items such as large file uploads cannot be performed.
 +This check only affects Apache servers.</td>
 +</tr>
 +</tbody>
 +</table>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/configuration/auth_ldap.html
index 2e38708,0000000..abd280e
mode 100644,000000..100644
--- a/core/doc/admin/configuration/auth_ldap.html
+++ b/core/doc/admin/configuration/auth_ldap.html
@@@ -1,784 -1,0 +1,785 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
-     <title>User Authentication with LDAP — ownCloud Administrators Manual 6.0 documentation</title>
++    <title>LDAP Authentication — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
 +    <link rel="up" title="Configuration" href="index.html" />
 +    <link rel="next" title="Background Jobs" href="background_jobs.html" />
 +    <link rel="prev" title="User Management" href="configuration_users.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
 +<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../installation/index.html">Installation</a></li>
 +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Configuration</a><ul class="current">
- <li class="toctree-l2"><a class="reference internal" href="configuration_apps.html">Apps Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_apps.html">Managing Apps</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_users.html">User Management</a></li>
- <li class="toctree-l2 current"><a class="current reference internal" href="">User Authentication with LDAP</a><ul>
++<li class="toctree-l2 current"><a class="current reference internal" href="">LDAP Authentication</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="#configuration">Configuration</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#advanced-settings">Advanced Settings</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#expert-settings">Expert Settings</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#testing-the-configuration">Testing the configuration</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#owncloud-avatar-integration">ownCloud Avatar integration</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#troubleshooting-tips-and-tricks">Troubleshooting, Tips and Tricks</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#ssl-certificate-verification-ldaps-tls">SSL Certificate Verification (LDAPS, TLS)</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#microsoft-active-directory">Microsoft Active Directory</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#duplicating-server-configurations">Duplicating Server Configurations</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#owncloud-ldap-internals">ownCloud LDAP Internals</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#groups">Groups</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#user-and-group-mapping">User and Group Mapping</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#caching">Caching</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#handling-with-backup-server">Handling with Backup Server</a></li>
 +</ul>
 +</li>
 +<li class="toctree-l2"><a class="reference internal" href="background_jobs.html">Background Jobs</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_3rdparty.html">3rd-Party Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_3rdparty.html">Find Third-Party Libraries</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_automation.html">Automatic Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_custom_clients.html">Custom Client Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_database.html">Database Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_encryption.html">Use Server-Side Encryption</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_knowledgebase.html">Knowledge Base Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_language.html">Language Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_logging.html">Logging Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_mail.html">Mail Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_maintenance.html">Maintenance Mode Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_preview.html">Preview Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_custom_clients.html">Customizing Client Download Links</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_database.html">MySQL/Postgres/SQLite Support</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_encryption.html">Using Server-Side Encryption</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_knowledgebase.html">Disable Knowledge Base</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_language.html">Setting the Default Language</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_logging.html">Configure Logging</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_mail.html">Sending Mail Notifications</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_maintenance.html">Enable Maintenance Mode</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_preview.html">Enabling File Previews</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_reverseproxy.html">Reverse Proxy Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html">Uploading big files > 512MB (as set by default)</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html#enabling-uploading-big-files">Enabling uploading big files</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html">Dealing with Big File Uploads</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_mount_config_gui.html">Custom Mount Configuration Web-GUI</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_mount_config.html">Custom Mount Configuration</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_user_backend.html">Custom User Backend Configuration</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="xsendfile.html">Serving static files via web server</a></li>
 +</ul>
 +</li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
-   <div class="section" id="user-authentication-with-ldap">
- <h1>User Authentication with LDAP<a class="headerlink" href="#user-authentication-with-ldap" title="Permalink to this headline">¶</a></h1>
++  <div class="section" id="ldap-authentication">
++<h1>LDAP Authentication<a class="headerlink" href="#ldap-authentication" title="Permalink to this headline">¶</a></h1>
 +<p>ownCloud ships an LDAP backend, which allows full use of ownCloud for user
 +logging in with LDAP credentials including:</p>
 +<ul class="simple">
 +<li>LDAP group support</li>
 +<li>File sharing with users and groups</li>
 +<li>Access via WebDAV and of course ownCloud Desktop Client</li>
 +<li>Versioning, external Storages and all other ownCloud goodies</li>
 +</ul>
 +<p>To connect to an LDAP server the configuration needs to be set up properly.
 +Once the LDAP backend is activated (Apps Sidebar→Apps, choose <strong>LDAP user and
 +group backend</strong>, click on <strong>Enable</strong>) the configuration can be found on
 +Settings→Admin. Read on for a detailed description of the configuration fields.</p>
 +<div class="section" id="configuration">
 +<h2>Configuration<a class="headerlink" href="#configuration" title="Permalink to this headline">¶</a></h2>
 +<p>The LDAP backend follows a wizard-like approach, splitted into four tabs. A
 +correctly completed first tab (“Server”) is mandatory to access the other tabs.
 +Also, the other tabs need to be reviewed by the admin, however the necessary
 +settings are detected automatically. An indicator will show whether the
 +configuration is incomplete, incorrect or OK.</p>
 +<p>The settings are changed automatically, as soon as a input element looses the
 +focus, i.e. the cursor is taken away by clicking somewhere else or pressing the
 +tabulator key.</p>
 +<p>The other tabs can be navigated by clicking the tabs or by using the <em>Continue</em>
 +and <em>Back</em> buttons. They are located on the lower right, next to the status
 +indicator.</p>
 +<div class="section" id="server">
 +<h3>Server<a class="headerlink" href="#server" title="Permalink to this headline">¶</a></h3>
 +<p>The server tab contains the basic information on the LDAP server. They make sure
 +that ownCloud will be able to connect to LDAP and be able to read data from
 +there. The admin at least needs to provide a hostname. If anonymous access is
 +not possible he will need to provide an account DN and a password, too. ownCloud
 +attempts to auto-detect the port and the base DN.</p>
 +<div class="figure">
 +<img alt="../_images/ldap-wizard-1-server.png" src="../_images/ldap-wizard-1-server.png" />
 +</div>
 +<dl class="docutils">
 +<dt>Server configuration:</dt>
 +<dd>ownCloud can be configured to connect to multiple LDAP servers. Using this
 +control you can pick a configuration you want to edit or add a new one. The
 +button <strong>Delete Configuration</strong> deletes the current configuration.</dd>
 +<dt>Host:</dt>
 +<dd><p class="first">The host name of the LDAP server. It can also be a <strong>ldaps://</strong> URI, for
 +instance.</p>
 +<p>It is also possible to pass a port number, which speeds up port detection. It
 +is especially useful, if a custom port is used. ownCloud will move the value
 +to the port field subsequently.</p>
 +<p>Examples:</p>
 +<ul class="last simple">
 +<li><em>directory.my-company.com</em></li>
 +<li><em>ldaps://directory.my-company.com</em></li>
 +<li><em>directory.my-company.com:9876</em></li>
 +</ul>
 +</dd>
 +<dt>Port:</dt>
 +<dd><p class="first">The port on which to connect to the LDAP server. The field is disabled in the
 +beginning of a new configuration. The port will be detected automatically,
 +if the LDAP server is running on a standard port. After ownCloud attempted to
 +determine the port, the field will be enabled for user input. A successfully
 +found port will be inserted by ownCloud, of course.</p>
 +<p>Example:</p>
 +<ul class="last simple">
 +<li><em>389</em></li>
 +</ul>
 +</dd>
 +<dt>User DN:</dt>
 +<dd><p class="first">The name as DN of a user who is able to do searches in the LDAP
 +directory. Leave it empty for anonymous access. It is recommended to have a
 +special system user for ownCloud.</p>
 +<p>Example:</p>
 +<ul class="last simple">
 +<li><em>uid=owncloudsystemuser,cn=sysusers,dc=my-company,dc=com</em></li>
 +</ul>
 +</dd>
 +<dt>Password:</dt>
 +<dd>The password for the user given above. Empty for anonymous access.</dd>
 +<dt>Base DN:</dt>
 +<dd><p class="first">The base DN of LDAP, from where all users and groups can be reached. Separated
 +Base DNs for users and groups can be set in the Advanced tab. Nevertheless,
 +this field is mandatory. ownCloud attempts to determine the Base DN according
 +to the provided User DN or the provided Host.</p>
 +<p>Example:</p>
 +<ul class="last simple">
 +<li><em>dc=my-company,dc=com</em></li>
 +</ul>
 +</dd>
 +</dl>
 +</div>
 +<div class="section" id="user-filter">
 +<h3>User Filter<a class="headerlink" href="#user-filter" title="Permalink to this headline">¶</a></h3>
 +<p>The settings in the user filter tab determine which LDAP users will appear and
 +are allowed to log in into ownCloud. It is also possible to enter a raw LDAP
 +filter.</p>
 +<div class="figure">
 +<img alt="../_images/ldap-wizard-2-user.png" src="../_images/ldap-wizard-2-user.png" />
 +</div>
 +<dl class="docutils">
 +<dt>only those object classes:</dt>
 +<dd>ownCloud will determine the object classes that are typically availalble for
 +(ideally only) user objects in your LDAP. ownCloud will automatically select
 +the object class that returns the highest amount of users. You can select
 +multiple object classes.</dd>
 +<dt>only from those groups:</dt>
 +<dd><p class="first">If your LDAP server supports the member-of-overlay in LDAP filters, you can
 +define that only users from one or more certain groups are allowed to
 +appear and log in into ownCloud. By default, no value will be selected. You
 +can select multiple groups.</p>
 +<p class="last">If your LDAP server does not support the member-of-overlay in LDAP filters,
 +the input field is disabled. Please contact your LDAP administrator.</p>
 +</dd>
 +<dt>Edit raw filter instead:</dt>
 +<dd><p class="first">Clicking on this text will toggle the filter mode. Instead of the assisted
 +approach, you can enter the raw LDAP filter directly in the appearing field.</p>
 +<p>Example:</p>
 +<ul class="last simple">
 +<li><em>objectClass=inetOrgPerson</em></li>
 +</ul>
 +</dd>
 +<dt>x users found:</dt>
 +<dd>This is an indicator that tells you approximately how many users will be
 +allowed to access ownCloud. The number will update after any change you do.</dd>
 +</dl>
 +</div>
 +<div class="section" id="login-filter">
 +<h3>Login Filter<a class="headerlink" href="#login-filter" title="Permalink to this headline">¶</a></h3>
 +<p>The settings in the login filter tab determine which user detail will be
 +compared to the login value entered by the user. It is possible to allow
 +multiple user details. It is also possible to enter a raw LDAP filter.</p>
 +<p>The user limitation as set up in the previous tab is in effect, unless you
 +manually configure the filter in raw mode.</p>
 +<div class="figure">
 +<img alt="../_images/ldap-wizard-3-login.png" src="../_images/ldap-wizard-3-login.png" />
 +</div>
 +<dl class="docutils">
 +<dt>LDAP Username:</dt>
 +<dd>If this value is checked, the login value will be compared to the username in
 +the LDAP directory. The corresponding attribute, usually <em>uid</em> or
 +<em>samaccountname</em> will be detected automatically by ownCloud.</dd>
 +<dt>LDAP Email Address:</dt>
 +<dd>If this value is checked, the login value will be compared to an email address
 +in the LDAP directory. The email address will be looked for in the
 +<em>mailPrimaryAddress</em> and <em>mail</em> attributes.</dd>
 +<dt>Other Attributes:</dt>
 +<dd>This multiselect box allows you to select other attributes for the comparison.
 +The list is generated automatically based on the attributes that a user object
 +contains in your LDAP server.</dd>
 +<dt>Edit raw filter instead:</dt>
 +<dd><p class="first">Clicking on this text will toggle the filter mode. Instead of the assisted
 +approach, you can enter the raw LDAP filter directly in the appearing field.</p>
 +<p>The <strong>%uid</strong> placeholder will be replaced with the login name entered by the user
 +upon login. When you enter the filter manually.</p>
 +<p>Examples:</p>
 +<ul class="last simple">
 +<li>only username: <em>uid=%uid</em></li>
 +<li>username or email address: <em>(|(uid=%uid)(mail=$uid))</em></li>
 +</ul>
 +</dd>
 +</dl>
 +</div>
 +<div class="section" id="group-filter">
 +<h3>Group Filter<a class="headerlink" href="#group-filter" title="Permalink to this headline">¶</a></h3>
 +<p>The settings in the group filter tab determine which groups will be availalble
 +in ownCloud. It does not have any restrictions on logins, this has been dealed
 +with in the prior tabs.  It is also possible to enter a raw LDAP
 +filter.</p>
 +<p>By default, no groups will be availalble in ownCloud. You actively need to
 +enable groups.</p>
 +<div class="figure">
 +<img alt="../_images/ldap-wizard-4-group.png" src="../_images/ldap-wizard-4-group.png" />
 +</div>
 +<dl class="docutils">
 +<dt>only those object classes:</dt>
 +<dd>ownCloud will determine the object classes that are typically availalble for
 +(ideally only) group objects in your LDAP. ownCloud will only list object
 +classes that return at least one group object. You can select multiple
 +object classes. A typical object class is “group”, or “posixGroup”.</dd>
 +<dt>only from those groups:</dt>
 +<dd>This setting lets you pick certain groups that shall be availalble in
 +ownCloud. This field follows a whitelist approach. ownCloud will generate a
 +list of available groups found in your LDAP server. You can select multiple
 +groups.</dd>
 +<dt>Edit raw filter instead:</dt>
 +<dd><p class="first">Clicking on this text will toggle the filter mode. Instead of the assisted
 +approach, you can enter the raw LDAP filter directly in the appearing field.</p>
 +<p>Example:</p>
 +<ul class="last simple">
 +<li><em>objectClass=group</em></li>
 +<li><em>objectClass=posixGroup</em></li>
 +</ul>
 +</dd>
 +<dt>y groups found:</dt>
 +<dd>This is an indicator that tells you approximately how many groups will be
 +available in  ownCloud. The number will update after any change you do.</dd>
 +</dl>
 +</div>
 +</div>
 +<div class="section" id="advanced-settings">
 +<h2>Advanced Settings<a class="headerlink" href="#advanced-settings" title="Permalink to this headline">¶</a></h2>
 +<p>In the LDAP Advanced settings section you can define options, that are less
 +common to set. They are not needed for a working connection. It can also have a
 +positive effect on the performance to specify distinguished bases for user and
 +group searches.</p>
 +<p>The Advanced Settings are structured into three parts:</p>
 +<ul class="simple">
 +<li>Connection Settings</li>
 +<li>Directory Settings</li>
 +<li>Special Attributes</li>
 +</ul>
 +<div class="section" id="connection-settings">
 +<h3>Connection Settings<a class="headerlink" href="#connection-settings" title="Permalink to this headline">¶</a></h3>
 +<div class="figure">
 +<img alt="../_images/ldap-advanced-1-connection.png" src="../_images/ldap-advanced-1-connection.png" />
 +<p class="caption">LDAP Advanced Settings, section Connection Settings</p>
 +</div>
 +<dl class="docutils">
 +<dt>Configuration Active:</dt>
 +<dd><p class="first">Enables or Disables the current configuration. Disabled configuration will not
 +connect to the LDAP server.</p>
 +<p class="last">By default, it is turned off. It will be automatically turned on, when using
 +the wizard and the configuration is OK and a test connection successful.</p>
 +</dd>
 +<dt>Backup (Replica) Host:</dt>
 +<dd><p class="first">A backup server can be defined here. ownCloud tries to connect to the backup
 +server automatically, when the main host (as specified in basic settings)
 +cannot be reached. It is import that the backup server is a replica of the
 +main server, because the object UUIDs must match.</p>
 +<p>Example:</p>
 +<ul class="last simple">
 +<li><em>directory2.my-company.com</em></li>
 +</ul>
 +</dd>
 +<dt>Backup (Replica) Port:</dt>
 +<dd><p class="first">The port on which to connect to the backup LDAP server. If no port is given,
 +but a host, then the main port (as specified above) will be used.</p>
 +<p>Example:</p>
 +<ul class="last simple">
 +<li><em>389</em></li>
 +</ul>
 +</dd>
 +<dt>Disable Main Server:</dt>
 +<dd>You can manually override the main server and make ownCloud only connect to
 +the backup server. It may be handy for planned downtimes.</dd>
 +<dt>Case insensitive LDAP server (Windows):</dt>
 +<dd>Whether the LDAP server is running on a Windows Host. Usually, it is not
 +necessary to check it, however.</dd>
 +<dt>Turn off SSL certificate validation:</dt>
 +<dd>Turns of check of valid SSL certificates. Use it – if needed –
 +for testing, only!</dd>
 +<dt>Cache Time-To-Live:</dt>
 +<dd><p class="first">A cache is introduced to avoid unnecessary LDAP traffic,
 +for example lookups check whether the users exists on every page request or
 +WebDAV interaction. It is also supposed to speed up the Admin → User page or
 +list of users to share with, once it is populated. Saving the configuration
 +empties the cache (changes are not necessary). The time is given in seconds.</p>
 +<p>Note that almost every PHP request would require to build up a new connection
 +to the LDAP server. If you require a most up-to-dateness it is recommended not
 +to totally switch off the cache, but define a minimum life time of 15s.</p>
 +<p>Examples:</p>
 +<ul class="last simple">
 +<li>ten minutes: <em>600</em></li>
 +<li>one hour: <em>3600</em></li>
 +</ul>
 +</dd>
 +</dl>
 +</div>
 +<div class="section" id="directory-settings">
 +<h3>Directory Settings<a class="headerlink" href="#directory-settings" title="Permalink to this headline">¶</a></h3>
 +<div class="figure">
 +<img alt="../_images/ldap-advanced-2-directory.png" src="../_images/ldap-advanced-2-directory.png" />
 +<p class="caption">LDAP Advanced Settings, section Directory Settings</p>
 +</div>
 +<dl class="docutils">
 +<dt>User Display Name Field:</dt>
 +<dd><p class="first">The attribute that should be used as display name in ownCloud.</p>
 +<ul class="last simple">
 +<li>Example: <em>displayName</em></li>
 +</ul>
 +</dd>
 +<dt>Base User Tree:</dt>
 +<dd><p class="first">The base DN of LDAP, from where all users can be reached. It needs to be given
 +completely despite to the Base DN from the Basic settings. You can specify
 +multiple base trees, one in each line.</p>
 +<ul class="last">
 +<li><p class="first">Example:</p>
 +<div class="line-block">
 +<div class="line"><em>cn=programmers,dc=my-company,dc=com</em></div>
 +<div class="line"><em>cn=designers,dc=my-company,dc=com</em></div>
 +</div>
 +</li>
 +</ul>
 +</dd>
 +<dt>User Search Attributes:</dt>
 +<dd><p class="first">These attributes are used when a search for users is done. This happens, for
 +instance, in the share dialogue. By default the user display name attribute as
 +specified above is being used. Multiple attributes can be given, one in each
 +line.</p>
 +<p>Beware that if an attribute is not available on a user object, the user will
 +neither be listed (e.g. in the share dialogue) nor be able to login. This also
 +affects the display name attribute as specified above. If you override the
 +default, the display name attribute will not be taken into account, unless you
 +specify it as well.</p>
 +<ul class="last">
 +<li><p class="first">Example:</p>
 +<div class="line-block">
 +<div class="line"><em>displayName</em></div>
 +<div class="line"><em>mail</em></div>
 +</div>
 +</li>
 +</ul>
 +</dd>
 +<dt>Group Display Name Field:</dt>
 +<dd><p class="first">The attribute that should be used as ownCloud group name. ownCloud allows a
 +limited set of characters (a-zA-Z0-9.-_@), every other character will be
 +replaced in ownCloud. Once a group name is assigned, it will not be changed,
 +i.e. changing this value will only have effect to new LDAP groups.</p>
 +<ul class="last simple">
 +<li>Example: <em>cn</em></li>
 +</ul>
 +</dd>
 +<dt>Base Group Tree:</dt>
 +<dd><p class="first">The base DN of LDAP, from where all groups can be reached.
 +It needs to be given completely despite to the Base DN from the Basic
 +settings. You can specify multiple base trees, one in each line.</p>
 +<ul class="last">
 +<li><p class="first">Example:</p>
 +<div class="line-block">
 +<div class="line"><em>cn=barcelona,dc=my-company,dc=com</em></div>
 +<div class="line"><em>cn=madrid,dc=my-company,dc=com</em></div>
 +</div>
 +</li>
 +</ul>
 +</dd>
 +<dt>Group Search Attributes:</dt>
 +<dd><p class="first">These attributes are used when a search for groups is done. This happens, for
 +instance, in the share dialogue. By default the group display name attribute
 +as specified above is being used. Multiple attributes can be given, one in
 +each line.</p>
 +<p>If you override the default, the group display name attribute will not be
 +taken into account, unless you specify it as well.</p>
 +<ul class="last">
 +<li><p class="first">Example:</p>
 +<div class="line-block">
 +<div class="line"><em>cn</em></div>
 +<div class="line"><em>description</em></div>
 +</div>
 +</li>
 +</ul>
 +</dd>
 +<dt>Group Member association:</dt>
 +<dd><p class="first">The attribute that is used to indicate group memberships, i.e. the attribute
 +used by LDAP groups to refer to their users.</p>
 +<p>ownCloud detects the value automatically, you should only change it, if you
 +have a very valid reason and know what you are doing.</p>
 +<ul class="last simple">
 +<li>Example: <em>uniquemember</em></li>
 +</ul>
 +</dd>
 +</dl>
 +</div>
 +<div class="section" id="special-attributes">
 +<h3>Special Attributes<a class="headerlink" href="#special-attributes" title="Permalink to this headline">¶</a></h3>
 +<div class="figure">
 +<img alt="../_images/ldap-advanced-3-attributes.png" src="../_images/ldap-advanced-3-attributes.png" />
 +<p class="caption">LDAP Advanced Settings, section Special Attributes</p>
 +</div>
 +<dl class="docutils">
 +<dt>Quota Field:</dt>
 +<dd><p class="first">ownCloud can read an LDAP attribute and set the user quota according to its
 +value. Specify the attribute here, otherwise keep it empty. The attribute
 +shall return human readable values, e.g. “2 GB”.</p>
 +<ul class="last simple">
 +<li>Example: <em>ownCloudQuota</em></li>
 +</ul>
 +</dd>
 +<dt>Quota Default:</dt>
 +<dd><p class="first">Override ownCloud default quota for LDAP users who do not
 +have a quota set in the attribute given above.</p>
 +<ul class="last simple">
 +<li>Example: <em>15 GB</em></li>
 +</ul>
 +</dd>
 +<dt>Email Field:</dt>
 +<dd><p class="first">ownCloud can read an LDAP attribute and set the user email
 +there from. Specify the attribute here, otherwise keep it empty.</p>
 +<p>Although the wizard offers you to check login by email, the correct email
 +attribute is not detected and you need to specify it manually.</p>
 +<ul class="last simple">
 +<li>Example: <em>mail</em></li>
 +</ul>
 +</dd>
 +<dt>User Home Folder Naming Rule:</dt>
 +<dd><p class="first">By default, the ownCloud creates the user
 +directory, where all files and meta data are kept, according to the ownCloud
 +user name. You may want to override this setting and name it after an
 +attribute value. The attribute given can also return an absolute path, e.g.
 +<tt class="docutils literal"><span class="pre">/mnt/storage43/alice</span></tt>. Leave it empty for default behavior.</p>
 +<ul class="last simple">
 +<li>Example: <em>cn</em></li>
 +</ul>
 +</dd>
 +</dl>
 +</div>
 +</div>
 +<div class="section" id="expert-settings">
 +<h2>Expert Settings<a class="headerlink" href="#expert-settings" title="Permalink to this headline">¶</a></h2>
 +<div class="figure">
 +<img alt="../_images/ldap-expert.png" src="../_images/ldap-expert.png" />
 +</div>
 +<p>In the Expert Settings fundamental behavior can be adjusted to your needs. The
 +configuration should be done before starting production use or when testing the
 +installation.</p>
 +<dl class="docutils">
 +<dt>Internal Username:</dt>
 +<dd><p class="first">The internal username is the identifier in ownCloud for LDAP users. By default
 +it will be created from the UUID attribute. By using the UUID attribute it is
 +made sure that the username is unique and characters do not need to be
 +converted. The internal username has the restriction that only these
 +characters are allowed: [a-zA-Z0-9_.@-]. Other characters are replaced with
 +their ASCII correspondence or are simply omitted.</p>
 +<p>The LDAP backend ensures that there are no duplicate internal usernames in
 +ownCloud, i.e. that it is checking all other activated user backends
 +(including local ownCloud users). On collisions a random number (between 1000
 +and 9999) will be attached to the retrieved value. For example, if “alice”
 +exists, the next username may be “alice_1337”.</p>
 +<p>The internal username is also the default name for the user home folder in
 +ownCloud. It is also a part of remote URLs, for instance for all *DAV services.
 +With this setting the default behaviour can be overridden.</p>
 +<p>Leave it empty for default behaviour. Changes will have effect only on newly
 +mapped (added) LDAP users.</p>
 +<ul class="last simple">
 +<li>Example: <em>uid</em></li>
 +</ul>
 +</dd>
 +<dt>Override UUID detection</dt>
 +<dd><p class="first">By default, ownCloud auto-detects the UUID attribute. The UUID attribute is
 +used to doubtlessly identify LDAP users and groups. Also, the internal
 +username will be created based on the UUID, if not specified otherwise above.</p>
 +<p>You can override the setting and pass an attribute of your choice. You must
 +make sure that the attribute of your choice can be fetched for both users and
 +groups and it is unique. Leave it empty for default behaviour. Changes will
 +have effect only on newly mapped (added) LDAP users and groups. It also will
 +have effect when a user’s or group’s DN changes and an old UUID was cached: It
 +will result in a new user. Because of this, the setting should be applied
 +before putting ownCloud in production use and cleaning the bindings
 +(see below).</p>
 +<ul class="last simple">
 +<li>Example: <em>cn</em></li>
 +</ul>
 +</dd>
 +<dt>Username-LDAP User Mapping</dt>
 +<dd><p class="first">ownCloud uses the usernames as key to store and assign data. In order to
 +precisely identify and recognize users, each LDAP user will have a internal
 +username in ownCloud. This requires a mapping from ownCloud username to LDAP
 +user. The created username is mapped to the UUID of the LDAP user.
 +Additionally the DN is cached as well to reduce LDAP interaction, but it is
 +not used for identification. If the DN changes, the change will be detected by
 +ownCloud by checking the UUID value.</p>
 +<p>The same is valid for groups.</p>
 +<p>The internal ownCloud name is used all over in ownCloud. Clearing the Mappings
 +will have leftovers everywhere. Do never clear the mappings
 +in a production environment. Only clear mappings in a testing or experimental
 +stage.</p>
 +<p class="last"><strong>Clearing the Mappings is not configuration sensitive, it affects all LDAP
 +configurations!</strong></p>
 +</dd>
 +</dl>
 +</div>
 +<div class="section" id="testing-the-configuration">
 +<h2>Testing the configuration<a class="headerlink" href="#testing-the-configuration" title="Permalink to this headline">¶</a></h2>
 +<p>In this version we introduced the <strong>Test Configuration</strong> button on the bottom
 +of the LDAP settings section. It will always check the values as currently
 +given in the input fields. You do not need to save before testing. By clicking
 +on the button, ownCloud will try to bind to the ownCloud server with the
 +settings currently given in the input fields. The response will look like this:</p>
 +<div class="figure">
 +<img alt="../_images/ldap-settings-invalid-oc45.png" src="../_images/ldap-settings-invalid-oc45.png" />
 +<p class="caption">Failure</p>
 +</div>
 +<p>In case the configuration fails, you can see details in ownCloud’s log, which
 +is in the data directory and called <strong>owncloud.log</strong> or on the bottom the
 +<strong>Settings →  Admin page</strong>. Unfortunately it requires a reload – sorry for the
 +inconvenience.</p>
 +<div class="figure">
 +<img alt="../_images/ldap-settings-valid-oc45.png" src="../_images/ldap-settings-valid-oc45.png" />
 +<p class="caption">Success</p>
 +</div>
 +<p>In this case, Save the settings. You can check if the users and groups are
 +fetched correctly on the Settings → Users page.</p>
 +</div>
 +<div class="section" id="owncloud-avatar-integration">
 +<h2>ownCloud Avatar integration<a class="headerlink" href="#owncloud-avatar-integration" title="Permalink to this headline">¶</a></h2>
 +<p>ownCloud 6 incorporates a user profile picture feature, called Avatar. If a user
 +has a photo stored in the <em>jpegPhoto</em> or, since 6.0.2, <em>thumbnailPhoto</em>
 +attribute, it will be used as Avatar. The user then is not able to change his
 +avatar in the personal settings. It must be done within LDAP. <em>jpegPhoto</em> is
 +preferred over <em>thumbnailPhoto</em>.</p>
 +<div class="figure">
 +<img alt="../_images/ldap-fetched-avatar.png" src="../_images/ldap-fetched-avatar.png" />
 +<p class="caption">Profile picture fetched from LDAP, Personal Settings</p>
 +</div>
 +<p>If the <em>jpegPhoto</em> or <em>thumbnailPhoto</em> attribute is not set or empty, the
 +default ownCloud behaviour is active, i.e. the user will be able to set and
 +change his profile picture in the personal settings. If the user sets a profile
 +picture within ownCloud it will _not_ be stored in LDAP.</p>
 +<p>The <em>jpegPhoto</em> or <em>thumbnailPhoto</em> attribute will be fetched once a day to make
 +sure the current photo from LDAP is used in ownCloud. If a picture is added
 +later, a possibly set profile picture will be overridden with the LDAP one. If a
 +photo stored in the <em>jpegPhoto</em> and/or <em>thumbnailPhoto</em> attribute is deleted
 +later, the last profile picture in ownCloud will still be used.</p>
 +<p>The photo taken from LDAP will be adjusted to the requirements of the ownCloud
 +avatar automatically. I.e. it will be transformed into a square. If the photo
 +needs to be cut, it will be done equally from both affected sides. The original
 +photo stored in LDAP will stay the same, of course.</p>
 +</div>
 +<div class="section" id="troubleshooting-tips-and-tricks">
 +<h2>Troubleshooting, Tips and Tricks<a class="headerlink" href="#troubleshooting-tips-and-tricks" title="Permalink to this headline">¶</a></h2>
 +</div>
 +<div class="section" id="ssl-certificate-verification-ldaps-tls">
 +<h2>SSL Certificate Verification (LDAPS, TLS)<a class="headerlink" href="#ssl-certificate-verification-ldaps-tls" title="Permalink to this headline">¶</a></h2>
 +<p>A common mistake with SSL certificates is that they may not be known to PHP.
 +If you have trouble with certificate validation make sure that</p>
 +<ul class="simple">
 +<li>you have the certificate of the server installed on the ownCloud server</li>
 +<li>the certificate is announced in the system’s LDAP configuration file (usually
 +<em>/etc/ldap/ldap.conf</em> on Linux, <em>C:\openldap\sysconf\ldap.conf</em> or
 +<em>C:\ldap.conf</em> on Windows) using a <strong>TLS_CACERT /path/to/cert</strong> line.</li>
 +<li>Using LDAPS, also make sure that the port is correctly configured (by default
 +686)</li>
 +</ul>
 +</div>
 +<div class="section" id="microsoft-active-directory">
 +<h2>Microsoft Active Directory<a class="headerlink" href="#microsoft-active-directory" title="Permalink to this headline">¶</a></h2>
 +<p>Compared to earlier ownCloud versions, no further tweaks need to be done to
 +make ownCloud work with Active Directory. ownCloud will automatically find the
 +correct configuration in the wizard-like set up process.</p>
 +</div>
 +<div class="section" id="duplicating-server-configurations">
 +<h2>Duplicating Server Configurations<a class="headerlink" href="#duplicating-server-configurations" title="Permalink to this headline">¶</a></h2>
 +<p>In case you have a working configuration and want to create a similar one or
 +“snapshot” configurations before modifying them you can do the following:</p>
 +<ol class="arabic simple">
 +<li>Go to the <strong>Server</strong> tab</li>
 +<li>On <strong>Server Configuration</strong> choose <em>Add Server Configuration</em></li>
 +<li>Answer the question <em>Take over settings from recent server configuration?</em>
 +with <em>yes</em>.</li>
 +<li>(optional) Switch to <strong>Advanced</strong> tab and uncheck <strong>Configuration Active</strong>
 +in the <em>Connection Settings</em>, so the new configuration is not used on Save</li>
 +<li>Click on <strong>Save</strong></li>
 +</ol>
 +<p>Now you can modify the configuration and enable it if you wish.</p>
 +</div>
 +<div class="section" id="owncloud-ldap-internals">
 +<h2>ownCloud LDAP Internals<a class="headerlink" href="#owncloud-ldap-internals" title="Permalink to this headline">¶</a></h2>
 +<p>Some parts of how the LDAP backend works are described here. May it be helpful.</p>
 +</div>
 +<div class="section" id="groups">
 +<h2>Groups<a class="headerlink" href="#groups" title="Permalink to this headline">¶</a></h2>
 +<p>At the moment, only secondary groups are read. That means that only the groups
 +are retrieved, which are returned by the attribute auto-detected (or manually
 +chosen) in Group-Member association. Primary groups are not being taken into
 +account.</p>
 +</div>
 +<div class="section" id="user-and-group-mapping">
 +<h2>User and Group Mapping<a class="headerlink" href="#user-and-group-mapping" title="Permalink to this headline">¶</a></h2>
 +<p>In ownCloud the user or group name is used to have all relevant information in
 +the database assigned. To work reliably a permanent internal user name and
 +group name is created and mapped to the LDAP DN and UUID. If the DN changes in
 +LDAP it will be detected, there will be no conflicts.</p>
 +<p>Those mappings are done in the database table ldap_user_mapping and
 +ldap_group_mapping. The user name is also used for the user’s folder (except
 +something else is specified in <em>User Home Folder Naming Rule</em>), which
 +contains files and meta data.</p>
 +<p>As of ownCloud 5 internal user name and a visible display name are separated.
 +This is not the case for group names, yet, i.e. group cannot be altered.</p>
 +<p>That means that your LDAP configuration should be good and ready before putting
 +it into production. The mapping tables are filled early, but as long as you are
 +testing, you can empty the tables any time. Do not do this in production. If you
 +want to rename a group, be very careful. Do not rename the user’s internal name.</p>
 +</div>
 +<div class="section" id="caching">
 +<h2>Caching<a class="headerlink" href="#caching" title="Permalink to this headline">¶</a></h2>
 +<p>For performance reasons a cache has been introduced to ownCloud. He we store
 +all users and groups, group memberships or internal userExists-requests. Since
 +ownCloud is written in PHP and each and every page request (also done by Ajax)
 +loads ownCloud and would execute one or more LDAP queries again, you do want to
 +have some of those queries cached and save those requests and traffic. It is
 +highly recommended to have the cache filled for a small amount of time, which
 +comes also very handy when using the sync client, as it is yet another request
 +for PHP.</p>
 +</div>
 +<div class="section" id="handling-with-backup-server">
 +<h2>Handling with Backup Server<a class="headerlink" href="#handling-with-backup-server" title="Permalink to this headline">¶</a></h2>
 +<p>When ownCloud is not able to contact the main server, he will be treated as
 +offline and no connection attempts will be done for the time specified in
 +<strong>Cache Time-To-Live</strong>. If a backup server is configured, it will be connected
 +instead. If you plan a maintained downtime, check <strong>Disable Main Server</strong> for
 +the time being to avoid unnecessary connection attempts every now and then.</p>
 +</div>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/configuration/background_jobs.html
index e08cafb,0000000..6eef29d
mode 100644,000000..100644
--- a/core/doc/admin/configuration/background_jobs.html
+++ b/core/doc/admin/configuration/background_jobs.html
@@@ -1,227 -1,0 +1,228 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
 +    <title>Background Jobs — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
 +    <link rel="up" title="Configuration" href="index.html" />
-     <link rel="next" title="3rd-Party Configuration" href="configuration_3rdparty.html" />
-     <link rel="prev" title="User Authentication with LDAP" href="auth_ldap.html" />
++    <link rel="next" title="Find Third-Party Libraries" href="configuration_3rdparty.html" />
++    <link rel="prev" title="LDAP Authentication" href="auth_ldap.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
 +<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../installation/index.html">Installation</a></li>
 +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Configuration</a><ul class="current">
- <li class="toctree-l2"><a class="reference internal" href="configuration_apps.html">Apps Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_apps.html">Managing Apps</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_users.html">User Management</a></li>
- <li class="toctree-l2"><a class="reference internal" href="auth_ldap.html">User Authentication with LDAP</a></li>
++<li class="toctree-l2"><a class="reference internal" href="auth_ldap.html">LDAP Authentication</a></li>
 +<li class="toctree-l2 current"><a class="current reference internal" href="">Background Jobs</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="#parameters">Parameters</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#cron-jobs">Cron-Jobs</a></li>
 +</ul>
 +</li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_3rdparty.html">3rd-Party Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_3rdparty.html">Find Third-Party Libraries</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_automation.html">Automatic Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_custom_clients.html">Custom Client Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_database.html">Database Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_encryption.html">Use Server-Side Encryption</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_knowledgebase.html">Knowledge Base Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_language.html">Language Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_logging.html">Logging Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_mail.html">Mail Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_maintenance.html">Maintenance Mode Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_preview.html">Preview Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_custom_clients.html">Customizing Client Download Links</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_database.html">MySQL/Postgres/SQLite Support</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_encryption.html">Using Server-Side Encryption</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_knowledgebase.html">Disable Knowledge Base</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_language.html">Setting the Default Language</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_logging.html">Configure Logging</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_mail.html">Sending Mail Notifications</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_maintenance.html">Enable Maintenance Mode</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_preview.html">Enabling File Previews</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_reverseproxy.html">Reverse Proxy Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html">Uploading big files > 512MB (as set by default)</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html#enabling-uploading-big-files">Enabling uploading big files</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html">Dealing with Big File Uploads</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_mount_config_gui.html">Custom Mount Configuration Web-GUI</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_mount_config.html">Custom Mount Configuration</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_user_backend.html">Custom User Backend Configuration</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="xsendfile.html">Serving static files via web server</a></li>
 +</ul>
 +</li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
 +  <div class="section" id="background-jobs">
 +<h1>Background Jobs<a class="headerlink" href="#background-jobs" title="Permalink to this headline">¶</a></h1>
 +<p>A system like ownCloud sometimes requires tasks to be done on a regular
 +base without blocking the user interface. For that purpose you, as a system
 +administrator, can define background jobs which make it possible to execute
 +tasks without any need of user interaction, e.g. database clean-ups etc.
 +For the sake of completeness it is worth to know that additionally background
 +jobs can also be defined by installed apps.</p>
 +<div class="section" id="parameters">
 +<h2>Parameters<a class="headerlink" href="#parameters" title="Permalink to this headline">¶</a></h2>
 +<p>In the admin settings menu you can configure how cron-jobs should be executed.
 +You can choose between the following options:</p>
 +<ul class="simple">
 +<li>AJAX</li>
 +<li>Webcron</li>
 +<li>Cron</li>
 +</ul>
 +</div>
 +<div class="section" id="cron-jobs">
 +<h2>Cron-Jobs<a class="headerlink" href="#cron-jobs" title="Permalink to this headline">¶</a></h2>
 +<p>OwnCloud requires various automated background jobs to be run. There are three methods to achieve this.
 +The default way is AJAX and the recommended way is cron.</p>
 +<div class="section" id="ajax">
 +<h3>AJAX<a class="headerlink" href="#ajax" title="Permalink to this headline">¶</a></h3>
 +<p>This option is the default option, although it is the least reliable. Every
 +time a user visits the ownCloud page a single background job will be executed.
 +The advantage of this mechanism is, that is does not require access to the
 +system nor registration at a third party service.
 +The disadvantage of this solution compared to the Webcron service is, that it
 +requires regular visits of the page to get triggered.</p>
 +</div>
 +<div class="section" id="webcron">
 +<h3>Webcron<a class="headerlink" href="#webcron" title="Permalink to this headline">¶</a></h3>
 +<p>By registering your ownCloud <tt class="docutils literal"><span class="pre">cron.php</span></tt> script address at an external webcron
 +service, like e.g. <a class="reference external" href="http://www.easycron.com/">easyCron</a>, you ensure that background jobs will be executed
 +regularly. To use such a service your server need to be reachable via the Internet.</p>
 +<p><strong>Example</strong></p>
 +<div class="highlight-python"><pre>URL to call: http[s]://<domain-of-your-server>/owncloud/cron.php</pre>
 +</div>
 +</div>
 +<div class="section" id="cron">
 +<h3>Cron<a class="headerlink" href="#cron" title="Permalink to this headline">¶</a></h3>
 +<p>Using the systems cron feature is the preferred way to run regular tasks,
 +because it allows to execute jobs without the limitations which a web server
 +may have.</p>
 +<p><strong>Example</strong></p>
 +<p>To run a cron job on a *nix system, e.g. every 15min, under the default web server
 +user, e.g. <strong>www-data</strong>, you need to set-up the following cron job to call the
 +<strong>cron.php</strong> script. Please check the crontab man page for the exact command syntax.</p>
 +<div class="highlight-python"><pre># crontab -u www-data -e
 +*/15  *  *  *  * php -f /var/www/owncloud/cron.php</pre>
 +</div>
 +</div>
 +</div>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/configuration/configuration_3rdparty.html
index 546a718,0000000..8086d9c
mode 100644,000000..100644
--- a/core/doc/admin/configuration/configuration_3rdparty.html
+++ b/core/doc/admin/configuration/configuration_3rdparty.html
@@@ -1,189 -1,0 +1,190 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
-     <title>3rd-Party Configuration — ownCloud Administrators Manual 6.0 documentation</title>
++    <title>Find Third-Party Libraries — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
 +    <link rel="up" title="Configuration" href="index.html" />
 +    <link rel="next" title="Automatic Configuration" href="configuration_automation.html" />
 +    <link rel="prev" title="Background Jobs" href="background_jobs.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
 +<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../installation/index.html">Installation</a></li>
 +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Configuration</a><ul class="current">
- <li class="toctree-l2"><a class="reference internal" href="configuration_apps.html">Apps Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_apps.html">Managing Apps</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_users.html">User Management</a></li>
- <li class="toctree-l2"><a class="reference internal" href="auth_ldap.html">User Authentication with LDAP</a></li>
++<li class="toctree-l2"><a class="reference internal" href="auth_ldap.html">LDAP Authentication</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="background_jobs.html">Background Jobs</a></li>
- <li class="toctree-l2 current"><a class="current reference internal" href="">3rd-Party Configuration</a><ul>
++<li class="toctree-l2 current"><a class="current reference internal" href="">Find Third-Party Libraries</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="#parameters">Parameters</a></li>
 +</ul>
 +</li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_automation.html">Automatic Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_custom_clients.html">Custom Client Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_database.html">Database Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_encryption.html">Use Server-Side Encryption</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_knowledgebase.html">Knowledge Base Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_language.html">Language Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_logging.html">Logging Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_mail.html">Mail Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_maintenance.html">Maintenance Mode Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_preview.html">Preview Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_custom_clients.html">Customizing Client Download Links</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_database.html">MySQL/Postgres/SQLite Support</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_encryption.html">Using Server-Side Encryption</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_knowledgebase.html">Disable Knowledge Base</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_language.html">Setting the Default Language</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_logging.html">Configure Logging</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_mail.html">Sending Mail Notifications</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_maintenance.html">Enable Maintenance Mode</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_preview.html">Enabling File Previews</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_reverseproxy.html">Reverse Proxy Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html">Uploading big files > 512MB (as set by default)</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html#enabling-uploading-big-files">Enabling uploading big files</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html">Dealing with Big File Uploads</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_mount_config_gui.html">Custom Mount Configuration Web-GUI</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_mount_config.html">Custom Mount Configuration</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_user_backend.html">Custom User Backend Configuration</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="xsendfile.html">Serving static files via web server</a></li>
 +</ul>
 +</li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
-   <div class="section" id="rd-party-configuration">
- <h1>3rd-Party Configuration<a class="headerlink" href="#rd-party-configuration" title="Permalink to this headline">¶</a></h1>
++  <div class="section" id="find-third-party-libraries">
++<h1>Find Third-Party Libraries<a class="headerlink" href="#find-third-party-libraries" title="Permalink to this headline">¶</a></h1>
 +<p>ownCloud resorts to some 3rd-party PHP components to provide its functionality.
 +These components are part of the software package and are usually shipped in
 +the <strong>/3rdparty</strong> folder.</p>
 +<div class="section" id="parameters">
 +<h2>Parameters<a class="headerlink" href="#parameters" title="Permalink to this headline">¶</a></h2>
 +<p>If you want to change the default location of the 3rd-party folder you can use the <strong>3rdpartyroot</strong> parameter to define
 +the absolute file system path to the folder. The <strong>3rdpartyurl</strong> parameter is used to define the http web path to that
 +folder, starting at the ownCloud web root.</p>
 +<div class="highlight-php"><div class="highlight"><pre><span class="cp"><?php</span>
 +
 +<span class="s2">"3rdpartyroot"</span> <span class="o">=></span> <span class="nx">OC</span><span class="o">::</span><span class="nv">$SERVERROOT</span><span class="o">.</span><span class="s2">"/3rdparty"</span><span class="p">,</span>
 +<span class="s2">"3rdpartyurl"</span>  <span class="o">=></span> <span class="s2">"/3rdparty"</span><span class="p">,</span>
 +</pre></div>
 +</div>
 +</div>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/configuration/configuration_apps.html
index 77e0001,0000000..7901d28
mode 100644,000000..100644
--- a/core/doc/admin/configuration/configuration_apps.html
+++ b/core/doc/admin/configuration/configuration_apps.html
@@@ -1,247 -1,0 +1,248 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
-     <title>Apps Configuration — ownCloud Administrators Manual 6.0 documentation</title>
++    <title>Managing Apps — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
 +    <link rel="up" title="Configuration" href="index.html" />
 +    <link rel="next" title="User Management" href="configuration_users.html" />
 +    <link rel="prev" title="Configuration" href="index.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
 +<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../installation/index.html">Installation</a></li>
 +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Configuration</a><ul class="current">
- <li class="toctree-l2 current"><a class="current reference internal" href="">Apps Configuration</a><ul>
++<li class="toctree-l2 current"><a class="current reference internal" href="">Managing Apps</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="#parameters">Parameters</a></li>
 +</ul>
 +</li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_users.html">User Management</a></li>
- <li class="toctree-l2"><a class="reference internal" href="auth_ldap.html">User Authentication with LDAP</a></li>
++<li class="toctree-l2"><a class="reference internal" href="auth_ldap.html">LDAP Authentication</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="background_jobs.html">Background Jobs</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_3rdparty.html">3rd-Party Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_3rdparty.html">Find Third-Party Libraries</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_automation.html">Automatic Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_custom_clients.html">Custom Client Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_database.html">Database Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_encryption.html">Use Server-Side Encryption</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_knowledgebase.html">Knowledge Base Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_language.html">Language Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_logging.html">Logging Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_mail.html">Mail Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_maintenance.html">Maintenance Mode Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_preview.html">Preview Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_custom_clients.html">Customizing Client Download Links</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_database.html">MySQL/Postgres/SQLite Support</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_encryption.html">Using Server-Side Encryption</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_knowledgebase.html">Disable Knowledge Base</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_language.html">Setting the Default Language</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_logging.html">Configure Logging</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_mail.html">Sending Mail Notifications</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_maintenance.html">Enable Maintenance Mode</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_preview.html">Enabling File Previews</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_reverseproxy.html">Reverse Proxy Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html">Uploading big files > 512MB (as set by default)</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html#enabling-uploading-big-files">Enabling uploading big files</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html">Dealing with Big File Uploads</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_mount_config_gui.html">Custom Mount Configuration Web-GUI</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_mount_config.html">Custom Mount Configuration</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_user_backend.html">Custom User Backend Configuration</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="xsendfile.html">Serving static files via web server</a></li>
 +</ul>
 +</li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
-   <div class="section" id="apps-configuration">
- <h1>Apps Configuration<a class="headerlink" href="#apps-configuration" title="Permalink to this headline">¶</a></h1>
++  <div class="section" id="managing-apps">
++<h1>Managing Apps<a class="headerlink" href="#managing-apps" title="Permalink to this headline">¶</a></h1>
 +<p>After you have installed ownCloud, you might realize that it would be nice to
 +provide an additional function on top of the core functionality in your ownCloud installation.</p>
 +<p>With ownCloud installation, you will find some apps enabled by default. To see which applications
 +are enabled, click on Apps button on the web interface navigation to go into applications page:</p>
 +<div class="figure">
 +<img alt="../_images/oc_admin_app_page.png" src="../_images/oc_admin_app_page.png" />
 +</div>
 +<p>Administrator application page</p>
 +<p>In this page, you can enable or disable applications simply by clicking on their names.
 +Enabled applications will be shown in <strong>bold</strong> while disabled ones will be shown in normal font.
 +If the app is not developed by ownCloud, it will have the <em>3rd party</em> notice next to it. To see what an
 +application does, clicking on its name will show a description on the right side of the same page.</p>
 +<p>To install new apps, you can use <em>More apps</em> button or check out the <a class="reference external" href="http://apps.owncloud.com/">ownCloud apps store</a>.
 +There you will find a lot of ready-to-use apps provided by the ownCloud community.</p>
 +<p>If you would like to add your own app, please use <em>Add your App...</em> button on the same page. This will redirect you to
 +our <a class="reference external" href="http://owncloud.org/dev">Developer Center</a>.</p>
 +<div class="section" id="parameters">
 +<h2>Parameters<a class="headerlink" href="#parameters" title="Permalink to this headline">¶</a></h2>
 +<p>Parameters are set in the <tt class="file docutils literal"><span class="pre">config/config.php</span></tt> inside the <strong>$CONFIG</strong> array.</p>
 +<div class="section" id="use-custom-app-directories">
 +<h3>Use custom app directories<a class="headerlink" href="#use-custom-app-directories" title="Permalink to this headline">¶</a></h3>
 +<p>Use the <strong>apps_paths</strong> array to set the apps folders which should be scanned
 +for available apps and/or where user specific apps should be installed.The key
 +<strong>path</strong> defines the absolute file system path to the app folder. The key
 +<strong>url</strong> defines the http web path to that folder, starting at the ownCloud
 +web root. The key <strong>writable</strong> indicates if a user can install apps in that
 +folder.</p>
 +<div class="admonition note">
 +<p class="first admonition-title">Note</p>
 +<p class="last">If you want to make sure that the default <strong>/apps/</strong> folder only contains apps shipped with ownCloud, you
 +should follow the example and set-up a <strong>/apps2/</strong> folder which will be used to store all apps downloaded by users</p>
 +</div>
 +<div class="highlight-php"><div class="highlight"><pre><span class="cp"><?php</span>
 +
 +  <span class="s2">"apps_paths"</span> <span class="o">=></span> <span class="k">array</span> <span class="p">(</span>
 +      <span class="mi">0</span> <span class="o">=></span> <span class="k">array</span> <span class="p">(</span>
 +              <span class="s2">"path"</span>     <span class="o">=></span> <span class="nx">OC</span><span class="o">::</span><span class="nv">$SERVERROOT</span><span class="o">.</span><span class="s2">"/apps"</span><span class="p">,</span>
 +              <span class="s2">"url"</span>      <span class="o">=></span> <span class="s2">"/apps"</span><span class="p">,</span>
 +              <span class="s2">"writable"</span> <span class="o">=></span> <span class="k">false</span><span class="p">,</span>
 +      <span class="p">),</span>
 +      <span class="mi">1</span> <span class="o">=></span> <span class="k">array</span> <span class="p">(</span>
 +              <span class="s2">"path"</span>     <span class="o">=></span> <span class="nx">OC</span><span class="o">::</span><span class="nv">$SERVERROOT</span><span class="o">.</span><span class="s2">"/apps2"</span><span class="p">,</span>
 +              <span class="s2">"url"</span>      <span class="o">=></span> <span class="s2">"/apps2"</span><span class="p">,</span>
 +              <span class="s2">"writable"</span> <span class="o">=></span> <span class="k">true</span><span class="p">,</span>
 +      <span class="p">),</span>
 +  <span class="p">),</span>
 +</pre></div>
 +</div>
 +</div>
 +<div class="section" id="use-your-own-appstore">
 +<h3>Use your own appstore<a class="headerlink" href="#use-your-own-appstore" title="Permalink to this headline">¶</a></h3>
 +<p>If you want to allow the installation of apps from the apps store you have to
 +set <strong>appstoreenabled</strong> parameter, but this can only be done if at least one
 +of the configured apps directories is writable.</p>
 +<p>The <strong>appstoreurl</strong> is used to set the http path to the ownCloud apps store. The appstore server has to use <abbr title="Open Collaboration Services">OCS</abbr>.</p>
 +<div class="highlight-php"><div class="highlight"><pre><span class="cp"><?php</span>
 +
 +  <span class="s2">"appstoreenabled"</span> <span class="o">=></span> <span class="k">true</span><span class="p">,</span>
 +  <span class="s2">"appstoreurl"</span> <span class="o">=></span> <span class="s2">"http://api.apps.owncloud.com/v1"</span><span class="p">,</span>
 +</pre></div>
 +</div>
 +</div>
 +<div class="section" id="guard-against-malicious-3rdparty-code">
 +<h3>Guard against malicious 3rdparty code<a class="headerlink" href="#guard-against-malicious-3rdparty-code" title="Permalink to this headline">¶</a></h3>
 +<p>Finally you can enable checks for malicious code fragments of 3rd-party apps
 +by setting the <strong>appcodechecker</strong> parameter.</p>
 +<div class="highlight-php"><div class="highlight"><pre><span class="cp"><?php</span>
 +
 +  <span class="s2">"appcodechecker"</span> <span class="o">=></span> <span class="k">false</span><span class="p">,</span>
 +</pre></div>
 +</div>
 +</div>
 +</div>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/configuration/configuration_automation.html
index 18f4292,0000000..059e417
mode 100644,000000..100644
--- a/core/doc/admin/configuration/configuration_automation.html
+++ b/core/doc/admin/configuration/configuration_automation.html
@@@ -1,286 -1,0 +1,287 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
 +    <title>Automatic Configuration — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
 +    <link rel="up" title="Configuration" href="index.html" />
-     <link rel="next" title="Custom Client Configuration" href="configuration_custom_clients.html" />
-     <link rel="prev" title="3rd-Party Configuration" href="configuration_3rdparty.html" />
++    <link rel="next" title="Customizing Client Download Links" href="configuration_custom_clients.html" />
++    <link rel="prev" title="Find Third-Party Libraries" href="configuration_3rdparty.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
 +<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../installation/index.html">Installation</a></li>
 +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Configuration</a><ul class="current">
- <li class="toctree-l2"><a class="reference internal" href="configuration_apps.html">Apps Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_apps.html">Managing Apps</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_users.html">User Management</a></li>
- <li class="toctree-l2"><a class="reference internal" href="auth_ldap.html">User Authentication with LDAP</a></li>
++<li class="toctree-l2"><a class="reference internal" href="auth_ldap.html">LDAP Authentication</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="background_jobs.html">Background Jobs</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_3rdparty.html">3rd-Party Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_3rdparty.html">Find Third-Party Libraries</a></li>
 +<li class="toctree-l2 current"><a class="current reference internal" href="">Automatic Configuration</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="#parameters">Parameters</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#sample-automatic-configurations">Sample Automatic Configurations</a></li>
 +</ul>
 +</li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_custom_clients.html">Custom Client Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_database.html">Database Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_encryption.html">Use Server-Side Encryption</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_knowledgebase.html">Knowledge Base Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_language.html">Language Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_logging.html">Logging Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_mail.html">Mail Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_maintenance.html">Maintenance Mode Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_preview.html">Preview Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_custom_clients.html">Customizing Client Download Links</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_database.html">MySQL/Postgres/SQLite Support</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_encryption.html">Using Server-Side Encryption</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_knowledgebase.html">Disable Knowledge Base</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_language.html">Setting the Default Language</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_logging.html">Configure Logging</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_mail.html">Sending Mail Notifications</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_maintenance.html">Enable Maintenance Mode</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_preview.html">Enabling File Previews</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_reverseproxy.html">Reverse Proxy Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html">Uploading big files > 512MB (as set by default)</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html#enabling-uploading-big-files">Enabling uploading big files</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html">Dealing with Big File Uploads</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_mount_config_gui.html">Custom Mount Configuration Web-GUI</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_mount_config.html">Custom Mount Configuration</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_user_backend.html">Custom User Backend Configuration</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="xsendfile.html">Serving static files via web server</a></li>
 +</ul>
 +</li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
 +  <div class="section" id="automatic-configuration">
 +<h1>Automatic Configuration<a class="headerlink" href="#automatic-configuration" title="Permalink to this headline">¶</a></h1>
 +<p>If you need to install ownCloud on multiple servers you normally do not want
- to set-up each instance separately as described in the <a class="reference internal" href="configuration_database.html"><em>Database Configuration</em></a>.
++to set-up each instance separately as described in the <a class="reference internal" href="configuration_database.html"><em>MySQL/Postgres/SQLite Support</em></a>.
 +For this reason the automatic configuration feature has been introduced.</p>
 +<p>To take advantage of this feature you need to create a configuration file, called
 +<tt class="file docutils literal"><span class="pre">../owncloud/config/autoconfig.php</span></tt> and set the parameters as required.
 +You can provide all parameters or just part of them - parameters which haven’t been provided (if any) will be asked
 +at “Finish setup” screen at first run of ownCloud.</p>
 +<p>The <tt class="file docutils literal"><span class="pre">../owncloud/config/autoconfig.php</span></tt> will be automatically removed after the initial configuration has been applied.</p>
 +<div class="section" id="parameters">
 +<h2>Parameters<a class="headerlink" href="#parameters" title="Permalink to this headline">¶</a></h2>
 +<p>You need to keep in mind that two parameters are named differently in this
 +configuration file compared to the normal <tt class="file docutils literal"><span class="pre">config.php</span></tt>.</p>
 +<table border="1" class="docutils">
 +<colgroup>
 +<col width="52%" />
 +<col width="48%" />
 +</colgroup>
 +<thead valign="bottom">
 +<tr class="row-odd"><th class="head">autoconfig.php</th>
 +<th class="head">config.php</th>
 +</tr>
 +</thead>
 +<tbody valign="top">
 +<tr class="row-even"><td>directory</td>
 +<td>datadirectory</td>
 +</tr>
 +<tr class="row-odd"><td>dbpass</td>
 +<td>dbpassword</td>
 +</tr>
 +</tbody>
 +</table>
 +</div>
 +<div class="section" id="sample-automatic-configurations">
 +<h2>Sample Automatic Configurations<a class="headerlink" href="#sample-automatic-configurations" title="Permalink to this headline">¶</a></h2>
 +<div class="section" id="data-directory">
 +<h3>Data Directory<a class="headerlink" href="#data-directory" title="Permalink to this headline">¶</a></h3>
 +<p>With the configuration below the “Finish setup” screen still will ask for database and admin credentials settings.</p>
 +<div class="highlight-php"><div class="highlight"><pre><span class="cp"><?php</span>
 +<span class="nv">$AUTOCONFIG</span> <span class="o">=</span> <span class="k">array</span><span class="p">(</span>
 +  <span class="s2">"directory"</span>     <span class="o">=></span> <span class="s2">"/www/htdocs/owncloud/data"</span><span class="p">,</span>
 +<span class="p">);</span>
 +</pre></div>
 +</div>
 +</div>
 +<div class="section" id="sqlite-database">
 +<h3>SQLite Database<a class="headerlink" href="#sqlite-database" title="Permalink to this headline">¶</a></h3>
 +<p>With the configuration below the “Finish setup” screen still will ask for data directory and admin credentials settings.</p>
 +<div class="highlight-php"><div class="highlight"><pre><span class="cp"><?php</span>
 +<span class="nv">$AUTOCONFIG</span> <span class="o">=</span> <span class="k">array</span><span class="p">(</span>
 +  <span class="s2">"dbtype"</span>        <span class="o">=></span> <span class="s2">"sqlite"</span><span class="p">,</span>
 +  <span class="s2">"dbname"</span>        <span class="o">=></span> <span class="s2">"owncloud"</span><span class="p">,</span>
 +  <span class="s2">"dbtableprefix"</span> <span class="o">=></span> <span class="s2">""</span><span class="p">,</span>
 +<span class="p">);</span>
 +</pre></div>
 +</div>
 +</div>
 +<div class="section" id="mysql-database">
 +<h3>MySQL Database<a class="headerlink" href="#mysql-database" title="Permalink to this headline">¶</a></h3>
 +<p>Keep in mind that the automatic configuration does not unburden you from creating the database user and database
- in advance, as described in <a class="reference internal" href="configuration_database.html"><em>Database Configuration</em></a>.</p>
++in advance, as described in <a class="reference internal" href="configuration_database.html"><em>MySQL/Postgres/SQLite Support</em></a>.</p>
 +<p>With the configuration below the “Finish setup” screen still will ask for data directory and admin credentials settings.</p>
 +<div class="highlight-php"><div class="highlight"><pre><span class="cp"><?php</span>
 +<span class="nv">$AUTOCONFIG</span> <span class="o">=</span> <span class="k">array</span><span class="p">(</span>
 +  <span class="s2">"dbtype"</span>        <span class="o">=></span> <span class="s2">"mysql"</span><span class="p">,</span>
 +  <span class="s2">"dbname"</span>        <span class="o">=></span> <span class="s2">"owncloud"</span><span class="p">,</span>
 +  <span class="s2">"dbuser"</span>        <span class="o">=></span> <span class="s2">"username"</span><span class="p">,</span>
 +  <span class="s2">"dbpass"</span>        <span class="o">=></span> <span class="s2">"password"</span><span class="p">,</span>
 +  <span class="s2">"dbhost"</span>        <span class="o">=></span> <span class="s2">"localhost"</span><span class="p">,</span>
 +  <span class="s2">"dbtableprefix"</span> <span class="o">=></span> <span class="s2">""</span><span class="p">,</span>
 +<span class="p">);</span>
 +</pre></div>
 +</div>
 +</div>
 +<div class="section" id="postgresql-database">
 +<h3>PostgreSQL Database<a class="headerlink" href="#postgresql-database" title="Permalink to this headline">¶</a></h3>
 +<p>Keep in mind that the automatic configuration does not unburden you from creating the database user and database
- in advance, as described in <a class="reference internal" href="configuration_database.html"><em>Database Configuration</em></a>.</p>
++in advance, as described in <a class="reference internal" href="configuration_database.html"><em>MySQL/Postgres/SQLite Support</em></a>.</p>
 +<p>With the configuration below the “Finish setup” screen still will ask for data directory and admin credentials settings.</p>
 +<div class="highlight-php"><div class="highlight"><pre><span class="cp"><?php</span>
 +<span class="nv">$AUTOCONFIG</span> <span class="o">=</span> <span class="k">array</span><span class="p">(</span>
 +  <span class="s2">"dbtype"</span>        <span class="o">=></span> <span class="s2">"pgsql"</span><span class="p">,</span>
 +  <span class="s2">"dbname"</span>        <span class="o">=></span> <span class="s2">"owncloud"</span><span class="p">,</span>
 +  <span class="s2">"dbuser"</span>        <span class="o">=></span> <span class="s2">"username"</span><span class="p">,</span>
 +  <span class="s2">"dbpass"</span>        <span class="o">=></span> <span class="s2">"password"</span><span class="p">,</span>
 +  <span class="s2">"dbhost"</span>        <span class="o">=></span> <span class="s2">"localhost"</span><span class="p">,</span>
 +  <span class="s2">"dbtableprefix"</span> <span class="o">=></span> <span class="s2">""</span><span class="p">,</span>
 +<span class="p">);</span>
 +</pre></div>
 +</div>
 +</div>
 +<div class="section" id="all-parameters">
 +<h3>All Parameters<a class="headerlink" href="#all-parameters" title="Permalink to this headline">¶</a></h3>
 +<p>Keep in mind that the automatic configuration does not unburden you from creating the database user and database
- in advance, as described in <a class="reference internal" href="configuration_database.html"><em>Database Configuration</em></a>.</p>
++in advance, as described in <a class="reference internal" href="configuration_database.html"><em>MySQL/Postgres/SQLite Support</em></a>.</p>
 +<p>With the configuration below “Finish setup” will be skipped at first ownCloud run since all parameters are already preconfigured.</p>
 +<div class="highlight-php"><div class="highlight"><pre><span class="cp"><?php</span>
 +<span class="nv">$AUTOCONFIG</span> <span class="o">=</span> <span class="k">array</span><span class="p">(</span>
 +  <span class="s2">"dbtype"</span>        <span class="o">=></span> <span class="s2">"mysql"</span><span class="p">,</span>
 +  <span class="s2">"dbname"</span>        <span class="o">=></span> <span class="s2">"owncloud"</span><span class="p">,</span>
 +  <span class="s2">"dbuser"</span>        <span class="o">=></span> <span class="s2">"username"</span><span class="p">,</span>
 +  <span class="s2">"dbpass"</span>        <span class="o">=></span> <span class="s2">"password"</span><span class="p">,</span>
 +  <span class="s2">"dbhost"</span>        <span class="o">=></span> <span class="s2">"localhost"</span><span class="p">,</span>
 +  <span class="s2">"dbtableprefix"</span> <span class="o">=></span> <span class="s2">""</span><span class="p">,</span>
 +  <span class="s2">"adminlogin"</span>    <span class="o">=></span> <span class="s2">"root"</span><span class="p">,</span>
 +  <span class="s2">"adminpass"</span>     <span class="o">=></span> <span class="s2">"root-password"</span><span class="p">,</span>
 +  <span class="s2">"directory"</span>     <span class="o">=></span> <span class="s2">"/www/htdocs/owncloud/data"</span><span class="p">,</span>
 +<span class="p">);</span>
 +</pre></div>
 +</div>
 +</div>
 +</div>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/configuration/configuration_custom_clients.html
index f10d581,0000000..8f1b43b
mode 100644,000000..100644
--- a/core/doc/admin/configuration/configuration_custom_clients.html
+++ b/core/doc/admin/configuration/configuration_custom_clients.html
@@@ -1,196 -1,0 +1,197 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
-     <title>Custom Client Configuration — ownCloud Administrators Manual 6.0 documentation</title>
++    <title>Customizing Client Download Links — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
 +    <link rel="up" title="Configuration" href="index.html" />
-     <link rel="next" title="Database Configuration" href="configuration_database.html" />
++    <link rel="next" title="MySQL/Postgres/SQLite Support" href="configuration_database.html" />
 +    <link rel="prev" title="Automatic Configuration" href="configuration_automation.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
 +<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../installation/index.html">Installation</a></li>
 +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Configuration</a><ul class="current">
- <li class="toctree-l2"><a class="reference internal" href="configuration_apps.html">Apps Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_apps.html">Managing Apps</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_users.html">User Management</a></li>
- <li class="toctree-l2"><a class="reference internal" href="auth_ldap.html">User Authentication with LDAP</a></li>
++<li class="toctree-l2"><a class="reference internal" href="auth_ldap.html">LDAP Authentication</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="background_jobs.html">Background Jobs</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_3rdparty.html">3rd-Party Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_3rdparty.html">Find Third-Party Libraries</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_automation.html">Automatic Configuration</a></li>
- <li class="toctree-l2 current"><a class="current reference internal" href="">Custom Client Configuration</a><ul>
++<li class="toctree-l2 current"><a class="current reference internal" href="">Customizing Client Download Links</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="#parameters">Parameters</a></li>
 +</ul>
 +</li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_database.html">Database Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_encryption.html">Use Server-Side Encryption</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_knowledgebase.html">Knowledge Base Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_language.html">Language Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_logging.html">Logging Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_mail.html">Mail Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_maintenance.html">Maintenance Mode Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_preview.html">Preview Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_database.html">MySQL/Postgres/SQLite Support</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_encryption.html">Using Server-Side Encryption</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_knowledgebase.html">Disable Knowledge Base</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_language.html">Setting the Default Language</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_logging.html">Configure Logging</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_mail.html">Sending Mail Notifications</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_maintenance.html">Enable Maintenance Mode</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_preview.html">Enabling File Previews</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_reverseproxy.html">Reverse Proxy Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html">Uploading big files > 512MB (as set by default)</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html#enabling-uploading-big-files">Enabling uploading big files</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html">Dealing with Big File Uploads</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_mount_config_gui.html">Custom Mount Configuration Web-GUI</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_mount_config.html">Custom Mount Configuration</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_user_backend.html">Custom User Backend Configuration</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="xsendfile.html">Serving static files via web server</a></li>
 +</ul>
 +</li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
-   <div class="section" id="custom-client-configuration">
- <h1>Custom Client Configuration<a class="headerlink" href="#custom-client-configuration" title="Permalink to this headline">¶</a></h1>
++  <div class="section" id="customizing-client-download-links">
++<h1>Customizing Client Download Links<a class="headerlink" href="#customizing-client-download-links" title="Permalink to this headline">¶</a></h1>
 +<p>If you want to access your ownCloud, you can choose between the standard Web-GUI
 +and different client sync applications. Download links which point to these
 +applications are shown at the top of the personal menu. The following sync
 +applications are currently available out of the box:</p>
 +<ul class="simple">
 +<li>Desktop sync clients for Windows, Max and Linux OS</li>
 +<li>Mobile sync client for Android devices</li>
 +<li>Mobile sync client for iOS devices</li>
 +</ul>
 +<div class="section" id="parameters">
 +<h2>Parameters<a class="headerlink" href="#parameters" title="Permalink to this headline">¶</a></h2>
 +<p>If you want to customize the download links for the sync clients the following
 +parameters need to be modified to fulfil your requirements:</p>
 +<div class="highlight-php"><div class="highlight"><pre><span class="cp"><?php</span>
 +
 +  <span class="s2">"customclient_desktop"</span> <span class="o">=></span> <span class="s2">"http://owncloud.org/sync-clients/"</span><span class="p">,</span>
 +  <span class="s2">"customclient_android"</span> <span class="o">=></span> <span class="s2">"https://play.google.com/store/apps/details?id=com.owncloud.android"</span><span class="p">,</span>
 +  <span class="s2">"customclient_ios"</span>     <span class="o">=></span> <span class="s2">"https://itunes.apple.com/us/app/owncloud/id543672169?mt=8"</span><span class="p">,</span>
 +</pre></div>
 +</div>
 +<p>This parameters can be set in the <tt class="file docutils literal"><span class="pre">config/config.php</span></tt></p>
 +</div>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/configuration/configuration_database.html
index 4a3cb82,0000000..a751f17
mode 100644,000000..100644
--- a/core/doc/admin/configuration/configuration_database.html
+++ b/core/doc/admin/configuration/configuration_database.html
@@@ -1,486 -1,0 +1,487 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
-     <title>Database Configuration — ownCloud Administrators Manual 6.0 documentation</title>
++    <title>MySQL/Postgres/SQLite Support — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
 +    <link rel="up" title="Configuration" href="index.html" />
-     <link rel="next" title="Use Server-Side Encryption" href="configuration_encryption.html" />
-     <link rel="prev" title="Custom Client Configuration" href="configuration_custom_clients.html" />
++    <link rel="next" title="Using Server-Side Encryption" href="configuration_encryption.html" />
++    <link rel="prev" title="Customizing Client Download Links" href="configuration_custom_clients.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
 +<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../installation/index.html">Installation</a></li>
 +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Configuration</a><ul class="current">
- <li class="toctree-l2"><a class="reference internal" href="configuration_apps.html">Apps Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_apps.html">Managing Apps</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_users.html">User Management</a></li>
- <li class="toctree-l2"><a class="reference internal" href="auth_ldap.html">User Authentication with LDAP</a></li>
++<li class="toctree-l2"><a class="reference internal" href="auth_ldap.html">LDAP Authentication</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="background_jobs.html">Background Jobs</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_3rdparty.html">3rd-Party Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_3rdparty.html">Find Third-Party Libraries</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_automation.html">Automatic Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_custom_clients.html">Custom Client Configuration</a></li>
- <li class="toctree-l2 current"><a class="current reference internal" href="">Database Configuration</a><ul>
++<li class="toctree-l2"><a class="reference internal" href="configuration_custom_clients.html">Customizing Client Download Links</a></li>
++<li class="toctree-l2 current"><a class="current reference internal" href="">MySQL/Postgres/SQLite Support</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="#requirements">Requirements</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#parameters">Parameters</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#trouble-shooting">Trouble Shooting</a></li>
 +</ul>
 +</li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_encryption.html">Use Server-Side Encryption</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_knowledgebase.html">Knowledge Base Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_language.html">Language Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_logging.html">Logging Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_mail.html">Mail Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_maintenance.html">Maintenance Mode Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_preview.html">Preview Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_encryption.html">Using Server-Side Encryption</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_knowledgebase.html">Disable Knowledge Base</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_language.html">Setting the Default Language</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_logging.html">Configure Logging</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_mail.html">Sending Mail Notifications</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_maintenance.html">Enable Maintenance Mode</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_preview.html">Enabling File Previews</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_reverseproxy.html">Reverse Proxy Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html">Uploading big files > 512MB (as set by default)</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html#enabling-uploading-big-files">Enabling uploading big files</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html">Dealing with Big File Uploads</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_mount_config_gui.html">Custom Mount Configuration Web-GUI</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_mount_config.html">Custom Mount Configuration</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_user_backend.html">Custom User Backend Configuration</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="xsendfile.html">Serving static files via web server</a></li>
 +</ul>
 +</li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
-   <div class="section" id="database-configuration">
- <h1>Database Configuration<a class="headerlink" href="#database-configuration" title="Permalink to this headline">¶</a></h1>
++  <div class="section" id="mysql-postgres-sqlite-support">
++<h1>MySQL/Postgres/SQLite Support<a class="headerlink" href="#mysql-postgres-sqlite-support" title="Permalink to this headline">¶</a></h1>
 +<p>ownCloud requires a database where administrative data will be held. Four different database types are currently
 +supported, <a class="reference external" href="http://www.mysql.com/">MySQL</a>, <a class="reference external" href="https://mariadb.org/">MariaDB</a>, <a class="reference external" href="http://www.sqlite.org/">SQLite</a>,
 +and <a class="reference external" href="http://www.postgresql.org/">PostgreSQL</a>. MySQL or MariaDB are the recommended database engines. By default
 +SQLite is chosen because it is a file based database with the least administrative overhead.</p>
 +<div class="admonition note">
 +<p class="first admonition-title">Note</p>
 +<p class="last">Because SQLite handles multiple users very badly SQLite is only recommended for single user ownCloud installations</p>
 +</div>
 +<div class="section" id="requirements">
 +<h2>Requirements<a class="headerlink" href="#requirements" title="Permalink to this headline">¶</a></h2>
 +<p>If you decide to use MySQL, MariaDB, or PostgreSQL you need to install and set-up the
 +database first. These steps will not be covered by this description as they are easy to find elsewhere.</p>
 +</div>
 +<div class="section" id="parameters">
 +<h2>Parameters<a class="headerlink" href="#parameters" title="Permalink to this headline">¶</a></h2>
 +<div class="section" id="mysql-mariadb-database">
 +<h3>MySQL/MariaDB Database<a class="headerlink" href="#mysql-mariadb-database" title="Permalink to this headline">¶</a></h3>
 +<p>If you decide to use a MySQL or MariaDB database make sure that you have installed and
 +enabled the MySQL extension in PHP and that the <strong>mysql.default_socket</strong>
 +points to the correct socket (if the database runs on same server as ownCloud).</p>
 +<p>Please note that MariaDB is backwards compatible with MySQL, so all instructions will work for both.
 +You will not need to replace mysql with anything.</p>
 +<p>The PHP configuration in <tt class="file docutils literal"><span class="pre">/etc/php5/conf.d/mysql.ini</span></tt> could look like this:</p>
 +<div class="highlight-ini"><div class="highlight"><pre><span class="c"># configuration for PHP MySQL module</span>
 +<span class="na">extension</span><span class="o">=</span><span class="s">pdo_mysql.so</span>
 +<span class="na">extension</span><span class="o">=</span><span class="s">mysql.so</span>
 +
 +<span class="k">[mysql]</span>
 +<span class="na">mysql.allow_local_infile</span><span class="o">=</span><span class="s">On</span>
 +<span class="na">mysql.allow_persistent</span><span class="o">=</span><span class="s">On</span>
 +<span class="na">mysql.cache_size</span><span class="o">=</span><span class="s">2000</span>
 +<span class="na">mysql.max_persistent</span><span class="o">=</span><span class="s">-1</span>
 +<span class="na">mysql.max_links</span><span class="o">=</span><span class="s">-1</span>
 +<span class="na">mysql.default_port</span><span class="o">=</span>
 +<span class="na">mysql.default_socket</span><span class="o">=</span><span class="s">/var/lib/mysql/mysql.sock  # Debian squeeze: /var/run/mysqld/mysqld.sock</span>
 +<span class="na">mysql.default_host</span><span class="o">=</span>
 +<span class="na">mysql.default_user</span><span class="o">=</span>
 +<span class="na">mysql.default_password</span><span class="o">=</span>
 +<span class="na">mysql.connect_timeout</span><span class="o">=</span><span class="s">60</span>
 +<span class="na">mysql.trace_mode</span><span class="o">=</span><span class="s">Off</span>
 +</pre></div>
 +</div>
 +<p>Now you need to create a database user and the database itself by using the
 +MySQL command line interface. The database tables will be created by ownCloud
 +when you login for the first time.</p>
 +<p>To start the MySQL command line mode use:</p>
 +<div class="highlight-python"><div class="highlight"><pre><span class="n">mysql</span> <span class="o">-</span><span class="n">uroot</span> <span class="o">-</span><span class="n">p</span>
 +</pre></div>
 +</div>
 +<p>Then a <strong>mysql></strong> or <strong>MariaDB [root]></strong> prompt will appear. Now enter the following lines and confirm them with the enter key:</p>
 +<div class="highlight-sql"><div class="highlight"><pre><span class="k">CREATE</span> <span class="k">USER</span> <span class="s1">'username'</span><span class="o">@</span><span class="s1">'localhost'</span> <span class="n">IDENTIFIED</span> <span class="k">BY</span> <span class="s1">'password'</span><span class="p">;</span>
 +<span class="k">CREATE</span> <span class="k">DATABASE</span> <span class="n">IF</span> <span class="k">NOT</span> <span class="k">EXISTS</span> <span class="n">owncloud</span><span class="p">;</span>
 +<span class="k">GRANT</span> <span class="k">ALL</span> <span class="k">PRIVILEGES</span> <span class="k">ON</span> <span class="n">owncloud</span><span class="p">.</span><span class="o">*</span> <span class="k">TO</span> <span class="s1">'username'</span><span class="o">@</span><span class="s1">'localhost'</span> <span class="n">IDENTIFIED</span> <span class="k">BY</span> <span class="s1">'password'</span><span class="p">;</span>
 +</pre></div>
 +</div>
 +<p>You can quit the prompt by entering:</p>
 +<div class="highlight-python"><div class="highlight"><pre><span class="n">quit</span>
 +</pre></div>
 +</div>
 +<p>In the ownCloud configuration you need to set the hostname on which the
 +database is running and a valid username and password to access it.</p>
 +<div class="highlight-php"><div class="highlight"><pre><span class="cp"><?php</span>
 +
 +  <span class="s2">"dbtype"</span>        <span class="o">=></span> <span class="s2">"mysql"</span><span class="p">,</span>
 +  <span class="s2">"dbname"</span>        <span class="o">=></span> <span class="s2">"owncloud"</span><span class="p">,</span>
 +  <span class="s2">"dbuser"</span>        <span class="o">=></span> <span class="s2">"username"</span><span class="p">,</span>
 +  <span class="s2">"dbpassword"</span>    <span class="o">=></span> <span class="s2">"password"</span><span class="p">,</span>
 +  <span class="s2">"dbhost"</span>        <span class="o">=></span> <span class="s2">"localhost"</span><span class="p">,</span>
 +  <span class="s2">"dbtableprefix"</span> <span class="o">=></span> <span class="s2">""</span><span class="p">,</span>
 +</pre></div>
 +</div>
 +</div>
 +<div class="section" id="sqlite-database">
 +<h3>SQLite Database<a class="headerlink" href="#sqlite-database" title="Permalink to this headline">¶</a></h3>
 +<p>If you decide to use a SQLite database make sure that you have installed and
 +enabled the SQLite extension in PHP. The PHP configuration in <tt class="file docutils literal"><span class="pre">/etc/php5/conf.d/sqlite3.ini</span></tt> could look like this:</p>
 +<div class="highlight-ini"><div class="highlight"><pre><span class="c"># configuration for PHP SQLite3 module</span>
 +<span class="na">extension</span><span class="o">=</span><span class="s">pdo_sqlite.so</span>
 +<span class="na">extension</span><span class="o">=</span><span class="s">sqlite3.so</span>
 +</pre></div>
 +</div>
 +<p>It is not necessary to create a database and a database user in advance
 +because this will automatically be done by ownCloud when you login for the
 +first time.</p>
 +<p>In the ownCloud configuration in <tt class="file docutils literal"><span class="pre">config/config.php</span></tt> you need to set at least the <strong>datadirectory</strong> parameter to
 +the directory where your data and database should be stored. Note that for the PDO SQLite driver this directory must
 +be writable (this is recommended for ownCloud anyway).  No authentication is required to access the database therefore
 +most of the default parameters could be taken as is:</p>
 +<div class="highlight-php"><div class="highlight"><pre><span class="cp"><?php</span>
 +
 +  <span class="s2">"dbtype"</span>        <span class="o">=></span> <span class="s2">"sqlite"</span><span class="p">,</span>
 +  <span class="s2">"dbname"</span>        <span class="o">=></span> <span class="s2">"owncloud"</span><span class="p">,</span>
 +  <span class="s2">"dbuser"</span>        <span class="o">=></span> <span class="s2">""</span><span class="p">,</span>
 +  <span class="s2">"dbpassword"</span>    <span class="o">=></span> <span class="s2">""</span><span class="p">,</span>
 +  <span class="s2">"dbhost"</span>        <span class="o">=></span> <span class="s2">""</span><span class="p">,</span>
 +  <span class="s2">"dbtableprefix"</span> <span class="o">=></span> <span class="s2">""</span><span class="p">,</span>
 +  <span class="s2">"datadirectory"</span> <span class="o">=></span> <span class="s2">"/www/htdocs/owncloud/data"</span><span class="p">,</span>
 +</pre></div>
 +</div>
 +</div>
 +<div class="section" id="postgresql-database">
 +<h3>PostgreSQL Database<a class="headerlink" href="#postgresql-database" title="Permalink to this headline">¶</a></h3>
 +<p>If you decide to use a PostgreSQL database make sure that you have installed
 +and enabled the PostgreSQL extension in PHP. The PHP configuration in <tt class="file docutils literal"><span class="pre">/etc/php5/conf.d/pgsql.ini</span></tt> could look
 +like this:</p>
 +<div class="highlight-ini"><div class="highlight"><pre><span class="c"># configuration for PHP PostgreSQL module</span>
 +<span class="na">extension</span><span class="o">=</span><span class="s">pdo_pgsql.so</span>
 +<span class="na">extension</span><span class="o">=</span><span class="s">pgsql.so</span>
 +
 +<span class="k">[PostgresSQL]</span>
 +<span class="na">pgsql.allow_persistent</span> <span class="o">=</span> <span class="s">On</span>
 +<span class="na">pgsql.auto_reset_persistent</span> <span class="o">=</span> <span class="s">Off</span>
 +<span class="na">pgsql.max_persistent</span> <span class="o">=</span> <span class="s">-1</span>
 +<span class="na">pgsql.max_links</span> <span class="o">=</span> <span class="s">-1</span>
 +<span class="na">pgsql.ignore_notice</span> <span class="o">=</span> <span class="s">0</span>
 +<span class="na">pgsql.log_notice</span> <span class="o">=</span> <span class="s">0</span>
 +</pre></div>
 +</div>
 +<p>Now you need to create a database user and the database itself by using the
 +PostgreSQL command line interface. The database tables will be created by
 +ownCloud when you login for the first time.</p>
 +<p>To start the postgres command line mode use:</p>
 +<div class="highlight-python"><div class="highlight"><pre><span class="n">psql</span> <span class="o">-</span><span class="n">hlocalhost</span> <span class="o">-</span><span class="n">Upostgres</span>
 +</pre></div>
 +</div>
 +<p>Then a <strong>postgres=#</strong> prompt will appear. Now enter the following lines and confirm them with the enter key:</p>
 +<div class="highlight-sql"><div class="highlight"><pre><span class="k">CREATE</span> <span class="k">USER</span> <span class="n">username</span> <span class="k">WITH</span> <span class="n">PASSWORD</span> <span class="s1">'password'</span><span class="p">;</span>
 +<span class="k">CREATE</span> <span class="k">DATABASE</span> <span class="n">owncloud</span> <span class="k">TEMPLATE</span> <span class="n">template0</span> <span class="k">ENCODING</span> <span class="s1">'UNICODE'</span><span class="p">;</span>
 +<span class="k">ALTER</span> <span class="k">DATABASE</span> <span class="n">owncloud</span> <span class="k">OWNER</span> <span class="k">TO</span> <span class="n">username</span><span class="p">;</span>
 +<span class="k">GRANT</span> <span class="k">ALL</span> <span class="k">PRIVILEGES</span> <span class="k">ON</span> <span class="k">DATABASE</span> <span class="n">owncloud</span> <span class="k">TO</span> <span class="n">username</span><span class="p">;</span>
 +</pre></div>
 +</div>
 +<p>You can quit the prompt by entering:</p>
 +<div class="highlight-python"><pre>\q</pre>
 +</div>
 +<p>In the ownCloud configuration you need to set the hostname on which the
 +database is running and a valid username (and sometimes a password) to
 +access it. If the database has been installed on the same server as
 +ownCloud a password is very often not required to access the database.</p>
 +<div class="highlight-php"><div class="highlight"><pre><span class="cp"><?php</span>
 +
 +  <span class="s2">"dbtype"</span>        <span class="o">=></span> <span class="s2">"pgsql"</span><span class="p">,</span>
 +  <span class="s2">"dbname"</span>        <span class="o">=></span> <span class="s2">"owncloud"</span><span class="p">,</span>
 +  <span class="s2">"dbuser"</span>        <span class="o">=></span> <span class="s2">"username"</span><span class="p">,</span>
 +  <span class="s2">"dbpassword"</span>    <span class="o">=></span> <span class="s2">"password"</span><span class="p">,</span>
 +  <span class="s2">"dbhost"</span>        <span class="o">=></span> <span class="s2">"localhost"</span><span class="p">,</span>
 +  <span class="s2">"dbtableprefix"</span> <span class="o">=></span> <span class="s2">""</span><span class="p">,</span>
 +</pre></div>
 +</div>
 +</div>
 +<div class="section" id="oracle-database">
 +<h3>Oracle Database<a class="headerlink" href="#oracle-database" title="Permalink to this headline">¶</a></h3>
 +<p>If you are deploying to an Oracle database make sure that you have installed
 +and enabled the <a class="reference external" href="http://php.net/manual/en/book.oci8.php">Oracle extension</a> in PHP. The PHP configuration in
 +<tt class="file docutils literal"><span class="pre">/etc/php5/conf.d/oci8.ini</span></tt> could look like this:</p>
 +<div class="highlight-ini"><div class="highlight"><pre><span class="c"># configuration for PHP Oracle extension</span>
 +<span class="na">extension</span><span class="o">=</span><span class="s">oci8.so</span>
 +</pre></div>
 +</div>
 +<p>Make sure that the Oracle environment has been set up for the process trying to use the Oracle extension.
 +For a local Oracle XE installation this can be done by exporting the following environment variables
 +(eg. in <tt class="file docutils literal"><span class="pre">/etc/apache2/envvars</span></tt> for Apache)</p>
 +<div class="highlight-bash"><div class="highlight"><pre><span class="nb">export </span><span class="nv">ORACLE_HOME</span><span class="o">=</span>/u01/app/oracle/product/11.2.0/xe
 +<span class="nb">export </span><span class="nv">LD_LIBRARY_PATH</span><span class="o">=</span><span class="nv">$LD_LIBRARY_PATH</span>:<span class="nv">$ORACLE_HOME</span>/lib
 +</pre></div>
 +</div>
 +<p>Installing and configuring Oracle support for PHP is way out of scope for this document.
 +The official Oracle documentation called <a class="reference external" href="http://www.oracle.com/technetwork/topics/php/underground-php-oracle-manual-098250.html">The Underground PHP and Oracle Manual</a>
 +should help you through the process.</p>
 +<p>Creating a database user for ownCloud can be done by using the sqlplus command line interface
 +or the Oracle Application Express web interface.
 +The database tables will be created by ownCloud when you login for the first time.</p>
 +<p>To start the Oracle command line mode with a DBA account use:</p>
 +<div class="highlight-python"><pre>sqlplus system AS SYSDBA</pre>
 +</div>
 +<p>After entering the password a <strong>SQL></strong> prompt will appear. Now enter the following lines and confirm them with the enter key:</p>
 +<div class="highlight-sql"><div class="highlight"><pre><span class="k">CREATE</span> <span class="k">USER</span> <span class="n">owncloud</span> <span class="n">IDENTIFIED</span> <span class="k">BY</span> <span class="n">password</span><span class="p">;</span>
 +<span class="k">ALTER</span> <span class="k">USER</span> <span class="n">owncloud</span> <span class="k">DEFAULT</span> <span class="n">TABLESPACE</span> <span class="n">users</span>
 +                    <span class="k">TEMPORARY</span> <span class="n">TABLESPACE</span> <span class="n">temp</span>
 +                    <span class="n">QUOTA</span> <span class="n">unlimited</span> <span class="k">ON</span> <span class="n">users</span><span class="p">;</span>
 +<span class="k">GRANT</span> <span class="k">create</span> <span class="k">session</span>
 +    <span class="p">,</span> <span class="k">create</span> <span class="k">table</span>
 +    <span class="p">,</span> <span class="k">create</span> <span class="k">procedure</span>
 +    <span class="p">,</span> <span class="k">create</span> <span class="n">sequence</span>
 +    <span class="p">,</span> <span class="k">create</span> <span class="k">trigger</span>
 +    <span class="p">,</span> <span class="k">create</span> <span class="k">view</span>
 +    <span class="p">,</span> <span class="k">create</span> <span class="n">synonym</span>
 +    <span class="p">,</span> <span class="k">alter</span> <span class="k">session</span>
 +   <span class="k">TO</span> <span class="n">owncloud</span><span class="p">;</span>
 +</pre></div>
 +</div>
 +<div class="admonition note">
 +<p class="first admonition-title">Note</p>
 +<p class="last">In Oracle creating a user is the same as creating a database in other RDBMs, so no <tt class="docutils literal"><span class="pre">CREATE</span> <span class="pre">DATABASE</span></tt> statement is necessary.</p>
 +</div>
 +<p>You can quit the prompt by entering:</p>
 +<div class="highlight-python"><div class="highlight"><pre><span class="nb">exit</span>
 +</pre></div>
 +</div>
 +<p>In the ownCloud configuration you need to set the hostname on which the
 +database is running and a valid username and password to
 +access it. If the database has been installed on the same server as
 +ownCloud to config file could look like this:</p>
 +<div class="highlight-php"><div class="highlight"><pre><span class="cp"><?php</span>
 +
 +  <span class="s2">"dbtype"</span>        <span class="o">=></span> <span class="s2">"oci"</span><span class="p">,</span>
 +  <span class="s2">"dbname"</span>        <span class="o">=></span> <span class="s2">"XE"</span><span class="p">,</span>
 +  <span class="s2">"dbuser"</span>        <span class="o">=></span> <span class="s2">"owncloud"</span><span class="p">,</span>
 +  <span class="s2">"dbpassword"</span>    <span class="o">=></span> <span class="s2">"password"</span><span class="p">,</span>
 +  <span class="s2">"dbhost"</span>        <span class="o">=></span> <span class="s2">"localhost"</span><span class="p">,</span>
 +</pre></div>
 +</div>
 +<div class="admonition note">
 +<p class="first admonition-title">Note</p>
 +<p class="last">This example assumes you are running an Oracle Express Edition on <tt class="docutils literal"><span class="pre">localhost</span></tt>. The <tt class="docutils literal"><span class="pre">dbname</span></tt> is the name</p>
 +</div>
 +<p>of the Oracle instance. For Oracle Express Edition it is always <tt class="docutils literal"><span class="pre">XE</span></tt>.</p>
 +</div>
 +</div>
 +<div class="section" id="trouble-shooting">
 +<h2>Trouble Shooting<a class="headerlink" href="#trouble-shooting" title="Permalink to this headline">¶</a></h2>
 +<div class="section" id="how-can-i-find-out-if-my-mysql-postgresql-server-is-reachable">
 +<h3>How can I find out if my MySQL/PostgreSQL  server is reachable?<a class="headerlink" href="#how-can-i-find-out-if-my-mysql-postgresql-server-is-reachable" title="Permalink to this headline">¶</a></h3>
 +<p>Use the ping command to check the server availability:</p>
 +<div class="highlight-python"><pre>ping db.server.dom</pre>
 +</div>
 +<div class="highlight-python"><pre>PING db.server.dom (ip-address) 56(84) bytes of data.
 +64 bytes from your-server.local.lan (192.168.1.10): icmp_req=1 ttl=64 time=3.64 ms
 +64 bytes from your-server.local.lan (192.168.1.10): icmp_req=2 ttl=64 time=0.055 ms
 +64 bytes from your-server.local.lan (192.168.1.10): icmp_req=3 ttl=64 time=0.062 ms</pre>
 +</div>
 +</div>
 +<div class="section" id="how-can-i-find-out-if-a-created-user-can-access-a-database">
 +<h3>How can I find out if a created user can access a database?<a class="headerlink" href="#how-can-i-find-out-if-a-created-user-can-access-a-database" title="Permalink to this headline">¶</a></h3>
 +<p>The easiest way to test if a database can be accessed is by starting the
 +command line interface:</p>
 +<p><strong>SQLite</strong>:</p>
 +<div class="highlight-python"><div class="highlight"><pre><span class="n">sqlite3</span> <span class="o">/</span><span class="n">www</span><span class="o">/</span><span class="n">htdocs</span><span class="o">/</span><span class="n">owncloud</span><span class="o">/</span><span class="n">data</span><span class="o">/</span><span class="n">owncloud</span><span class="o">.</span><span class="n">db</span>
 +</pre></div>
 +</div>
 +<div class="highlight-python"><pre>sqlite> .version
 +SQLite 3.7.15.1 2012-12-19 20:39:10 6b85b767d0ff7975146156a99ad673f2c1a23318
 +sqlite> .quit</pre>
 +</div>
 +<p><strong>MySQL</strong>:</p>
 +<div class="highlight-python"><div class="highlight"><pre><span class="n">mysql</span> <span class="o">-</span><span class="n">uUSERNAME</span> <span class="o">-</span><span class="n">p</span>
 +</pre></div>
 +</div>
 +<div class="highlight-python"><pre>mysql> SHOW VARIABLES LIKE "version";
 ++---------------+--------+
 +| Variable_name | Value  |
 ++---------------+--------+
 +| version       | 5.1.67 |
 ++---------------+--------+
 +1 row in set (0.00 sec)
 +mysql> quit</pre>
 +</div>
 +<p><strong>PostgreSQL</strong>:</p>
 +<div class="highlight-python"><div class="highlight"><pre><span class="n">psql</span> <span class="o">-</span><span class="n">Uusername</span> <span class="o">-</span><span class="n">downcloud</span>
 +</pre></div>
 +</div>
 +<div class="highlight-python"><pre>postgres=# SELECT version();
 +PostgreSQL 8.4.12 on i686-pc-linux-gnu, compiled by GCC gcc (GCC) 4.1.3 20080704 (prerelease), 32-bit
 +(1 row)
 +postgres=# \q</pre>
 +</div>
 +<p><strong>Oracle</strong>:</p>
 +<div class="highlight-python"><pre>sqlplus username</pre>
 +</div>
 +<div class="highlight-python"><pre>SQL> select * from v$version;
 +
 +BANNER
 +--------------------------------------------------------------------------------
 +Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64bit Production
 +PL/SQL Release 11.2.0.2.0 - Production
 +CORE  11.2.0.2.0      Production
 +TNS for Linux: Version 11.2.0.2.0 - Production
 +NLSRTL Version 11.2.0.2.0 - Production
 +
 +SQL> exit</pre>
 +</div>
 +</div>
 +<div class="section" id="useful-sql-commands">
 +<h3>Useful SQL commands<a class="headerlink" href="#useful-sql-commands" title="Permalink to this headline">¶</a></h3>
 +<p><strong>Show Database Users</strong>:</p>
 +<div class="highlight-python"><pre>SQLite    : No database user is required.
 +MySQL     : SELECT User,Host FROM mysql.user;
 +PostgreSQL: SELECT * FROM pg_user;
 +Oracle    : SELECT * FROM all_users;</pre>
 +</div>
 +<p><strong>Show available Databases</strong>:</p>
 +<div class="highlight-python"><pre>SQLite    : .databases (normally one database per file!)
 +MySQL     : SHOW DATABASES;
 +PostgreSQL: \l
 +Oracle    : SELECT name FROM v$database; (requires DBA privileges)</pre>
 +</div>
 +<p><strong>Show ownCloud Tables in Database</strong>:</p>
 +<div class="highlight-python"><pre>SQLite    : .tables
 +MySQL     : USE owncloud; SHOW TABLES;
 +PostgreSQL: \c owncloud; \d
 +Oracle    : SELECT table_name FROM user_tables;</pre>
 +</div>
 +<p><strong>Quit Database</strong>:</p>
 +<div class="highlight-python"><pre>SQLite    : .quit
 +MySQL     : quit
 +PostgreSQL: \q
 +Oracle    : quit</pre>
 +</div>
 +</div>
 +</div>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/configuration/configuration_encryption.html
index 8a7bd00,0000000..6e7e346
mode 100644,000000..100644
--- a/core/doc/admin/configuration/configuration_encryption.html
+++ b/core/doc/admin/configuration/configuration_encryption.html
@@@ -1,224 -1,0 +1,225 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
-     <title>Use Server-Side Encryption — ownCloud Administrators Manual 6.0 documentation</title>
++    <title>Using Server-Side Encryption — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
 +    <link rel="up" title="Configuration" href="index.html" />
-     <link rel="next" title="Knowledge Base Configuration" href="configuration_knowledgebase.html" />
-     <link rel="prev" title="Database Configuration" href="configuration_database.html" />
++    <link rel="next" title="Disable Knowledge Base" href="configuration_knowledgebase.html" />
++    <link rel="prev" title="MySQL/Postgres/SQLite Support" href="configuration_database.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
 +<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../installation/index.html">Installation</a></li>
 +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Configuration</a><ul class="current">
- <li class="toctree-l2"><a class="reference internal" href="configuration_apps.html">Apps Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_apps.html">Managing Apps</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_users.html">User Management</a></li>
- <li class="toctree-l2"><a class="reference internal" href="auth_ldap.html">User Authentication with LDAP</a></li>
++<li class="toctree-l2"><a class="reference internal" href="auth_ldap.html">LDAP Authentication</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="background_jobs.html">Background Jobs</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_3rdparty.html">3rd-Party Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_3rdparty.html">Find Third-Party Libraries</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_automation.html">Automatic Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_custom_clients.html">Custom Client Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_database.html">Database Configuration</a></li>
- <li class="toctree-l2 current"><a class="current reference internal" href="">Use Server-Side Encryption</a><ul>
++<li class="toctree-l2"><a class="reference internal" href="configuration_custom_clients.html">Customizing Client Download Links</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_database.html">MySQL/Postgres/SQLite Support</a></li>
++<li class="toctree-l2 current"><a class="current reference internal" href="">Using Server-Side Encryption</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="#enable-file-recovery-feature">Enable File Recovery Feature</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#recover-user-files">Recover User Files</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#ldap-and-other-external-user-back-ends">LDAP and other external user back-ends</a></li>
 +</ul>
 +</li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_knowledgebase.html">Knowledge Base Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_language.html">Language Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_logging.html">Logging Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_mail.html">Mail Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_maintenance.html">Maintenance Mode Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_preview.html">Preview Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_knowledgebase.html">Disable Knowledge Base</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_language.html">Setting the Default Language</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_logging.html">Configure Logging</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_mail.html">Sending Mail Notifications</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_maintenance.html">Enable Maintenance Mode</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_preview.html">Enabling File Previews</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_reverseproxy.html">Reverse Proxy Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html">Uploading big files > 512MB (as set by default)</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html#enabling-uploading-big-files">Enabling uploading big files</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html">Dealing with Big File Uploads</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_mount_config_gui.html">Custom Mount Configuration Web-GUI</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_mount_config.html">Custom Mount Configuration</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_user_backend.html">Custom User Backend Configuration</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="xsendfile.html">Serving static files via web server</a></li>
 +</ul>
 +</li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
-   <div class="section" id="use-server-side-encryption">
- <h1>Use Server-Side Encryption<a class="headerlink" href="#use-server-side-encryption" title="Permalink to this headline">¶</a></h1>
++  <div class="section" id="using-server-side-encryption">
++<h1>Using Server-Side Encryption<a class="headerlink" href="#using-server-side-encryption" title="Permalink to this headline">¶</a></h1>
 +<p>ownCloud ships a encryption app, which allows to encrypt all files stored in
 +your ownCloud. Encryption and decryption always happens server-side. This
 +enables the user to continue to use all the other apps to view and edit his
 +data.</p>
 +<p>The app uses the user’s log-in password as encryption-password. This means that
 +by default the user will lose access to his files if he loses his log-in
 +password.</p>
 +<p>It might be a good idea to make regular backups of all encryption keys. The
 +encryption keys are stored in following folders:</p>
 +<ul class="simple">
 +<li>data/owncloud_private_key (recovery key, if enabled and public share key)</li>
 +<li>data/public-keys (public keys from all users)</li>
 +<li>data/<user>/files_encryption (users’ private keys and all other keys necessary to
 +decrypt the users’ files)</li>
 +</ul>
 +<div class="section" id="enable-file-recovery-feature">
 +<h2>Enable File Recovery Feature<a class="headerlink" href="#enable-file-recovery-feature" title="Permalink to this headline">¶</a></h2>
 +<p>The admin can offer the user some kind of protection against password
 +loss. Therefore you have to enable the recovery key in the admin settings and
 +provide a strong recovery key password. The admin settings also enables you to
 +change the recovery key password if you wish. But you should make sure to never
 +lose this password, because that’s the only way to recover users’ files.</p>
 +<p>Once the recovery key was enabled every user can choose in his personal
 +settings to enable this feature or not.</p>
 +</div>
 +<div class="section" id="recover-user-files">
 +<h2>Recover User Files<a class="headerlink" href="#recover-user-files" title="Permalink to this headline">¶</a></h2>
 +<p>If the recovery feature was enabled the admin will see a additional input field
 +at the top of the user management settings. After entering the recovery-key
 +password the admin can change the user’s log-in password which will
 +automatically recover the user’s file.</p>
 +<p>If you use a user back-end which doesn’t allow you to change the log-in
 +password directly within ownCloud, e.g. the LDAP back-end, than you can follow
 +the same procedure to recover a user’s files. The only difference is that
 +you need to change the log-in password additionally at your back-end. In this
 +case make sure to use both times the same password.</p>
 +</div>
 +<div class="section" id="ldap-and-other-external-user-back-ends">
 +<h2>LDAP and other external user back-ends<a class="headerlink" href="#ldap-and-other-external-user-back-ends" title="Permalink to this headline">¶</a></h2>
 +<p>if you configure a external user back-end you will be able to change the user’s log-in password
 +at the back-end. Since the encryption password must be the same as the user’s log-in password
 +this will result in a non-functional encryption system. If the recovery feature was enabled,
 +the administrator will be able to recover the user’s files directly over the recovery feature.
 +See the description above. Otherwise the user will be informed that his log-in password and
 +his encryption password no longer matches after his next log-in. In this case the user will be
 +able to adjust his encryption password in the personal settings by providing both, his old and
 +his new log-in password.</p>
 +</div>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/configuration/configuration_knowledgebase.html
index 983723c,0000000..3966a40
mode 100644,000000..100644
--- a/core/doc/admin/configuration/configuration_knowledgebase.html
+++ b/core/doc/admin/configuration/configuration_knowledgebase.html
@@@ -1,193 -1,0 +1,195 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
-     <title>Knowledge Base Configuration — ownCloud Administrators Manual 6.0 documentation</title>
++    <title>Disable Knowledge Base — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
 +    <link rel="up" title="Configuration" href="index.html" />
-     <link rel="next" title="Language Configuration" href="configuration_language.html" />
-     <link rel="prev" title="Use Server-Side Encryption" href="configuration_encryption.html" />
++    <link rel="next" title="Setting the Default Language" href="configuration_language.html" />
++    <link rel="prev" title="Using Server-Side Encryption" href="configuration_encryption.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
 +<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../installation/index.html">Installation</a></li>
 +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Configuration</a><ul class="current">
- <li class="toctree-l2"><a class="reference internal" href="configuration_apps.html">Apps Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_apps.html">Managing Apps</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_users.html">User Management</a></li>
- <li class="toctree-l2"><a class="reference internal" href="auth_ldap.html">User Authentication with LDAP</a></li>
++<li class="toctree-l2"><a class="reference internal" href="auth_ldap.html">LDAP Authentication</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="background_jobs.html">Background Jobs</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_3rdparty.html">3rd-Party Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_3rdparty.html">Find Third-Party Libraries</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_automation.html">Automatic Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_custom_clients.html">Custom Client Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_database.html">Database Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_encryption.html">Use Server-Side Encryption</a></li>
- <li class="toctree-l2 current"><a class="current reference internal" href="">Knowledge Base Configuration</a><ul>
++<li class="toctree-l2"><a class="reference internal" href="configuration_custom_clients.html">Customizing Client Download Links</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_database.html">MySQL/Postgres/SQLite Support</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_encryption.html">Using Server-Side Encryption</a></li>
++<li class="toctree-l2 current"><a class="current reference internal" href="">Disable Knowledge Base</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="#parameters">Parameters</a></li>
 +</ul>
 +</li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_language.html">Language Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_logging.html">Logging Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_mail.html">Mail Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_maintenance.html">Maintenance Mode Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_preview.html">Preview Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_language.html">Setting the Default Language</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_logging.html">Configure Logging</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_mail.html">Sending Mail Notifications</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_maintenance.html">Enable Maintenance Mode</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_preview.html">Enabling File Previews</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_reverseproxy.html">Reverse Proxy Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html">Uploading big files > 512MB (as set by default)</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html#enabling-uploading-big-files">Enabling uploading big files</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html">Dealing with Big File Uploads</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_mount_config_gui.html">Custom Mount Configuration Web-GUI</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_mount_config.html">Custom Mount Configuration</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_user_backend.html">Custom User Backend Configuration</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="xsendfile.html">Serving static files via web server</a></li>
 +</ul>
 +</li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
-   <div class="section" id="knowledge-base-configuration">
- <h1>Knowledge Base Configuration<a class="headerlink" href="#knowledge-base-configuration" title="Permalink to this headline">¶</a></h1>
++  <div class="section" id="disable-knowledge-base">
++<h1>Disable Knowledge Base<a class="headerlink" href="#disable-knowledge-base" title="Permalink to this headline">¶</a></h1>
 +<p>The usage of ownCloud is more or less self explaining but nevertheless a user
- might run into a problem where he needs to consult the documentation or knowledge base. To ease access to the ownCloud
- documentation and knowledge base, a help menu item is shown in the settings menu by default.</p>
++might run into a problem where he needs to consult the documentation or
++knowledge base. To ease access to the ownCloud documentation and knowledge
++base, a help menu item is shown in the settings menu by default.</p>
 +<div class="section" id="parameters">
 +<h2>Parameters<a class="headerlink" href="#parameters" title="Permalink to this headline">¶</a></h2>
 +<p>If you want to disable the ownCloud help menu item you can use the <strong>knowledgebaseenabled</strong> parameter inside the
 +<tt class="file docutils literal"><span class="pre">config/config.php</span></tt>. The <strong>knowledgebaseurl</strong> parameter is used to set the http path to the ownCloud help page.
 +The server should support <abbr title="Open Collaboration Services">OCS</abbr>.</p>
 +<div class="highlight-php"><div class="highlight"><pre><span class="cp"><?php</span>
 +
 +  <span class="s2">"knowledgebaseenabled"</span> <span class="o">=></span> <span class="k">true</span><span class="p">,</span>
 +  <span class="s2">"knowledgebaseurl"</span>     <span class="o">=></span> <span class="s2">"http://api.apps.owncloud.com/v1"</span><span class="p">,</span>
 +</pre></div>
 +</div>
 +<div class="admonition note">
 +<p class="first admonition-title">Note</p>
 +<p class="last">Disabling the help menu item might increase the number of support request you have to answer in the future</p>
 +</div>
 +</div>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/configuration/configuration_language.html
index 0dd60d6,0000000..a098c4c
mode 100644,000000..100644
--- a/core/doc/admin/configuration/configuration_language.html
+++ b/core/doc/admin/configuration/configuration_language.html
@@@ -1,190 -1,0 +1,191 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
-     <title>Language Configuration — ownCloud Administrators Manual 6.0 documentation</title>
++    <title>Setting the Default Language — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
 +    <link rel="up" title="Configuration" href="index.html" />
-     <link rel="next" title="Logging Configuration" href="configuration_logging.html" />
-     <link rel="prev" title="Knowledge Base Configuration" href="configuration_knowledgebase.html" />
++    <link rel="next" title="Configure Logging" href="configuration_logging.html" />
++    <link rel="prev" title="Disable Knowledge Base" href="configuration_knowledgebase.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
 +<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../installation/index.html">Installation</a></li>
 +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Configuration</a><ul class="current">
- <li class="toctree-l2"><a class="reference internal" href="configuration_apps.html">Apps Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_apps.html">Managing Apps</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_users.html">User Management</a></li>
- <li class="toctree-l2"><a class="reference internal" href="auth_ldap.html">User Authentication with LDAP</a></li>
++<li class="toctree-l2"><a class="reference internal" href="auth_ldap.html">LDAP Authentication</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="background_jobs.html">Background Jobs</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_3rdparty.html">3rd-Party Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_3rdparty.html">Find Third-Party Libraries</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_automation.html">Automatic Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_custom_clients.html">Custom Client Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_database.html">Database Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_encryption.html">Use Server-Side Encryption</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_knowledgebase.html">Knowledge Base Configuration</a></li>
- <li class="toctree-l2 current"><a class="current reference internal" href="">Language Configuration</a><ul>
++<li class="toctree-l2"><a class="reference internal" href="configuration_custom_clients.html">Customizing Client Download Links</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_database.html">MySQL/Postgres/SQLite Support</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_encryption.html">Using Server-Side Encryption</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_knowledgebase.html">Disable Knowledge Base</a></li>
++<li class="toctree-l2 current"><a class="current reference internal" href="">Setting the Default Language</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="#parameters">Parameters</a></li>
 +</ul>
 +</li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_logging.html">Logging Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_mail.html">Mail Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_maintenance.html">Maintenance Mode Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_preview.html">Preview Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_logging.html">Configure Logging</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_mail.html">Sending Mail Notifications</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_maintenance.html">Enable Maintenance Mode</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_preview.html">Enabling File Previews</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_reverseproxy.html">Reverse Proxy Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html">Uploading big files > 512MB (as set by default)</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html#enabling-uploading-big-files">Enabling uploading big files</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html">Dealing with Big File Uploads</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_mount_config_gui.html">Custom Mount Configuration Web-GUI</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_mount_config.html">Custom Mount Configuration</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_user_backend.html">Custom User Backend Configuration</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="xsendfile.html">Serving static files via web server</a></li>
 +</ul>
 +</li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
-   <div class="section" id="language-configuration">
- <h1>Language Configuration<a class="headerlink" href="#language-configuration" title="Permalink to this headline">¶</a></h1>
++  <div class="section" id="setting-the-default-language">
++<h1>Setting the Default Language<a class="headerlink" href="#setting-the-default-language" title="Permalink to this headline">¶</a></h1>
 +<p>In normal cases ownCloud will automatically detect the language of the Web-GUI.
 +If this doesn’t work properly or you want to make sure that ownCloud always
 +starts with a given language, you can use the <strong>default_language</strong> parameter.</p>
 +<p>Please keep in mind, that this will not effect a users language preference,
 +which has been configured under “personal -> language” once he has logged in.</p>
 +<p>Please check <tt class="file docutils literal"><span class="pre">settings/languageCodes.php</span></tt> for the list of supported language
 +codes.</p>
 +<div class="section" id="parameters">
 +<h2>Parameters<a class="headerlink" href="#parameters" title="Permalink to this headline">¶</a></h2>
 +<div class="highlight-php"><div class="highlight"><pre><span class="cp"><?php</span>
 +
 +  <span class="s2">"default_language"</span> <span class="o">=></span> <span class="s2">"en"</span><span class="p">,</span>
 +</pre></div>
 +</div>
 +<p>This parameters can be set in the <tt class="file docutils literal"><span class="pre">config/config.php</span></tt></p>
 +</div>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/configuration/configuration_logging.html
index 7ff2992,0000000..0a1e134
mode 100644,000000..100644
--- a/core/doc/admin/configuration/configuration_logging.html
+++ b/core/doc/admin/configuration/configuration_logging.html
@@@ -1,226 -1,0 +1,227 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
-     <title>Logging Configuration — ownCloud Administrators Manual 6.0 documentation</title>
++    <title>Configure Logging — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
 +    <link rel="up" title="Configuration" href="index.html" />
-     <link rel="next" title="Mail Configuration" href="configuration_mail.html" />
-     <link rel="prev" title="Language Configuration" href="configuration_language.html" />
++    <link rel="next" title="Sending Mail Notifications" href="configuration_mail.html" />
++    <link rel="prev" title="Setting the Default Language" href="configuration_language.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
 +<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../installation/index.html">Installation</a></li>
 +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Configuration</a><ul class="current">
- <li class="toctree-l2"><a class="reference internal" href="configuration_apps.html">Apps Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_apps.html">Managing Apps</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_users.html">User Management</a></li>
- <li class="toctree-l2"><a class="reference internal" href="auth_ldap.html">User Authentication with LDAP</a></li>
++<li class="toctree-l2"><a class="reference internal" href="auth_ldap.html">LDAP Authentication</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="background_jobs.html">Background Jobs</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_3rdparty.html">3rd-Party Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_3rdparty.html">Find Third-Party Libraries</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_automation.html">Automatic Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_custom_clients.html">Custom Client Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_database.html">Database Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_encryption.html">Use Server-Side Encryption</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_knowledgebase.html">Knowledge Base Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_language.html">Language Configuration</a></li>
- <li class="toctree-l2 current"><a class="current reference internal" href="">Logging Configuration</a><ul>
++<li class="toctree-l2"><a class="reference internal" href="configuration_custom_clients.html">Customizing Client Download Links</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_database.html">MySQL/Postgres/SQLite Support</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_encryption.html">Using Server-Side Encryption</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_knowledgebase.html">Disable Knowledge Base</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_language.html">Setting the Default Language</a></li>
++<li class="toctree-l2 current"><a class="current reference internal" href="">Configure Logging</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="#parameters">Parameters</a></li>
 +</ul>
 +</li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_mail.html">Mail Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_maintenance.html">Maintenance Mode Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_preview.html">Preview Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_mail.html">Sending Mail Notifications</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_maintenance.html">Enable Maintenance Mode</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_preview.html">Enabling File Previews</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_reverseproxy.html">Reverse Proxy Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html">Uploading big files > 512MB (as set by default)</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html#enabling-uploading-big-files">Enabling uploading big files</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html">Dealing with Big File Uploads</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_mount_config_gui.html">Custom Mount Configuration Web-GUI</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_mount_config.html">Custom Mount Configuration</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_user_backend.html">Custom User Backend Configuration</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="xsendfile.html">Serving static files via web server</a></li>
 +</ul>
 +</li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
-   <div class="section" id="logging-configuration">
- <h1>Logging Configuration<a class="headerlink" href="#logging-configuration" title="Permalink to this headline">¶</a></h1>
++  <div class="section" id="configure-logging">
++<h1>Configure Logging<a class="headerlink" href="#configure-logging" title="Permalink to this headline">¶</a></h1>
 +<p>To get an idea of how the current status of an ownCloud system is or to
 +solve issues log information is a good point to start with. ownCloud allows
 +to configure the way how and which depth of information should be logged.</p>
 +<div class="section" id="parameters">
 +<h2>Parameters<a class="headerlink" href="#parameters" title="Permalink to this headline">¶</a></h2>
 +<p>First you need to decide in which way logging should be done. You can
 +choose between the two options <strong>owncloud</strong> and <strong>syslog</strong>. Then you need
 +to configure the log level which directly influences how much information
 +will be logged. You can choose between:</p>
 +<ul class="simple">
 +<li><strong>0</strong>: DEBUG</li>
 +<li><strong>1</strong>: INFO</li>
 +<li><strong>2</strong>: WARN</li>
 +<li><strong>3</strong>: ERROR</li>
 +</ul>
 +<p>The most detailed information will be written if <strong>0</strong> (DEBUG) is set, the
 +least information will be written if <strong>3</strong> (ERROR) is set. Keep in mind that
 +it might slow down the whole system if a too detailed logging will has been
 +configured. By default the log level is set to <strong>2</strong> (WARN).</p>
 +<p>This parameters can be set in the <tt class="file docutils literal"><span class="pre">config/config.php</span></tt></p>
 +<div class="section" id="owncloud">
 +<h3>ownCloud<a class="headerlink" href="#owncloud" title="Permalink to this headline">¶</a></h3>
 +<p>All log information will be written to a separate log file which can be
 +viewed using the log menu in the admin menu of ownCloud. By default a log
 +file named <strong>owncloud.log</strong> will be created in the directory which has
 +been configured by the <strong>datadirectory</strong> parameter.</p>
 +<p>The desired date format can optionally be defined using the <strong>logdateformat</strong>.
 +By default the <a class="reference external" href="http://www.php.net/manual/en/function.date.php">PHP date function</a> parameter “<em>c</em>” is used and therefore the
 +date/time is written in the format “<em>2013-01-10T15:20:25+02:00</em>”. By using the
 +date format in the example the date/time format will be written in the format
 +“<em>January 10, 2013 15:20:25</em>”.</p>
 +<div class="highlight-php"><div class="highlight"><pre><span class="cp"><?php</span>
 +
 +  <span class="s2">"log_type"</span> <span class="o">=></span> <span class="s2">"owncloud"</span><span class="p">,</span>
 +  <span class="s2">"logfile"</span> <span class="o">=></span> <span class="s2">"owncloud.log"</span><span class="p">,</span>
 +  <span class="s2">"loglevel"</span> <span class="o">=></span> <span class="s2">"3"</span><span class="p">,</span>
 +  <span class="s2">"logdateformat"</span> <span class="o">=></span> <span class="s2">"F d, Y H:i:s"</span><span class="p">,</span>
 +</pre></div>
 +</div>
 +</div>
 +<div class="section" id="syslog">
 +<h3>syslog<a class="headerlink" href="#syslog" title="Permalink to this headline">¶</a></h3>
 +<p>All log information will be send to the default syslog daemon of a system.</p>
 +<div class="highlight-php"><div class="highlight"><pre><span class="cp"><?php</span>
 +
 +  <span class="s2">"log_type"</span> <span class="o">=></span> <span class="s2">"syslog"</span><span class="p">,</span>
 +  <span class="s2">"logfile"</span> <span class="o">=></span> <span class="s2">""</span><span class="p">,</span>
 +  <span class="s2">"loglevel"</span> <span class="o">=></span> <span class="s2">"3"</span><span class="p">,</span>
 +</pre></div>
 +</div>
 +</div>
 +</div>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/configuration/configuration_mail.html
index 3bdc12a,0000000..e483127
mode 100644,000000..100644
--- a/core/doc/admin/configuration/configuration_mail.html
+++ b/core/doc/admin/configuration/configuration_mail.html
@@@ -1,456 -1,0 +1,457 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
-     <title>Mail Configuration — ownCloud Administrators Manual 6.0 documentation</title>
++    <title>Sending Mail Notifications — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
 +    <link rel="up" title="Configuration" href="index.html" />
-     <link rel="next" title="Maintenance Mode Configuration" href="configuration_maintenance.html" />
-     <link rel="prev" title="Logging Configuration" href="configuration_logging.html" />
++    <link rel="next" title="Enable Maintenance Mode" href="configuration_maintenance.html" />
++    <link rel="prev" title="Configure Logging" href="configuration_logging.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
 +<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../installation/index.html">Installation</a></li>
 +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Configuration</a><ul class="current">
- <li class="toctree-l2"><a class="reference internal" href="configuration_apps.html">Apps Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_apps.html">Managing Apps</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_users.html">User Management</a></li>
- <li class="toctree-l2"><a class="reference internal" href="auth_ldap.html">User Authentication with LDAP</a></li>
++<li class="toctree-l2"><a class="reference internal" href="auth_ldap.html">LDAP Authentication</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="background_jobs.html">Background Jobs</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_3rdparty.html">3rd-Party Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_3rdparty.html">Find Third-Party Libraries</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_automation.html">Automatic Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_custom_clients.html">Custom Client Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_database.html">Database Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_encryption.html">Use Server-Side Encryption</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_knowledgebase.html">Knowledge Base Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_language.html">Language Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_logging.html">Logging Configuration</a></li>
- <li class="toctree-l2 current"><a class="current reference internal" href="">Mail Configuration</a><ul>
++<li class="toctree-l2"><a class="reference internal" href="configuration_custom_clients.html">Customizing Client Download Links</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_database.html">MySQL/Postgres/SQLite Support</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_encryption.html">Using Server-Side Encryption</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_knowledgebase.html">Disable Knowledge Base</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_language.html">Setting the Default Language</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_logging.html">Configure Logging</a></li>
++<li class="toctree-l2 current"><a class="current reference internal" href="">Sending Mail Notifications</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="#requirements">Requirements</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#parameters">Parameters</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#send-a-test-email">Send a Test Email</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#trouble-shooting">Trouble shooting</a></li>
 +</ul>
 +</li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_maintenance.html">Maintenance Mode Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_preview.html">Preview Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_maintenance.html">Enable Maintenance Mode</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_preview.html">Enabling File Previews</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_reverseproxy.html">Reverse Proxy Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html">Uploading big files > 512MB (as set by default)</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html#enabling-uploading-big-files">Enabling uploading big files</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html">Dealing with Big File Uploads</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_mount_config_gui.html">Custom Mount Configuration Web-GUI</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_mount_config.html">Custom Mount Configuration</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_user_backend.html">Custom User Backend Configuration</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="xsendfile.html">Serving static files via web server</a></li>
 +</ul>
 +</li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
-   <div class="section" id="mail-configuration">
- <h1>Mail Configuration<a class="headerlink" href="#mail-configuration" title="Permalink to this headline">¶</a></h1>
++  <div class="section" id="sending-mail-notifications">
++<h1>Sending Mail Notifications<a class="headerlink" href="#sending-mail-notifications" title="Permalink to this headline">¶</a></h1>
 +<p>ownCloud does not contain a full email program but contains some parameters to
 +allow to send e.g. password reset email to the users. This function relies on
 +the <a class="reference external" href="http://sourceforge.net/projects/phpmailer/">PHPMailer library</a>. To
 +take advantage of this function it needs to be configured properly.</p>
 +<div class="section" id="requirements">
 +<h2>Requirements<a class="headerlink" href="#requirements" title="Permalink to this headline">¶</a></h2>
 +<p>Different requirements need to be matched, depending on the environment which
 +you are using and the way how you want to send email. You can choose between
 +<strong>SMTP</strong>, <strong>PHP mail</strong>, <strong>Sendmail</strong> and <strong>qmail</strong>.</p>
 +</div>
 +<div class="section" id="parameters">
 +<h2>Parameters<a class="headerlink" href="#parameters" title="Permalink to this headline">¶</a></h2>
 +<p>All parameters need to be set in <tt class="file docutils literal"><span class="pre">config/config.php</span></tt></p>
 +<div class="section" id="smtp">
 +<h3>SMTP<a class="headerlink" href="#smtp" title="Permalink to this headline">¶</a></h3>
 +<p>If you want to send email using a local or remote SMTP server it is necessary
 +to enter the name or ip address of the server, optionally followed by a colon
 +separated port number, e.g. <strong>:425</strong>. If this value is not given the default
 +port 25/tcp will be used unless you will change that by modifying the
 +<strong>mail_smtpport</strong> parameter. Multiple server can be entered separated by
 +semicolon:</p>
 +<div class="highlight-php"><div class="highlight"><pre><span class="cp"><?php</span>
 +
 +  <span class="s2">"mail_smtpmode"</span>     <span class="o">=></span> <span class="s2">"smtp"</span><span class="p">,</span>
 +  <span class="s2">"mail_smtphost"</span>     <span class="o">=></span> <span class="s2">"smtp-1.server.dom;smtp-2.server.dom:425"</span><span class="p">,</span>
 +  <span class="s2">"mail_smtpport"</span>     <span class="o">=></span> <span class="mi">25</span><span class="p">,</span>
 +</pre></div>
 +</div>
 +<p>or</p>
 +<div class="highlight-php"><div class="highlight"><pre><span class="cp"><?php</span>
 +
 +  <span class="s2">"mail_smtpmode"</span>     <span class="o">=></span> <span class="s2">"smtp"</span><span class="p">,</span>
 +  <span class="s2">"mail_smtphost"</span>     <span class="o">=></span> <span class="s2">"smtp.server.dom"</span><span class="p">,</span>
 +  <span class="s2">"mail_smtpport"</span>     <span class="o">=></span> <span class="mi">425</span><span class="p">,</span>
 +</pre></div>
 +</div>
 +<p>If a malware or SPAM scanner is running on the SMTP server it might be
 +necessary that you increase the SMTP timeout to e.g. 30s:</p>
 +<div class="highlight-php"><div class="highlight"><pre><span class="cp"><?php</span>
 +
 +  <span class="s2">"mail_smtptimeout"</span>  <span class="o">=></span> <span class="mi">30</span><span class="p">,</span>
 +</pre></div>
 +</div>
 +<p>If the SMTP server accepts insecure connections, the default setting can be
 +used:</p>
 +<div class="highlight-php"><div class="highlight"><pre><span class="cp"><?php</span>
 +
 +<span class="s2">"mail_smtpsecure"</span>   <span class="o">=></span> <span class="s1">''</span><span class="p">,</span>
 +</pre></div>
 +</div>
 +<p>If the SMTP server only accepts secure connections you can choose between
 +the following two variants:</p>
 +<div class="section" id="ssl">
 +<h4>SSL<a class="headerlink" href="#ssl" title="Permalink to this headline">¶</a></h4>
 +<p>A secure connection will be initiated using the outdated SMTPS protocol
 +which uses the port 465/tcp:</p>
 +<div class="highlight-php"><div class="highlight"><pre><span class="cp"><?php</span>
 +
 +  <span class="s2">"mail_smtphost"</span>     <span class="o">=></span> <span class="s2">"smtp.server.dom:465"</span><span class="p">,</span>
 +  <span class="s2">"mail_smtpsecure"</span>   <span class="o">=></span> <span class="s1">'ssl'</span><span class="p">,</span>
 +</pre></div>
 +</div>
 +</div>
 +<div class="section" id="tls">
 +<h4>TLS<a class="headerlink" href="#tls" title="Permalink to this headline">¶</a></h4>
 +<p>A secure connection will be initiated using the STARTTLS protocol which
 +uses the default port 25/tcp:</p>
 +<div class="highlight-php"><div class="highlight"><pre><span class="cp"><?php</span>
 +
 +  <span class="s2">"mail_smtphost"</span>     <span class="o">=></span> <span class="s2">"smtp.server.dom"</span><span class="p">,</span>
 +  <span class="s2">"mail_smtpsecure"</span>   <span class="o">=></span> <span class="s1">'tls'</span><span class="p">,</span>
 +</pre></div>
 +</div>
 +<p>And finally it is necessary to configure if the SMTP server requires
 +authentication, if not, the default values can be taken as it.</p>
 +<div class="highlight-php"><div class="highlight"><pre><span class="cp"><?php</span>
 +
 +  <span class="s2">"mail_smtpauth"</span>     <span class="o">=></span> <span class="k">false</span><span class="p">,</span>
 +  <span class="s2">"mail_smtpname"</span>     <span class="o">=></span> <span class="s2">""</span><span class="p">,</span>
 +  <span class="s2">"mail_smtppassword"</span> <span class="o">=></span> <span class="s2">""</span><span class="p">,</span>
 +</pre></div>
 +</div>
 +<p>If SMTP authentication is required you have to set the required username
 +and password and can optionally choose between the authentication types
 +<strong>LOGIN</strong> (default) or <strong>PLAIN</strong>.</p>
 +<div class="highlight-php"><div class="highlight"><pre><span class="cp"><?php</span>
 +
 +  <span class="s2">"mail_smtpauth"</span>     <span class="o">=></span> <span class="k">true</span><span class="p">,</span>
 +  <span class="s2">"mail_smtpauthtype"</span> <span class="o">=></span> <span class="s2">"LOGIN"</span><span class="p">,</span>
 +  <span class="s2">"mail_smtpname"</span>     <span class="o">=></span> <span class="s2">"username"</span><span class="p">,</span>
 +  <span class="s2">"mail_smtppassword"</span> <span class="o">=></span> <span class="s2">"password"</span><span class="p">,</span>
 +</pre></div>
 +</div>
 +</div>
 +</div>
 +<div class="section" id="php-mail">
 +<h3>PHP mail<a class="headerlink" href="#php-mail" title="Permalink to this headline">¶</a></h3>
 +<p>If you want to use PHP mail it is necessary to have an installed and working
 +email system on your server. Which program in detail is used to send email is
 +defined by the configuration settings in the <strong>php.ini</strong> file. (On *nix
 +systems this will most likely be Sendmail.) ownCloud should be able to send
 +email out of the box.</p>
 +<div class="highlight-php"><div class="highlight"><pre><span class="cp"><?php</span>
 +
 +  <span class="s2">"mail_smtpmode"</span>     <span class="o">=></span> <span class="s2">"php"</span><span class="p">,</span>
 +  <span class="s2">"mail_smtphost"</span>     <span class="o">=></span> <span class="s2">"127.0.0.1"</span><span class="p">,</span>
 +  <span class="s2">"mail_smtpport"</span>     <span class="o">=></span> <span class="mi">25</span><span class="p">,</span>
 +  <span class="s2">"mail_smtptimeout"</span>  <span class="o">=></span> <span class="mi">10</span><span class="p">,</span>
 +  <span class="s2">"mail_smtpsecure"</span>   <span class="o">=></span> <span class="s2">""</span><span class="p">,</span>
 +  <span class="s2">"mail_smtpauth"</span>     <span class="o">=></span> <span class="k">false</span><span class="p">,</span>
 +  <span class="s2">"mail_smtpauthtype"</span> <span class="o">=></span> <span class="s2">"LOGIN"</span><span class="p">,</span>
 +  <span class="s2">"mail_smtpname"</span>     <span class="o">=></span> <span class="s2">""</span><span class="p">,</span>
 +  <span class="s2">"mail_smtppassword"</span> <span class="o">=></span> <span class="s2">""</span><span class="p">,</span>
 +</pre></div>
 +</div>
 +</div>
 +<div class="section" id="sendmail">
 +<h3>Sendmail<a class="headerlink" href="#sendmail" title="Permalink to this headline">¶</a></h3>
 +<p>If you want to use the well known Sendmail program to send email, it is
 +necessary to have an installed and working email system on your *nix server.
 +The sendmail binary (<strong>/usr/sbin/sendmail</strong>) is usually part of that system.
 +ownCloud should be able to send email out of the box.</p>
 +<div class="highlight-php"><div class="highlight"><pre><span class="cp"><?php</span>
 +
 +  <span class="s2">"mail_smtpmode"</span>     <span class="o">=></span> <span class="s2">"sendmail"</span><span class="p">,</span>
 +  <span class="s2">"mail_smtphost"</span>     <span class="o">=></span> <span class="s2">"127.0.0.1"</span><span class="p">,</span>
 +  <span class="s2">"mail_smtpport"</span>     <span class="o">=></span> <span class="mi">25</span><span class="p">,</span>
 +  <span class="s2">"mail_smtptimeout"</span>  <span class="o">=></span> <span class="mi">10</span><span class="p">,</span>
 +  <span class="s2">"mail_smtpsecure"</span>   <span class="o">=></span> <span class="s2">""</span><span class="p">,</span>
 +  <span class="s2">"mail_smtpauth"</span>     <span class="o">=></span> <span class="k">false</span><span class="p">,</span>
 +  <span class="s2">"mail_smtpauthtype"</span> <span class="o">=></span> <span class="s2">"LOGIN"</span><span class="p">,</span>
 +  <span class="s2">"mail_smtpname"</span>     <span class="o">=></span> <span class="s2">""</span><span class="p">,</span>
 +  <span class="s2">"mail_smtppassword"</span> <span class="o">=></span> <span class="s2">""</span><span class="p">,</span>
 +</pre></div>
 +</div>
 +</div>
 +<div class="section" id="qmail">
 +<h3>qmail<a class="headerlink" href="#qmail" title="Permalink to this headline">¶</a></h3>
 +<p>If you want to use the qmail program to send email, it is necessary to have an
 +installed and working qmail email system on your server. The sendmail binary
 +(<strong>/var/qmail/bin/sendmail</strong>) will then be used to send email. ownCloud should
 +be able to send email out of the box.</p>
 +<div class="highlight-php"><div class="highlight"><pre><span class="cp"><?php</span>
 +
 +  <span class="s2">"mail_smtpmode"</span>     <span class="o">=></span> <span class="s2">"qmail"</span><span class="p">,</span>
 +  <span class="s2">"mail_smtphost"</span>     <span class="o">=></span> <span class="s2">"127.0.0.1"</span><span class="p">,</span>
 +  <span class="s2">"mail_smtpport"</span>     <span class="o">=></span> <span class="mi">25</span><span class="p">,</span>
 +  <span class="s2">"mail_smtptimeout"</span>  <span class="o">=></span> <span class="mi">10</span><span class="p">,</span>
 +  <span class="s2">"mail_smtpsecure"</span>   <span class="o">=></span> <span class="s2">""</span><span class="p">,</span>
 +  <span class="s2">"mail_smtpauth"</span>     <span class="o">=></span> <span class="k">false</span><span class="p">,</span>
 +  <span class="s2">"mail_smtpauthtype"</span> <span class="o">=></span> <span class="s2">"LOGIN"</span><span class="p">,</span>
 +  <span class="s2">"mail_smtpname"</span>     <span class="o">=></span> <span class="s2">""</span><span class="p">,</span>
 +  <span class="s2">"mail_smtppassword"</span> <span class="o">=></span> <span class="s2">""</span><span class="p">,</span>
 +</pre></div>
 +</div>
 +</div>
 +</div>
 +<div class="section" id="send-a-test-email">
 +<h2>Send a Test Email<a class="headerlink" href="#send-a-test-email" title="Permalink to this headline">¶</a></h2>
 +<p>The only way to test your email configuration is, to force a login failure,
 +because a function to send a test email has not be implemented yet.</p>
 +<p>First make sure that you are using a full qualified domain and not an ip address in the ownCloud URL, like:</p>
 +<div class="highlight-python"><pre>http://my-owncloud-server.domain.dom/owncloud/</pre>
 +</div>
 +<p>The password reset function fetches the domain name from that URL to build the
 +email sender address, e.g.:</p>
 +<div class="highlight-python"><pre>john at domain.dom</pre>
 +</div>
 +<p>Next you need to enter your login and an <em>invalid</em> password. As soon as you
 +press the login button the login mask reappears and a <strong>I’ve forgotten my password</strong> link will be shown above the login
 +field. Click on that link, re-enter your login and press the <strong>Reset password</strong> button - that’s all.</p>
 +</div>
 +<div class="section" id="trouble-shooting">
 +<h2>Trouble shooting<a class="headerlink" href="#trouble-shooting" title="Permalink to this headline">¶</a></h2>
 +<div class="section" id="my-web-domain-is-different-from-my-mail-domain">
 +<h3>My web domain is different from my mail domain?<a class="headerlink" href="#my-web-domain-is-different-from-my-mail-domain" title="Permalink to this headline">¶</a></h3>
 +<p>The default domain name used for the sender address is the hostname where your ownCloud installation is served.
 +If you have a different mail domain name you can override this behavior by setting the following configuration parameter:</p>
 +<div class="highlight-php"><div class="highlight"><pre><span class="cp"><?php</span>
 +
 +  <span class="s2">"mail_domain"</span> <span class="o">=></span> <span class="s2">"example.com"</span><span class="p">,</span>
 +</pre></div>
 +</div>
 +<p>Now every mail send by ownCloud e.g. password reset email, will have the domain part of the sender address look like:</p>
 +<div class="highlight-python"><pre>no-reply at example.com</pre>
 +</div>
 +</div>
 +<div class="section" id="how-can-i-find-out-if-a-smtp-server-is-reachable">
 +<h3>How can I find out if a SMTP server is reachable?<a class="headerlink" href="#how-can-i-find-out-if-a-smtp-server-is-reachable" title="Permalink to this headline">¶</a></h3>
 +<p>Use the ping command to check the server availability:</p>
 +<div class="highlight-python"><pre>ping smtp.server.dom</pre>
 +</div>
 +<div class="highlight-python"><pre>PING smtp.server.dom (ip-address) 56(84) bytes of data.
 +64 bytes from your-server.local.lan (192.168.1.10): icmp_req=1 ttl=64 time=3.64 ms
 +64 bytes from your-server.local.lan (192.168.1.10): icmp_req=2 ttl=64 time=0.055 ms
 +64 bytes from your-server.local.lan (192.168.1.10): icmp_req=3 ttl=64 time=0.062 ms</pre>
 +</div>
 +</div>
 +<div class="section" id="how-can-i-find-out-if-the-smtp-server-is-listening-on-a-specific-tcp-port">
 +<h3>How can I find out if the SMTP server is listening on a specific tcp port?<a class="headerlink" href="#how-can-i-find-out-if-the-smtp-server-is-listening-on-a-specific-tcp-port" title="Permalink to this headline">¶</a></h3>
 +<p>A SMTP server is usually listening on port <strong>25/tcp</strong> (smtp) and/or in
 +rare circumstances is also listening on the outdated port <strong>465/tcp</strong> (smtps).
 +You can use the telnet command to check if a port is available:</p>
 +<div class="highlight-python"><pre>telnet smtp.domain.dom 25</pre>
 +</div>
 +<div class="highlight-python"><pre>Trying 192.168.1.10...
 +Connected to smtp.domain.dom.
 +Escape character is '^]'.
 +220 smtp.domain.dom ESMTP Exim 4.80.1 Tue, 22 Jan 2013 22:28:14 +0100</pre>
 +</div>
 +</div>
 +<div class="section" id="how-can-i-find-out-if-a-smtp-server-supports-the-outdated-smtps-protocol">
 +<h3>How can I find out if a SMTP server supports the outdated SMTPS protocol?<a class="headerlink" href="#how-can-i-find-out-if-a-smtp-server-supports-the-outdated-smtps-protocol" title="Permalink to this headline">¶</a></h3>
 +<p>A good indication that a SMTP server supports the SMTPS protocol is that it
 +is listening on port <strong>465/tcp</strong>. How this can be checked has been described
 +previously.</p>
 +</div>
 +<div class="section" id="how-can-i-find-out-if-a-smtp-server-supports-the-tls-protocol">
 +<h3>How can I find out if a SMTP server supports the TLS protocol?<a class="headerlink" href="#how-can-i-find-out-if-a-smtp-server-supports-the-tls-protocol" title="Permalink to this headline">¶</a></h3>
 +<p>A SMTP server usually announces the availability of STARTTLS right after a
 +connection has been established. This can easily been checked with the telnet command. You need to enter the marked lines to get the information displayed:</p>
 +<div class="highlight-python"><pre>telnet smtp.domain.dom 25</pre>
 +</div>
 +<div class="highlight-python"><pre>Trying 192.168.1.10...
 +Connected to smtp.domain.dom.
 +Escape character is '^]'.
 +220 smtp.domain.dom ESMTP Exim 4.80.1 Tue, 22 Jan 2013 22:39:55 +0100
 +EHLO your-server.local.lan                                             # <<< enter this command
 +250-smtp.domain.dom Hello your-server.local.lan [ip-address]
 +250-SIZE 52428800
 +250-8BITMIME
 +250-PIPELINING
 +250-AUTH PLAIN LOGIN CRAM-MD5
 +250-STARTTLS                                                           # <<< STARTTLS is supported!
 +250 HELP
 +QUIT                                                                   # <<< enter this command
 +221 smtp.domain.dom closing connection
 +Connection closed by foreign host.</pre>
 +</div>
 +</div>
 +<div class="section" id="how-can-i-find-out-which-authentication-types-methods-a-smtp-server-supports">
 +<h3>How can I find out which authentication types/methods a SMTP server supports?<a class="headerlink" href="#how-can-i-find-out-which-authentication-types-methods-a-smtp-server-supports" title="Permalink to this headline">¶</a></h3>
 +<p>A SMTP server usually announces the available authentication types/methods
 +right after a connection has been established. This can easily been checked
 +with the telnet command. You need to enter the marked lines to get the
 +information displayed:</p>
 +<div class="highlight-python"><pre>telnet smtp.domain.dom 25</pre>
 +</div>
 +<div class="highlight-python"><pre>Trying 192.168.1.10...
 +Connected to smtp.domain.dom.
 +Escape character is '^]'.
 +220 smtp.domain.dom ESMTP Exim 4.80.1 Tue, 22 Jan 2013 22:39:55 +0100
 +EHLO your-server.local.lan                                             # <<< enter this command
 +250-smtp.domain.dom Hello your-server.local.lan [ip-address]
 +250-SIZE 52428800
 +250-8BITMIME
 +250-PIPELINING
 +250-AUTH PLAIN LOGIN CRAM-MD5                                          # <<< available Authentication types
 +250-STARTTLS
 +250 HELP
 +QUIT                                                                   # <<< enter this command
 +221 smtp.domain.dom closing connection
 +Connection closed by foreign host.</pre>
 +</div>
 +</div>
 +<div class="section" id="enable-debug-mode">
 +<h3>Enable Debug Mode<a class="headerlink" href="#enable-debug-mode" title="Permalink to this headline">¶</a></h3>
 +<p>If you are still not able to send email it might be useful to activate
 +further debug messages by setting the following parameter. Right after
 +you have pressed the <strong>Reset password</strong> button, as described before, a
 +lot of <strong>SMTP -> get_lines(): ...</strong> messages will be written on the
 +screen.</p>
 +<div class="highlight-php"><div class="highlight"><pre><span class="cp"><?php</span>
 +
 +  <span class="s2">"mail_smtpdebug"</span> <span class="o">=></span> <span class="k">true</span><span class="p">;</span>
 +</pre></div>
 +</div>
 +</div>
 +</div>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/configuration/configuration_maintenance.html
index df98200,0000000..522d3f3
mode 100644,000000..100644
--- a/core/doc/admin/configuration/configuration_maintenance.html
+++ b/core/doc/admin/configuration/configuration_maintenance.html
@@@ -1,187 -1,0 +1,188 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
-     <title>Maintenance Mode Configuration — ownCloud Administrators Manual 6.0 documentation</title>
++    <title>Enable Maintenance Mode — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
 +    <link rel="up" title="Configuration" href="index.html" />
-     <link rel="next" title="Preview Configuration" href="configuration_preview.html" />
-     <link rel="prev" title="Mail Configuration" href="configuration_mail.html" />
++    <link rel="next" title="Enabling File Previews" href="configuration_preview.html" />
++    <link rel="prev" title="Sending Mail Notifications" href="configuration_mail.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
 +<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../installation/index.html">Installation</a></li>
 +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Configuration</a><ul class="current">
- <li class="toctree-l2"><a class="reference internal" href="configuration_apps.html">Apps Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_apps.html">Managing Apps</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_users.html">User Management</a></li>
- <li class="toctree-l2"><a class="reference internal" href="auth_ldap.html">User Authentication with LDAP</a></li>
++<li class="toctree-l2"><a class="reference internal" href="auth_ldap.html">LDAP Authentication</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="background_jobs.html">Background Jobs</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_3rdparty.html">3rd-Party Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_3rdparty.html">Find Third-Party Libraries</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_automation.html">Automatic Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_custom_clients.html">Custom Client Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_database.html">Database Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_encryption.html">Use Server-Side Encryption</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_knowledgebase.html">Knowledge Base Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_language.html">Language Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_logging.html">Logging Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_mail.html">Mail Configuration</a></li>
- <li class="toctree-l2 current"><a class="current reference internal" href="">Maintenance Mode Configuration</a><ul>
++<li class="toctree-l2"><a class="reference internal" href="configuration_custom_clients.html">Customizing Client Download Links</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_database.html">MySQL/Postgres/SQLite Support</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_encryption.html">Using Server-Side Encryption</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_knowledgebase.html">Disable Knowledge Base</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_language.html">Setting the Default Language</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_logging.html">Configure Logging</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_mail.html">Sending Mail Notifications</a></li>
++<li class="toctree-l2 current"><a class="current reference internal" href="">Enable Maintenance Mode</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="#parameters">Parameters</a></li>
 +</ul>
 +</li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_preview.html">Preview Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_preview.html">Enabling File Previews</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_reverseproxy.html">Reverse Proxy Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html">Uploading big files > 512MB (as set by default)</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html#enabling-uploading-big-files">Enabling uploading big files</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html">Dealing with Big File Uploads</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_mount_config_gui.html">Custom Mount Configuration Web-GUI</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_mount_config.html">Custom Mount Configuration</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_user_backend.html">Custom User Backend Configuration</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="xsendfile.html">Serving static files via web server</a></li>
 +</ul>
 +</li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
-   <div class="section" id="maintenance-mode-configuration">
- <h1>Maintenance Mode Configuration<a class="headerlink" href="#maintenance-mode-configuration" title="Permalink to this headline">¶</a></h1>
++  <div class="section" id="enable-maintenance-mode">
++<h1>Enable Maintenance Mode<a class="headerlink" href="#enable-maintenance-mode" title="Permalink to this headline">¶</a></h1>
 +<p>If you want to prevent users to login to ownCloud before you start doing
 +some maintenance work, you need to set the value of the <strong>maintenance</strong>
 +parameter to <em>true</em>. Please keep in mind that users who are already logged-in
 +are kicked out of ownCloud instantly.</p>
 +<div class="section" id="parameters">
 +<h2>Parameters<a class="headerlink" href="#parameters" title="Permalink to this headline">¶</a></h2>
 +<div class="highlight-php"><div class="highlight"><pre><span class="cp"><?php</span>
 +
 +  <span class="s2">"maintenance"</span> <span class="o">=></span> <span class="k">false</span><span class="p">,</span>
 +</pre></div>
 +</div>
 +<p>This parameters can be set in the <tt class="file docutils literal"><span class="pre">config/config.php</span></tt></p>
 +</div>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/configuration/configuration_preview.html
index 47a9fd1,0000000..e00262d
mode 100644,000000..100644
--- a/core/doc/admin/configuration/configuration_preview.html
+++ b/core/doc/admin/configuration/configuration_preview.html
@@@ -1,283 -1,0 +1,283 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
-     <title>Preview Configuration — ownCloud Administrators Manual 6.0 documentation</title>
++    <title>Enabling File Previews — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
 +    <link rel="up" title="Configuration" href="index.html" />
 +    <link rel="next" title="Reverse Proxy Configuration" href="configuration_reverseproxy.html" />
-     <link rel="prev" title="Maintenance Mode Configuration" href="configuration_maintenance.html" />
++    <link rel="prev" title="Enable Maintenance Mode" href="configuration_maintenance.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
 +<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../installation/index.html">Installation</a></li>
 +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Configuration</a><ul class="current">
- <li class="toctree-l2"><a class="reference internal" href="configuration_apps.html">Apps Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_apps.html">Managing Apps</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_users.html">User Management</a></li>
- <li class="toctree-l2"><a class="reference internal" href="auth_ldap.html">User Authentication with LDAP</a></li>
++<li class="toctree-l2"><a class="reference internal" href="auth_ldap.html">LDAP Authentication</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="background_jobs.html">Background Jobs</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_3rdparty.html">3rd-Party Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_3rdparty.html">Find Third-Party Libraries</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_automation.html">Automatic Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_custom_clients.html">Custom Client Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_database.html">Database Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_encryption.html">Use Server-Side Encryption</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_knowledgebase.html">Knowledge Base Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_language.html">Language Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_logging.html">Logging Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_mail.html">Mail Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_maintenance.html">Maintenance Mode Configuration</a></li>
- <li class="toctree-l2 current"><a class="current reference internal" href="">Preview Configuration</a><ul>
++<li class="toctree-l2"><a class="reference internal" href="configuration_custom_clients.html">Customizing Client Download Links</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_database.html">MySQL/Postgres/SQLite Support</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_encryption.html">Using Server-Side Encryption</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_knowledgebase.html">Disable Knowledge Base</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_language.html">Setting the Default Language</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_logging.html">Configure Logging</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_mail.html">Sending Mail Notifications</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_maintenance.html">Enable Maintenance Mode</a></li>
++<li class="toctree-l2 current"><a class="current reference internal" href="">Enabling File Previews</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="#soft-dependencies">Soft dependencies:</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#parameters">Parameters</a></li>
 +</ul>
 +</li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_reverseproxy.html">Reverse Proxy Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html">Uploading big files > 512MB (as set by default)</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html#enabling-uploading-big-files">Enabling uploading big files</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html">Dealing with Big File Uploads</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_mount_config_gui.html">Custom Mount Configuration Web-GUI</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_mount_config.html">Custom Mount Configuration</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_user_backend.html">Custom User Backend Configuration</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="xsendfile.html">Serving static files via web server</a></li>
 +</ul>
 +</li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
-   <div class="section" id="preview-configuration">
- <h1>Preview Configuration<a class="headerlink" href="#preview-configuration" title="Permalink to this headline">¶</a></h1>
++  <div class="section" id="enabling-file-previews">
++<h1>Enabling File Previews<a class="headerlink" href="#enabling-file-previews" title="Permalink to this headline">¶</a></h1>
 +<p>ownCloud 6 introduced the new thumbnail system. It is used to generate
- thumbnails from various file types.
- By default, it can generate previews for:</p>
++thumbnails from various file types.  By default, it can generate previews for:</p>
 +<ul class="simple">
 +<li>Images</li>
 +<li>Movies</li>
 +<li>Cover from mp3 files</li>
 +<li>various office files</li>
 +<li>Pdf</li>
 +<li>Svg</li>
 +<li>Text</li>
 +</ul>
 +<div class="section" id="soft-dependencies">
 +<h2>Soft dependencies:<a class="headerlink" href="#soft-dependencies" title="Permalink to this headline">¶</a></h2>
 +<div class="section" id="imagick">
 +<h3>imagick:<a class="headerlink" href="#imagick" title="Permalink to this headline">¶</a></h3>
 +<p>ownCloud needs the imagick php extension to generate previews from office, pdf
 +and svg files. For further information on how to install the imagick php
 +extension on your system take a look at the <a class="reference external" href="http://www.php.net/manual/en/imagick.installation.php">PHP documentation</a>.
 +If imagick is not installed, ownCloud will show file type icons instead of previews.</p>
 +</div>
 +<div class="section" id="libreoffice-openoffice">
 +<h3>LibreOffice / OpenOffice:<a class="headerlink" href="#libreoffice-openoffice" title="Permalink to this headline">¶</a></h3>
 +<p>ownCloud comes with a php-only preview system for office files. But this
 +preview system has limited capabilities and is only able to create previews
 +from basic Microsoft Office files. If you need previews from advanced
 +Microsoft Office files or OpenDocument files, you have to install LibreOffice
 +or OpenOffice. To learn more about installing LibreOffice/OpenOffice consider
 +your distribution’s documentation.</p>
 +</div>
 +<div class="section" id="avconv-ffmpeg">
 +<h3>avconv / ffmpeg:<a class="headerlink" href="#avconv-ffmpeg" title="Permalink to this headline">¶</a></h3>
 +<p>ownCloud requires avconv of ffmpeg to generate previews from movies. To learn
 +more about installing avconv or ffmpeg consider your distribution’s
 +documentation.</p>
 +</div>
 +</div>
 +<div class="section" id="parameters">
 +<h2>Parameters<a class="headerlink" href="#parameters" title="Permalink to this headline">¶</a></h2>
 +<div class="section" id="disabling-previews">
 +<h3>Disabling previews:<a class="headerlink" href="#disabling-previews" title="Permalink to this headline">¶</a></h3>
 +<p>Under certain circumstances like a big user base or limited resources you might
 +want to consider disabling previews.</p>
 +<div class="highlight-php"><div class="highlight"><pre><span class="cp"><?php</span>
 +  <span class="s1">'enable_previews'</span> <span class="o">=></span> <span class="k">true</span><span class="p">,</span>
 +</pre></div>
 +</div>
 +<p>There is a config option called ‘enable_previews’. By default it’s set to true.
 +You can disable previews by setting this option to false:</p>
 +<div class="highlight-php"><div class="highlight"><pre><span class="cp"><?php</span>
 +  <span class="s1">'enable_previews'</span> <span class="o">=></span> <span class="k">false</span><span class="p">,</span>
 +</pre></div>
 +</div>
 +</div>
 +<div class="section" id="maximum-preview-size">
 +<h3>Maximum preview size:<a class="headerlink" href="#maximum-preview-size" title="Permalink to this headline">¶</a></h3>
 +<p>There are two config options to set the maximum size of a preview.</p>
 +<div class="highlight-php"><div class="highlight"><pre><span class="cp"><?php</span>
 +  <span class="s1">'preview_max_x'</span> <span class="o">=></span> <span class="k">null</span><span class="p">,</span>
 +  <span class="s1">'preview_max_y'</span> <span class="o">=></span> <span class="k">null</span><span class="p">,</span>
 +</pre></div>
 +</div>
 +<p>By default, both config options are set to null. ‘Null’ is equal to no limit.
 +Numeric values represent the size in pixel. The following code limits previews
 +to a maximum size of 100px by 100px:</p>
 +<div class="highlight-php"><div class="highlight"><pre><span class="cp"><?php</span>
 +  <span class="s1">'preview_max_x'</span> <span class="o">=></span> <span class="mi">100</span><span class="p">,</span>
 +  <span class="s1">'preview_max_y'</span> <span class="o">=></span> <span class="mi">100</span><span class="p">,</span>
 +</pre></div>
 +</div>
 +<p>‘preview_max_x’ represents the x-axis and ‘preview_max_y’ represents the y-axis.</p>
 +</div>
 +<div class="section" id="maximum-scale-factor">
 +<h3>Maximum scale factor:<a class="headerlink" href="#maximum-scale-factor" title="Permalink to this headline">¶</a></h3>
 +<p>If you have a lot of small pictures and the preview system generates blurry
 +previews, you might want to consider setting a maximum scale factor. By default,
 +ownCloud scales pictures up to 10 times the original size:</p>
 +<div class="highlight-php"><div class="highlight"><pre><span class="cp"><?php</span>
 +  <span class="s1">'preview_max_scale_factor'</span> <span class="o">=></span> <span class="mi">10</span><span class="p">,</span>
 +</pre></div>
 +</div>
 +<p>If you want to disable scaling at all, you can set the config value to ‘1’:</p>
 +<div class="highlight-php"><div class="highlight"><pre><span class="cp"><?php</span>
 +  <span class="s1">'preview_max_scale_factor'</span> <span class="o">=></span> <span class="mi">1</span><span class="p">,</span>
 +</pre></div>
 +</div>
 +<p>If you want to disable the maximum scaling factor, you can set the config value to ‘null’:</p>
 +<div class="highlight-php"><div class="highlight"><pre><span class="cp"><?php</span>
 +  <span class="s1">'preview_max_scale_factor'</span> <span class="o">=></span> <span class="k">null</span><span class="p">,</span>
 +</pre></div>
 +</div>
 +</div>
 +<div class="section" id="id1">
 +<h3>LibreOffice / OpenOffice:<a class="headerlink" href="#id1" title="Permalink to this headline">¶</a></h3>
 +<p>You can set a custom path for the LibreOffice binary. If LibreOffice is not yet
 +available on your system, you can also use OpenOffice instead.</p>
 +<div class="highlight-php"><div class="highlight"><pre><span class="cp"><?php</span>
 +  <span class="s1">'preview_libreoffice_path'</span> <span class="o">=></span> <span class="s1">'/usr/bin/libreoffice'</span><span class="p">,</span>
 +</pre></div>
 +</div>
 +<p>You can set custom LibreOffice / OpenOffice command line parameters by setting
 +the preview_office_cl_parameters option.</p>
 +<div class="highlight-php"><div class="highlight"><pre><span class="cp"><?php</span>
 +  <span class="s1">'preview_office_cl_parameters'</span> <span class="o">=></span> <span class="s1">' '</span><span class="p">,</span>
 +</pre></div>
 +</div>
 +</div>
 +</div>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/configuration/configuration_reverseproxy.html
index c519abe,0000000..d436bfa
mode 100644,000000..100644
--- a/core/doc/admin/configuration/configuration_reverseproxy.html
+++ b/core/doc/admin/configuration/configuration_reverseproxy.html
@@@ -1,219 -1,0 +1,220 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
 +    <title>Reverse Proxy Configuration — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
 +    <link rel="up" title="Configuration" href="index.html" />
-     <link rel="next" title="Uploading big files > 512MB (as set by default)" href="configuring_big_file_upload.html" />
-     <link rel="prev" title="Preview Configuration" href="configuration_preview.html" />
++    <link rel="next" title="Dealing with Big File Uploads" href="configuring_big_file_upload.html" />
++    <link rel="prev" title="Enabling File Previews" href="configuration_preview.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
 +<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../installation/index.html">Installation</a></li>
 +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Configuration</a><ul class="current">
- <li class="toctree-l2"><a class="reference internal" href="configuration_apps.html">Apps Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_apps.html">Managing Apps</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_users.html">User Management</a></li>
- <li class="toctree-l2"><a class="reference internal" href="auth_ldap.html">User Authentication with LDAP</a></li>
++<li class="toctree-l2"><a class="reference internal" href="auth_ldap.html">LDAP Authentication</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="background_jobs.html">Background Jobs</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_3rdparty.html">3rd-Party Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_3rdparty.html">Find Third-Party Libraries</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_automation.html">Automatic Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_custom_clients.html">Custom Client Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_database.html">Database Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_encryption.html">Use Server-Side Encryption</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_knowledgebase.html">Knowledge Base Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_language.html">Language Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_logging.html">Logging Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_mail.html">Mail Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_maintenance.html">Maintenance Mode Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_preview.html">Preview Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_custom_clients.html">Customizing Client Download Links</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_database.html">MySQL/Postgres/SQLite Support</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_encryption.html">Using Server-Side Encryption</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_knowledgebase.html">Disable Knowledge Base</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_language.html">Setting the Default Language</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_logging.html">Configure Logging</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_mail.html">Sending Mail Notifications</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_maintenance.html">Enable Maintenance Mode</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_preview.html">Enabling File Previews</a></li>
 +<li class="toctree-l2 current"><a class="current reference internal" href="">Reverse Proxy Configuration</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="#parameters">Parameters</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#example">Example</a></li>
 +</ul>
 +</li>
- <li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html">Uploading big files > 512MB (as set by default)</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html#enabling-uploading-big-files">Enabling uploading big files</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html">Dealing with Big File Uploads</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_mount_config_gui.html">Custom Mount Configuration Web-GUI</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_mount_config.html">Custom Mount Configuration</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_user_backend.html">Custom User Backend Configuration</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="xsendfile.html">Serving static files via web server</a></li>
 +</ul>
 +</li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
 +  <div class="section" id="reverse-proxy-configuration">
 +<h1>Reverse Proxy Configuration<a class="headerlink" href="#reverse-proxy-configuration" title="Permalink to this headline">¶</a></h1>
 +<p>The automatic hostname, protocol or webroot detection of ownCloud can fail in
 +certain reverse proxy situations. This configuration allows to manually override
 +the automatic detection.</p>
 +<div class="section" id="parameters">
 +<h2>Parameters<a class="headerlink" href="#parameters" title="Permalink to this headline">¶</a></h2>
 +<p>If ownCloud fails to automatically detected the hostname, protocol or webroot
 +you can use the <strong>overwrite</strong> parameters inside the <tt class="file docutils literal"><span class="pre">config/config.php</span></tt>.
 +The <strong>overwritehost</strong> parameter is used to set the hostname of the proxy. You
 +can also specify a port. The <strong>overwriteprotocol</strong> parameter is used to set the
 +protocol of the proxy. You can choose between the two options <strong>http</strong> and
 +<strong>https</strong>. The <strong>overwritewebroot</strong> parameter is used to set the absolute web
 +path of the proxy to the ownCloud folder. When you want to keep the automatic
 +detection of one of the three parameters you can leave the value empty or don’t
 +set it. The <strong>overwritecondaddr</strong> parameter is used to overwrite the values
 +dependent on the remote address. The value must be a <strong>regular expression</strong> of
 +the IP addresses of the proxy. This is useful when you use a reverse SSL proxy
 +only for https access and you want to use the automatic detection for http
 +access.</p>
 +</div>
 +<div class="section" id="example">
 +<h2>Example<a class="headerlink" href="#example" title="Permalink to this headline">¶</a></h2>
 +<div class="section" id="multiple-domains-reverse-ssl-proxy">
 +<h3>Multiple Domains Reverse SSL Proxy<a class="headerlink" href="#multiple-domains-reverse-ssl-proxy" title="Permalink to this headline">¶</a></h3>
 +<p>If you want to access your ownCloud installation <strong>http://domain.tld/owncloud</strong>
 +via a multiple domains reverse SSL proxy
 +<strong>https://ssl-proxy.tld/domain.tld/owncloud</strong> with the IP address <strong>10.0.0.1</strong>
 +you can set the following parameters inside the <tt class="file docutils literal"><span class="pre">config/config.php</span></tt>.</p>
 +<div class="highlight-php"><div class="highlight"><pre><span class="cp"><?php</span>
 +<span class="nv">$CONFIG</span> <span class="o">=</span> <span class="k">array</span> <span class="p">(</span>
 +  <span class="s2">"overwritehost"</span>     <span class="o">=></span> <span class="s2">"ssl-proxy.tld"</span><span class="p">,</span>
 +  <span class="s2">"overwriteprotocol"</span> <span class="o">=></span> <span class="s2">"https"</span><span class="p">,</span>
 +  <span class="s2">"overwritewebroot"</span>  <span class="o">=></span> <span class="s2">"/domain.tld/owncloud"</span><span class="p">,</span>
 +  <span class="s2">"overwritecondaddr"</span> <span class="o">=></span> <span class="s2">"^10\.0\.0\.1$"</span><span class="p">,</span>
 +<span class="p">);</span>
 +</pre></div>
 +</div>
 +<div class="admonition note">
 +<p class="first admonition-title">Note</p>
 +<p class="last">If you want to use the SSL proxy during installation you have to
 +create the <tt class="file docutils literal"><span class="pre">config/config.php</span></tt> otherwise you have to extend to existing
 +<strong>$CONFIG</strong> array.</p>
 +</div>
 +</div>
 +</div>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/configuration/configuration_users.html
index e4e6653,0000000..6ea33cf
mode 100644,000000..100644
--- a/core/doc/admin/configuration/configuration_users.html
+++ b/core/doc/admin/configuration/configuration_users.html
@@@ -1,378 -1,0 +1,379 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
 +    <title>User Management — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
 +    <link rel="up" title="Configuration" href="index.html" />
-     <link rel="next" title="User Authentication with LDAP" href="auth_ldap.html" />
-     <link rel="prev" title="Apps Configuration" href="configuration_apps.html" />
++    <link rel="next" title="LDAP Authentication" href="auth_ldap.html" />
++    <link rel="prev" title="Managing Apps" href="configuration_apps.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
 +<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../installation/index.html">Installation</a></li>
 +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Configuration</a><ul class="current">
- <li class="toctree-l2"><a class="reference internal" href="configuration_apps.html">Apps Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_apps.html">Managing Apps</a></li>
 +<li class="toctree-l2 current"><a class="current reference internal" href="">User Management</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="#users">Users</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#user-groups">User Groups</a></li>
 +</ul>
 +</li>
- <li class="toctree-l2"><a class="reference internal" href="auth_ldap.html">User Authentication with LDAP</a></li>
++<li class="toctree-l2"><a class="reference internal" href="auth_ldap.html">LDAP Authentication</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="background_jobs.html">Background Jobs</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_3rdparty.html">3rd-Party Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_3rdparty.html">Find Third-Party Libraries</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_automation.html">Automatic Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_custom_clients.html">Custom Client Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_database.html">Database Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_encryption.html">Use Server-Side Encryption</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_knowledgebase.html">Knowledge Base Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_language.html">Language Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_logging.html">Logging Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_mail.html">Mail Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_maintenance.html">Maintenance Mode Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_preview.html">Preview Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_custom_clients.html">Customizing Client Download Links</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_database.html">MySQL/Postgres/SQLite Support</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_encryption.html">Using Server-Side Encryption</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_knowledgebase.html">Disable Knowledge Base</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_language.html">Setting the Default Language</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_logging.html">Configure Logging</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_mail.html">Sending Mail Notifications</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_maintenance.html">Enable Maintenance Mode</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_preview.html">Enabling File Previews</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_reverseproxy.html">Reverse Proxy Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html">Uploading big files > 512MB (as set by default)</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html#enabling-uploading-big-files">Enabling uploading big files</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html">Dealing with Big File Uploads</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_mount_config_gui.html">Custom Mount Configuration Web-GUI</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_mount_config.html">Custom Mount Configuration</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_user_backend.html">Custom User Backend Configuration</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="xsendfile.html">Serving static files via web server</a></li>
 +</ul>
 +</li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
 +  <div class="section" id="user-management">
 +<h1>User Management<a class="headerlink" href="#user-management" title="Permalink to this headline">¶</a></h1>
 +<p>ownCloud administrators can easily manage users via the web interface. To go into
 +user management page, click your username on the web interface and select <em>Users</em>.
 +A page similar to the image below will be shown:</p>
 +<div class="figure">
 +<img alt="../_images/oc_admin_user_manage.png" src="../_images/oc_admin_user_manage.png" />
 +</div>
 +<p>Users management page</p>
 +<p>A fictive use case will help you understand the concept of users, user groups
 +and group admins.</p>
 +<p>Think of a small, 25-member staff company, named “Cloud Lovers”, that is lead
 +by its founder Richard. In this company Bob acts as IT operator and recently
 +set up ownCloud. Being the installing user, Bob is member of the so called
 +“admin” user group of ownCloud. His colleague Tom, who provides support if Bob
 +is on holiday, is member of the “admin” user group as well. All employees,
 +including Bob and Tom, are members of the user group “Internal”, that is used
 +to share data across the company. Mostly for operational data, that should not
 +be accessible to all employees, Bob created the “Administration” user group
 +having two members: Richard and his assistant Susan. Richard is group admin of
 +this user group, so he can manage the members of the “Administration” user
 +group on his own.</p>
 +<div class="section" id="users">
 +<h2>Users<a class="headerlink" href="#users" title="Permalink to this headline">¶</a></h2>
 +<p>A user represents an account of the ownCloud installation. In this section the
 +core properties are listed.</p>
 +<dl class="docutils">
 +<dt><em>Login name (Username)</em></dt>
 +<dd>This is the unique ID of a ownCloud user (e.g. test, jon.doe).</dd>
 +<dt><em>Full Name</em></dt>
 +<dd>This is the name that is used all over the user interface to identify the
 +user i.e. when sharing data or sending mails. If no display name is set, it
 +defaults to the login name.</dd>
 +<dt><em>Password</em></dt>
 +<dd>This is the password the user uses to login to ownCloud.</dd>
 +<dt><em>Groups</em></dt>
 +<dd>This is a list of security groups the user is assigned to. By default the
 +user is not member of any user group.</dd>
 +<dt><em>Group Admin</em></dt>
 +<dd>This is a list of security groups the user has administration privileges for.
 +By default the user is not registered as group admin for any user group.</dd>
 +<dt><em>Storage</em></dt>
 +<dd>This is the maximum disk space that may be used by the user. If the user
 +reaches this limit he/she is not able to upload or sync further data. The
 +storage quota is specified in the format <em>Number Unit</em> (e.g. 100 B (byte),
 +50 KB (kilobyte), 20 MB (megabyte), 5 GB (gigabyte)). If no unit is given,
 +the number is interpreted as bytes.</dd>
 +</dl>
 +<p>Each user is able to change its display name and password.</p>
 +<div class="section" id="create-a-user">
 +<h3>Create a user<a class="headerlink" href="#create-a-user" title="Permalink to this headline">¶</a></h3>
 +<p>Before users can sign in and share data, they need ownCloud user accounts.</p>
 +<p>To create a user account:</p>
 +<ol class="arabic">
 +<li><p class="first">Enter the new user’s <strong>Login Name</strong> and its initial <strong>Password</strong> in the
 +appropriate fields.</p>
 +</li>
 +<li><p class="first">(Optional) Select the <strong>Groups</strong> to which you want to assign the new user.</p>
 +</li>
 +<li><p class="first">Click <strong>Create</strong>.</p>
 +</li>
 +<li><p class="first">(Optional) Edit additional user settings.</p>
 +<p>To set other user settings, such as setting a display name or limiting the
 +user’s storage, see instructions as follows.</p>
 +</li>
 +</ol>
 +<p>Created users will have the storage specified on <em>Default Storage</em> setting
 +on the same page.</p>
 +<p>Login names may contain letters (a-z, A-Z), numbers (0-9), dashes (-),
 +underscores (_), periods (.) and at signs (@).</p>
 +</div>
 +<div class="section" id="reset-a-user-s-password">
 +<h3>Reset a user’s password<a class="headerlink" href="#reset-a-user-s-password" title="Permalink to this headline">¶</a></h3>
 +<p>To reset a user’s password:</p>
 +<ol class="arabic simple">
 +<li>Hover the line of the user.</li>
 +<li>Click on the <strong>pencil icon</strong> next to the password field.</li>
 +<li>Enter the user’s new password in the password field and then hit the
 +<strong>Enter</strong> key of your keyboard.</li>
 +</ol>
 +<p>Remember to provide the user with the new login information after you have
 +reset the password.</p>
 +</div>
 +<div class="section" id="rename-a-user">
 +<h3>Rename a user<a class="headerlink" href="#rename-a-user" title="Permalink to this headline">¶</a></h3>
 +<p>Each ownCloud user has two names: an unique <em>login name</em> used for
 +authentication, and a <em>display name</em> (e.g. the user’s first name and last name)
 +used in the user interface. You can edit the display name of a user, but you
 +cannot change the login name of any user.</p>
 +<p>To set a user’s display name:</p>
 +<ol class="arabic simple">
 +<li>Hover the line of the user.</li>
 +<li>Click on the <strong>pencil icon</strong> next to the display name field.</li>
 +<li>Enter the user’s new display name in the corresponding field and then hit
 +the <strong>Enter</strong> key of your keyboard.</li>
 +</ol>
 +</div>
 +<div class="section" id="grant-administrator-privileges-to-a-user">
 +<h3>Grant administrator privileges to a user<a class="headerlink" href="#grant-administrator-privileges-to-a-user" title="Permalink to this headline">¶</a></h3>
 +<p>If a user has administrator privileges, the user has the right to manage other
 +users. Within ownCloud there are two types of administrators: <em>Super
 +Administrators</em> and <em>Group Administrators</em>.</p>
 +<p>Group administrators have the management rights to:</p>
 +<ul class="simple">
 +<li>Create new users and assign them to the group of the group administrator</li>
 +<li>Edit and delete users that are assigned to the group of the group
 +administrator</li>
 +</ul>
 +<p>Group administrators cannot access system settings or modify installation-wide
 +configuration like the default storage.</p>
 +<p>To assign the <em>super administrator</em> role to a user:</p>
 +<ol class="arabic simple">
 +<li>Use the drop-down list in <em>Groups</em> column of the user</li>
 +<li>Assign the user to the “admin” user group</li>
 +</ol>
 +<p>To assign the <em>group administrator</em> role to a user:</p>
 +<p>Find the user and select the user groups from the <strong>Group Admin</strong> drop-down
 +list you want the user become group administrator for.</p>
 +</div>
 +<div class="section" id="assign-a-user-to-a-user-group">
 +<h3>Assign a user to a user group<a class="headerlink" href="#assign-a-user-to-a-user-group" title="Permalink to this headline">¶</a></h3>
 +<p>To assign a user to a user group:</p>
 +<p>Find the user and select the user groups from the <strong>Groups</strong> drop-down list
 +you want to assign the user to. You can use <em>add group</em> link to create a new
 +group to assign the user to. You can assign the user more than one group by checking
 +multiple groups.</p>
 +<div class="admonition note">
 +<p class="first admonition-title">Note</p>
 +<p class="last">If a file/folder is shared with a group, newly created users will immediately
 +have access to the share.</p>
 +</div>
 +<div class="admonition note">
 +<p class="first admonition-title">Note</p>
 +<p class="last">If you assign a user to the <em>admin</em> user group, the user will become a
 +<em>Super Administrator</em> with unlimited privileges.</p>
 +</div>
 +</div>
 +<div class="section" id="limit-a-user-s-storage">
 +<h3>Limit a user’s storage<a class="headerlink" href="#limit-a-user-s-storage" title="Permalink to this headline">¶</a></h3>
 +<p>To limit a user’s storage quota:</p>
 +<p>Find the user and select an item from the <strong>Storage</strong> drop-down list.</p>
 +<blockquote>
 +<div><ul class="simple">
 +<li>If you select <em>Default</em>, the default storage limit, specified in the
 +action bar at the top, is applied.</li>
 +<li>If you select <em>Unlimited</em>, the user is not limited until the total disk
 +space is consumed.</li>
 +<li>If you want to enter a custom limit, select <em>Other...</em>, enter the storage
 +quota of your choice and hit the <strong>Enter</strong> key of your keyboard.</li>
 +</ul>
 +</div></blockquote>
 +<p>If you edit the value of the <strong>Default Storage</strong> field in the action bar, all
 +users with storage <em>Default</em> are affected by this change, i.e. changing the
 +default storage from <em>Unlimited</em> to <em>1 GB</em> will cause all users with <em>Default</em>
 +storage being limited to 1 GB storage each.</p>
 +</div>
 +<div class="section" id="delete-user">
 +<h3>Delete User<a class="headerlink" href="#delete-user" title="Permalink to this headline">¶</a></h3>
 +<p><strong>Important considerations before deleting a user:</strong></p>
 +<ul class="simple">
 +<li>The user will no longer be able to sign in to your ownCloud installation.</li>
 +<li>You cannot revert the deletion or restore a deleted account.</li>
 +</ul>
 +<div class="admonition note">
 +<p class="first admonition-title">Note</p>
 +<p class="last">If this user had a share with a group or user, the share also will
 +be deleted permanently.</p>
 +</div>
 +<p>To delete a user account:</p>
 +<ol class="arabic simple">
 +<li>Hover the line of the user you want to delete.</li>
 +<li>Click the <strong>cross icon</strong> at the end of the line.</li>
 +</ol>
 +<div class="admonition note">
 +<p class="first admonition-title">Note</p>
 +<p class="last">If you accidentally delete a user, you can use undo button shown on
 +notification bar at the top of the page.</p>
 +</div>
 +</div>
 +</div>
 +<div class="section" id="user-groups">
 +<h2>User Groups<a class="headerlink" href="#user-groups" title="Permalink to this headline">¶</a></h2>
 +<div class="section" id="create-group">
 +<h3>Create Group<a class="headerlink" href="#create-group" title="Permalink to this headline">¶</a></h3>
 +<p>To create a user group:</p>
 +<ol class="arabic simple">
 +<li>Open the <strong>Groups</strong> drop-down list in the action bar.</li>
 +<li>Click <strong>add group</strong>.</li>
 +<li>Enter the name of the new group and then hit the <strong>Enter</strong> key of your
 +keyboard.</li>
 +</ol>
 +<p>You can <em>assign users</em> to the newly created user groups anytime by using users’
 +group drop-down list.</p>
 +</div>
 +<div class="section" id="edit-delete-group">
 +<h3>Edit/Delete Group<a class="headerlink" href="#edit-delete-group" title="Permalink to this headline">¶</a></h3>
 +<p>Currently, groups cannot be edited (e.g. renamed) or removed. This feature
 +will be available in a future version of ownCloud.</p>
 +<div class="admonition note">
 +<p class="first admonition-title">Note</p>
 +<p class="last">If you have direct access to the database, you can manually delete the group
 +from database tables oc_groups and oc_group_user.</p>
 +</div>
 +</div>
 +</div>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/configuration/configuring_big_file_upload.html
index 517a219,0000000..9da9933
mode 100644,000000..100644
--- a/core/doc/admin/configuration/configuring_big_file_upload.html
+++ b/core/doc/admin/configuration/configuring_big_file_upload.html
@@@ -1,220 -1,0 +1,225 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
-     <title>Uploading big files > 512MB (as set by default) — ownCloud Administrators Manual 6.0 documentation</title>
++    <title>Dealing with Big File Uploads — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
 +    <link rel="up" title="Configuration" href="index.html" />
 +    <link rel="next" title="Custom Mount Configuration Web-GUI" href="custom_mount_config_gui.html" />
 +    <link rel="prev" title="Reverse Proxy Configuration" href="configuration_reverseproxy.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
 +<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../installation/index.html">Installation</a></li>
 +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Configuration</a><ul class="current">
- <li class="toctree-l2"><a class="reference internal" href="configuration_apps.html">Apps Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_apps.html">Managing Apps</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_users.html">User Management</a></li>
- <li class="toctree-l2"><a class="reference internal" href="auth_ldap.html">User Authentication with LDAP</a></li>
++<li class="toctree-l2"><a class="reference internal" href="auth_ldap.html">LDAP Authentication</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="background_jobs.html">Background Jobs</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_3rdparty.html">3rd-Party Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_3rdparty.html">Find Third-Party Libraries</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_automation.html">Automatic Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_custom_clients.html">Custom Client Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_database.html">Database Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_encryption.html">Use Server-Side Encryption</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_knowledgebase.html">Knowledge Base Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_language.html">Language Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_logging.html">Logging Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_mail.html">Mail Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_maintenance.html">Maintenance Mode Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_preview.html">Preview Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_custom_clients.html">Customizing Client Download Links</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_database.html">MySQL/Postgres/SQLite Support</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_encryption.html">Using Server-Side Encryption</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_knowledgebase.html">Disable Knowledge Base</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_language.html">Setting the Default Language</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_logging.html">Configure Logging</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_mail.html">Sending Mail Notifications</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_maintenance.html">Enable Maintenance Mode</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_preview.html">Enabling File Previews</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_reverseproxy.html">Reverse Proxy Configuration</a></li>
- <li class="toctree-l2 current"><a class="current reference internal" href="">Uploading big files > 512MB (as set by default)</a><ul>
++<li class="toctree-l2 current"><a class="current reference internal" href="">Dealing with Big File Uploads</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="#not-outnumberable-upload-limits">Not outnumberable upload limits:</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#other-recommendable-preconditions">Other recommendable preconditions:</a></li>
++<li class="toctree-l3"><a class="reference internal" href="#enabling-uploading-big-files">Enabling uploading big files</a></li>
 +</ul>
 +</li>
- <li class="toctree-l2"><a class="reference internal" href="#enabling-uploading-big-files">Enabling uploading big files</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_mount_config_gui.html">Custom Mount Configuration Web-GUI</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_mount_config.html">Custom Mount Configuration</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_user_backend.html">Custom User Backend Configuration</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="xsendfile.html">Serving static files via web server</a></li>
 +</ul>
 +</li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
-   <div class="section" id="uploading-big-files-512mb-as-set-by-default">
- <h1>Uploading big files > 512MB (as set by default)<a class="headerlink" href="#uploading-big-files-512mb-as-set-by-default" title="Permalink to this headline">¶</a></h1>
- <p>It’s usefull to know limiting factors, that make it impossible to exceed the values given by the ownCloud-system:</p>
++  <div class="section" id="dealing-with-big-file-uploads">
++<h1>Dealing with Big File Uploads<a class="headerlink" href="#dealing-with-big-file-uploads" title="Permalink to this headline">¶</a></h1>
++<p>It’s useful to know limiting factors, that make it impossible to exceed the values given by the ownCloud-system:</p>
 +<div class="section" id="not-outnumberable-upload-limits">
 +<h2>Not outnumberable upload limits:<a class="headerlink" href="#not-outnumberable-upload-limits" title="Permalink to this headline">¶</a></h2>
 +<ul class="simple">
 +<li>< 2GB on 32Bit OS-architecture</li>
 +<li>< 2GB with Server Version 4.5 or older</li>
 +<li>< 2GB with IE6 - IE8</li>
 +<li>< 4GB with IE9 - IE10</li>
 +</ul>
 +</div>
 +<div class="section" id="other-recommendable-preconditions">
 +<h2>Other recommendable preconditions:<a class="headerlink" href="#other-recommendable-preconditions" title="Permalink to this headline">¶</a></h2>
 +<ul class="simple">
- <li>Make sure, that the latest version of php (at least 5.4.9) is installed</li>
++<li>Make sure, that the latest version of PHP (at least 5.4.9) is installed</li>
 +<li>Disable user quota. This means: set the user quota of the account, you are currently logged in, to “unlimited”.</li>
 +</ul>
 +<p>This is important, because you possibly could not watch otherwise, whether the desired changes take effect.</p>
 +</div>
- </div>
 +<div class="section" id="enabling-uploading-big-files">
- <h1>Enabling uploading big files<a class="headerlink" href="#enabling-uploading-big-files" title="Permalink to this headline">¶</a></h1>
- <p>Note: The order of the following steps is important! If you swap steps described below, the settings may fail.</p>
++<h2>Enabling uploading big files<a class="headerlink" href="#enabling-uploading-big-files" title="Permalink to this headline">¶</a></h2>
++<div class="admonition note">
++<p class="first admonition-title">Note</p>
++<p class="last">The order of the following steps is important! If you swap steps described below, the settings may fail.</p>
++</div>
 +<p><strong>Go to the admin section in the ownCloud-WebUI and do the following:</strong></p>
 +<ul class="simple">
 +<li>Under “File handling” set the Maximum upload size to the desired value (e.g. 16GB)</li>
 +<li>Click the “save”-Button</li>
 +</ul>
 +<p><strong>Open the php.ini - file</strong></p>
 +<ul class="simple">
- <li>Under Debian or SUSE and their derivatives this file lies at /etc/php5/apache2/php.ini</li>
- <li>On Windows, you can find this file within C:/Program Files (x86)/PHP/PHP.ini</li>
++<li>Under Debian or SUSE and their derivatives this file resides at <tt class="docutils literal"><span class="pre">/etc/php5/apache2/php.ini</span></tt></li>
++<li>On Windows, you can find this file within <tt class="docutils literal"><span class="pre">C:\Program</span> <span class="pre">Files</span> <span class="pre">(x86)\PHP\PHP.ini</span></tt></li>
 +</ul>
 +<p><strong>Do the following:</strong></p>
 +<ul class="simple">
 +<li>Set the following three parameters inside th php.ini to the same value as chosen inside the admin-section one step before:</li>
- <li>upload_max_filesize = 16G   (e.g., to stay consistent with the example value above)</li>
- <li>post_max_size = 16G   (e.g., to stay consistent with the example value above)</li>
- <li>output_buffering = 16384      (e.g., to stay consistent with the example value above)</li>
++<li><tt class="docutils literal"><span class="pre">upload_max_filesize</span> <span class="pre">=</span> <span class="pre">16G</span></tt>   (e.g., to stay consistent with the example value above)</li>
++<li><tt class="docutils literal"><span class="pre">post_max_size</span> <span class="pre">=</span> <span class="pre">16G</span></tt>   (e.g., to stay consistent with the example value above)</li>
++<li><tt class="docutils literal"><span class="pre">output_buffering</span> <span class="pre">=</span> <span class="pre">16384</span></tt>  (e.g., to stay consistent with the example value above)</li>
 +</ul>
 +<p>whereas the “output_buffering” has to be given in MegaBytes but as a plain figure (without size-units as ‘M’ or ‘G’)</p>
 +<p>These client configurations have been proven by testing maximum file sizes of 16 GB:</p>
 +<ul class="simple">
 +<li>Linux 32 Bit: Ubuntu, Firefox => 16GB</li>
 +<li>Windows 8  64 Bit: Google Chrome => 8GB</li>
 +</ul>
 +</div>
++</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/configuration/custom_mount_config.html
index b91898c,0000000..cdd282f
mode 100644,000000..100644
--- a/core/doc/admin/configuration/custom_mount_config.html
+++ b/core/doc/admin/configuration/custom_mount_config.html
@@@ -1,495 -1,0 +1,496 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
 +    <title>Custom Mount Configuration — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
 +    <link rel="up" title="Configuration" href="index.html" />
 +    <link rel="next" title="Custom User Backend Configuration" href="custom_user_backend.html" />
 +    <link rel="prev" title="Custom Mount Configuration Web-GUI" href="custom_mount_config_gui.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
 +<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../installation/index.html">Installation</a></li>
 +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Configuration</a><ul class="current">
- <li class="toctree-l2"><a class="reference internal" href="configuration_apps.html">Apps Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_apps.html">Managing Apps</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_users.html">User Management</a></li>
- <li class="toctree-l2"><a class="reference internal" href="auth_ldap.html">User Authentication with LDAP</a></li>
++<li class="toctree-l2"><a class="reference internal" href="auth_ldap.html">LDAP Authentication</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="background_jobs.html">Background Jobs</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_3rdparty.html">3rd-Party Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_3rdparty.html">Find Third-Party Libraries</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_automation.html">Automatic Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_custom_clients.html">Custom Client Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_database.html">Database Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_encryption.html">Use Server-Side Encryption</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_knowledgebase.html">Knowledge Base Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_language.html">Language Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_logging.html">Logging Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_mail.html">Mail Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_maintenance.html">Maintenance Mode Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_preview.html">Preview Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_custom_clients.html">Customizing Client Download Links</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_database.html">MySQL/Postgres/SQLite Support</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_encryption.html">Using Server-Side Encryption</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_knowledgebase.html">Disable Knowledge Base</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_language.html">Setting the Default Language</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_logging.html">Configure Logging</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_mail.html">Sending Mail Notifications</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_maintenance.html">Enable Maintenance Mode</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_preview.html">Enabling File Previews</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_reverseproxy.html">Reverse Proxy Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html">Uploading big files > 512MB (as set by default)</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html#enabling-uploading-big-files">Enabling uploading big files</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html">Dealing with Big File Uploads</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_mount_config_gui.html">Custom Mount Configuration Web-GUI</a></li>
 +<li class="toctree-l2 current"><a class="current reference internal" href="">Custom Mount Configuration</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="#example">Example</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#backends">Backends</a></li>
 +</ul>
 +</li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_user_backend.html">Custom User Backend Configuration</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="xsendfile.html">Serving static files via web server</a></li>
 +</ul>
 +</li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
 +  <div class="section" id="custom-mount-configuration">
 +<h1>Custom Mount Configuration<a class="headerlink" href="#custom-mount-configuration" title="Permalink to this headline">¶</a></h1>
 +<p>Since ownCloud 4.0 it is possible to configure the filesystem to mount external
 +storage providers into ownCloud’s virtual file system. You can configure these
 +file systems by creating and editing <tt class="file docutils literal"><span class="pre">data/mount.json</span></tt>. This file contains
 +all settings in JSON (JavaScript Object Notation) format. At the moment two
 +different types of entries exist:</p>
 +<ul class="simple">
 +<li><strong>Group mounts:</strong> each entry configures a mount for each user in group.</li>
 +<li><strong>User mounts:</strong> each entry configures a mount for a single user or for all
 +users.</li>
 +</ul>
 +<p>For each type, there is a JSON array with the user/group name as key, and an
 +array of configuration entries as value. Each entry consist of the class name
 +of the storage backend and an array of backend specific options and will be
 +replaced by the user login. The template <strong>$user</strong> can be used in the mount
 +point or backend options. As of writing the following storage backends are
 +available for use:</p>
 +<ul class="simple">
 +<li>Local file system</li>
 +<li>FTP (or FTPS)</li>
 +<li>SFTP</li>
 +<li>SMB</li>
 +<li>WebDAV</li>
 +<li><a class="reference external" href="http://aws.amazon.com/de/s3/">Amazon S3</a></li>
 +<li><a class="reference external" href="https://www.dropbox.com/">Dropbox</a></li>
 +<li><a class="reference external" href="https://drive.google.com/start">Google Drive</a></li>
 +<li><a class="reference external" href="http://openstack.org/projects/storage/">OpenStack Swift</a></li>
 +</ul>
 +<p>Please keep in mind that some formatting has been applied and carriage returns
 +have been added for better readability. In the <tt class="file docutils literal"><span class="pre">data/mount.json</span></tt> all
 +values need to be concatenated and written in a row without these modifications!</p>
 +<p>It is recommended to use the <a class="reference internal" href="custom_mount_config_gui.html"><em>Web-GUI</em></a> in the
 +administrator panel to add, remove or modify mount options to prevent any problems!</p>
 +<div class="section" id="example">
 +<h2>Example<a class="headerlink" href="#example" title="Permalink to this headline">¶</a></h2>
 +<div class="highlight-json"><pre>{"group":{
 +    "admin":{
 +        "\/$user\/files\/Admin_Stuff":{
 +            "class":"\\OC\\Files\\Storage\\Local",
 +            "options":{ ... }
 +            }
 +        }
 +    }
 + "user":{
 +    "all":{
 +        "\/$user\/files\/Pictures":{
 +            "class":"\\OC\\Files\\Storage\\DAV",
 +            "options":{ ... }
 +            }
 +        }
 +    "someuser":{
 +        "\/someuser\/files\/Music":{
 +            "class":"\\OC\\Files\\Storage\\FTP",
 +            "options":{ ... }
 +            }
 +        }
 +    }
 +}</pre>
 +</div>
 +</div>
 +<div class="section" id="backends">
 +<h2>Backends<a class="headerlink" href="#backends" title="Permalink to this headline">¶</a></h2>
 +<div class="section" id="local-filesystem">
 +<h3>Local Filesystem<a class="headerlink" href="#local-filesystem" title="Permalink to this headline">¶</a></h3>
 +<p>The local filesystem backend mounts a folder on the server into the virtual
 +filesystem, the class to be used is <strong>\OC\Files\Storage\Local</strong> and
 +takes the following options:</p>
 +<ul class="simple">
 +<li><strong>datadir</strong> : the path to the local directory to be mounted</li>
 +</ul>
 +<div class="section" id="id1">
 +<h4>Example<a class="headerlink" href="#id1" title="Permalink to this headline">¶</a></h4>
 +<div class="highlight-json"><div class="highlight"><pre><span class="p">{</span> <span class="nt">"class"</span><span class="p">:</span><span class="s2">"\\OC\\Files\\Storage\\Local"</span><span class="p">,</span>
 +  <span class="nt">"options"</span><span class="p">:{</span> <span class="nt">"datadir"</span><span class="p">:</span><span class="s2">"\/mnt\/additional_storage"</span> <span class="p">}</span>
 +<span class="p">}</span>
 +</pre></div>
 +</div>
 +<div class="admonition note">
 +<p class="first admonition-title">Note</p>
 +<p class="last">You must ensure that the web server has sufficient permissions on the folder.</p>
 +</div>
 +</div>
 +</div>
 +<div class="section" id="ftp-or-ftps">
 +<h3>FTP (or FTPS)<a class="headerlink" href="#ftp-or-ftps" title="Permalink to this headline">¶</a></h3>
 +<p>The FTP backend mounts a folder on a remote FTP server into the virtual
 +filesystem and is part of the ‘External storage support’ app, the class
 +to be used is <strong>\OC\Files\Storage\FTP</strong> and takes the following
 +options:</p>
 +<ul class="simple">
 +<li><strong>host</strong>: the hostname of the ftp server</li>
 +<li><strong>user</strong>: the username used to login on the ftp server</li>
 +<li><strong>password</strong>: the password to login on the ftp server</li>
 +<li><strong>secure</strong>: whether to use ftps:// (FTP over TLS) to connect to the ftp
 +server instead of ftp:// (optional, defaults to false)</li>
 +<li><strong>root</strong>: the folder inside the ftp server to mount (optional, defaults
 +to ‘/’)</li>
 +</ul>
 +<div class="section" id="id2">
 +<h4>Example<a class="headerlink" href="#id2" title="Permalink to this headline">¶</a></h4>
 +<div class="highlight-json"><div class="highlight"><pre><span class="p">{</span>   <span class="nt">"class"</span><span class="p">:</span><span class="s2">"\\OC\\Files\\Storage\\FTP"</span><span class="p">,</span>
 +    <span class="nt">"options"</span><span class="p">:{</span>
 +        <span class="nt">"host"</span><span class="p">:</span><span class="s2">"ftp.myhost.com"</span><span class="p">,</span>
 +        <span class="nt">"user"</span><span class="p">:</span><span class="s2">"johndoe"</span><span class="p">,</span>
 +        <span class="nt">"password"</span><span class="p">:</span><span class="s2">"secret"</span><span class="p">,</span>
 +        <span class="nt">"root"</span><span class="p">:</span><span class="s2">"\/Videos"</span><span class="p">,</span>
 +        <span class="nt">"secure"</span><span class="p">:</span><span class="s2">"false"</span>
 +    <span class="p">}</span>
 +<span class="p">}</span>
 +</pre></div>
 +</div>
 +<div class="admonition note">
 +<p class="first admonition-title">Note</p>
 +<p class="last">PHP needs to be build with FTP support for this backend to work.</p>
 +</div>
 +</div>
 +</div>
 +<div class="section" id="sftp">
 +<h3>SFTP<a class="headerlink" href="#sftp" title="Permalink to this headline">¶</a></h3>
 +<p>The SFTP backend mounts a folder on a remote SSH server into the virtual
 +filesystem and is part of the ‘External storage support’ app. The class
 +to be used is <strong>\OC\Files\Storage\SFTP</strong> and takes the following
 +options:</p>
 +<ul class="simple">
 +<li><strong>host</strong>: the hostname of the SSH server</li>
 +<li><strong>user</strong>: the username used to login to the SSH server</li>
 +<li><strong>password</strong>: the password to login on the SSH server</li>
 +<li><strong>root</strong>: the folder inside the SSH server to mount (optional, defaults
 +to ‘/’)</li>
 +</ul>
 +<div class="section" id="id3">
 +<h4>Example<a class="headerlink" href="#id3" title="Permalink to this headline">¶</a></h4>
 +<div class="highlight-json"><div class="highlight"><pre><span class="p">{</span>   <span class="nt">"class"</span><span class="p">:</span><span class="s2">"\\OC\\Files\\Storage\\SFTP"</span><span class="p">,</span>
 +    <span class="nt">"options"</span><span class="p">:{</span>
 +        <span class="nt">"host"</span><span class="p">:</span><span class="s2">"ssh.myhost.com"</span><span class="p">,</span>
 +        <span class="nt">"user"</span><span class="p">:</span><span class="s2">"johndoe"</span><span class="p">,</span>
 +        <span class="nt">"password"</span><span class="p">:</span><span class="s2">"secret"</span><span class="p">,</span>
 +        <span class="nt">"root"</span><span class="p">:</span><span class="s2">"\/Books"</span>
 +    <span class="p">}</span>
 +<span class="p">}</span>
 +</pre></div>
 +</div>
 +<div class="admonition note">
 +<p class="first admonition-title">Note</p>
 +<p class="last">PHP needs to be build with SFTP support for this backend to work.</p>
 +</div>
 +</div>
 +</div>
 +<div class="section" id="smb">
 +<h3>SMB<a class="headerlink" href="#smb" title="Permalink to this headline">¶</a></h3>
 +<p>The SMB backend mounts a folder on a remote Samba server, a NAS appliance or
 +a Windows machine into the virtual file system. It is part of the ‘External
 +storage support’ app, the class to be used is <strong>\OC\Files\Storage\SMB</strong> and
 +takes the following options:</p>
 +<ul class="simple">
 +<li><strong>host</strong>: the host name of the samba server</li>
 +<li><strong>user</strong>: the user name used to login on the samba server</li>
 +<li><strong>password</strong>: the password to login on the samba server</li>
 +<li><strong>share</strong>: the share on the samba server to mount</li>
 +<li><strong>root</strong>: the folder inside the samba share to mount (optional, defaults
 +to ‘/’)</li>
 +</ul>
 +<div class="admonition note">
 +<p class="first admonition-title">Note</p>
 +<p class="last">The SMB backend requires <strong>smbclient</strong> to be installed on the server.</p>
 +</div>
 +<div class="section" id="id4">
 +<h4>Example<a class="headerlink" href="#id4" title="Permalink to this headline">¶</a></h4>
 +<div class="highlight-json"><div class="highlight"><pre><span class="p">{</span>   <span class="nt">"class"</span><span class="p">:</span><span class="s2">"\\OC\\Files\\Storage\\SMB"</span><span class="p">,</span>
 +    <span class="nt">"options"</span><span class="p">:{</span>
 +        <span class="nt">"host"</span><span class="p">:</span><span class="s2">"myhost.com"</span><span class="p">,</span>
 +        <span class="nt">"user"</span><span class="p">:</span><span class="s2">"johndoe"</span><span class="p">,</span>
 +        <span class="nt">"password"</span><span class="p">:</span><span class="s2">"secret"</span><span class="p">,</span>
 +        <span class="nt">"share"</span><span class="p">:</span><span class="s2">"\/test"</span><span class="p">,</span>
 +        <span class="nt">"root"</span><span class="p">:</span><span class="s2">"\/Pictures"</span>
 +    <span class="p">}</span>
 +<span class="p">}</span>
 +</pre></div>
 +</div>
 +</div>
 +</div>
 +<div class="section" id="webdav">
 +<h3>WebDAV<a class="headerlink" href="#webdav" title="Permalink to this headline">¶</a></h3>
 +<p>The WebDAV backend mounts a folder on a remote WebDAV server into the
 +virtual filesystem and is part of the ‘External storage support’ app,
 +the class to be used is <strong>\OC\Files\Storage\DAV</strong> and takes the
 +following options:</p>
 +<ul class="simple">
 +<li><strong>host</strong>: the hostname of the webdav server.</li>
 +<li><strong>user</strong>: the username used to login on the webdav server</li>
 +<li><strong>password</strong>: the password to login on the webdav server</li>
 +<li><strong>secure</strong>: whether to use <a class="reference external" href="https://">https://</a> to connect to the webdav server
 +instead of <a class="reference external" href="http://">http://</a> (optional, defaults to false)</li>
 +<li><strong>root</strong>: the folder inside the webdav server to mount (optional,
 +defaults to ‘/’)</li>
 +</ul>
 +<div class="section" id="id5">
 +<h4>Example<a class="headerlink" href="#id5" title="Permalink to this headline">¶</a></h4>
 +<div class="highlight-json"><div class="highlight"><pre><span class="p">{</span>   <span class="nt">"class"</span><span class="p">:</span><span class="s2">"\\OC\\Files\\Storage\\DAV"</span><span class="p">,</span>
 +    <span class="nt">"options"</span><span class="p">:{</span>
 +        <span class="nt">"host"</span><span class="p">:</span><span class="s2">"myhost.com\/webdav.php"</span><span class="p">,</span>
 +        <span class="nt">"user"</span><span class="p">:</span><span class="s2">"johndoe"</span><span class="p">,</span>
 +        <span class="nt">"password"</span><span class="p">:</span><span class="s2">"secret"</span><span class="p">,</span>
 +        <span class="nt">"secure"</span><span class="p">:</span><span class="s2">"true"</span>
 +    <span class="p">}</span>
 +<span class="p">}</span>
 +</pre></div>
 +</div>
 +</div>
 +</div>
 +<div class="section" id="amazon-s3">
 +<h3>Amazon S3<a class="headerlink" href="#amazon-s3" title="Permalink to this headline">¶</a></h3>
 +<p>The Amazon S3 backend mounts a bucket in the Amazon cloud into the virtual
 +filesystem and is part of the ‘External storage support’ app, the class to
 +be used is <strong>\OC\Files\Storage\AmazonS3</strong> and takes the following
 +options:</p>
 +<ul class="simple">
 +<li><strong>key</strong>: the key to login to the Amazon cloud</li>
 +<li><strong>secret</strong>: the secret to login to the Amazon cloud</li>
 +<li><strong>bucket</strong>: the bucket in the Amazon cloud to mount</li>
 +</ul>
 +<div class="section" id="id6">
 +<h4>Example<a class="headerlink" href="#id6" title="Permalink to this headline">¶</a></h4>
 +<div class="highlight-json"><div class="highlight"><pre><span class="p">{</span>   <span class="nt">"class"</span><span class="p">:</span><span class="s2">"\\OC\\Files\\Storage\\AmazonS3"</span><span class="p">,</span>
 +    <span class="nt">"options"</span><span class="p">:{</span>
 +        <span class="nt">"key"</span><span class="p">:</span><span class="s2">"key"</span><span class="p">,</span>
 +        <span class="nt">"secret"</span><span class="p">:</span><span class="s2">"secret"</span><span class="p">,</span>
 +        <span class="nt">"bucket"</span><span class="p">:</span><span class="s2">"bucket"</span>
 +    <span class="p">}</span>
 +<span class="p">}</span>
 +</pre></div>
 +</div>
 +</div>
 +</div>
 +<div class="section" id="dropbox">
 +<h3>Dropbox<a class="headerlink" href="#dropbox" title="Permalink to this headline">¶</a></h3>
 +<p>The Dropbox backend mounts a dropbox in the Dropbox cloud into the virtual
 +filesystem and is part of the ‘External storage support’ app, the class to
 +be used is <strong>\OC\Files\Storage\Dropbox</strong> and takes the following options:</p>
 +<ul class="simple">
 +<li><strong>configured</strong>: whether the drive has been configured or not (true or false)</li>
 +<li><strong>app_key</strong>: the app key to login to your Dropbox</li>
 +<li><strong>app_secret</strong>: the app secret to login to your Dropbox</li>
 +<li><strong>token</strong>: the OAuth token to login to your Dropbox</li>
 +<li><strong>token_secret</strong>: the OAuth secret to login to your Dropbox</li>
 +</ul>
 +<div class="section" id="id7">
 +<h4>Example<a class="headerlink" href="#id7" title="Permalink to this headline">¶</a></h4>
 +<div class="highlight-json"><div class="highlight"><pre><span class="p">{</span>   <span class="nt">"class"</span><span class="p">:</span><span class="s2">"\\OC\\Files\\Storage\\Dropbox"</span><span class="p">,</span>
 +    <span class="nt">"options"</span><span class="p">:{</span>
 +        <span class="nt">"configured"</span><span class="p">:</span><span class="s2">"#configured"</span><span class="p">,</span>
 +        <span class="nt">"app_key"</span><span class="p">:</span><span class="s2">"key"</span><span class="p">,</span>
 +        <span class="nt">"app_secret"</span><span class="p">:</span><span class="s2">"secret"</span><span class="p">,</span>
 +        <span class="nt">"token"</span><span class="p">:</span><span class="s2">"#token"</span><span class="p">,</span>
 +        <span class="nt">"token_secret"</span><span class="p">:</span><span class="s2">"#token_secret"</span>
 +    <span class="p">}</span>
 +<span class="p">}</span>
 +</pre></div>
 +</div>
 +</div>
 +</div>
 +<div class="section" id="google-drive">
 +<h3>Google Drive<a class="headerlink" href="#google-drive" title="Permalink to this headline">¶</a></h3>
 +<p>The Google Drive backend mounts a share in the Google cloud into the virtual
 +filesystem and is part of the ‘External storage support’ app, the class to
 +be used is <strong>\OC\Files\Storage\Google</strong> and is done via an OAuth2.0 request.
 +That means that the App must be registered through the Google APIs Console.
 +The result of the registration process is a set of values (incl. client_id, client_secret).
 +It takes the following options:</p>
 +<ul class="simple">
 +<li><strong>configured</strong>: whether the drive has been configured or not (true or false)</li>
 +<li><strong>client_id</strong>: the client id to login to the Google drive</li>
 +<li><strong>client_secret</strong>: the client secret to login to the Google drive</li>
 +<li><strong>token</strong>: a compound value including access and refresh tokens</li>
 +</ul>
 +<div class="section" id="id8">
 +<h4>Example<a class="headerlink" href="#id8" title="Permalink to this headline">¶</a></h4>
 +<div class="highlight-json"><div class="highlight"><pre><span class="p">{</span>   <span class="nt">"class"</span><span class="p">:</span><span class="s2">"\\OC\\Files\\Storage\\Google"</span><span class="p">,</span>
 +    <span class="nt">"options"</span><span class="p">:{</span>
 +        <span class="nt">"configured"</span><span class="p">:</span><span class="s2">"#configured"</span><span class="p">,</span>
 +        <span class="nt">"client_id"</span><span class="p">:</span><span class="s2">"#client_id"</span><span class="p">,</span>
 +        <span class="nt">"client_secret"</span><span class="p">:</span><span class="s2">"#client_secret"</span><span class="p">,</span>
 +        <span class="nt">"token"</span><span class="p">:</span><span class="s2">"#token"</span>
 +    <span class="p">}</span>
 +<span class="p">}</span>
 +</pre></div>
 +</div>
 +</div>
 +</div>
 +<div class="section" id="openstack-swift">
 +<h3>OpenStack Swift<a class="headerlink" href="#openstack-swift" title="Permalink to this headline">¶</a></h3>
 +<p>The Swift backend mounts a container on an OpenStack Object Storage server
 +into the virtual filesystem and is part of the ‘External storage support’
 +app, the class to be used is <strong>\OC\Files\Storage\SWIFT</strong> and takes
 +the following options:</p>
 +<ul class="simple">
 +<li><strong>host</strong>: the hostname of the authentication server for the swift
 +storage.</li>
 +<li><strong>user</strong>: the username used to login on the swift server</li>
 +<li><strong>token</strong>: the authentication token to login on the swift server</li>
 +<li><strong>secure</strong>: whether to use ftps:// to connect to the swift server instead
 +of ftp:// (optional, defaults to false)</li>
 +<li><strong>root</strong>: the container inside the swift server to mount (optional,
 +defaults to ‘/’)</li>
 +</ul>
 +<div class="section" id="id9">
 +<h4>Example<a class="headerlink" href="#id9" title="Permalink to this headline">¶</a></h4>
 +<div class="highlight-json"><div class="highlight"><pre><span class="p">{</span>   <span class="nt">"class"</span><span class="p">:</span><span class="s2">"\\OC\\Files\\Storage\\SWIFT"</span><span class="p">,</span>
 +    <span class="nt">"options"</span><span class="p">:{</span>
 +        <span class="nt">"host"</span><span class="p">:</span><span class="s2">"swift.myhost.com\/auth"</span><span class="p">,</span>
 +        <span class="nt">"user"</span><span class="p">:</span><span class="s2">"johndoe"</span><span class="p">,</span>
 +        <span class="nt">"token"</span><span class="p">:</span><span class="s2">"secret"</span><span class="p">,</span>
 +        <span class="nt">"root"</span><span class="p">:</span><span class="s2">"\/Videos"</span><span class="p">,</span>
 +        <span class="nt">"secure"</span><span class="p">:</span><span class="s2">"true"</span>
 +    <span class="p">}</span>
 +<span class="p">}</span>
 +</pre></div>
 +</div>
 +</div>
 +</div>
 +</div>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/configuration/custom_mount_config_gui.html
index d99c89a,0000000..99c982c
mode 100644,000000..100644
--- a/core/doc/admin/configuration/custom_mount_config_gui.html
+++ b/core/doc/admin/configuration/custom_mount_config_gui.html
@@@ -1,235 -1,0 +1,236 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
 +    <title>Custom Mount Configuration Web-GUI — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
 +    <link rel="up" title="Configuration" href="index.html" />
 +    <link rel="next" title="Custom Mount Configuration" href="custom_mount_config.html" />
-     <link rel="prev" title="Uploading big files > 512MB (as set by default)" href="configuring_big_file_upload.html" />
++    <link rel="prev" title="Dealing with Big File Uploads" href="configuring_big_file_upload.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
 +<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../installation/index.html">Installation</a></li>
 +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Configuration</a><ul class="current">
- <li class="toctree-l2"><a class="reference internal" href="configuration_apps.html">Apps Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_apps.html">Managing Apps</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_users.html">User Management</a></li>
- <li class="toctree-l2"><a class="reference internal" href="auth_ldap.html">User Authentication with LDAP</a></li>
++<li class="toctree-l2"><a class="reference internal" href="auth_ldap.html">LDAP Authentication</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="background_jobs.html">Background Jobs</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_3rdparty.html">3rd-Party Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_3rdparty.html">Find Third-Party Libraries</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_automation.html">Automatic Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_custom_clients.html">Custom Client Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_database.html">Database Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_encryption.html">Use Server-Side Encryption</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_knowledgebase.html">Knowledge Base Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_language.html">Language Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_logging.html">Logging Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_mail.html">Mail Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_maintenance.html">Maintenance Mode Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_preview.html">Preview Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_custom_clients.html">Customizing Client Download Links</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_database.html">MySQL/Postgres/SQLite Support</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_encryption.html">Using Server-Side Encryption</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_knowledgebase.html">Disable Knowledge Base</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_language.html">Setting the Default Language</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_logging.html">Configure Logging</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_mail.html">Sending Mail Notifications</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_maintenance.html">Enable Maintenance Mode</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_preview.html">Enabling File Previews</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_reverseproxy.html">Reverse Proxy Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html">Uploading big files > 512MB (as set by default)</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html#enabling-uploading-big-files">Enabling uploading big files</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html">Dealing with Big File Uploads</a></li>
 +<li class="toctree-l2 current"><a class="current reference internal" href="">Custom Mount Configuration Web-GUI</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="#id1">Dropbox</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#id2">Google Drive</a></li>
 +</ul>
 +</li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_mount_config.html">Custom Mount Configuration</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_user_backend.html">Custom User Backend Configuration</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="xsendfile.html">Serving static files via web server</a></li>
 +</ul>
 +</li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
 +  <div class="section" id="custom-mount-configuration-web-gui">
 +<h1>Custom Mount Configuration Web-GUI<a class="headerlink" href="#custom-mount-configuration-web-gui" title="Permalink to this headline">¶</a></h1>
 +<p>Since ownCloud 5.0 it is possible to mount external storage providers into
 +ownCloud’s virtual file system. To add an external storage backend to your
 +ownCloud head to <em>Settings</em> -> <em>Admin</em> or <em>Personal</em>. As administrator you
 +can mount external storage for any group or user. Users are also allowed
 +to mount external storage for themselves if this setting has been enabled
 +by the administrator.</p>
 +<div class="figure">
 +<img alt="../_images/custom_mount_config_gui-1.png" src="../_images/custom_mount_config_gui-1.png" />
 +</div>
 +<p>At first the mount point has to be entered, this is the directory in ownCloud’s
 +virtual file system, that the storage will be mounted to. Then the storage
 +backend has to be selected from the list of supported backends. As of writing
 +ownCloud currently supports the following storage backends:</p>
 +<div class="figure">
 +<img alt="../_images/custom_mount_config_gui-2.png" src="../_images/custom_mount_config_gui-2.png" />
 +</div>
 +<ul class="simple">
 +<li>Local file system (mount local storage that is outside ownCloud’s data
 +directory)</li>
 +<li>FTP (or FTPS)</li>
 +<li>SFTP</li>
 +<li>SMB</li>
 +<li>WebDAV</li>
 +<li><a class="reference external" href="http://aws.amazon.com/de/s3/">Amazon S3</a></li>
 +<li><a class="reference external" href="https://www.dropbox.com/">Dropbox</a></li>
 +<li><a class="reference external" href="https://drive.google.com/start">Google Drive</a></li>
 +<li><a class="reference external" href="http://openstack.org/projects/storage/">OpenStack Swift</a></li>
 +</ul>
 +<p>Please keep in mind, that users are not allowed to mount local file storage for
 +security purposes.</p>
 +<div class="figure">
 +<img alt="../_images/custom_mount_config_gui-3.png" src="../_images/custom_mount_config_gui-3.png" />
 +</div>
 +<div class="figure">
 +<img alt="../_images/custom_mount_config_gui-4.png" src="../_images/custom_mount_config_gui-4.png" />
 +</div>
 +<p>Once a backend has been selected, more configuration fields will appear. The
 +displayed configuration fields may vary depending on the selected storage backend.
 +For example, the FTP storage backend needs the following configuration details
 +to be entered:</p>
 +<ul class="simple">
 +<li><strong>host</strong>: the hostname of the ftp server</li>
 +<li><strong>user</strong>: the username used to login to the ftp server</li>
 +<li><strong>password</strong>: the password to login to the ftp server</li>
 +<li><strong>secure</strong>: whether to use ftps:// (FTP over TLS) to connect to the ftp
 +server instead of ftp:// (optional, defaults to false)</li>
 +<li><strong>root</strong>: the name of the folder inside the ftp server to mount (optional,
 +defaults to ‘/’)</li>
 +</ul>
 +<div class="section" id="id1">
 +<h2>Dropbox<a class="headerlink" href="#id1" title="Permalink to this headline">¶</a></h2>
 +<p>Mounting a Dropbox account requires that you create an app with Dropbox and then provide the app key and secret to the
 +external storage configuration user interface. Go to My apps at Dropbox and create an app. Select <em>Full Dropbox</em> access
 +level. Copy the app key and app secret and paste them into the corresponding fields for the Dropbox storage.</p>
 +<p>Click the <em>Grant access</em> button and you will be redirected to a Dropbox website to give ownCloud permission to access your account.</p>
 +</div>
 +<div class="section" id="id2">
 +<h2>Google Drive<a class="headerlink" href="#id2" title="Permalink to this headline">¶</a></h2>
 +<p>For a detailed step-by-step guide read <a class="reference external" href="../../user_manual/external_storage/google_drive.html">User Manual</a></p>
 +</div>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/configuration/custom_user_backend.html
index 942656d,0000000..3acff52
mode 100644,000000..100644
--- a/core/doc/admin/configuration/custom_user_backend.html
+++ b/core/doc/admin/configuration/custom_user_backend.html
@@@ -1,254 -1,0 +1,255 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
 +    <title>Custom User Backend Configuration — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
 +    <link rel="up" title="Configuration" href="index.html" />
 +    <link rel="next" title="Serving static files via web server" href="xsendfile.html" />
 +    <link rel="prev" title="Custom Mount Configuration" href="custom_mount_config.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
 +<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../installation/index.html">Installation</a></li>
 +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Configuration</a><ul class="current">
- <li class="toctree-l2"><a class="reference internal" href="configuration_apps.html">Apps Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_apps.html">Managing Apps</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_users.html">User Management</a></li>
- <li class="toctree-l2"><a class="reference internal" href="auth_ldap.html">User Authentication with LDAP</a></li>
++<li class="toctree-l2"><a class="reference internal" href="auth_ldap.html">LDAP Authentication</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="background_jobs.html">Background Jobs</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_3rdparty.html">3rd-Party Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_3rdparty.html">Find Third-Party Libraries</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_automation.html">Automatic Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_custom_clients.html">Custom Client Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_database.html">Database Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_encryption.html">Use Server-Side Encryption</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_knowledgebase.html">Knowledge Base Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_language.html">Language Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_logging.html">Logging Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_mail.html">Mail Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_maintenance.html">Maintenance Mode Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_preview.html">Preview Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_custom_clients.html">Customizing Client Download Links</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_database.html">MySQL/Postgres/SQLite Support</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_encryption.html">Using Server-Side Encryption</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_knowledgebase.html">Disable Knowledge Base</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_language.html">Setting the Default Language</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_logging.html">Configure Logging</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_mail.html">Sending Mail Notifications</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_maintenance.html">Enable Maintenance Mode</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_preview.html">Enabling File Previews</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_reverseproxy.html">Reverse Proxy Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html">Uploading big files > 512MB (as set by default)</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html#enabling-uploading-big-files">Enabling uploading big files</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html">Dealing with Big File Uploads</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_mount_config_gui.html">Custom Mount Configuration Web-GUI</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_mount_config.html">Custom Mount Configuration</a></li>
 +<li class="toctree-l2 current"><a class="current reference internal" href="">Custom User Backend Configuration</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="#imap">IMAP</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#smb">SMB</a></li>
 +</ul>
 +</li>
 +<li class="toctree-l2"><a class="reference internal" href="xsendfile.html">Serving static files via web server</a></li>
 +</ul>
 +</li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
 +  <div class="section" id="custom-user-backend-configuration">
 +<h1>Custom User Backend Configuration<a class="headerlink" href="#custom-user-backend-configuration" title="Permalink to this headline">¶</a></h1>
 +<p>Starting with ownCloud 4.5 is possible to configure additional user backends
 +in ownCloud’s configuration <tt class="file docutils literal"><span class="pre">config/config.php</span></tt> using the following
 +syntax:</p>
 +<div class="highlight-php"><div class="highlight"><pre><span class="cp"><?php</span>
 +
 +<span class="s2">"user_backends"</span> <span class="o">=></span> <span class="k">array</span> <span class="p">(</span>
 +    <span class="mi">0</span> <span class="o">=></span> <span class="k">array</span> <span class="p">(</span>
 +            <span class="s2">"class"</span>     <span class="o">=></span> <span class="o">...</span><span class="p">,</span>
 +            <span class="s2">"arguments"</span> <span class="o">=></span> <span class="k">array</span> <span class="p">(</span>
 +                              <span class="mi">0</span> <span class="o">=></span> <span class="o">...</span>
 +                              <span class="p">),</span>
 +    <span class="p">),</span>
 +<span class="p">),</span>
 +</pre></div>
 +</div>
 +<p>Currently the “External user support” (user_external) app provides the following user backends:</p>
 +<div class="section" id="imap">
 +<h2>IMAP<a class="headerlink" href="#imap" title="Permalink to this headline">¶</a></h2>
 +<p>Provides authentication against IMAP servers</p>
 +<ul class="simple">
 +<li><strong>Class:</strong> OC_User_IMAP</li>
 +<li><strong>Arguments:</strong>  a mailbox string as defined <a class="reference external" href="http://www.php.net/manual/en/function.imap-open.php">in the PHP documention</a></li>
 +<li><strong>Example:</strong></li>
 +</ul>
 +<div class="highlight-php"><div class="highlight"><pre><span class="cp"><?php</span>
 +
 +<span class="s2">"user_backends"</span> <span class="o">=></span> <span class="k">array</span> <span class="p">(</span>
 +    <span class="mi">0</span> <span class="o">=></span> <span class="k">array</span> <span class="p">(</span>
 +            <span class="s2">"class"</span>     <span class="o">=></span> <span class="s2">"OC_User_IMAP"</span><span class="p">,</span>
 +            <span class="s2">"arguments"</span> <span class="o">=></span> <span class="k">array</span> <span class="p">(</span>
 +                              <span class="mi">0</span> <span class="o">=></span> <span class="s1">'{imap.gmail.com:993/imap/ssl}'</span>
 +                              <span class="p">),</span>
 +    <span class="p">),</span>
 +<span class="p">),</span>
 +</pre></div>
 +</div>
 +</div>
 +<div class="section" id="smb">
 +<h2>SMB<a class="headerlink" href="#smb" title="Permalink to this headline">¶</a></h2>
 +<p>Provides authentication against Samba servers</p>
 +<ul class="simple">
 +<li><strong>Class:</strong> OC_User_SMB</li>
 +<li><strong>Arguments:</strong> the samba server to authenticate against</li>
 +<li><strong>Example:</strong></li>
 +</ul>
 +<div class="highlight-php"><div class="highlight"><pre><span class="cp"><?php</span>
 +
 +<span class="s2">"user_backends"</span> <span class="o">=></span> <span class="k">array</span> <span class="p">(</span>
 +    <span class="mi">0</span> <span class="o">=></span> <span class="k">array</span> <span class="p">(</span>
 +            <span class="s2">"class"</span>     <span class="o">=></span> <span class="s2">"OC_User_SMB"</span><span class="p">,</span>
 +            <span class="s2">"arguments"</span> <span class="o">=></span> <span class="k">array</span> <span class="p">(</span>
 +                              <span class="mi">0</span> <span class="o">=></span> <span class="s1">'localhost'</span>
 +                              <span class="p">),</span>
 +    <span class="p">),</span>
 +<span class="p">),</span>
 +</pre></div>
 +</div>
 +<div class="section" id="ftp">
 +<h3>FTP<a class="headerlink" href="#ftp" title="Permalink to this headline">¶</a></h3>
 +<p>Provides authentication against FTP servers</p>
 +<ul class="simple">
 +<li><strong>Class:</strong> OC_User_FTP</li>
 +<li><strong>Arguments:</strong> the FTP server to authenticate against</li>
 +<li><strong>Example:</strong></li>
 +</ul>
 +<div class="highlight-php"><div class="highlight"><pre><span class="cp"><?php</span>
 +
 +<span class="s2">"user_backends"</span> <span class="o">=></span> <span class="k">array</span> <span class="p">(</span>
 +    <span class="mi">0</span> <span class="o">=></span> <span class="k">array</span> <span class="p">(</span>
 +            <span class="s2">"class"</span>     <span class="o">=></span> <span class="s2">"OC_User_FTP"</span><span class="p">,</span>
 +            <span class="s2">"arguments"</span> <span class="o">=></span> <span class="k">array</span> <span class="p">(</span>
 +                              <span class="mi">0</span> <span class="o">=></span> <span class="s1">'localhost'</span>
 +                              <span class="p">),</span>
 +    <span class="p">),</span>
 +<span class="p">),</span>
 +</pre></div>
 +</div>
 +</div>
 +</div>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/configuration/index.html
index 4d64ba0,0000000..ddc8304
mode 100644,000000..100644
--- a/core/doc/admin/configuration/index.html
+++ b/core/doc/admin/configuration/index.html
@@@ -1,196 -1,0 +1,196 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
 +    <title>Configuration — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
-     <link rel="next" title="Apps Configuration" href="configuration_apps.html" />
++    <link rel="next" title="Managing Apps" href="configuration_apps.html" />
 +    <link rel="prev" title="PageKite Configuration" href="../installation/installation_others.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
 +<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../installation/index.html">Installation</a></li>
 +<li class="toctree-l1 current"><a class="current reference internal" href="">Configuration</a><ul>
- <li class="toctree-l2"><a class="reference internal" href="configuration_apps.html">Apps Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_apps.html">Managing Apps</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_users.html">User Management</a></li>
- <li class="toctree-l2"><a class="reference internal" href="auth_ldap.html">User Authentication with LDAP</a></li>
++<li class="toctree-l2"><a class="reference internal" href="auth_ldap.html">LDAP Authentication</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="background_jobs.html">Background Jobs</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_3rdparty.html">3rd-Party Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_3rdparty.html">Find Third-Party Libraries</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_automation.html">Automatic Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_custom_clients.html">Custom Client Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_database.html">Database Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_encryption.html">Use Server-Side Encryption</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_knowledgebase.html">Knowledge Base Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_language.html">Language Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_logging.html">Logging Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_mail.html">Mail Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_maintenance.html">Maintenance Mode Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_preview.html">Preview Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_custom_clients.html">Customizing Client Download Links</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_database.html">MySQL/Postgres/SQLite Support</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_encryption.html">Using Server-Side Encryption</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_knowledgebase.html">Disable Knowledge Base</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_language.html">Setting the Default Language</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_logging.html">Configure Logging</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_mail.html">Sending Mail Notifications</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_maintenance.html">Enable Maintenance Mode</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_preview.html">Enabling File Previews</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_reverseproxy.html">Reverse Proxy Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html">Uploading big files > 512MB (as set by default)</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html#enabling-uploading-big-files">Enabling uploading big files</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html">Dealing with Big File Uploads</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_mount_config_gui.html">Custom Mount Configuration Web-GUI</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_mount_config.html">Custom Mount Configuration</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_user_backend.html">Custom User Backend Configuration</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="xsendfile.html">Serving static files via web server</a></li>
 +</ul>
 +</li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
 +  <div class="section" id="configuration">
 +<h1>Configuration<a class="headerlink" href="#configuration" title="Permalink to this headline">¶</a></h1>
 +<div class="toctree-wrapper compound">
 +<ul>
- <li class="toctree-l1"><a class="reference internal" href="configuration_apps.html">Apps Configuration</a></li>
++<li class="toctree-l1"><a class="reference internal" href="configuration_apps.html">Managing Apps</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="configuration_users.html">User Management</a></li>
- <li class="toctree-l1"><a class="reference internal" href="auth_ldap.html">User Authentication with LDAP</a></li>
++<li class="toctree-l1"><a class="reference internal" href="auth_ldap.html">LDAP Authentication</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="background_jobs.html">Background Jobs</a></li>
- <li class="toctree-l1"><a class="reference internal" href="configuration_3rdparty.html">3rd-Party Configuration</a></li>
++<li class="toctree-l1"><a class="reference internal" href="configuration_3rdparty.html">Find Third-Party Libraries</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="configuration_automation.html">Automatic Configuration</a></li>
- <li class="toctree-l1"><a class="reference internal" href="configuration_custom_clients.html">Custom Client Configuration</a></li>
- <li class="toctree-l1"><a class="reference internal" href="configuration_database.html">Database Configuration</a></li>
- <li class="toctree-l1"><a class="reference internal" href="configuration_encryption.html">Use Server-Side Encryption</a></li>
- <li class="toctree-l1"><a class="reference internal" href="configuration_knowledgebase.html">Knowledge Base Configuration</a></li>
- <li class="toctree-l1"><a class="reference internal" href="configuration_language.html">Language Configuration</a></li>
- <li class="toctree-l1"><a class="reference internal" href="configuration_logging.html">Logging Configuration</a></li>
- <li class="toctree-l1"><a class="reference internal" href="configuration_mail.html">Mail Configuration</a></li>
- <li class="toctree-l1"><a class="reference internal" href="configuration_maintenance.html">Maintenance Mode Configuration</a></li>
- <li class="toctree-l1"><a class="reference internal" href="configuration_preview.html">Preview Configuration</a></li>
++<li class="toctree-l1"><a class="reference internal" href="configuration_custom_clients.html">Customizing Client Download Links</a></li>
++<li class="toctree-l1"><a class="reference internal" href="configuration_database.html">MySQL/Postgres/SQLite Support</a></li>
++<li class="toctree-l1"><a class="reference internal" href="configuration_encryption.html">Using Server-Side Encryption</a></li>
++<li class="toctree-l1"><a class="reference internal" href="configuration_knowledgebase.html">Disable Knowledge Base</a></li>
++<li class="toctree-l1"><a class="reference internal" href="configuration_language.html">Setting the Default Language</a></li>
++<li class="toctree-l1"><a class="reference internal" href="configuration_logging.html">Configure Logging</a></li>
++<li class="toctree-l1"><a class="reference internal" href="configuration_mail.html">Sending Mail Notifications</a></li>
++<li class="toctree-l1"><a class="reference internal" href="configuration_maintenance.html">Enable Maintenance Mode</a></li>
++<li class="toctree-l1"><a class="reference internal" href="configuration_preview.html">Enabling File Previews</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="configuration_reverseproxy.html">Reverse Proxy Configuration</a></li>
- <li class="toctree-l1"><a class="reference internal" href="configuring_big_file_upload.html">Uploading big files > 512MB (as set by default)</a></li>
- <li class="toctree-l1"><a class="reference internal" href="configuring_big_file_upload.html#enabling-uploading-big-files">Enabling uploading big files</a></li>
++<li class="toctree-l1"><a class="reference internal" href="configuring_big_file_upload.html">Dealing with Big File Uploads</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="custom_mount_config_gui.html">Custom Mount Configuration Web-GUI</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="custom_mount_config.html">Custom Mount Configuration</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="custom_user_backend.html">Custom User Backend Configuration</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="xsendfile.html">Serving static files via web server</a></li>
 +</ul>
 +</div>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/configuration/xsendfile.html
index 75fd643,0000000..ec73f9f
mode 100644,000000..100644
--- a/core/doc/admin/configuration/xsendfile.html
+++ b/core/doc/admin/configuration/xsendfile.html
@@@ -1,290 -1,0 +1,291 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
 +    <title>Serving static files via web server — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
 +    <link rel="up" title="Configuration" href="index.html" />
-     <link rel="next" title="Maintenance" href="../maintenance/index.html" />
++    <link rel="next" title="Apps" href="../apps/index.html" />
 +    <link rel="prev" title="Custom User Backend Configuration" href="custom_user_backend.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
 +<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../installation/index.html">Installation</a></li>
 +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Configuration</a><ul class="current">
- <li class="toctree-l2"><a class="reference internal" href="configuration_apps.html">Apps Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_apps.html">Managing Apps</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_users.html">User Management</a></li>
- <li class="toctree-l2"><a class="reference internal" href="auth_ldap.html">User Authentication with LDAP</a></li>
++<li class="toctree-l2"><a class="reference internal" href="auth_ldap.html">LDAP Authentication</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="background_jobs.html">Background Jobs</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_3rdparty.html">3rd-Party Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_3rdparty.html">Find Third-Party Libraries</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_automation.html">Automatic Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_custom_clients.html">Custom Client Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_database.html">Database Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_encryption.html">Use Server-Side Encryption</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_knowledgebase.html">Knowledge Base Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_language.html">Language Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_logging.html">Logging Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_mail.html">Mail Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_maintenance.html">Maintenance Mode Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuration_preview.html">Preview Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_custom_clients.html">Customizing Client Download Links</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_database.html">MySQL/Postgres/SQLite Support</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_encryption.html">Using Server-Side Encryption</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_knowledgebase.html">Disable Knowledge Base</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_language.html">Setting the Default Language</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_logging.html">Configure Logging</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_mail.html">Sending Mail Notifications</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_maintenance.html">Enable Maintenance Mode</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuration_preview.html">Enabling File Previews</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration_reverseproxy.html">Reverse Proxy Configuration</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html">Uploading big files > 512MB (as set by default)</a></li>
- <li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html#enabling-uploading-big-files">Enabling uploading big files</a></li>
++<li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html">Dealing with Big File Uploads</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_mount_config_gui.html">Custom Mount Configuration Web-GUI</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_mount_config.html">Custom Mount Configuration</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="custom_user_backend.html">Custom User Backend Configuration</a></li>
 +<li class="toctree-l2 current"><a class="current reference internal" href="">Serving static files via web server</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="#apache2-x-sendfile">Apache2 (X-Sendfile)</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#lighttpd-x-sendfile2">LigHTTPd (X-Sendfile2)</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#nginx-x-accel-redirect">Nginx (X-Accel-Redirect)</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#how-to-check-if-it-s-working">How to check if it’s working?</a></li>
 +</ul>
 +</li>
 +</ul>
 +</li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
 +  <div class="section" id="serving-static-files-via-web-server">
 +<h1>Serving static files via web server<a class="headerlink" href="#serving-static-files-via-web-server" title="Permalink to this headline">¶</a></h1>
 +<p>Since ownCloud 5 it is possible to let web servers handle static file serving.
 +This should generally improve performance (web servers are optimized for this) and in some cases permits controlled
 +file serving (i.e. pause and resume downloads).</p>
 +<div class="admonition note">
 +<p class="first admonition-title">Note</p>
 +<p class="last">This feature can currently only be activated for local files, i.e. files inside the <strong>data/</strong> directory</p>
 +</div>
 +<p>and local mounts. Controlled file serving <strong>does not work for generated zip files</strong>. This is due to how temporary files are created.</p>
 +<div class="section" id="apache2-x-sendfile">
 +<h2>Apache2 (X-Sendfile)<a class="headerlink" href="#apache2-x-sendfile" title="Permalink to this headline">¶</a></h2>
 +<p>It is possible to let Apache handle static file serving via <a class="reference external" href="https://tn123.org/mod_xsendfile/">mod_xsendfile</a>.</p>
 +<div class="section" id="installation">
 +<h3>Installation<a class="headerlink" href="#installation" title="Permalink to this headline">¶</a></h3>
 +<p>On Debian and Ubuntu systems use:</p>
 +<div class="highlight-bash"><div class="highlight"><pre>apt-get install libapache2-mod-xsendfile
 +</pre></div>
 +</div>
 +</div>
 +<div class="section" id="configuration">
 +<h3>Configuration<a class="headerlink" href="#configuration" title="Permalink to this headline">¶</a></h3>
 +<p>Configuration of mod_xsendfile for ownCloud depends on its version.
 +For versions below 0.10 (Debian squeeze ships with 0.9)</p>
 +<div class="highlight-xml"><pre><Directory /var/www/owncloud>
 +    ...
 +    SetEnv MOD_X_SENDFILE_ENABLED 1
 +    XSendFile On
 +    XSendFileAllowAbove On
 +</Directory></pre>
 +</div>
 +<p>For versions >=0.10 (e.g. Ubuntu 12.10)</p>
 +<div class="highlight-xml"><pre><Directory /var/www/owncloud>
 +    ...
 +    SetEnv MOD_X_SENDFILE_ENABLED 1
 +    XSendFile On
 +    XSendFilePath /tmp/oc-noclean
 +    XSendFilePath /home/valerio
 +</Directory></pre>
 +</div>
 +<ul class="simple">
 +<li><strong>SetEnv MOD_X_SENDFILE_ENABLED</strong>: tells ownCloud scripts that they should add the X-Sendfile header when serving files</li>
 +<li><strong>XSendFile</strong>: enables web server handling of X-Sendfile headers (and therefore file serving) for the specified Directory</li>
 +<li><strong>XSendFileAllowAbove (<0.10)</strong>: enables file serving through web server on path outside the specified Directory. This is needed for PHP temporary directory where zip files are created and for configured local mounts which may reside outside data directory</li>
 +<li><strong>XSendFilePath (>=0.10)</strong>: a white list of paths that the web server is allowed to serve outside of the specified Directory. At least PHP temporary directory concatenated with <em>oc-noclean</em> must be configured. Temporary zip files will be created inside this directory when using mod_xsendfile. Other paths which correspond to local mounts should be configured here as well. For a more in-dept documentation of this directive refer to mod_xsendfile website linked a [...]
 +</ul>
 +</div>
 +</div>
 +<div class="section" id="lighttpd-x-sendfile2">
 +<h2>LigHTTPd (X-Sendfile2)<a class="headerlink" href="#lighttpd-x-sendfile2" title="Permalink to this headline">¶</a></h2>
 +<p>LigHTTPd uses similar headers to Apache2, apart from the fact that it does not handle partial downloads in the same way
 +Apache2 does. For this reason, a different method is used for LigHTTPd.</p>
 +<div class="section" id="id1">
 +<h3>Installation<a class="headerlink" href="#id1" title="Permalink to this headline">¶</a></h3>
 +<p>X-Sendfile and X-Sendfile2 are supported by default in LigHTTPd and no additional operation should be needed to install it.</p>
 +</div>
 +<div class="section" id="id2">
 +<h3>Configuration<a class="headerlink" href="#id2" title="Permalink to this headline">¶</a></h3>
 +<p>Your server configuration should include the following statements:</p>
 +<div class="highlight-python"><pre>fastcgi.server          = ( ".php" => ((
 +   ...
 +   "allow-x-send-file" => "enable",
 +   "bin-environment" => (
 +      "MOD_X_SENDFILE2_ENABLED" => "1",
 +   ),
 +)))</pre>
 +</div>
 +<ul class="simple">
 +<li><strong>allow-x-send-file</strong>: enables LigHTTPd to use X-Sendfile and X-Sendfile2 headers to serve files</li>
 +<li><strong>bin-environment</strong>: is used to parse MOD_X_SENDFILE2_ENABLED to the ownCloud backend, to make it use the X-Sendfile and X-Sendfile2 headers in it’s response</li>
 +</ul>
 +</div>
 +</div>
 +<div class="section" id="nginx-x-accel-redirect">
 +<h2>Nginx (X-Accel-Redirect)<a class="headerlink" href="#nginx-x-accel-redirect" title="Permalink to this headline">¶</a></h2>
 +<p>Nginx supports handling of static files differently from Apache. Documentation can be found in the Nginx Wiki
 +section <a class="reference external" href="http://wiki.nginx.org/XSendfile">Mod X-Sendfile</a> and section <a class="reference external" href="http://wiki.nginx.org/X-accel">X-Accell</a>.
 +The header used by Nginx is X-Accel-Redirect.</p>
 +<div class="section" id="id3">
 +<h3>Installation<a class="headerlink" href="#id3" title="Permalink to this headline">¶</a></h3>
 +<p>X-Accel-Redirect is supported by default in Nginx and no additional operation should be needed to install it.</p>
 +</div>
 +<div class="section" id="id4">
 +<h3>Configuration<a class="headerlink" href="#id4" title="Permalink to this headline">¶</a></h3>
 +<p>Configuration is similar to Apache:</p>
 +<div class="highlight-python"><pre>location ~ \.php$ {
 +    ...
 +    fastcgi_param MOD_X_ACCEL_REDIRECT_ENABLED on;
 +}
 +
 +location ~ ^/home/valerio/(owncloud/)?data {
 +    internal;
 +    root /;
 +}
 +
 +location ~ ^/tmp/oc-noclean/.+$ {
 +    internal;
 +    root /;
 +}</pre>
 +</div>
 +<ul class="simple">
 +<li><strong>fastcgi_param MOD_X_ACCEL_REDIRECT_ENABLED:</strong> tells ownCloud scripts that they should add the X-Accel-Redirect header when serving files</li>
 +<li><strong>internal location:</strong> each directory that contains local user data should correspond to an internal location. In the example uses the following directories:<ul>
 +<li><strong>/home/valerio/owncloud/data</strong>: ownCloud data directory</li>
 +<li><strong>/home/valerio/data</strong>: a local mount</li>
 +<li><strong>/tmp/oc-noclean</strong>: PHP temporary directory concatenated with <em>oc-noclean</em>. Temporary zip files will be created inside this directory when using X-Accel-Redirect</li>
 +</ul>
 +</li>
 +</ul>
 +</div>
 +</div>
 +<div class="section" id="how-to-check-if-it-s-working">
 +<h2>How to check if it’s working?<a class="headerlink" href="#how-to-check-if-it-s-working" title="Permalink to this headline">¶</a></h2>
 +<p>You are still able to download stuff via the web interface and single, local file downloads can be paused and resumed.</p>
 +</div>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/contents.html
index a9a6a44,0000000..3366a1a
mode 100644,000000..100644
--- a/core/doc/admin/contents.html
+++ b/core/doc/admin/contents.html
@@@ -1,336 -1,0 +1,406 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
 +    <title>ownCloud documentation contents — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="_static/jquery.js"></script>
 +    <script type="text/javascript" src="_static/underscore.js"></script>
 +    <script type="text/javascript" src="_static/doctools.js"></script>
 +    <script type="text/javascript" src="_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="index.html" />
 +    <link rel="next" title="ownCloud 6.0 Admin Documentation" href="index.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="#">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="#">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
 +<ul>
 +<li class="toctree-l1"><a class="reference internal" href="installation/index.html">Installation</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="configuration/index.html">Configuration</a></li>
++<li class="toctree-l1"><a class="reference internal" href="apps/index.html">Apps</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1"><a class="reference internal" href="config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
 +  <div class="section" id="owncloud-documentation-contents">
 +<span id="contents"></span><h1>ownCloud documentation contents<a class="headerlink" href="#owncloud-documentation-contents" title="Permalink to this headline">¶</a></h1>
 +<div class="toctree-wrapper compound">
 +</div>
 +<div class="toctree-wrapper compound">
 +<ul>
 +<li class="toctree-l1"><a class="reference internal" href="installation/index.html">Installation</a><ul>
 +<li class="toctree-l2"><a class="reference internal" href="installation/installation_appliance.html">Appliances</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="installation/installation_appliance.html#software-appliances">Software Appliances</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="installation/installation_appliance.html#owncloud-on-hardware-appliances">ownCloud on Hardware Appliances</a></li>
 +</ul>
 +</li>
 +<li class="toctree-l2"><a class="reference internal" href="installation/installation_linux.html">Linux Distributions</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="installation/installation_linux.html#supported-distribution-packages">Supported Distribution Packages</a></li>
 +</ul>
 +</li>
 +<li class="toctree-l2"><a class="reference internal" href="installation/installation_macos.html">Mac OS X</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="installation/installation_windows.html">Windows 7 and Windows Server 2008</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="installation/installation_windows.html#activate-iis-with-cgi-support">Activate IIS with CGI Support</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="installation/installation_windows.html#installing-php">Installing PHP</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="installation/installation_windows.html#installing-mysql">Installing MySQL</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="installation/installation_windows.html#installing-owncloud">Installing ownCloud</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="installation/installation_windows.html#ensure-proper-http-verb-handling">Ensure Proper HTTP-Verb handling</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="installation/installation_windows.html#configuring-owncloud-php-and-iis-for-large-file-uploads">Configuring ownCloud, PHP and IIS for Large File Uploads</a></li>
 +</ul>
 +</li>
 +<li class="toctree-l2"><a class="reference internal" href="installation/installation_ucs.html">Univention Corporate Server</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="installation/installation_ucs.html#pre-configuration">Pre configuration</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="installation/installation_ucs.html#installation">Installation</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="installation/installation_ucs.html#postconfiguration-optional">Postconfiguration (optional)</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="installation/installation_ucs.html#using-owncloud">Using ownCloud</a></li>
 +</ul>
 +</li>
 +<li class="toctree-l2"><a class="reference internal" href="installation/installation_source.html">Manual Installation</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="installation/installation_source.html#prerequisites">Prerequisites</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="installation/installation_source.html#download-extract-and-copy-owncloud-to-your-web-server">Download, extract and copy ownCloud to Your Web Server</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="installation/installation_source.html#set-the-directory-permissions">Set the Directory Permissions</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="installation/installation_source.html#web-server-configuration">Web Server Configuration</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="installation/installation_source.html#follow-the-install-wizard">Follow the Install Wizard</a></li>
++<li class="toctree-l3"><a class="reference internal" href="installation/installation_source.html#note">Note</a></li>
 +</ul>
 +</li>
 +<li class="toctree-l2"><a class="reference internal" href="installation/installation_others.html">PageKite Configuration</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="installation/installation_others.html#open-wrt">Open Wrt</a></li>
 +</ul>
 +</li>
 +<li class="toctree-l1"><a class="reference internal" href="configuration/index.html">Configuration</a><ul>
- <li class="toctree-l2"><a class="reference internal" href="configuration/configuration_apps.html">Apps Configuration</a><ul>
++<li class="toctree-l2"><a class="reference internal" href="configuration/configuration_apps.html">Managing Apps</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="configuration/configuration_apps.html#parameters">Parameters</a></li>
 +</ul>
 +</li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration/configuration_users.html">User Management</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="configuration/configuration_users.html#users">Users</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="configuration/configuration_users.html#user-groups">User Groups</a></li>
 +</ul>
 +</li>
- <li class="toctree-l2"><a class="reference internal" href="configuration/auth_ldap.html">User Authentication with LDAP</a><ul>
++<li class="toctree-l2"><a class="reference internal" href="configuration/auth_ldap.html">LDAP Authentication</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="configuration/auth_ldap.html#configuration">Configuration</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="configuration/auth_ldap.html#advanced-settings">Advanced Settings</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="configuration/auth_ldap.html#expert-settings">Expert Settings</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="configuration/auth_ldap.html#testing-the-configuration">Testing the configuration</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="configuration/auth_ldap.html#owncloud-avatar-integration">ownCloud Avatar integration</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="configuration/auth_ldap.html#troubleshooting-tips-and-tricks">Troubleshooting, Tips and Tricks</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="configuration/auth_ldap.html#ssl-certificate-verification-ldaps-tls">SSL Certificate Verification (LDAPS, TLS)</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="configuration/auth_ldap.html#microsoft-active-directory">Microsoft Active Directory</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="configuration/auth_ldap.html#duplicating-server-configurations">Duplicating Server Configurations</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="configuration/auth_ldap.html#owncloud-ldap-internals">ownCloud LDAP Internals</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="configuration/auth_ldap.html#groups">Groups</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="configuration/auth_ldap.html#user-and-group-mapping">User and Group Mapping</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="configuration/auth_ldap.html#caching">Caching</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="configuration/auth_ldap.html#handling-with-backup-server">Handling with Backup Server</a></li>
 +</ul>
 +</li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration/background_jobs.html">Background Jobs</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="configuration/background_jobs.html#parameters">Parameters</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="configuration/background_jobs.html#cron-jobs">Cron-Jobs</a></li>
 +</ul>
 +</li>
- <li class="toctree-l2"><a class="reference internal" href="configuration/configuration_3rdparty.html">3rd-Party Configuration</a><ul>
++<li class="toctree-l2"><a class="reference internal" href="configuration/configuration_3rdparty.html">Find Third-Party Libraries</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="configuration/configuration_3rdparty.html#parameters">Parameters</a></li>
 +</ul>
 +</li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration/configuration_automation.html">Automatic Configuration</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="configuration/configuration_automation.html#parameters">Parameters</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="configuration/configuration_automation.html#sample-automatic-configurations">Sample Automatic Configurations</a></li>
 +</ul>
 +</li>
- <li class="toctree-l2"><a class="reference internal" href="configuration/configuration_custom_clients.html">Custom Client Configuration</a><ul>
++<li class="toctree-l2"><a class="reference internal" href="configuration/configuration_custom_clients.html">Customizing Client Download Links</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="configuration/configuration_custom_clients.html#parameters">Parameters</a></li>
 +</ul>
 +</li>
- <li class="toctree-l2"><a class="reference internal" href="configuration/configuration_database.html">Database Configuration</a><ul>
++<li class="toctree-l2"><a class="reference internal" href="configuration/configuration_database.html">MySQL/Postgres/SQLite Support</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="configuration/configuration_database.html#requirements">Requirements</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="configuration/configuration_database.html#parameters">Parameters</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="configuration/configuration_database.html#trouble-shooting">Trouble Shooting</a></li>
 +</ul>
 +</li>
- <li class="toctree-l2"><a class="reference internal" href="configuration/configuration_encryption.html">Use Server-Side Encryption</a><ul>
++<li class="toctree-l2"><a class="reference internal" href="configuration/configuration_encryption.html">Using Server-Side Encryption</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="configuration/configuration_encryption.html#enable-file-recovery-feature">Enable File Recovery Feature</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="configuration/configuration_encryption.html#recover-user-files">Recover User Files</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="configuration/configuration_encryption.html#ldap-and-other-external-user-back-ends">LDAP and other external user back-ends</a></li>
 +</ul>
 +</li>
- <li class="toctree-l2"><a class="reference internal" href="configuration/configuration_knowledgebase.html">Knowledge Base Configuration</a><ul>
++<li class="toctree-l2"><a class="reference internal" href="configuration/configuration_knowledgebase.html">Disable Knowledge Base</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="configuration/configuration_knowledgebase.html#parameters">Parameters</a></li>
 +</ul>
 +</li>
- <li class="toctree-l2"><a class="reference internal" href="configuration/configuration_language.html">Language Configuration</a><ul>
++<li class="toctree-l2"><a class="reference internal" href="configuration/configuration_language.html">Setting the Default Language</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="configuration/configuration_language.html#parameters">Parameters</a></li>
 +</ul>
 +</li>
- <li class="toctree-l2"><a class="reference internal" href="configuration/configuration_logging.html">Logging Configuration</a><ul>
++<li class="toctree-l2"><a class="reference internal" href="configuration/configuration_logging.html">Configure Logging</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="configuration/configuration_logging.html#parameters">Parameters</a></li>
 +</ul>
 +</li>
- <li class="toctree-l2"><a class="reference internal" href="configuration/configuration_mail.html">Mail Configuration</a><ul>
++<li class="toctree-l2"><a class="reference internal" href="configuration/configuration_mail.html">Sending Mail Notifications</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="configuration/configuration_mail.html#requirements">Requirements</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="configuration/configuration_mail.html#parameters">Parameters</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="configuration/configuration_mail.html#send-a-test-email">Send a Test Email</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="configuration/configuration_mail.html#trouble-shooting">Trouble shooting</a></li>
 +</ul>
 +</li>
- <li class="toctree-l2"><a class="reference internal" href="configuration/configuration_maintenance.html">Maintenance Mode Configuration</a><ul>
++<li class="toctree-l2"><a class="reference internal" href="configuration/configuration_maintenance.html">Enable Maintenance Mode</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="configuration/configuration_maintenance.html#parameters">Parameters</a></li>
 +</ul>
 +</li>
- <li class="toctree-l2"><a class="reference internal" href="configuration/configuration_preview.html">Preview Configuration</a><ul>
++<li class="toctree-l2"><a class="reference internal" href="configuration/configuration_preview.html">Enabling File Previews</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="configuration/configuration_preview.html#soft-dependencies">Soft dependencies:</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="configuration/configuration_preview.html#parameters">Parameters</a></li>
 +</ul>
 +</li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration/configuration_reverseproxy.html">Reverse Proxy Configuration</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="configuration/configuration_reverseproxy.html#parameters">Parameters</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="configuration/configuration_reverseproxy.html#example">Example</a></li>
 +</ul>
 +</li>
- <li class="toctree-l2"><a class="reference internal" href="configuration/configuring_big_file_upload.html">Uploading big files > 512MB (as set by default)</a><ul>
++<li class="toctree-l2"><a class="reference internal" href="configuration/configuring_big_file_upload.html">Dealing with Big File Uploads</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="configuration/configuring_big_file_upload.html#not-outnumberable-upload-limits">Not outnumberable upload limits:</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="configuration/configuring_big_file_upload.html#other-recommendable-preconditions">Other recommendable preconditions:</a></li>
++<li class="toctree-l3"><a class="reference internal" href="configuration/configuring_big_file_upload.html#enabling-uploading-big-files">Enabling uploading big files</a></li>
 +</ul>
 +</li>
- <li class="toctree-l2"><a class="reference internal" href="configuration/configuring_big_file_upload.html#enabling-uploading-big-files">Enabling uploading big files</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration/custom_mount_config_gui.html">Custom Mount Configuration Web-GUI</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="configuration/custom_mount_config_gui.html#id1">Dropbox</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="configuration/custom_mount_config_gui.html#id2">Google Drive</a></li>
 +</ul>
 +</li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration/custom_mount_config.html">Custom Mount Configuration</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="configuration/custom_mount_config.html#example">Example</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="configuration/custom_mount_config.html#backends">Backends</a></li>
 +</ul>
 +</li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration/custom_user_backend.html">Custom User Backend Configuration</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="configuration/custom_user_backend.html#imap">IMAP</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="configuration/custom_user_backend.html#smb">SMB</a></li>
 +</ul>
 +</li>
 +<li class="toctree-l2"><a class="reference internal" href="configuration/xsendfile.html">Serving static files via web server</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="configuration/xsendfile.html#apache2-x-sendfile">Apache2 (X-Sendfile)</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="configuration/xsendfile.html#lighttpd-x-sendfile2">LigHTTPd (X-Sendfile2)</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="configuration/xsendfile.html#nginx-x-accel-redirect">Nginx (X-Accel-Redirect)</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="configuration/xsendfile.html#how-to-check-if-it-s-working">How to check if it’s working?</a></li>
 +</ul>
 +</li>
 +</ul>
 +</li>
++<li class="toctree-l1"><a class="reference internal" href="apps/index.html">Apps</a><ul>
++<li class="toctree-l2"><a class="reference internal" href="apps/activity/index.html">Activity</a><ul>
++<li class="toctree-l3"><a class="reference internal" href="apps/activity/index.html#configuration">Configuration</a></li>
++<li class="toctree-l3"><a class="reference internal" href="apps/activity/index.html#utilization">Utilization</a></li>
++<li class="toctree-l3"><a class="reference internal" href="apps/activity/index.html#rss-feed">RSS Feed</a></li>
++</ul>
++</li>
++<li class="toctree-l2"><a class="reference internal" href="apps/admin_dependencies_chk/index.html">Finding Deployment Dependencies</a><ul>
++<li class="toctree-l3"><a class="reference internal" href="apps/admin_dependencies_chk/index.html#configuration">Configuration</a></li>
++<li class="toctree-l3"><a class="reference internal" href="apps/admin_dependencies_chk/index.html#utilization">Utilization</a></li>
++</ul>
++</li>
++<li class="toctree-l2"><a class="reference internal" href="apps/files_antivirus/index.html">File Antivirus Engine</a><ul>
++<li class="toctree-l3"><a class="reference internal" href="apps/files_antivirus/index.html#configuration">Configuration</a></li>
++</ul>
++</li>
++<li class="toctree-l2"><a class="reference internal" href="apps/files_encryption/index.html">Encryption</a><ul>
++<li class="toctree-l3"><a class="reference internal" href="apps/files_encryption/index.html#what-gets-encrypted">What gets encrypted?</a></li>
++<li class="toctree-l3"><a class="reference internal" href="apps/files_encryption/index.html#decrypting-the-data">Decrypting the data</a></li>
++<li class="toctree-l3"><a class="reference internal" href="apps/files_encryption/index.html#configuration">Configuration</a></li>
++<li class="toctree-l3"><a class="reference internal" href="apps/files_encryption/index.html#file-systems">File Systems</a></li>
++</ul>
++</li>
++<li class="toctree-l2"><a class="reference internal" href="apps/files_external/index.html">External storage support</a><ul>
++<li class="toctree-l3"><a class="reference internal" href="apps/files_external/index.html#supported-mounts">Supported mounts</a></li>
++<li class="toctree-l3"><a class="reference internal" href="apps/files_external/index.html#configuration">Configuration</a></li>
++</ul>
++</li>
++<li class="toctree-l2"><a class="reference internal" href="apps/files_sharing/index.html">Sharing</a><ul>
++<li class="toctree-l3"><a class="reference internal" href="apps/files_sharing/index.html#configuration">Configuration</a></li>
++<li class="toctree-l3"><a class="reference internal" href="apps/files_sharing/index.html#utilization">Utilization</a></li>
++<li class="toctree-l3"><a class="reference internal" href="apps/files_sharing/index.html#retrieving-shared-data">Retrieving shared data</a></li>
++</ul>
++</li>
++<li class="toctree-l2"><a class="reference internal" href="apps/files_trashbin/index.html">Deleted Files</a><ul>
++<li class="toctree-l3"><a class="reference internal" href="apps/files_trashbin/index.html#expiry-of-deleted-files">Expiry of deleted files</a></li>
++<li class="toctree-l3"><a class="reference internal" href="apps/files_trashbin/index.html#configuration-and-storage">Configuration and storage</a></li>
++<li class="toctree-l3"><a class="reference internal" href="apps/files_trashbin/index.html#utilization">Utilization</a></li>
++</ul>
++</li>
++<li class="toctree-l2"><a class="reference internal" href="apps/files_versions/index.html">Versions</a><ul>
++<li class="toctree-l3"><a class="reference internal" href="apps/files_versions/index.html#expiry-of-versions">Expiry of versions</a></li>
++<li class="toctree-l3"><a class="reference internal" href="apps/files_versions/index.html#space-limitations">Space limitations</a></li>
++<li class="toctree-l3"><a class="reference internal" href="apps/files_versions/index.html#configuration-and-storage">Configuration and storage</a></li>
++<li class="toctree-l3"><a class="reference internal" href="apps/files_versions/index.html#utilization">Utilization</a></li>
++</ul>
++</li>
++<li class="toctree-l2"><a class="reference internal" href="apps/firstrunwizard/index.html">First Run Wizard</a><ul>
++<li class="toctree-l3"><a class="reference internal" href="apps/firstrunwizard/index.html#configuration">Configuration</a></li>
++<li class="toctree-l3"><a class="reference internal" href="apps/firstrunwizard/index.html#usage">Usage</a></li>
++<li class="toctree-l3"><a class="reference internal" href="apps/firstrunwizard/index.html#links">Links</a></li>
++</ul>
++</li>
++<li class="toctree-l2"><a class="reference internal" href="apps/user_ldap/index.html">LDAP user and group backend</a><ul>
++<li class="toctree-l3"><a class="reference internal" href="apps/user_ldap/index.html#configuration">Configuration</a></li>
++</ul>
++</li>
++<li class="toctree-l2"><a class="reference internal" href="apps/viewers/index.html">File Viewers</a><ul>
++<li class="toctree-l3"><a class="reference internal" href="apps/viewers/index.html#configuration">Configuration</a></li>
++<li class="toctree-l3"><a class="reference internal" href="apps/viewers/index.html#utilization">Utilization</a></li>
++</ul>
++</li>
++</ul>
++</li>
 +<li class="toctree-l1"><a class="reference internal" href="maintenance/index.html">Maintenance</a><ul>
 +<li class="toctree-l2"><a class="reference internal" href="maintenance/backup.html">Backing up ownCloud</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="maintenance/backup.html#backup-folders">Backup Folders</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="maintenance/backup.html#backup-database">Backup Database</a></li>
 +</ul>
 +</li>
 +<li class="toctree-l2"><a class="reference internal" href="maintenance/update.html">Updating ownCloud</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="maintenance/update.html#update">Update</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="maintenance/update.html#upgrade">Upgrade</a></li>
 +</ul>
 +</li>
 +<li class="toctree-l2"><a class="reference internal" href="maintenance/restore.html">Restoring ownCloud</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="maintenance/restore.html#restore-folders">Restore Folders</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="maintenance/restore.html#restore-database">Restore Database</a></li>
 +</ul>
 +</li>
 +<li class="toctree-l2"><a class="reference internal" href="maintenance/migrating.html">Migrating ownCloud Installations</a></li>
 +</ul>
 +</li>
++<li class="toctree-l1"><a class="reference internal" href="config/index.html">The Configuration File</a><ul>
++</ul>
++</li>
 +<li class="toctree-l1"><a class="reference internal" href="issues/index.html">Issues</a></li>
 +</ul>
 +</div>
 +<div class="section" id="indices-and-tables">
 +<h2>Indices and tables<a class="headerlink" href="#indices-and-tables" title="Permalink to this headline">¶</a></h2>
 +<ul class="simple">
 +<li><a class="reference internal" href="genindex.html"><em>Index</em></a></li>
 +</ul>
 +</div>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/cron/index.html
index 1e32757,0000000..ec0efe8
mode 100644,000000..100644
--- a/core/doc/admin/cron/index.html
+++ b/core/doc/admin/cron/index.html
@@@ -1,148 -1,0 +1,174 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
-     <title><no title> — ownCloud Administrators Manual 6.0 documentation</title>
++    <title>Driving Events with Cron — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
 +<ul>
 +<li class="toctree-l1"><a class="reference internal" href="../installation/index.html">Installation</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../configuration/index.html">Configuration</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
-   <p><strong>ownCloud cron.php</strong></p>
- <div class="toctree-wrapper compound">
- <ul>
- <li class="toctree-l1"><a class="reference internal" href="Introduction.html">Introduction</a></li>
- <li class="toctree-l1"><a class="reference internal" href="Usage.html">Usage</a></li>
- </ul>
++  <div class="section" id="driving-events-with-cron">
++<h1>Driving Events with Cron<a class="headerlink" href="#driving-events-with-cron" title="Permalink to this headline">¶</a></h1>
++<div class="section" id="introduction">
++<h2>Introduction<a class="headerlink" href="#introduction" title="Permalink to this headline">¶</a></h2>
++<p>ownCloud is written in PHP, and because PHP is a request driven language – in
++other words it runs only when a client takes an action and calls php, and then
++it executes and ends – it does not have a built in CRON process. Instead,
++ownCloud provides <tt class="docutils literal"><span class="pre">cron.php</span></tt>, which is called by the server’s CRON daemon.
++<tt class="docutils literal"><span class="pre">cron.php</span></tt> is an ownCloud internal process that runs various background jobs
++on demand.  It is called by the server cron, and can be set by the
++administrator.</p>
++<p>ownCloud plug-in applications register actions with <tt class="docutils literal"><span class="pre">cron.php</span></tt> automatically to
++take care of typical housekeeping operations, such as garbage collecting of
++temporary files or checking for newly updated files using <tt class="docutils literal"><span class="pre">filescan()</span></tt> for
++externally mounted file systems.</p>
++</div>
++<div class="section" id="usage">
++<h2>Usage<a class="headerlink" href="#usage" title="Permalink to this headline">¶</a></h2>
++<p>The interval at which this script is executed, and thus the ownCloud registered
++actions, can depend on the size of the installation and the load of the system.
++Recommended intervals are 15 or 30 minutes.</p>
++<p>Cron.php needs to be called by the system’s cron daemon and run as the same
++user the web server runs as.</p>
++<p>As an example, on an ordinary Linux distribution, place the following in the
++webserver’s user’s crontab:</p>
++<div class="highlight-python"><pre>*/15 * * * * /usr/bin/php -f /srv/http/owncloud/cron.php /dev/null 2>&1</pre>
++</div>
++<p>This will run <tt class="docutils literal"><span class="pre">cron.php</span></tt> every 15 minutes and suppress any warnings or output
++which may be generated.</p>
++</div>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/genindex.html
index 7ae01da,0000000..ea567fb
mode 100644,000000..100644
--- a/core/doc/admin/genindex.html
+++ b/core/doc/admin/genindex.html
@@@ -1,149 -1,0 +1,151 @@@
 +
 +
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
 +    <title>Index — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="_static/jquery.js"></script>
 +    <script type="text/javascript" src="_static/underscore.js"></script>
 +    <script type="text/javascript" src="_static/doctools.js"></script>
 +    <script type="text/javascript" src="_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="index.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
 +<ul>
 +<li class="toctree-l1"><a class="reference internal" href="installation/index.html">Installation</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="configuration/index.html">Configuration</a></li>
++<li class="toctree-l1"><a class="reference internal" href="apps/index.html">Apps</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1"><a class="reference internal" href="config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
 +
 +<h1 id="index">Index</h1>
 +
 +<div class="genindex-jumpbox">
 + 
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/index.html
index b0a5342,7785f2c..ef774bc
--- a/core/doc/admin/index.html
+++ b/core/doc/admin/index.html
@@@ -1,226 -1,2 +1,248 @@@
 -Here goes the admin documentation.
 -In the meantime go to <a href="http://owncloud.org/support/" target="_blank">ownCloud.org/support</a>
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
 +    <title>ownCloud 6.0 Admin Documentation — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="_static/jquery.js"></script>
 +    <script type="text/javascript" src="_static/underscore.js"></script>
 +    <script type="text/javascript" src="_static/doctools.js"></script>
 +    <script type="text/javascript" src="_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="#" />
 +    <link rel="next" title="Installation" href="installation/index.html" />
 +    <link rel="prev" title="ownCloud documentation contents" href="contents.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="contents.html">Overview</a></li>
 +									</ul>
 +                  <ul class="current">
 +<li class="toctree-l1 current"><a class="current reference internal" href="">ownCloud 6.0 Admin Documentation</a><ul>
 +<li class="toctree-l2"><a class="reference internal" href="#introduction">Introduction</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="#target-audience">Target audience</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#structure-of-this-document">Structure of this document</a></li>
 +</ul>
 +</li>
 +<li class="toctree-l2"><a class="reference internal" href="#installation">Installation</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="#configuration">Configuration</a></li>
++<li class="toctree-l2"><a class="reference internal" href="#apps">Apps</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="#maintenance">Maintenance</a></li>
 +</ul>
 +</li>
 +</ul>
 +<ul>
 +<li class="toctree-l1"><a class="reference internal" href="installation/index.html">Installation</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="configuration/index.html">Configuration</a></li>
++<li class="toctree-l1"><a class="reference internal" href="apps/index.html">Apps</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1"><a class="reference internal" href="config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
 +  <div class="section" id="owncloud-version-admin-documentation">
 +<h1>ownCloud 6.0 Admin Documentation<a class="headerlink" href="#owncloud-version-admin-documentation" title="Permalink to this headline">¶</a></h1>
 +<div class="section" id="introduction">
 +<h2>Introduction<a class="headerlink" href="#introduction" title="Permalink to this headline">¶</a></h2>
 +<p>This is the administrators manual for ownCloud, a flexible, open source file
 +sync and share solution. It comprises of the ownCloud server, as well as client
 +applications for Microsoft Windows, Mac OS X and Linux (Desktop Client) and
 +mobile clients for the Android and Apple iOS operating system.</p>
 +<div class="section" id="target-audience">
 +<h3>Target audience<a class="headerlink" href="#target-audience" title="Permalink to this headline">¶</a></h3>
 +<p>This guide is targeted towards people who want to install, administer and
 +optimize ownCloud Server. If you want to learn how to use the Web UI, or how to
 +install clients on the server, please refer to the <a class="reference external" href="http://doc.owncloud.com/">User Manual</a> or the <a class="reference external" href="http://doc.owncloud.com/">Desktop
 +Client Manual</a> respectively.</p>
 +</div>
 +<div class="section" id="structure-of-this-document">
 +<h3>Structure of this document<a class="headerlink" href="#structure-of-this-document" title="Permalink to this headline">¶</a></h3>
 +<p>The next chapters describes how to set up ownCloud Server on different platforms
 +and operating systems, as well as how to update existing installations.</p>
 +<p>Further chapters will then detail on integrating ownCloud into your existing
 +environment, e.g. how to setup LDAP or how to mount your storage.</p>
 +</div>
 +</div>
 +<div class="section" id="installation">
 +<h2>Installation<a class="headerlink" href="#installation" title="Permalink to this headline">¶</a></h2>
 +<p>This chapter will introduce you to the installation of ownCloud in different scenarios.</p>
 +<p>If you want to just try ownCloud in a virtual machine without any configuration, check the section
 +<a class="reference internal" href="installation/installation_appliance.html"><em>Appliances</em></a>, where you will find ready-to-use images.</p>
 +<ul class="simple">
 +<li><a class="reference internal" href="installation/installation_linux.html"><em>Linux Distributions</em></a> (recommended)</li>
 +<li><a class="reference internal" href="installation/installation_windows.html"><em>Windows 7 and Windows Server 2008</em></a></li>
 +<li><a class="reference internal" href="installation/installation_source.html"><em>Manual Installation</em></a></li>
 +<li><a class="reference internal" href="installation/installation_others.html"><em>PageKite Configuration</em></a></li>
 +<li><a class="reference internal" href="installation/installation_ucs.html"><em>Univention Corporate Server</em></a></li>
 +<li><a class="reference internal" href="installation/installation_macos.html"><em>Mac OS X</em></a> (not supported)</li>
 +<li><a class="reference internal" href="installation/installation_appliance.html"><em>Appliances</em></a></li>
 +</ul>
 +</div>
 +<div class="section" id="configuration">
 +<h2>Configuration<a class="headerlink" href="#configuration" title="Permalink to this headline">¶</a></h2>
 +<p>This chapter covers ownCloud and web server configuration.</p>
 +<ul class="simple">
- <li><a class="reference internal" href="configuration/configuration_apps.html"><em>Apps Configuration</em></a></li>
++<li><a class="reference internal" href="configuration/configuration_apps.html"><em>Managing Apps</em></a></li>
 +<li><a class="reference internal" href="configuration/configuration_users.html"><em>User Management</em></a></li>
- <li><a class="reference internal" href="configuration/configuration_database.html"><em>Database Configuration</em></a></li>
- <li><a class="reference internal" href="configuration/auth_ldap.html"><em>User Authentication with LDAP</em></a></li>
++<li><a class="reference internal" href="configuration/configuration_database.html"><em>MySQL/Postgres/SQLite Support</em></a></li>
++<li><a class="reference internal" href="configuration/auth_ldap.html"><em>LDAP Authentication</em></a></li>
 +<li><a class="reference internal" href="configuration/custom_mount_config_gui.html"><em>Custom Mount Configuration Web-GUI</em></a></li>
 +<li><a class="reference internal" href="configuration/custom_mount_config.html"><em>Custom Mount Configuration</em></a></li>
 +<li><a class="reference internal" href="configuration/background_jobs.html"><em>Background Jobs</em></a></li>
- <li><a class="reference internal" href="configuration/configuration_mail.html"><em>Mail Configuration</em></a></li>
++<li><a class="reference internal" href="configuration/configuration_mail.html"><em>Sending Mail Notifications</em></a></li>
 +<li><a class="reference internal" href="configuration/configuration_automation.html"><em>Automatic Configuration</em></a></li>
- <li><a class="reference internal" href="configuration/configuration_encryption.html"><em>Use Server-Side Encryption</em></a></li>
- <li><a class="reference internal" href="configuration/configuring_big_file_upload.html"><em>Uploading big files > 512MB (as set by default)</em></a></li>
++<li><a class="reference internal" href="configuration/configuration_encryption.html"><em>Using Server-Side Encryption</em></a></li>
++<li><a class="reference internal" href="configuration/configuring_big_file_upload.html"><em>Dealing with Big File Uploads</em></a></li>
 +<li><a class="reference internal" href="configuration/configuration_reverseproxy.html"><em>Reverse Proxy Configuration</em></a></li>
 +<li><a class="reference internal" href="configuration/xsendfile.html"><em>Serving static files via web server</em></a></li>
- <li><a class="reference internal" href="configuration/configuration_3rdparty.html"><em>3rd-Party Configuration</em></a></li>
++<li><a class="reference internal" href="configuration/configuration_3rdparty.html"><em>Find Third-Party Libraries</em></a></li>
 +<li><a class="reference internal" href="configuration/custom_user_backend.html"><em>Custom User Backend Configuration</em></a></li>
- <li><a class="reference internal" href="configuration/configuration_custom_clients.html"><em>Custom Client Configuration</em></a></li>
- <li><a class="reference internal" href="configuration/configuration_maintenance.html"><em>Maintenance Mode Configuration</em></a></li>
- <li><a class="reference internal" href="configuration/configuration_knowledgebase.html"><em>Knowledge Base Configuration</em></a></li>
- <li><a class="reference internal" href="configuration/configuration_logging.html"><em>Logging Configuration</em></a></li>
- <li><a class="reference internal" href="configuration/configuration_language.html"><em>Language Configuration</em></a></li>
++<li><a class="reference internal" href="configuration/configuration_custom_clients.html"><em>Customizing Client Download Links</em></a></li>
++<li><a class="reference internal" href="configuration/configuration_maintenance.html"><em>Enable Maintenance Mode</em></a></li>
++<li><a class="reference internal" href="configuration/configuration_knowledgebase.html"><em>Disable Knowledge Base</em></a></li>
++<li><a class="reference internal" href="configuration/configuration_logging.html"><em>Configure Logging</em></a></li>
++<li><a class="reference internal" href="configuration/configuration_language.html"><em>Setting the Default Language</em></a></li>
++</ul>
++<p>Finally, the chapter <a class="reference internal" href="config/index.html"><em>The Configuration File</em></a> details on the switches
++in the <tt class="docutils literal"><span class="pre">config.php</span></tt> file.</p>
++</div>
++<div class="section" id="apps">
++<h2>Apps<a class="headerlink" href="#apps" title="Permalink to this headline">¶</a></h2>
++<p>This chapter covers individual ownCloud apps.</p>
++<ul class="simple">
++<li><a class="reference internal" href="apps/activity/index.html"><em>Activity</em></a></li>
++<li><a class="reference internal" href="apps/admin_dependencies_chk/index.html"><em>Finding Deployment Dependencies</em></a></li>
++<li><a class="reference internal" href="apps/files_antivirus/index.html"><em>File Antivirus Engine</em></a></li>
++<li><a class="reference internal" href="apps/files_encryption/index.html"><em>Encryption</em></a></li>
++<li><a class="reference internal" href="apps/files_external/index.html"><em>External storage support</em></a></li>
++<li><a class="reference internal" href="apps/files_sharing/index.html"><em>Sharing</em></a></li>
++<li><a class="reference internal" href="apps/files_trashbin/index.html"><em>Deleted Files</em></a></li>
++<li><a class="reference internal" href="apps/files_versions/index.html"><em>Versions</em></a></li>
++<li><a class="reference internal" href="apps/firstrunwizard/index.html"><em>First Run Wizard</em></a></li>
++<li><a class="reference internal" href="apps/user_ldap/index.html"><em>LDAP user and group backend</em></a></li>
++<li><a class="reference internal" href="apps/viewers/index.html"><em>File Viewers</em></a></li>
 +</ul>
 +</div>
 +<div class="section" id="maintenance">
 +<h2>Maintenance<a class="headerlink" href="#maintenance" title="Permalink to this headline">¶</a></h2>
 +<p>This chapter covers maintenance tasks such as updating or migrating to a new version.</p>
 +<ul class="simple">
 +<li><a class="reference internal" href="maintenance/migrating.html"><em>Migrating ownCloud Installations</em></a></li>
 +<li><a class="reference internal" href="maintenance/update.html"><em>Updating ownCloud</em></a></li>
 +</ul>
 +</div>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/installation/index.html
index cc8010b,0000000..7d8ff3c
mode 100644,000000..100644
--- a/core/doc/admin/installation/index.html
+++ b/core/doc/admin/installation/index.html
@@@ -1,168 -1,0 +1,170 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
 +    <title>Installation — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
 +    <link rel="next" title="Appliances" href="installation_appliance.html" />
 +    <link rel="prev" title="ownCloud 6.0 Admin Documentation" href="../index.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
 +<ul class="current">
 +<li class="toctree-l1 current"><a class="current reference internal" href="">Installation</a><ul>
 +<li class="toctree-l2"><a class="reference internal" href="installation_appliance.html">Appliances</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="installation_linux.html">Linux Distributions</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="installation_macos.html">Mac OS X</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="installation_windows.html">Windows 7 and Windows Server 2008</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="installation_ucs.html">Univention Corporate Server</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="installation_source.html">Manual Installation</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="installation_others.html">PageKite Configuration</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="installation_others.html#open-wrt">Open Wrt</a></li>
 +</ul>
 +</li>
 +<li class="toctree-l1"><a class="reference internal" href="../configuration/index.html">Configuration</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
 +  <div class="section" id="installation">
 +<h1>Installation<a class="headerlink" href="#installation" title="Permalink to this headline">¶</a></h1>
 +<div class="toctree-wrapper compound">
 +<ul>
 +<li class="toctree-l1"><a class="reference internal" href="installation_appliance.html">Appliances</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="installation_linux.html">Linux Distributions</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="installation_macos.html">Mac OS X</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="installation_windows.html">Windows 7 and Windows Server 2008</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="installation_ucs.html">Univention Corporate Server</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="installation_source.html">Manual Installation</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="installation_others.html">PageKite Configuration</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="installation_others.html#open-wrt">Open Wrt</a></li>
 +</ul>
 +</div>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/installation/installation_appliance.html
index 82e78c5,0000000..a6207a8
mode 100644,000000..100644
--- a/core/doc/admin/installation/installation_appliance.html
+++ b/core/doc/admin/installation/installation_appliance.html
@@@ -1,185 -1,0 +1,187 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
 +    <title>Appliances — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
 +    <link rel="up" title="Installation" href="index.html" />
 +    <link rel="next" title="Linux Distributions" href="installation_linux.html" />
 +    <link rel="prev" title="Installation" href="index.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
 +<ul class="current">
 +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Installation</a><ul class="current">
 +<li class="toctree-l2 current"><a class="current reference internal" href="">Appliances</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="#software-appliances">Software Appliances</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#owncloud-on-hardware-appliances">ownCloud on Hardware Appliances</a></li>
 +</ul>
 +</li>
 +<li class="toctree-l2"><a class="reference internal" href="installation_linux.html">Linux Distributions</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="installation_macos.html">Mac OS X</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="installation_windows.html">Windows 7 and Windows Server 2008</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="installation_ucs.html">Univention Corporate Server</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="installation_source.html">Manual Installation</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="installation_others.html">PageKite Configuration</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="installation_others.html#open-wrt">Open Wrt</a></li>
 +</ul>
 +</li>
 +<li class="toctree-l1"><a class="reference internal" href="../configuration/index.html">Configuration</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
 +  <div class="section" id="appliances">
 +<h1>Appliances<a class="headerlink" href="#appliances" title="Permalink to this headline">¶</a></h1>
 +<p>If you are looking for virtual machine images, check the Software Appliances
 +section.  The Hardware Appliances section is of interest for people seeking to
 +run ownCloud on appliance hardware (i.e. NAS filers, routers, etc.).</p>
 +<div class="section" id="software-appliances">
 +<h2>Software Appliances<a class="headerlink" href="#software-appliances" title="Permalink to this headline">¶</a></h2>
 +<p>There are number of pre-made virtual machine-based appliances:</p>
 +<ul class="simple">
 +<li><a class="reference external" href="http://susestudio.com/a/TadMax/owncloud-in-a-box">SUSE Studio, ownCloud on openSuSE</a>, runnable directly from an USB stick.</li>
 +<li><a class="reference external" href="http://jujucharms.com/charms/precise/owncloud">Ubuntu charm, ownCloud</a></li>
 +</ul>
 +</div>
 +<div class="section" id="owncloud-on-hardware-appliances">
 +<h2>ownCloud on Hardware Appliances<a class="headerlink" href="#owncloud-on-hardware-appliances" title="Permalink to this headline">¶</a></h2>
 +<p>These are tutorials provided by the user communities of the respective appliances:</p>
 +<ul class="simple">
 +<li><a class="reference external" href="http://wiki.qnap.com/wiki/Category:OwnCloud">QNAP Guide</a> for QNAP NAS appliances</li>
 +<li><a class="reference external" href="http://wiki.openwrt.org/doc/howto/owncloud">OpenWrt Guide</a> for the popular embedded distribution for routers and NAS devices.</li>
 +<li><a class="reference external" href="http://www.cphub.net/index.php?id=40&pid=213">Synology Package</a> for Synology NAS products</li>
 +</ul>
 +<div class="admonition-todo admonition" id="index-0">
 +<p class="first admonition-title">Todo</p>
 +<p class="last">Tutorials for running ownCloud on Dreamplug.</p>
 +</div>
 +</div>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/installation/installation_linux.html
index 5556911,0000000..d3bad13
mode 100644,000000..100644
--- a/core/doc/admin/installation/installation_linux.html
+++ b/core/doc/admin/installation/installation_linux.html
@@@ -1,172 -1,0 +1,174 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
 +    <title>Linux Distributions — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
 +    <link rel="up" title="Installation" href="index.html" />
 +    <link rel="next" title="Mac OS X" href="installation_macos.html" />
 +    <link rel="prev" title="Appliances" href="installation_appliance.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
 +<ul class="current">
 +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Installation</a><ul class="current">
 +<li class="toctree-l2"><a class="reference internal" href="installation_appliance.html">Appliances</a></li>
 +<li class="toctree-l2 current"><a class="current reference internal" href="">Linux Distributions</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="#supported-distribution-packages">Supported Distribution Packages</a></li>
 +</ul>
 +</li>
 +<li class="toctree-l2"><a class="reference internal" href="installation_macos.html">Mac OS X</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="installation_windows.html">Windows 7 and Windows Server 2008</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="installation_ucs.html">Univention Corporate Server</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="installation_source.html">Manual Installation</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="installation_others.html">PageKite Configuration</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="installation_others.html#open-wrt">Open Wrt</a></li>
 +</ul>
 +</li>
 +<li class="toctree-l1"><a class="reference internal" href="../configuration/index.html">Configuration</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
 +  <div class="section" id="linux-distributions">
 +<h1>Linux Distributions<a class="headerlink" href="#linux-distributions" title="Permalink to this headline">¶</a></h1>
 +<div class="section" id="supported-distribution-packages">
 +<h2>Supported Distribution Packages<a class="headerlink" href="#supported-distribution-packages" title="Permalink to this headline">¶</a></h2>
 +<p>Ready-to-use packages are available at <a class="reference external" href="http://software.opensuse.org/download.html?project=isv:ownCloud:community&package=owncloud">openSUSE Build Service</a> for a variety of Linux distributions.</p>
 +<p>If your distribution is not listed please follow <a class="reference internal" href="installation_source.html"><em>Manual Installation</em></a>.</p>
 +<div class="section" id="additional-installation-guides-and-notes">
 +<h3>Additional installation guides and notes<a class="headerlink" href="#additional-installation-guides-and-notes" title="Permalink to this headline">¶</a></h3>
 +<p><strong>Fedora:</strong> Make sure <a class="reference external" href="https://fedoraproject.org/wiki/SELinux_FAQ#How_do_I_enable_or_disable_SELinux_.3F">SELinux is disabled</a>
 +or else the installation process might fail.</p>
- <p><strong>Archlinux:</strong> There are two AUR packages for ownCloud: <a class="reference external" href="https://www.archlinux.org/packages/community/any/owncloud/">stable version</a> and <a class="reference external" href="http://aur.archlinux.org/packages.php?ID=38767">development version</a>.</p>
++<p><strong>Archlinux:</strong> The are two packages for ownCloud: <a class="reference external" href="https://www.archlinux.org/packages/community/any/owncloud/">stable version</a> in the official community repository and <a class="reference external" href="http://aur.archlinux.org/packages.php?ID=38767">development version</a> in AUR.</p>
 +<p><strong>PCLinuxOS:</strong> Follow the Tutorial <a class="reference external" href="http://pclinuxoshelp.com/index.php/Owncloud,_installation_and_setup">ownCloud, installation and setup</a> on the PCLinuxOS web site.</p>
 +</div>
 +</div>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/installation/installation_macos.html
index 0213942,0000000..8d6de74
mode 100644,000000..100644
--- a/core/doc/admin/installation/installation_macos.html
+++ b/core/doc/admin/installation/installation_macos.html
@@@ -1,162 -1,0 +1,164 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
 +    <title>Mac OS X — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
 +    <link rel="up" title="Installation" href="index.html" />
 +    <link rel="next" title="Windows 7 and Windows Server 2008" href="installation_windows.html" />
 +    <link rel="prev" title="Linux Distributions" href="installation_linux.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
 +<ul class="current">
 +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Installation</a><ul class="current">
 +<li class="toctree-l2"><a class="reference internal" href="installation_appliance.html">Appliances</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="installation_linux.html">Linux Distributions</a></li>
 +<li class="toctree-l2 current"><a class="current reference internal" href="">Mac OS X</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="installation_windows.html">Windows 7 and Windows Server 2008</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="installation_ucs.html">Univention Corporate Server</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="installation_source.html">Manual Installation</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="installation_others.html">PageKite Configuration</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="installation_others.html#open-wrt">Open Wrt</a></li>
 +</ul>
 +</li>
 +<li class="toctree-l1"><a class="reference internal" href="../configuration/index.html">Configuration</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
 +  <div class="section" id="mac-os-x">
 +<h1>Mac OS X<a class="headerlink" href="#mac-os-x" title="Permalink to this headline">¶</a></h1>
 +<div class="admonition note">
 +<p class="first admonition-title">Note</p>
 +<p class="last">Due to an <a class="reference external" href="https://github.com/owncloud/core/issues/2377">issue</a> with Mac OS Unicode support, installing ownCloud Server 6.0 on
 +Mac OS is currently not supported.</p>
 +</div>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/installation/installation_others.html
index 1a30b31,0000000..c832dc7
mode 100644,000000..100644
--- a/core/doc/admin/installation/installation_others.html
+++ b/core/doc/admin/installation/installation_others.html
@@@ -1,163 -1,0 +1,165 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
 +    <title>PageKite Configuration — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
 +    <link rel="up" title="Installation" href="index.html" />
 +    <link rel="next" title="Configuration" href="../configuration/index.html" />
 +    <link rel="prev" title="Manual Installation" href="installation_source.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
 +<ul class="current">
 +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Installation</a><ul class="current">
 +<li class="toctree-l2"><a class="reference internal" href="installation_appliance.html">Appliances</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="installation_linux.html">Linux Distributions</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="installation_macos.html">Mac OS X</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="installation_windows.html">Windows 7 and Windows Server 2008</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="installation_ucs.html">Univention Corporate Server</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="installation_source.html">Manual Installation</a></li>
 +<li class="toctree-l2 current"><a class="current reference internal" href="">PageKite Configuration</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="#open-wrt">Open Wrt</a></li>
 +</ul>
 +</li>
 +<li class="toctree-l1"><a class="reference internal" href="../configuration/index.html">Configuration</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
 +  <div class="section" id="pagekite-configuration">
 +<h1>PageKite Configuration<a class="headerlink" href="#pagekite-configuration" title="Permalink to this headline">¶</a></h1>
 +<p>You can use this <a class="reference external" href="https://pagekite.net/wiki/Howto/GNULinux/OwnCloud/">PageKite how to</a> to make your local ownCloud accessible from the
 +internet using PageKite.</p>
 +</div>
 +<div class="section" id="open-wrt">
 +<h1>Open Wrt<a class="headerlink" href="#open-wrt" title="Permalink to this headline">¶</a></h1>
 +<p>Here you can find a <a class="reference external" href="http://wiki.openwrt.org/doc/howto/owncloud">tutorial for open Wrt</a></p>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/installation/installation_source.html
index 02000c4,0000000..97bbc7d
mode 100644,000000..100644
--- a/core/doc/admin/installation/installation_source.html
+++ b/core/doc/admin/installation/installation_source.html
@@@ -1,698 -1,0 +1,829 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
 +    <title>Manual Installation — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
 +    <link rel="up" title="Installation" href="index.html" />
 +    <link rel="next" title="PageKite Configuration" href="installation_others.html" />
 +    <link rel="prev" title="Univention Corporate Server" href="installation_ucs.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
 +<ul class="current">
 +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Installation</a><ul class="current">
 +<li class="toctree-l2"><a class="reference internal" href="installation_appliance.html">Appliances</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="installation_linux.html">Linux Distributions</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="installation_macos.html">Mac OS X</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="installation_windows.html">Windows 7 and Windows Server 2008</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="installation_ucs.html">Univention Corporate Server</a></li>
 +<li class="toctree-l2 current"><a class="current reference internal" href="">Manual Installation</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="#prerequisites">Prerequisites</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#download-extract-and-copy-owncloud-to-your-web-server">Download, extract and copy ownCloud to Your Web Server</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#set-the-directory-permissions">Set the Directory Permissions</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#web-server-configuration">Web Server Configuration</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#follow-the-install-wizard">Follow the Install Wizard</a></li>
++<li class="toctree-l3"><a class="reference internal" href="#note">Note</a></li>
 +</ul>
 +</li>
 +<li class="toctree-l2"><a class="reference internal" href="installation_others.html">PageKite Configuration</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="installation_others.html#open-wrt">Open Wrt</a></li>
 +</ul>
 +</li>
 +<li class="toctree-l1"><a class="reference internal" href="../configuration/index.html">Configuration</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
 +  <div class="section" id="manual-installation">
 +<h1>Manual Installation<a class="headerlink" href="#manual-installation" title="Permalink to this headline">¶</a></h1>
 +<p>If you do not want to use packages, here is how you setup ownCloud on
- from scratch using a classic <abbr title="Linux, Apache, MySQL, PHP">LAMP</abbr> setup:</p>
++from scratch using a classic <abbr title="Linux, Apache, MySQL, PHP">LAMP</abbr> setup.</p>
 +<p>This document provides a complete walk-through for installing ownCloud
 +on Ubuntu 12.04 LTS Server with Apache and MySQL.
 +It also provides guidelines for installing it on other distributions,
 +webservers and database systems.</p>
++<p>Although this document tries to describe all aspects of setting up ownCloud,
++a basic understanding of the Linux operating system and of server administration
++is required.</p>
 +<div class="section" id="prerequisites">
 +<h2>Prerequisites<a class="headerlink" href="#prerequisites" title="Permalink to this headline">¶</a></h2>
 +<div class="admonition note">
 +<p class="first admonition-title">Note</p>
 +<p class="last">This tutorial assumes you have terminal access to the machine you want
 +to install owncloud on. Although this is not an absolute requirement,
 +installation without it is highly likely to require contacting your
 +hoster (e.g. for installing required modules).</p>
 +</div>
 +<p>To run ownCloud, your web server must have the following installed:</p>
 +<ul class="simple">
 +<li>PHP (>= 5.3.3 minimum, 5.4 or higher recommended)</li>
 +<li>PHP module ctype</li>
 +<li>PHP module dom</li>
 +<li>PHP module GD</li>
 +<li>PHP module iconv</li>
 +<li>PHP module JSON</li>
 +<li>PHP module libxml</li>
 +<li>PHP module mb multibyte</li>
 +<li>PHP module SimpleXML</li>
 +<li>PHP module zip</li>
 +<li>PHP module zlib</li>
 +</ul>
 +<p>Database connectors (pick at least one):</p>
 +<ul class="simple">
- <li>PHP module sqlite (>= 3, usually not recommendable for performance reasons)</li>
++<li>PHP module sqlite (requires sqlite >= 3.0; simple configuration, but inferior performance)</li>
 +<li>PHP module mysql</li>
 +<li>PHP module pgsql (requires PostgreSQL >= 9.0)</li>
 +</ul>
 +<p><em>Recommended</em> packages:</p>
 +<ul class="simple">
 +<li>PHP module curl (highly recommended, some functionality, e.g. http user
 +authentication, depends on this)</li>
 +<li>PHP module fileinfo (highly recommended, enhances file analysis performance)</li>
 +<li>PHP module bz2 (recommended, required for extraction of apps)</li>
 +<li>PHP module intl (increases language translation performance)</li>
 +<li>PHP module mcrypt (increases file encryption performance)</li>
 +<li>PHP module openssl (required for accessing HTTPS resources)</li>
 +</ul>
 +<p>Required for specific apps (if you use the mentioned app, you must install that
 +package):</p>
 +<ul class="simple">
 +<li>PHP module ldap (for ldap integration)</li>
 +<li>smbclient (for SMB storage)</li>
 +<li>PHP module ftp (for FTP storage)</li>
 +</ul>
 +<p>Recommended for specific apps (<em>optional</em>):</p>
 +<ul class="simple">
 +<li>PHP module exif (for image rotation in pictures app)</li>
 +</ul>
 +<p>For enhanced performance (<em>optional</em> / select only one of the following):</p>
 +<ul class="simple">
 +<li>PHP module apc</li>
 +<li>PHP module apcu</li>
 +<li>PHP module xcache</li>
 +</ul>
 +<p>For preview generation (<em>optional</em>):</p>
 +<ul class="simple">
 +<li>PHP module imagick</li>
 +<li>avconv or ffmpeg</li>
 +<li>OpenOffice or libreOffice</li>
 +</ul>
 +<p><strong>Remarks:</strong></p>
 +<ul>
 +<li><p class="first">Please check your distribution, operating system or hosting partner documentation
 +on how to install/enable these modules.</p>
 +</li>
 +<li><p class="first">Make sure your distribution’s php version fulfils the version requirements
- specified above. If it doesn’t, there might be custom repositories you can use.
- If you are e.g. running Ubuntu 10.04 LTS, you can update your
- PHP using a custom <a class="reference external" href="https://launchpad.net/~ondrej/+archive/php5">PHP PPA</a>:</p>
++specified above. If it doesn’t, there might be custom repositories you can
++use. If you are e.g. running Ubuntu 10.04 LTS, you can update your PHP using
++a custom <a class="reference external" href="https://launchpad.net/~ondrej/+archive/php5">PHP PPA</a>:</p>
 +<div class="highlight-python"><pre>sudo add-apt-repository ppa:ondrej/php5
 +sudo apt-get update
 +sudo apt-get install php5</pre>
 +</div>
 +</li>
 +<li><p class="first">You don’t need any WebDAV support module for your web server (i.e. Apache’s
 +mod_webdav) to access your ownCloud data via WebDAV. ownCloud has a built-in
 +WebDAV server of its own.</p>
 +</li>
 +</ul>
- <div class="section" id="example-installation-on-ubuntu-12-04-4-lts-server">
- <h3>Example installation on Ubuntu 12.04.4 LTS Server<a class="headerlink" href="#example-installation-on-ubuntu-12-04-4-lts-server" title="Permalink to this headline">¶</a></h3>
++<div class="section" id="installation-of-packages-on-ubuntu-12-04-4-lts-server">
++<h3>Installation of packages on Ubuntu 12.04.4 LTS Server<a class="headerlink" href="#installation-of-packages-on-ubuntu-12-04-4-lts-server" title="Permalink to this headline">¶</a></h3>
 +<p>On a machine running a pristine Ubuntu 12.04.4 LTS server, you would install the
 +required and recommended modules for a typical ownCloud installation, using
 +Apache and MySQL by issuing the following commands in a terminal:</p>
 +<div class="highlight-python"><pre>sudo apt-get install apache2 mysql-server libapache2-mod-php5
 +sudo apt-get install php5-gd php5-json php5-mysql php5-curl
 +sudo apt-get install php5-intl php5-mcrypt php5-imagick</pre>
 +</div>
 +<p><strong>Remarks:</strong></p>
 +<ul class="simple">
- <li>If you want to use any other combination of distribution, webserver or database,
- please consult the respective documentation.</li>
++<li>This installs the packages for the ownCloud core system. If you are planning on
++running additional apps, keep in mind that they might require additional packages.
++See the list above for details.</li>
 +<li>At the execution of each of the above commands you might be prompted whether you
 +want to continue; press “Y” for Yes (that is if your system language is English.
 +You might have to press a different key if you have a different system language).</li>
 +<li>At the installation of the MySQL server, you will be prompted for a root password.
- Be sure to remember that password for later use.</li>
- <li>This installs the packages for the ownCloud core system. If you are planning on
- running additional apps, keep in mind that they might require additional packages.
- See the list above for details.</li>
++Be sure to remember the password you enter there for later use (you will need it
++during ownCloud database setup).</li>
 +</ul>
 +</div>
 +</div>
 +<div class="section" id="download-extract-and-copy-owncloud-to-your-web-server">
 +<h2>Download, extract and copy ownCloud to Your Web Server<a class="headerlink" href="#download-extract-and-copy-owncloud-to-your-web-server" title="Permalink to this headline">¶</a></h2>
 +<p>First, download the archive of the latest ownCloud version:</p>
 +<ul>
- <li><p class="first">Navigate to <cite>http://owncloud.org/install</cite></p>
++<li><p class="first">Navigate to the <a class="reference external" href="http://owncloud.org/install">ownCloud Installation Page</a></p>
 +</li>
 +<li><p class="first">Click “Tar or Zip file”</p>
 +</li>
 +<li><p class="first">In the opening dialog, chose the “Linux” link.</p>
 +</li>
 +<li><p class="first">This will start the download of a file named owncloud-x.y.z.tar.bz2 (where
 +x.y.z is the version number of the current latest version).</p>
 +</li>
- <li><p class="first">Save this file on the machine you want to install ownCloud on.</p>
- </li>
- <li><p class="first">If that’s a different machine than the one you are currently working on, use
++<li><p class="first">Save this file on the machine you want to install ownCloud on.
++If that’s a different machine than the one you are currently working on, use
 +e.g. FTP to transfer the downloaded archive file there.</p>
 +</li>
- <li><p class="first">Note down the directory where you put the file.</p>
- </li>
- <li><p class="first">Extract the archive contents. Open a terminal on the machine
- you plan to run ownCloud on, and run:</p>
++<li><p class="first">Extract the archive contents. Open a terminal and run:</p>
 +<div class="highlight-python"><pre>cd path/to/downloaded/archive
 +tar -xjf owncloud-x.y.z.tar.bz2</pre>
 +</div>
- <p>where <tt class="code docutils literal"><span class="pre">path/to/downloaded/archive</span></tt> is to be replaced by the path where you
++<p>where <tt class="docutils literal"><span class="pre">path/to/downloaded/archive</span></tt> is to be replaced by the path where you
 +put the downloaded archive, and x.y.z of course has to be replaced by the actual
 +version number as in the file you have downloaded.</p>
 +</li>
 +<li><p class="first">Copy the ownCloud files to their final destination in the document root of your
 +webserver (you can skip this step if you already downloaded and extracted the
 +files there):</p>
- <div class="highlight-python"><pre>sudo cp -r owncloud /path/to/your/webserver/document-root</pre>
++<div class="highlight-python"><pre>sudo cp -r owncloud /path/to/your/webservers/document-root</pre>
 +</div>
++<p>where <tt class="docutils literal"><span class="pre">/path/to/your/webservers/document-root</span></tt>, needs to be replaced by the
++actual path where the document root of your webserver is configured to be.</p>
 +<ul>
- <li><p class="first">If you don’t know where your webserver’s document root is located, consult its
- documentation. For Apache on Ubuntu 12.04 LTS for example, this would usually be
- <tt class="code docutils literal"><span class="pre">/var/www</span></tt>. So above command should look like this:</p>
++<li><p class="first">If you don’t know where your webserver’s document root is located, consult
++its documentation. For Apache on Ubuntu 12.04 LTS for example, this would
++usually be <tt class="docutils literal"><span class="pre">/var/www</span></tt>. So the concrete command to run would be:</p>
 +<div class="highlight-python"><pre>sudo cp -r owncloud /var/www</pre>
 +</div>
 +</li>
 +<li><p class="first">The above assumes you want to install ownCloud into a subdirectory “owncloud”
 +on your webserver. For installing it anywhere else, you’ll have to adapt the
- above command accordingly.</p>
++above command (and also the commands in the following section) accordingly.</p>
 +</li>
 +</ul>
 +</li>
 +</ul>
 +</div>
 +<div class="section" id="set-the-directory-permissions">
 +<h2>Set the Directory Permissions<a class="headerlink" href="#set-the-directory-permissions" title="Permalink to this headline">¶</a></h2>
- <p>The user running your web server must own at least the apps/, data/ and config/
- directories in your ownCloud installation folder.
- The following command will change the ownership of the whole folder to that user.</p>
++<p>The user running your web server must own at least the config/, data/ and apps/
++directories in your ownCloud installation folder so that you can configure ownCloud,
++create/modify and delete your data files through ownCloud and install apps through
++the web interface. If you are planning on also using the automatic updater app for
++updating, the whole <tt class="docutils literal"><span class="pre">owncloud</span></tt> folder must be owned by (or at least be writable to)
++the user running php on your system.</p>
++<div class="admonition note">
++<p class="first admonition-title">Note</p>
++<p class="last">When using an NFS mount for the data directory, do not change ownership as above.
++The simple act of mounting the drive will set proper permissions for ownCloud to
++write to the directory. Changing ownership as above could result in some issues
++if the NFS mount is lost.</p>
++</div>
++<p>The following command will change the ownership of the whole ownCloud folder to
++that user.</p>
 +<ul>
- <li><p class="first">For Debian-based distributions (like Ubuntu, Debian or Linux Mint) and Gentoo, run:</p>
- <div class="highlight-python"><pre>sudo chown -R www-data:www-data /path/to/your/owncloud</pre>
++<li><p class="first">The generic command to run is:</p>
++<div class="highlight-python"><pre>sudo chown -R <php-user>:<php-user> /path/to/your/webservers/document-root/owncloud</pre>
 +</div>
++<p>where <tt class="docutils literal"><span class="pre"><php-user></span></tt> is to be replaced by the user running php scripts, and
++<tt class="docutils literal"><span class="pre">/path/to/your/webservers/document-root/owncloud</span></tt> by the folder where the
++extracted ownCloud files are located.</p>
 +</li>
- <li><p class="first">Continuing the example from above, for Ubuntu 12.04 LTS, where the install location
- was <tt class="code docutils literal"><span class="pre">/var/www</span></tt>, you would run:</p>
++<li><p class="first">For Ubuntu 12.04 LTS server, where the <tt class="docutils literal"><span class="pre">owncloud</span></tt> folder was copied into the
++Apache document root at <tt class="docutils literal"><span class="pre">/var/www</span></tt>, and the user running Apache and php
++scripts is called <tt class="docutils literal"><span class="pre">www-data</span></tt>, this would mean you need to run:</p>
 +<div class="highlight-python"><pre>sudo chown -R www-data:www-data /var/www/owncloud</pre>
 +</div>
 +</li>
- <li><p class="first">For ArchLinux should run (as root):</p>
- <div class="highlight-python"><pre>chown -R http:http /path/to/your/owncloud</pre>
- </div>
++<li><p class="first">For all Debian-based distributions (like Ubuntu, Debian or Linux Mint) and Gentoo,
++use <tt class="docutils literal"><span class="pre">www-data</span></tt> user</p>
 +</li>
- <li><p class="first">Fedora users should run (as root):</p>
- <div class="highlight-python"><pre>chown -R apache:apache /path/to/your/owncloud</pre>
++<li><p class="first">On ArchLinux, use <tt class="docutils literal"><span class="pre">http</span></tt> user.</p>
++</li>
++<li><p class="first">On Fedora, use <tt class="docutils literal"><span class="pre">apache</span></tt> user.</p>
++</li>
++<li><p class="first">When you had extracted ownCloud as user <tt class="docutils literal"><span class="pre">root</span></tt>, you should adjust file and directory
++permission to avoid world writeable files and folder:</p>
++<div class="highlight-python"><pre>find /path/to/your/webservers/document-root/owncloud -type d -exec chmod 750 {} \;
++find /path/to/your/webservers/document-root/owncloud -type f -exec chmod 640 {} \;</pre>
 +</div>
++<p>Running this in combination with the above <tt class="docutils literal"><span class="pre">chown</span></tt> command will give a secure
++set-up.</p>
 +</li>
 +</ul>
- <p>When using an NFS mount for the data directory, do not change ownership as above.
- The simple act of mounting the drive will set proper permissions for ownCloud to
- write to the directory. Changing ownership as above could result in some issues
- if the NFS mount is lost.</p>
 +</div>
 +<div class="section" id="web-server-configuration">
 +<h2>Web Server Configuration<a class="headerlink" href="#web-server-configuration" title="Permalink to this headline">¶</a></h2>
 +<div class="admonition note">
 +<p class="first admonition-title">Note</p>
 +<p class="last">You can use ownCloud over plain http, but we strongly encourage you to
 +use SSL/TLS. If you don’t use it, and you for example access your
 +ownCloud over an unsecured WiFi, everyone in the same WiFi can grab
 +your authentication data or the content of files synchronized while you
 +are on the WiFi.</p>
 +</div>
 +<p>Apache is the recommended web server.</p>
 +<div class="section" id="apache-configuration">
 +<h3>Apache Configuration<a class="headerlink" href="#apache-configuration" title="Permalink to this headline">¶</a></h3>
 +<div class="section" id="enabling-ssl">
 +<h4>Enabling SSL<a class="headerlink" href="#enabling-ssl" title="Permalink to this headline">¶</a></h4>
 +<p>An Apache installed under Ubuntu comes already set-up with a simple
 +self-signed certificate. All you have to do is to enable the ssl module and
- the according site. Open a terminal and run</p>
++the according site. Open a terminal and run:</p>
 +<div class="highlight-python"><pre>sudo a2enmod ssl
 +sudo a2ensite default-ssl
 +sudo service apache2 reload</pre>
 +</div>
 +<p>If you are using a different distribution, check their documentation on how to
 +enable SSL.</p>
 +<div class="admonition note">
 +<p class="first admonition-title">Note</p>
 +<p class="last">Self-signed certificates have their drawbacks - especially when you
 +plan to make your ownCloud server publicly accessible. You might want
 +to consider getting a certificate signed by an official signing
- authority. If you’re looking for a free certificate, you can consult
- e.g. this article:
- <cite>https://www.sslshopper.com/article-free-ssl-certificates-from-a-free-certificate-authority.html</cite></p>
++authority. SSLShopper for example has an article on your
++<a class="reference external" href="https://www.sslshopper.com/article-free-ssl-certificates-from-a-free-certificate-authority.html">options for free SSL certificates</a>.</p>
 +</div>
 +</div>
 +<div class="section" id="configuring-owncloud">
 +<h4>Configuring ownCloud<a class="headerlink" href="#configuring-owncloud" title="Permalink to this headline">¶</a></h4>
 +<p>Since there was a change in the way versions 2.2 and 2.4 are configured,
 +you’ll have to find out which Apache version you are using.</p>
 +<p>Usually you can do this by running one of the following commands:</p>
 +<div class="highlight-python"><pre>sudo apachectl -v
 +apache2 -v</pre>
 +</div>
 +<p>Example output:</p>
 +<div class="highlight-python"><pre>Server version: Apache/2.2.22 (Ubuntu)
 +Server built:   Jul 12 2013 13:37:10</pre>
 +</div>
 +<p>This indicates an Apache of the 2.2 version branch (as e.g. you will find on
 +Ubuntu 12.04 LTS).</p>
 +<p>Example config for Apache 2.2:</p>
 +<div class="highlight-xml"><pre><Directory /path/to/your/owncloud/install>
 +    Options Indexes FollowSymLinks MultiViews
 +    AllowOverride All
 +    Order allow,deny
 +    allow from all
 +</Directory></pre>
 +</div>
 +<p>Example config for Apache 2.4:</p>
 +<div class="highlight-xml"><pre><Directory /path/to/your/owncloud/install>
 +    Options Indexes FollowSymLinks MultiViews
 +    AllowOverride All
 +    Require all granted
 +</Directory></pre>
 +</div>
 +<ul>
 +<li><p class="first">This config entry needs to go into the configuration file of the “site” you want
 +to use.</p>
 +</li>
- <li><p class="first">On a Ubuntu system, this typically is the “default-ssl” site (to be found at
- <tt class="code docutils literal"><span class="pre">/etc/apache2/sites-available/default-ssl</span></tt>).</p>
++<li><p class="first">On a Ubuntu system, this typically is the “default-ssl” site (to be found in
++the <tt class="file docutils literal"><span class="pre">/etc/apache2/sites-available/default-ssl</span></tt>).</p>
 +</li>
 +<li><p class="first">Edit the site file with your favorite editor (note that you’ll need root
 +permissions to modify that file). For Ubuntu 12.04 LTS, you could for example run
 +the following command in a Terminal:</p>
 +<div class="highlight-python"><pre>sudo nano /etc/apache2/sites-available/default-ssl</pre>
 +</div>
 +</li>
- <li><p class="first">Add the entry shown above immediately before the line containing</p>
++<li><p class="first">Add the entry shown above immediately before the line containing:</p>
 +<div class="highlight-python"><pre></VirtualHost></pre>
 +</div>
 +<p>(this should be one of the last lines in the file).</p>
 +</li>
- <li><p class="first">For ownCloud to work correctly, we need the module mod_rewrite. Enable it by running:</p>
- <div class="highlight-python"><pre>sudo a2enmod rewrite</pre>
- </div>
- </li>
- <li><p class="first">In distributions that do not come with a2enmod the module needs to be enabled
- manually by editing the config Apache files, usually <tt class="file docutils literal"><span class="pre">/etc/httpd/httpd.conf</span></tt>.
- consult the Apache documentation or your distributions documentation.</p>
- </li>
- <li><p class="first">Then restart Apache.</p>
- <ul>
- <li><p class="first">For Ubuntu systems (or distributions using upstartd), run:</p>
- <div class="highlight-python"><pre>sudo service apache2 restart</pre>
- </div>
- </li>
- <li><p class="first">For systemd systems (Fedora, ArchLinux, OpenSUSE), run:</p>
- <div class="highlight-python"><pre>systemctl restart httpd.service</pre>
- </div>
- </li>
- </ul>
- </li>
- <li><p class="first">In order for the maximum upload size to be configurable, the .htaccess file in the
- ownCloud folder needs to be made writable by the server (this should already be done,
- see section <a class="reference internal" href="#set-the-directory-permissions">Set the Directory Permissions</a>).</p>
- </li>
- <li><p class="first">You should make sure that any built-in WebDAV module of your web server is disabled
- (at least for the ownCloud directory), as it will interfere with ownCloud’s
- built-in WebDAV support.</p>
- <p>If you need the WebDAV support in the rest of your configuration, you can turn it off
- specifically for the ownCloud entry by adding the following line in the
- configuration of your ownCloud. In above “<Directory ...” code, add the following line
- directly after the “allow from all” / “Require all granted” line):</p>
- <div class="highlight-python"><pre>Dav Off</pre>
- </div>
- </li>
- <li><p class="first">Furthermore, you need to disable any server-configured authentication for ownCloud, as
- it’s internally using Basic authentication for its *DAV services.
- If you have turned on authentication on a parent folder (via e.g. an “AuthType Basic”
- directive), you can turn off the authentication specifically for the ownCloud entry;
- to do so, in above “<Directory ...” code, add the following line directly after the
- “allow from all” / “Require all granted” line):</p>
- <div class="highlight-python"><pre>Satisfy Any</pre>
- </div>
++<li><p class="first">A minimal site configuration file on Ubuntu 12.04 might look like this:</p>
 +</li>
 +</ul>
- <p>A minimal site configuration on Ubuntu 12.04 might look like this:</p>
 +<div class="highlight-xml"><pre><IfModule mod_ssl.c>
 +<VirtualHost _default_:443>
 +        ServerName YourServerName
 +        ServerAdmin webmaster at localhost
 +        DocumentRoot /var/www
 +        <Directory />
 +                Options FollowSymLinks
 +                AllowOverride None
 +        </Directory>
 +        <Directory /var/www/>
 +                Options Indexes FollowSymLinks MultiViews
 +                AllowOverride None
 +                Order allow,deny
 +                allow from all
 +        </Directory>
 +        ErrorLog ${APACHE_LOG_DIR}/error.log
 +        LogLevel warn
 +        CustomLog ${APACHE_LOG_DIR}/ssl_access.log combined
 +        SSLEngine on
 +        SSLCertificateFile    /etc/ssl/certs/ssl-cert-snakeoil.pem
 +        SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key
 +        <FilesMatch "\.(cgi|shtml|phtml|php)$">
 +                SSLOptions +StdEnvVars
 +        </FilesMatch>
 +        <Directory /usr/lib/cgi-bin>
 +                SSLOptions +StdEnvVars
 +        </Directory>
 +        BrowserMatch "MSIE [2-6]" \
 +                nokeepalive ssl-unclean-shutdown \
 +                downgrade-1.0 force-response-1.0
 +        BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown
 +        <Directory /var/www/owncloud>
 +                Options Indexes FollowSymLinks MultiViews
 +                AllowOverride All
 +                Order allow,deny
 +                Allow from all
 +                # add any possibly required additional directives here
-                 # e.g. the Satisfy directive:
++                # e.g. the Satisfy directive (see below for details):
 +                Satisfy Any
 +        </Directory>
 +</VirtualHost>
 +</IfModule></pre>
 +</div>
- <p>When using ssl, take special note on the ServerName. You should specify one in the
++<ul>
++<li><p class="first">For ownCloud to work correctly, we need the module mod_rewrite. Enable it by running:</p>
++<div class="highlight-python"><pre>sudo a2enmod rewrite</pre>
++</div>
++</li>
++<li><p class="first">In distributions that do not come with <tt class="docutils literal"><span class="pre">a2enmod</span></tt>, the module needs to be
++enabled manually by editing the Apache config files, usually <tt class="file docutils literal"><span class="pre">/etc/httpd/httpd.conf</span></tt>.
++consult the Apache documentation or your distributions documentation.</p>
++</li>
++<li><p class="first">In order for the maximum upload size to be configurable, the
++<tt class="file docutils literal"><span class="pre">.htaccess</span></tt> in the ownCloud folder needs to be made writable by the
++server (this should already be done, see section <a class="reference internal" href="#set-the-directory-permissions">Set the Directory Permissions</a>).</p>
++</li>
++<li><p class="first">You should make sure that any built-in WebDAV module of your web server is disabled
++(at least for the ownCloud directory), as it will interfere with ownCloud’s
++built-in WebDAV support.</p>
++<p>If you need the WebDAV support in the rest of your configuration, you can turn it off
++specifically for the ownCloud entry by adding the following line in the
++configuration of your ownCloud. In above “<Directory ...” code, add the following line
++directly after the <tt class="docutils literal"><span class="pre">allow</span> <span class="pre">from</span> <span class="pre">all</span></tt> / <tt class="docutils literal"><span class="pre">Require</span> <span class="pre">all</span> <span class="pre">granted</span></tt> line):</p>
++<div class="highlight-python"><pre>Dav Off</pre>
++</div>
++</li>
++<li><p class="first">Furthermore, you need to disable any server-configured authentication for ownCloud, as
++it’s internally using Basic authentication for its *DAV services.
++If you have turned on authentication on a parent folder (via e.g. an <tt class="docutils literal"><span class="pre">AuthType</span> <span class="pre">Basic</span></tt>
++directive), you can turn off the authentication specifically for the ownCloud entry;
++to do so, in above “<Directory ...” code, add the following line directly after the
++<tt class="docutils literal"><span class="pre">allow</span> <span class="pre">from</span> <span class="pre">all</span></tt> / <tt class="docutils literal"><span class="pre">Require</span> <span class="pre">all</span> <span class="pre">granted</span></tt> line):</p>
++<div class="highlight-python"><pre>Satisfy Any</pre>
++</div>
++</li>
++<li><p class="first">When using ssl, take special note on the ServerName. You should specify one in the
 +server configuration, as well as in the CommonName field of the certificate. If you want
 +your ownCloud to be reachable via the internet, then set both these to the domain you
 +want to reach your ownCloud under.</p>
++</li>
++</ul>
 +<div class="admonition note">
 +<p class="first admonition-title">Note</p>
- <p class="last">By default, the certificates’ CommonName will get set to the host name at the time
- when the ssl-cert package was installed.</p>
++<p class="last">By default, the certificates’ CommonName will get set to the host
++name at the time when the ssl-cert package was installed.</p>
 +</div>
++<ul>
++<li><p class="first">Finally, restart Apache.</p>
++<ul>
++<li><p class="first">For Ubuntu systems (or distributions using upstartd), run:</p>
++<div class="highlight-python"><pre>sudo service apache2 restart</pre>
++</div>
++</li>
++<li><p class="first">For systemd systems (Fedora, ArchLinux, OpenSUSE), run:</p>
++<div class="highlight-python"><pre>systemctl restart httpd.service</pre>
++</div>
++</li>
++</ul>
++</li>
++</ul>
 +</div>
 +</div>
 +<div class="section" id="nginx-configuration">
 +<h3>Nginx Configuration<a class="headerlink" href="#nginx-configuration" title="Permalink to this headline">¶</a></h3>
- <ul class="simple">
- <li>You need to insert the following code into <strong>your nginx config file.</strong></li>
- <li>Adjust <strong>server_name</strong>, <strong>root</strong>, <strong>ssl_certificate</strong> and <strong>ssl_certificate_key</strong> to suit your needs.</li>
- <li>Make sure your SSL certificates are readable by the server (see <a class="reference external" href="http://wiki.nginx.org/HttpSslModule">http://wiki.nginx.org/HttpSslModule</a>).</li>
++<ul>
++<li><p class="first">You need to insert the following code into <strong>your nginx config file.</strong></p>
++</li>
++<li><p class="first">Adjust <strong>server_name</strong>, <strong>root</strong>, <strong>ssl_certificate</strong> and <strong>ssl_certificate_key</strong> to suit your needs.</p>
++</li>
++<li><dl class="first docutils">
++<dt>Make sure your SSL certificates are readable by the server (see the</dt>
++<dd><p class="first last"><a class="reference external" href="http://wiki.nginx.org/HttpSslModule">Nginx HTTP SSL Module documentation</a>).</p>
++</dd>
++</dl>
++</li>
 +</ul>
 +<div class="highlight-python"><pre>upstream php-handler {
 +        server 127.0.0.1:9000;
 +        #server unix:/var/run/php5-fpm.sock;
 +}
 +
 +server {
 +        listen 80;
 +        server_name cloud.example.com;
 +        return 301 https://$server_name$request_uri;  # enforce https
 +}
 +
 +server {
 +        listen 443 ssl;
 +        server_name cloud.example.com;
 +
 +        ssl_certificate /etc/ssl/nginx/cloud.example.com.crt;
 +        ssl_certificate_key /etc/ssl/nginx/cloud.example.com.key;
 +
 +        # Path to the root of your installation
 +        root /var/www/;
 +
 +        client_max_body_size 10G; # set max upload size
 +        fastcgi_buffers 64 4K;
 +
 +        rewrite ^/caldav(.*)$ /remote.php/caldav$1 redirect;
 +        rewrite ^/carddav(.*)$ /remote.php/carddav$1 redirect;
 +        rewrite ^/webdav(.*)$ /remote.php/webdav$1 redirect;
 +
 +        index index.php;
 +        error_page 403 /core/templates/403.php;
 +        error_page 404 /core/templates/404.php;
 +
 +        location = /robots.txt {
 +            allow all;
 +            log_not_found off;
 +            access_log off;
 +        }
 +
 +        location ~ ^/(data|config|\.ht|db_structure\.xml|README) {
 +                deny all;
 +        }
 +
 +        location / {
 +                # The following 2 rules are only needed with webfinger
 +                rewrite ^/.well-known/host-meta /public.php?service=host-meta last;
 +                rewrite ^/.well-known/host-meta.json /public.php?service=host-meta-json last;
 +
 +                rewrite ^/.well-known/carddav /remote.php/carddav/ redirect;
 +                rewrite ^/.well-known/caldav /remote.php/caldav/ redirect;
 +
 +                rewrite ^(/core/doc/[^\/]+/)$ $1/index.html;
 +
 +                try_files $uri $uri/ index.php;
 +        }
 +
 +        location ~ ^(.+?\.php)(/.*)?$ {
-                 try_files $1 = 404;
++                try_files $1 =404;
 +
 +                include fastcgi_params;
 +                fastcgi_param SCRIPT_FILENAME $document_root$1;
 +                fastcgi_param PATH_INFO $2;
 +                fastcgi_param HTTPS on;
 +                fastcgi_pass php-handler;
 +        }
 +
 +        # Optional: set long EXPIRES header on static assets
 +        location ~* ^.+\.(jpg|jpeg|gif|bmp|ico|png|css|js|swf)$ {
 +                expires 30d;
 +                # Optional: Don't log access to assets
 +                access_log off;
 +        }
 +
 +}</pre>
 +</div>
 +<p>To enable SSL support:
 +-  Remove the server block containing the redirect
 +-  Change <strong>listen 443 ssl</strong> to <strong>listen 80;</strong>
 +-  Remove <strong>ssl_certificate</strong> and <strong>ssl_certificate_key</strong>.
 +-  Remove <strong>fastcgi_params HTTPS on;</strong></p>
 +<div class="admonition note">
 +<p class="first admonition-title">Note</p>
 +<p class="last">If you want to effectively increase maximum upload size you will also
 +have to modify your <strong>php-fpm configuration</strong> (<strong>usually at
 +/etc/php5/fpm/php.ini</strong>) and increase <strong>upload_max_filesize</strong> and
 +<strong>post_max_size</strong> values. You’ll need to restart php5-fpm and nginx
 +services in order these changes to be applied.</p>
 +</div>
 +</div>
 +<div class="section" id="lighttpd-configuration">
 +<h3>Lighttpd Configuration<a class="headerlink" href="#lighttpd-configuration" title="Permalink to this headline">¶</a></h3>
 +<p>This assumes that you are familiar with installing PHP application on
 +lighttpd.</p>
- <p>It is important to note that the <strong>.htaccess</strong> files used by ownCloud to protect the <strong>data</strong> folder are ignored by
- lighttpd, so you have to secure it by yourself, otherwise your <strong>owncloud.db</strong> database and user data are publicly
- readable even if directory listing is off. You need to add two snippets to your lighttpd configuration file:</p>
++<p>It is important to note that the <tt class="file docutils literal"><span class="pre">.htaccess</span></tt> used by ownCloud to
++protect the <tt class="file docutils literal"><span class="pre">data</span></tt> folder are ignored by lighttpd, so you have to secure
++it by yourself, otherwise your <tt class="file docutils literal"><span class="pre">owncloud.db</span></tt> database and user data are
++publicly readable even if directory listing is off. You need to add two
++snippets to your lighttpd configuration file:</p>
 +<p>Disable access to data folder:</p>
 +<div class="highlight-python"><pre>$HTTP["url"] =~ "^/owncloud/data/" {
-      url.access-deny = ("")
-    }</pre>
++        url.access-deny = ("")
++}</pre>
 +</div>
 +<p>Disable directory listing:</p>
 +<div class="highlight-python"><pre>$HTTP["url"] =~ "^/owncloud($|/)" {
-      dir-listing.activate = "disable"
-    }</pre>
++        dir-listing.activate = "disable"
++}</pre>
 +</div>
++<p><strong>Note for Lighttpd users on Debian stable (wheezy):</strong></p>
++<p>Recent versions of ownCloud make use of the <strong>HTTP PATCH</strong> feature, which was added to Lighttpd at version 1.4.32 while Debian stable only ships 1.4.31. The patch is simple, however, and easy to integrate if you’re willing to build your own package.</p>
++<p>Download the patch from <a class="reference external" href="http://redmine.lighttpd.net/attachments/download/1370/patch.patch">http://redmine.lighttpd.net/attachments/download/1370/patch.patch</a></p>
++<p>Make sure you have the build tools you need:</p>
++<div class="highlight-python"><pre>apt-get build-dep lighttpd
++apt-get install quilt patch devscripts</pre>
++</div>
++<p>Patch the package source:</p>
++<div class="highlight-python"><pre>apt-get source lighttpd
++cd lighttpd-1.4.31
++export QUILT_PATCHES=debian/patches # This tells quilt to put the patch in the right spot
++quilt new http-patch.patch
++quilt add src/connections.c src/keyvalue.c src/keyvalue.h # Make quilt watch the files we'll be changing
++patch -p1 -i /patch/to/downloaded/patch.patch
++quilt refresh</pre>
++</div>
++<p>Increment the package version with <tt class="docutils literal"><span class="pre">dch</span> <span class="pre">-i</span></tt>. This will open the changelog with a new entry. You can save as-is or add info to it. The important bit is that the version is bumped so apt will not try to “upgrade” back to Debian’s version.</p>
++<p>Then build with <tt class="docutils literal"><span class="pre">debuild</span></tt> and install the .debs for any Lighttpd packages you already have installed.</p>
 +</div>
 +<div class="section" id="yaws-configuration">
 +<h3>Yaws Configuration<a class="headerlink" href="#yaws-configuration" title="Permalink to this headline">¶</a></h3>
 +<p>This should be in your <strong>yaws_server.conf</strong>. In the configuration file, the
 +<strong>dir_listings = false</strong> is important and also the redirect from <strong>/data</strong>
 +to somewhere else, because files will be saved in this directory and it
 +should not be accessible from the outside. A configuration file would look
 +like this</p>
 +<div class="highlight-xml"><pre><server owncloud.myserver.com/>
 +        port = 80
 +        listen = 0.0.0.0
 +        docroot = /var/www/owncloud/src
 +        allowed_scripts = php
 +        php_handler = <cgi, /usr/local/bin/php-cgi>
 +        errormod_404 = yaws_404_to_index_php
 +        access_log = false
 +        dir_listings = false
 +        <redirect>
 +                /data == /
 +        </redirect>
 +</server></pre>
 +</div>
- <p>The Apache <strong>.htaccess</strong> file that comes with ownCloud is configured to
++<p>The Apache <tt class="file docutils literal"><span class="pre">.htaccess</span></tt> that comes with ownCloud is configured to
 +redirect requests to nonexistent pages. To emulate that behaviour, you
- need a custom error handler for yaws. See this <a class="reference external" href="https://gist.github.com/2200407">github gist for further instructions</a> on how to create and compile that error handler.</p>
++need a custom error handler for yaws. See this
++<a class="reference external" href="https://gist.github.com/2200407">github gist for further instructions</a> on how to create and compile that error
++handler.</p>
 +</div>
 +<div class="section" id="hiawatha-configuration">
 +<h3>Hiawatha Configuration<a class="headerlink" href="#hiawatha-configuration" title="Permalink to this headline">¶</a></h3>
- <p>Add <strong>WebDAVapp = yes</strong> to the ownCloud virtual host. Users accessing
- WebDAV from MacOS will also need to add <strong>AllowDotFiles = yes</strong>.</p>
++<p>Add <tt class="docutils literal"><span class="pre">WebDAVapp</span> <span class="pre">=</span> <span class="pre">yes</span></tt> to the ownCloud virtual host. Users accessing
++WebDAV from MacOS will also need to add <tt class="docutils literal"><span class="pre">AllowDotFiles</span> <span class="pre">=</span> <span class="pre">yes</span></tt>.</p>
 +<p>Disable access to data folder:</p>
 +<div class="highlight-python"><pre>UrlToolkit {
 +    ToolkitID = denyData
 +    Match ^/data DenyAccess
 +}</pre>
 +</div>
 +</div>
 +<div class="section" id="microsoft-internet-information-server-iis">
 +<h3>Microsoft Internet Information Server (IIS)<a class="headerlink" href="#microsoft-internet-information-server-iis" title="Permalink to this headline">¶</a></h3>
 +<p>See <a class="reference internal" href="installation_windows.html"><em>Windows 7 and Windows Server 2008</em></a> for further instructions.</p>
 +</div>
 +</div>
 +<div class="section" id="follow-the-install-wizard">
 +<h2>Follow the Install Wizard<a class="headerlink" href="#follow-the-install-wizard" title="Permalink to this headline">¶</a></h2>
- <p>Open your web browser and navigate to your ownCloud instance. If you are
- installing ownCloud on the same machine as you will access the install wizard
- from, the url will be: <a class="reference external" href="http://localhost/">http://localhost/</a> (or <a class="reference external" href="http://localhost/owncloud">http://localhost/owncloud</a>).</p>
- <p>For basic installs we recommend SQLite as it is easy to setup (ownCloud will do it for you). For larger installs you
- should use MySQL or PostgreSQL. Click on the Advanced options to show the configuration options. You may enter admin
- credentials and let ownCloud create its own database user, or enter a preconfigured user.  If you are not using Apache
- as the web server, please set the data directory to a location outside of the document root. See the advanced
- install settings.</p>
++<ul class="simple">
++<li>Open your web browser</li>
++<li>Navigate to your ownCloud instance.<ul>
++<li>If you are installing ownCloud on the same machine as you are accessing the
++install wizard from, the url will be <a class="reference external" href="https://localhost/owncloud">https://localhost/owncloud</a></li>
++<li>If you are installing ownCloud on a different machine, you’ll have to access
++it by its hostname or IP address, e.g. <a class="reference external" href="https://example.com/owncloud">https://example.com/owncloud</a></li>
++<li>If you are using a self-signed certificate, you will be presented with a
++security warning about the issuer of the certificate not being trusted which
++you can ignore.</li>
++</ul>
++</li>
++<li>You will be presented with the setup screen</li>
++<li>Enter username and password for the administrative user account</li>
++<li>Expand Advanced options to choose a data folder and the database system</li>
++<li>If you are not using Apache as the web server, please set the data directory
++to a location outside of the document root.</li>
++<li>If following the Ubuntu-Apache-MySQL walk-through:<ul>
++<li>choose MySQL as Database backend (you might not be presented with any other
++choice if you haven’t installed any other database systems).</li>
++<li>As Database host, enter <tt class="docutils literal"><span class="pre">localhost</span></tt>.</li>
++<li>As Database user enter <tt class="docutils literal"><span class="pre">root</span></tt>.</li>
++<li>As Database password, enter the password you entered during installation of
++the MySQL server package.</li>
++<li>As Database name, enter an arbitrary name as you see fit<ul>
++<li>Beware that there are restrictions as to what characters a database name
++may or may not contain, see the
++<a class="reference external" href="http://dev.mysql.com/doc/refman/5.5/en/identifiers.html">MySQL Schema Object Names documentation</a> for details);</li>
++<li>Make sure to choose a name under which no database exists yet</li>
++</ul>
++</li>
++<li>ownCloud will use the provided credentials and create its own user with
++permissions only on its own database.</li>
++</ul>
++</li>
++<li>In general, you have the following choices regarding the database:<ul>
++<li>For basic installs we recommend SQLite as it is easy to setup (ownCloud will do
++it for you). The performance when using sqlite is however inferior to the two
++other options.</li>
++<li>For larger installs you should use MySQL or PostgreSQL.</li>
++<li>Note that you will only be able to choose among the php database connectors
++which are actually installed on the system (see package requirements above).</li>
++<li>Further, it is not easily possible to migrate to another database system
++once you have set up your ownCloud to use a specific one. So make sure to
++carefully consider which database system to use.</li>
++<li>When using MySQL or PostgreSQL you have two options  regarding the database
++name and user account you specify:<ul>
++<li>You can specify either an admin/root user, and the name of a database
++which does not yet exist. This lets ownCloud create its own database; it
++will also create a database user account with restricted rights (with the
++same username as you specified for the administrative user, plus an
++<tt class="docutils literal"><span class="pre">oc_</span></tt> prefix) and will use that for all subsequent database access.</li>
++<li>You can enter the name of an existing database and the username/password
++of a user with restricted permissions<ul>
++<li>You can create such a user yourself e.g. via phpmyadmin.</li>
++<li>This user shouldn’t have permission to create a database.</li>
++<li>It should have full permissions on the (existing) database with the
++name you specify.</li>
++</ul>
++</li>
++</ul>
++</li>
++</ul>
++</li>
++<li>Press “Finish Setup”</li>
++<li>ownCloud will set up your cloud according to the given settings</li>
++<li>When its finished, it will log you in as administrative user and present the
++“Welcome to ownCloud” screen.</li>
++</ul>
++</div>
++<div class="section" id="note">
++<h2>Note<a class="headerlink" href="#note" title="Permalink to this headline">¶</a></h2>
++<p>When the initial ownCloud configuration is performed, ownCloud will take the URL used to access it and insert that
++the config.php file under the ‘trusted_domains’ header.</p>
++<p>Users will only be able to log into ownCloud when the addressed URL is as stated in the ‘trusted_domans’  header
++in the config.php file.</p>
++<p>In the event that a load balancer is in place, as long as it sends the correct X-Forwarded-Host header, there will
++be no issues.</p>
++<p>It should be noted that the loopback address, 127.0.0.1, is white labeled and therefore users on the ownCloud
++server who access ownCloud with the loopback will successfully login.
++In the event that an improper URL is used, the following error will appear:</p>
++<img alt="../_images/untrusted-domain.png" src="../_images/untrusted-domain.png" />
++<p>For configuration examples, refer to the config.php document.</p>
 +</div>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/installation/installation_ucs.html
index ad88098,0000000..22a6fb2
mode 100644,000000..100644
--- a/core/doc/admin/installation/installation_ucs.html
+++ b/core/doc/admin/installation/installation_ucs.html
@@@ -1,409 -1,0 +1,411 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
 +    <title>Univention Corporate Server — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
 +    <link rel="up" title="Installation" href="index.html" />
 +    <link rel="next" title="Manual Installation" href="installation_source.html" />
 +    <link rel="prev" title="Windows 7 and Windows Server 2008" href="installation_windows.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
 +<ul class="current">
 +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Installation</a><ul class="current">
 +<li class="toctree-l2"><a class="reference internal" href="installation_appliance.html">Appliances</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="installation_linux.html">Linux Distributions</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="installation_macos.html">Mac OS X</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="installation_windows.html">Windows 7 and Windows Server 2008</a></li>
 +<li class="toctree-l2 current"><a class="current reference internal" href="">Univention Corporate Server</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="#pre-configuration">Pre configuration</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#installation">Installation</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#postconfiguration-optional">Postconfiguration (optional)</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#using-owncloud">Using ownCloud</a></li>
 +</ul>
 +</li>
 +<li class="toctree-l2"><a class="reference internal" href="installation_source.html">Manual Installation</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="installation_others.html">PageKite Configuration</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="installation_others.html#open-wrt">Open Wrt</a></li>
 +</ul>
 +</li>
 +<li class="toctree-l1"><a class="reference internal" href="../configuration/index.html">Configuration</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
 +  <div class="section" id="univention-corporate-server">
 +<h1>Univention Corporate Server<a class="headerlink" href="#univention-corporate-server" title="Permalink to this headline">¶</a></h1>
 +<p>Subscribers to the ownCloud Enterprise edition can also integrate with
 +<abbr title="Univention Corporate Server">UCS</abbr>.</p>
 +<div class="section" id="pre-configuration">
 +<span id="preconfig"></span><h2>Pre configuration<a class="headerlink" href="#pre-configuration" title="Permalink to this headline">¶</a></h2>
 +<p>ownCloud makes use of the UCR, the Univention Configuration Registry. The values
 +are being read during installation, most of them can be changed later, too.
 +Changes done directly via ownCloud are not taken over to UCR. We think we found
 +sane defaults, nevertheless you might have your own requirements. The
 +installation script will listen to the UCR keys listed below. In case you want
 +to override any default setting, simply add the key in question to the UCR and
 +assign your required value.</p>
 +<table border="1" class="longtable docutils">
 +<colgroup>
 +<col width="20%" />
 +<col width="30%" />
 +<col width="30%" />
 +<col width="20%" />
 +</colgroup>
 +<thead valign="bottom">
 +<tr class="row-odd"><th class="head">Key</th>
 +<th class="head">Default</th>
 +<th class="head">Description</th>
 +<th class="head">Introduced</th>
 +</tr>
 +</thead>
 +<tbody valign="top">
 +<tr class="row-even"><td>owncloud/directory/data</td>
 +<td>/var/lib/owncloud</td>
 +<td>Specifies where the file storage will be placed</td>
 +<td>2012.0.1</td>
 +</tr>
 +<tr class="row-odd"><td>owncloud/db/name</td>
 +<td>owncloud</td>
 +<td>Name of the MySQL database. ownCloud will create an own user for it.</td>
 +<td>2012.0.1</td>
 +</tr>
 +<tr class="row-even"><td>owncloud/user/quota</td>
 +<td>(empty)</td>
 +<td>The default quota, when a user is being added. Assign values in human readable strings, e.g. “2 GB”. Unlimited if empty.</td>
 +<td>2012.0.1</td>
 +</tr>
 +<tr class="row-odd"><td>owncloud/user/enabled</td>
 +<td>0</td>
 +<td>Wether a new user is allowed to use ownCloud by default.</td>
 +<td>2012.0.1</td>
 +</tr>
 +<tr class="row-even"><td>owncloud/group/enabled</td>
 +<td>0</td>
 +<td>Wether a new group is allowed to be used in ownCloud by default.</td>
 +<td>2012.4.0.4</td>
 +</tr>
 +<tr class="row-odd"><td>owncloud/ldap/base/users</td>
 +<td>cn=users,$ldap_base</td>
 +<td>The users-subtree in the LDAP directory. If left blank it will fall back to the LDAP base.</td>
 +<td>2012.4.0.4</td>
 +</tr>
 +<tr class="row-even"><td>owncloud/ldap/base/groups</td>
 +<td>cn=groups,$ldap_base</td>
 +<td>The groups-subtree in the LDAP directory. If left blank it will fall back to the LDAP base.</td>
 +<td>2012.4.0.4</td>
 +</tr>
 +<tr class="row-odd"><td>owncloud/ldap/groupMemberAssoc</td>
 +<td>uniqueMember</td>
 +<td>The LDAP attribute showing the group-member relationship. Possible values: uniqueMember, memberUid and member</td>
 +<td>2012.4.0.4</td>
 +</tr>
 +<tr class="row-even"><td>owncloud/ldap/tls</td>
 +<td>1</td>
 +<td>Whether to talk to the LDAP server via TLS.</td>
 +<td>2012.0.1</td>
 +</tr>
 +<tr class="row-odd"><td>owncloud/ldap/disableMainServer</td>
 +<td>0</td>
 +<td>Deactivates the (first) LDAP Configuration</td>
 +<td>5.0.9</td>
 +</tr>
 +<tr class="row-even"><td>owncloud/ldap/cacheTTL</td>
 +<td>600</td>
 +<td>Lifetime of the ownCloud LDAP Cache in seconds</td>
 +<td>5.0.9</td>
 +</tr>
 +<tr class="row-odd"><td>owncloud/ldap/UUIDAttribute</td>
 +<td>(empty)</td>
 +<td>Attribute that provides a unique value for each user and group entry. Empty value for autodetection.</td>
 +<td>5.0.9</td>
 +</tr>
 +<tr class="row-even"><td>owncloud/ldap/loginFilter</td>
 +<td>(&(|(&(objectClass=posixAccount) (objectClass=shadowAccount)) (objectClass=univentionMail) (objectClass=sambaSamAccount) (objectClass=simpleSecurityObject) (&(objectClass=person) (objectClass=organizationalPerson) (objectClass=inetOrgPerson))) (!(uidNumber=0)) (!(uid=*$)) (&(uid=%uid) (ownCloudEnabled=1)))</td>
 +<td>The LDAP filter that shall be used when a user tries to log in.</td>
 +<td>2012.0.1</td>
 +</tr>
 +<tr class="row-odd"><td>owncloud/ldap/userlistFilter</td>
 +<td>(&(|(&(objectClass=posixAccount) (objectClass=shadowAccount)) (objectClass=univentionMail) (objectClass=sambaSamAccount) (objectClass=simpleSecurityObject) (&(objectClass=person) (objectClass=organizationalPerson) (objectClass=inetOrgPerson))) (!(uidNumber=0))(!(uid=*$)) (&(ownCloudEnabled=1)))</td>
 +<td>The LDAP filter that shall be used when the user list is being retrieved (e.g. for sharing)</td>
 +<td>2012.0.1</td>
 +</tr>
 +<tr class="row-even"><td>owncloud/ldap/groupFilter</td>
 +<td>(&(objectClass=posixGroup) (ownCloudEnabled=1))</td>
 +<td>The LDAP filter that shall be used when the group list is being retrieved (e.g. for sharing)</td>
 +<td>2012.4.0.4</td>
 +</tr>
 +<tr class="row-odd"><td>owncloud/ldap/internalNameAttribute</td>
 +<td>uid</td>
 +<td>Attribute that should be used to create the user’s owncloud internal name</td>
 +<td>5.0.9</td>
 +</tr>
 +<tr class="row-even"><td>owncloud/ldap/displayName</td>
 +<td>uid</td>
 +<td>The LDAP attribute that should be displayed as name in ownCloud</td>
 +<td>2012.0.1</td>
 +</tr>
 +<tr class="row-odd"><td>owncloud/ldap/user/searchAttributes</td>
 +<td>uid,givenName,sn,description,employeeNumber,mailPrimaryAddress</td>
 +<td>Attributes taken into consideration when searching for users (comma separated)</td>
 +<td>5.0.9</td>
 +</tr>
 +<tr class="row-even"><td>owncloud/ldap/user/quotaAttribute</td>
 +<td>ownCloudQuota</td>
 +<td>Name of the quota attribute. The default attribute is provided by owncloud-schema.</td>
 +<td>5.0.9</td>
 +</tr>
 +<tr class="row-odd"><td>owncloud/ldap/user/homeAttribute</td>
 +<td>(empty)</td>
 +<td>Attribute that should be used to create the user’s owncloud internal home folder</td>
 +<td>5.0.9</td>
 +</tr>
 +<tr class="row-even"><td>owncloud/ldap/group/displayName</td>
 +<td>cn</td>
 +<td>The LDAP attribute that should be used as groupname in ownCloud</td>
 +<td>2012.4.0.4</td>
 +</tr>
 +<tr class="row-odd"><td>owncloud/ldap/group/searchAttributes</td>
 +<td>cn,description, mailPrimaryAddress</td>
 +<td>Attributes taken into consideration when searching for groups (comma separated)</td>
 +<td>5.0.9</td>
 +</tr>
 +<tr class="row-even"><td>owncloud/join/users/update</td>
 +<td>yes</td>
 +<td>Wether ownCloud LDAP schema should be applied to existing users</td>
 +<td>2012.0.1</td>
 +</tr>
 +<tr class="row-odd"><td>owncloud/group/enableDomainUsers</td>
 +<td>1</td>
 +<td>Wether the group “Domain Users” shall be enabled for ownCloud on install</td>
 +<td>2012.4.0.4</td>
 +</tr>
 +<tr class="row-even"><td>owncloud/join/users/filter</td>
 +<td>(&(|(&(objectClass=posixAccount) (objectClass=shadowAccount)) (objectClass=univentionMail) (objectClass=sambaSamAccount) (objectClass=simpleSecurityObject) (&(objectClass=person) (objectClass=organizationalPerson) (objectClass=inetOrgPerson))) (!(uidNumber=0)) (!(|(uid=*$) (uid=owncloudsystemuser) (uid=join-backup) (uid=join-slave))) (!(objectClass=ownCloudUser)))</td>
 +<td>Filters, on which LDAP users the ownCloud schema should be applied to. The default excludes system users and already ownCloudUsers.</td>
 +<td>2012.0.1</td>
 +</tr>
 +<tr class="row-odd"><td>owncloud/join/groups/filter</td>
 +<td>(empty)</td>
 +<td>Filters which LDAP groups will be en/disabled for ownCloud when running the script /usr/share/owncloud/update-groups.sh</td>
 +<td>2012.4.0.4</td>
 +</tr>
 +</tbody>
 +</table>
 +<p>If you want to override the default settings, simply create the key in
 +question in the UCR and assign your required value, for example:</p>
 +<div class="highlight-python"><pre>ucr set owncloud/user/enabled=1</pre>
 +</div>
 +<p>or via UMC:</p>
 +<img alt="../_images/ucsint2.png" src="../_images/ucsint2.png" />
 +</div>
 +<div class="section" id="installation">
 +<h2>Installation<a class="headerlink" href="#installation" title="Permalink to this headline">¶</a></h2>
 +<p>Now, we are ready to install ownCloud. This can be either done through the UCS
 +App Center (recommended) or by downloading the packages.</p>
 +<div class="section" id="ucs-app-center">
 +<h3>UCS App Center<a class="headerlink" href="#ucs-app-center" title="Permalink to this headline">¶</a></h3>
 +<p>Open the Univention Management Console and choose the App Center module. You
 +will see a variety of available applications, including ownCloud.</p>
 +<img alt="../_images/ucs-app-center-module.png" src="../_images/ucs-app-center-module.png" />
 +<p>Click on ownCloud 5 and follow the instructions.</p>
 +<img alt="../_images/ucs-app-center-install.png" src="../_images/ucs-app-center-install.png" />
 +<p>In the UCS App Center, you can also upgrade from ownCloud 4.5 by installing
 +ownCloud 5.0. They are provided as separate apps. It is only possible to have
 +one version of ownCloud installed.</p>
 +</div>
 +<div class="section" id="manually-by-download">
 +<h3>Manually by download<a class="headerlink" href="#manually-by-download" title="Permalink to this headline">¶</a></h3>
 +<p>Download the integration packages <a class="reference external" href="https://owncloud.com/download">from our website</a> and install them from
 +within your download folder (note: the package owncloud-unsupported is
 +optional) via command line:</p>
 +<div class="highlight-python"><pre>dpkg -i owncloud*.deb</pre>
 +</div>
 +<p>ownCloud will be configured to fully work with LDAP.</p>
 +</div>
 +<div class="section" id="reinstallation">
 +<h3>Reinstallation<a class="headerlink" href="#reinstallation" title="Permalink to this headline">¶</a></h3>
 +<p>When ownCloud was installed before and uninstalled via AppCenter or via command
 +line using apt-get remove, ownCloud can be simply installed again. The old
 +configuration will be used again.</p>
 +<p>When an older ownCloud was installed and has been purged (only possible via
 +command line using apt-get purge) the old configuration is gone, but data is
 +left. This blocks an installation. You can either install the old version and
 +upgrade to ownCloud 5 or (re)move the old data. This is done by removing the
 +MySQL database “ownCloud” using the command line:</p>
 +<div class="highlight-python"><pre>mysql -u root -e "DROP DATABASE owncloud" -p`tail /etc/mysql.secret</pre>
 +</div>
 +<p>In this case you probably also want to remove the data directory
 +<strong>/var/lib/owncloud</strong> although this is not mandatory.</p>
 +</div>
 +</div>
 +<div class="section" id="postconfiguration-optional">
 +<h2>Postconfiguration (optional)<a class="headerlink" href="#postconfiguration-optional" title="Permalink to this headline">¶</a></h2>
 +<p>There is only one local admin user “owncloudadmin”, you can find his password in
 +<cite>/etc/owncloudadmin.secret</cite>. Use this account, if you want to change basic
 +ownCloud settings.</p>
 +<p>In the installation process a virtual host is set up (Apache is required
 +therefore). If you want to modify the settings, edit
 +<tt class="file docutils literal"><span class="pre">/etc/apache2/sites-available/owncloud</span></tt> and restart the web server. You
 +might want to do it to enable HTTPS connections. Besides that, you can edit the
 +<strong>.htaccess-File in /var/www/owncloud/</strong>. In the latter file there are also the
 +PHP limits for file transfer specified.</p>
 +</div>
 +<div class="section" id="using-owncloud">
 +<h2>Using ownCloud<a class="headerlink" href="#using-owncloud" title="Permalink to this headline">¶</a></h2>
 +<p>If you decided to enable every user by default to use ownCloud, simply
 +open up <a class="reference external" href="http://myserver.com/owncloud/">http://myserver.com/owncloud/</a> and log in with your LDAP
 +credentials and enjoy.</p>
 +<p>If you did not, go to the UMC and enable the users who shall have access
 +(see picture below). Then, login at <a class="reference external" href="http://myserver.com/owncloud/">http://myserver.com/owncloud/</a> with
 +your LDAP credentials.</p>
 +<img alt="../_images/ucsint1.png" src="../_images/ucsint1.png" />
 +<p>Updating users can also be done by the script
 +<tt class="file docutils literal"><span class="pre">/usr/share/owncloud/update-users.sh</span></tt> . It takes the following UCR
 +variables as parameters: <strong>owncloud/user/enabled</strong> for enabling or disabling,
 +<strong>owncloud/user/quota</strong> as the Quota value and <strong>owncloud/join/users/filter</strong> as
 +LDAP filter to select the users to update.</p>
 +<div class="section" id="groups-2012-4-0-4">
 +<h3>Groups 2012.4.0.4<a class="headerlink" href="#groups-2012-4-0-4" title="Permalink to this headline">¶</a></h3>
 +<p>Since ownCloud Enterprise 2012.4.0.4 group support is enabled. Groups,
 +that are activated for ownCloud usage, can be used to share files to
 +instead of single users, for example. It is also important to note, that
 +users can only share within groups where they belong to. Groups can be
 +enabled and disabled via UCM as shown in the screen shot below.</p>
 +<img alt="../_images/ucsint.png" src="../_images/ucsint.png" />
 +<p>Another way to enable or disable groups is to use the script
 +<tt class="file docutils literal"><span class="pre">/usr/share/owncloud/update-groups.sh</span></tt>. Currently, it takes an argument
 +which can be 1=enable groups or 0=disable groups. The filter applied is being
 +taken from the UCR variable <strong>owncloud/join/groups/filter</strong>. In case it is
 +empty, a message will be displayed.</p>
 +</div>
 +</div>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/installation/installation_windows.html
index 27c0efe,0000000..495f383
mode 100644,000000..100644
--- a/core/doc/admin/installation/installation_windows.html
+++ b/core/doc/admin/installation/installation_windows.html
@@@ -1,427 -1,0 +1,429 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
 +    <title>Windows 7 and Windows Server 2008 — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
 +    <link rel="up" title="Installation" href="index.html" />
 +    <link rel="next" title="Univention Corporate Server" href="installation_ucs.html" />
 +    <link rel="prev" title="Mac OS X" href="installation_macos.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
 +<ul class="current">
 +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Installation</a><ul class="current">
 +<li class="toctree-l2"><a class="reference internal" href="installation_appliance.html">Appliances</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="installation_linux.html">Linux Distributions</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="installation_macos.html">Mac OS X</a></li>
 +<li class="toctree-l2 current"><a class="current reference internal" href="">Windows 7 and Windows Server 2008</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="#activate-iis-with-cgi-support">Activate IIS with CGI Support</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#installing-php">Installing PHP</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#installing-mysql">Installing MySQL</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#installing-owncloud">Installing ownCloud</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#ensure-proper-http-verb-handling">Ensure Proper HTTP-Verb handling</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#configuring-owncloud-php-and-iis-for-large-file-uploads">Configuring ownCloud, PHP and IIS for Large File Uploads</a></li>
 +</ul>
 +</li>
 +<li class="toctree-l2"><a class="reference internal" href="installation_ucs.html">Univention Corporate Server</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="installation_source.html">Manual Installation</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="installation_others.html">PageKite Configuration</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="installation_others.html#open-wrt">Open Wrt</a></li>
 +</ul>
 +</li>
 +<li class="toctree-l1"><a class="reference internal" href="../configuration/index.html">Configuration</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
 +  <div class="section" id="windows-7-and-windows-server-2008">
 +<h1>Windows 7 and Windows Server 2008<a class="headerlink" href="#windows-7-and-windows-server-2008" title="Permalink to this headline">¶</a></h1>
 +<div class="admonition note">
 +<p class="first admonition-title">Note</p>
 +<p class="last">You must move the data directory outside of your public root (See
 +advanced install settings)</p>
 +</div>
 +<p>This section describes how to install ownCloud on Windows with <abbr title="Internet Information Services">IIS</abbr>.</p>
 +<p>It assumes that you have a vanilla, non-IIS enabled Windows
 +machine – Windows 7 or Server 2008. After enabling IIS, the steps are
 +essentially identical for Windows 7 and Windows Server 2008.</p>
 +<p>For installing ownCloud physical access or a remote desktop connection is
 +required. You should leverage MySQL as the backend database for ownCloud. If you
 +do not want to use MySQL, it is possible to use Postgres or SQLite instead.
 +Microsoft SQL Server is not yet support.</p>
 +<p>Enabling SSL is not yet covered by this section.</p>
 +<div class="admonition note">
 +<p class="first admonition-title">Note</p>
 +<p class="last">If you make your desktop machine or server available outside of your
 +LAN, you must maintain it. Monitor the logs, manage the access, apply patches to
 +avoid compromising the system at large.</p>
 +</div>
 +<p>There are 4 primary steps to the installation, and then a 5th step
 +required for configuring everything to allow files larger than the
 +default 2MB.</p>
 +<ol class="arabic simple">
 +<li>Install IIS with CGI support – enable IIS on your Windows machine.</li>
 +<li>Install PHP – Grab, download and install PHP.</li>
 +<li>Install MySQL – Setup the MySQL server manager and enable ownCloud to create
 +an instance.</li>
 +<li>Install ownCloud – The whole reason we are here!</li>
 +<li>Configure upload sizes and timeouts to enable large file uploads – So that
 +you can upload larger files.</li>
 +</ol>
 +<div class="section" id="activate-iis-with-cgi-support">
 +<h2>Activate IIS with CGI Support<a class="headerlink" href="#activate-iis-with-cgi-support" title="Permalink to this headline">¶</a></h2>
 +<div class="section" id="windows-7">
 +<h3>Windows 7<a class="headerlink" href="#windows-7" title="Permalink to this headline">¶</a></h3>
 +<ol class="arabic simple">
 +<li>Go to <em class="guilabel">Start –> Control Panel –> Programs</em>.</li>
 +<li>Under Programs and Features, there is link titled <em class="guilabel">Turn Windows Features on
 +and Off</em>. Click on it.</li>
 +<li>There is a box labeled Internet Information Services, expand it.</li>
 +<li>Expand World Wide Web Services and all the folders underneath.</li>
 +<li>Select the folders as illustrated in the picture below to get your IIS
 +server up and running.</li>
 +</ol>
 +<div class="align-center figure align-center">
 +<img alt="Windows features required for ownCloud on Windows 7" src="../_images/win7features.jpg" style="width: 250px;" />
 +<p class="caption">Windows Features required for ownCloud on Windows 7</p>
 +</div>
 +<p>You do not need an FTP server running, so you should tune
 +that feature off for your server. You definitely need the IIS Management
 +Console, as that is the easiest way to start, stop, restart you server,
 +as well as where you change certificate options and manage items like
 +file upload size. You must check the CGI box under Application
 +Development Features, because CGI is how you enable PHP on IIS.</p>
 +<p>You have to turn off WebDAV publishing or the Windows WebDAV
 +conflicts with the ownCloud WebDAV interface. This might already be
 +turned off for you, just make sure it stays that way. The common HTTP
 +features are the features you would expect from a web server.
 +With the selections on this page, IIS will now serve up a web page for you.</p>
 +<p>Restart IIS by going to the IIS manager (<em class="guilabel">Start –> IIS Manager</em>).</p>
 +<p>Select your website, and on the far right side is a section titled
 +<em class="guilabel">Manage Server</em>. Make sure that the service is started, or click
 +<em class="guilabel">Start</em> to start the services selected. Once this is complete, you
 +should be able to go to a web browser and navigate to <a class="reference external" href="http://localhost">http://localhost</a>.</p>
 +<p>This should open the standard IIS 7 splash page, which is just a static image
 +that says your web server is running. Assuming you were able to get the
 +splash page, it is safe to say your web server is now up and running.</p>
 +</div>
 +<div class="section" id="windows-server-2008">
 +<h3>Windows Server 2008<a class="headerlink" href="#windows-server-2008" title="Permalink to this headline">¶</a></h3>
 +<ol class="arabic simple">
 +<li>Go to <em class="guilabel">Start –> Control Panel –> Programs</em>.</li>
 +<li>Under Programs and Features, there is link titled
 +<em class="guilabel">Turn Windows Features on and Off</em>. Click on it.</li>
 +<li>This will bring up the Server Manager.</li>
 +<li>In the server manager, Click on Roles, and then click Add Roles.</li>
 +<li>Use the <em class="guilabel">Add Roles Wizard</em> to add the web server role.</li>
 +</ol>
 +<div class="align-center figure align-center">
 +<img alt="server roles required for ownCloud" src="../_images/winserverroles.jpg" style="width: 300px;" />
 +<p class="caption">Server roles required for ownCloud</p>
 +</div>
 +<ol class="arabic simple" start="6">
 +<li>Make sure that, at a minimum, the same boxes are checked in this wizard that
 +are checked in the Windows 7 Section. For example, make sure that the CGI box
 +is checked under Application Development Features, and that WebDAV Publishing
 +is turned off. With Remote Desktop Sharing turned on, the detailed role
 +service list looks like the figure “Role Services”.</li>
 +<li>Restart IIS by going to the IIS manager (<em class="guilabel">Start –> IIS Manager</em>).</li>
 +<li>Select your website, and on the far right side is a section titled Manage
 +server. Make sure that the service is started, or click “Start” to start the
 +services selected.</li>
 +<li>Once this is complete, you should be able to go to a web browser and type
 +<cite>localhost</cite>. This should open the standard IIS 7 splash page, which is just a
 +static image that says your web server is running.Assuming you were able to get
 +the splash page, it is safe to say your web server is now up and running. The
 +next part of this “how to” installs PHP on the server.</li>
 +</ol>
 +</div>
 +</div>
 +<div class="section" id="installing-php">
 +<h2>Installing PHP<a class="headerlink" href="#installing-php" title="Permalink to this headline">¶</a></h2>
 +<p>This part is also straightforward, but it is necessary to remind you that this
 +is for IIS only.</p>
 +<ol class="arabic simple">
 +<li>Go to the following link and grab the <a class="reference external" href="http://windows.php.net/download/">PHP installer</a> for version “VC9 Non Thread Safe” 32 or
 +64 bit based on your system.</li>
 +</ol>
 +<div class="admonition note">
 +<p class="first admonition-title">Note</p>
 +<p class="last">If you are using Apache, make sure you grab VC6 instead, lower on the page.</p>
 +</div>
 +<ol class="arabic simple" start="2">
 +<li>Once through that login, select the location that is closest to you
 +geographically.</li>
 +<li>Run that install wizard once it is downloaded. Read the license agreement,
 +agree, select an install directory.</li>
 +<li>Then select IIS FastCGI as the install server.</li>
 +<li>Take the default selections for the items to install, and click next.
 +Then click <cite>install</cite>.</li>
 +<li>After a few minutes, PHP will be installed. On to MySQL.</li>
 +</ol>
 +</div>
 +<div class="section" id="installing-mysql">
 +<h2>Installing MySQL<a class="headerlink" href="#installing-mysql" title="Permalink to this headline">¶</a></h2>
 +<p>This part installs MySQL on your Windows machine.</p>
 +<ol class="arabic simple">
 +<li>Point your browser to <a class="reference external" href="http://dev.mysql.com/downloads/">http://dev.mysql.com/downloads/</a> and download the latest
 +community edition for your OS – the 32 or 64 bit version. Please download the
 +<strong>MSI Installer</strong> as it will make life easier.</li>
 +<li>Once downloaded, install MySQL (5.5 at the time of writing). Select the
 +Typical installation.</li>
 +<li>When that finishes, check the box to launch the MySQL Instance Configuration
 +Wizard and click Finish.</li>
 +<li>Select a standard configuration, as this will be the only version of MySQL on
 +this machine.</li>
 +<li>Select to install as a windows service, and Check the Launch the MySQL Server
 +Automatically button.</li>
 +<li>Select the modify security settings box on the next page, and enter a
 +password you will remember. You will need this password when you configure
 +ownCloud.</li>
 +<li>Uncheck <strong>enable</strong> root access from remote machines” for security reasons.</li>
 +<li>Click execute, and wait while the instance is created and launched.</li>
 +<li>Click Finish when this is all complete.</li>
 +</ol>
 +<p>Take particular note of your MySQL password, as the user name <strong>root</strong>
 +and the password you select will be necessary later on in the ownCloud
 +installation. As an aside, this link is an excellent resource for questions on
 +how to configure your MySQL instance, and also to configure PHP to work with
 +MySQL. This, however, is not strictly necessary as much of this is handled when
 +you download ownCloud.</p>
 +<p>More information in this topic can be found in a <a class="reference external" href="http://learn.iis.net/page.aspx/353/install-and-configure-mysql-for-php-applications-on-iis-7-and-above/">tutorial on the IIS web site</a>.</p>
 +</div>
 +<div class="section" id="installing-owncloud">
 +<h2>Installing ownCloud<a class="headerlink" href="#installing-owncloud" title="Permalink to this headline">¶</a></h2>
 +<ol class="arabic simple">
 +<li>Download the latest version of ownCloud from <a class="reference external" href="http://owncloud.org/download">http://owncloud.org/download</a>.</li>
 +<li>It will arrive as a tar.bz2 file, and I recommend something like jZip for a
 +free utility to unzip it.</li>
 +<li>Once you have the ownCloud directory unzipped and saved locally, copy it into
 +your wwwroot directory (probably <strong>C:\inetpub\wwwroot</strong>).</li>
 +</ol>
 +<div class="admonition note">
 +<p class="first admonition-title">Note</p>
 +<p class="last">You cannot install directly into the directory <strong>wwwroot</strong> from jzip,
 +as only the administrator can unzip into the <strong>wwwroot</strong> directory. If you save
 +it in a different folder, and then move the files into <strong>wwwroot</strong> in windows
 +explorer, it works. This will install ownCloud locally in your root web
 +directory. You can use a subdirectory called owncloud, or whatever you want –
 +the www root, or something else.</p>
 +</div>
 +<ol class="arabic simple" start="4">
 +<li>It is now time to give write access to the ownCloud directory to the ownCloud
 +server: Navigate your windows explorer over to  <strong>inetpub/wwwroot/owncloud</strong> (or
 +your installation directory if you selected something different).</li>
 +<li>Right click and select properties. Click on the security tab, and click the
 +button “to change permissions, click edit”.</li>
 +<li>Select the “users” user from the list, and check the box “write”.</li>
 +<li>Apply these settings and close out.</li>
 +<li>Now open your browser and go to <a class="reference external" href="http://localhost/owncloud">http://localhost/owncloud</a> (or localhost if it
 +is installed in the root www directory). This should bring up the ownCloud
 +configuration page.</li>
 +<li>At this page, you enter your desired ownCloud user name and password for the
 +administrator, and expand the little arrow.</li>
 +<li>Select MySQL as the database, and enter your MySQL database user name,
 +password and desired instance name – use the user name and password you setup
 +for MySQL earlier in step 3, and pick any name for the database instance.</li>
 +</ol>
 +<div class="admonition note">
 +<p class="first admonition-title">Note</p>
 +<p class="last">The ownCloud admin password and the MySQL password CANNOT be the same
 +in any way.</p>
 +</div>
 +<ol class="arabic simple" start="11">
 +<li>Click next, and ownCloud should have you logged in as the admin user, and
 +you can get started exploring ownCloud, creating other users and more!</li>
 +</ol>
 +</div>
 +<div class="section" id="ensure-proper-http-verb-handling">
 +<h2>Ensure Proper HTTP-Verb handling<a class="headerlink" href="#ensure-proper-http-verb-handling" title="Permalink to this headline">¶</a></h2>
 +<p>IIS must pass all HTTP and WebDAV verbs to the PHP/CGI handler, and must not try
 +to handle them by itself. If it does, syncing with the Desktop and Mobile
 +Clients will fail. Here is how to ensure your configuration is correct:</p>
 +<ol class="arabic simple">
 +<li>Open IIS Manager7.</li>
 +<li>In the <cite>Connections</cite> bar, pick your site below <cite>Sites</cite>, or choose the top
 +level entry if you want to modify the machine-wide settings.</li>
 +<li>Choose the <cite>Handler Mappings</cite> feature click <cite>PHP_via_fastCGI</cite>.</li>
 +<li>Choose <cite>Request Restrictions</cite> and find the <cite>Verbs</cite> tab.</li>
 +<li>Ensure <cite>All Verbs</cite> is checked.</li>
 +<li>Click <cite>OK</cite>.</li>
 +<li>Next, choose <cite>Request Filtering</cite> feature from IIS Manager.</li>
 +<li>Ensure that all verbs are permitted (or none are forbidden) in the <cite>Verbs</cite>
 +tab.</li>
 +</ol>
 +<p>Also, ensure that you did not enable the WebDAV authoring module, since ownCloud
 +needs to be able to handle WebDAV on the application level.</p>
 +</div>
 +<div class="section" id="configuring-owncloud-php-and-iis-for-large-file-uploads">
 +<h2>Configuring ownCloud, PHP and IIS for Large File Uploads<a class="headerlink" href="#configuring-owncloud-php-and-iis-for-large-file-uploads" title="Permalink to this headline">¶</a></h2>
 +<p>Before going too nuts on ownCloud, it is important to do a couple of
 +configuration changes to make this a useful service for you. You will probably
 +want to increase the <strong>max upload size</strong>, for example. The default upload is
 +set to <strong>2MB</strong>, which is too small for even most MP3 files.</p>
 +<p>To do that, simply go into your <strong>PHP.ini</strong> file, which can be found in your
 +<strong>C:\Program Files (x86)\PHP</strong> folder. In here, you will find a <strong>PHP.ini</strong>
 +file. Open this in a text editor, and look for a few key attributes to
 +change:</p>
 +<ul class="simple">
 +<li><strong>upload_max_filesize</strong> – change this to something good, like 1G, and you
 +will get to upload much larger files.</li>
 +<li><strong>post_max_size</strong> – also change this size, and make it larger than the max
 +upload size you chose, like 1G.</li>
 +</ul>
 +<p>There are other changes you can make, such as the timeout duration for
 +uploads, but for now you should be all set in the <strong>PHP.ini</strong> file.</p>
 +<p>Now you have to go back to IIS manager and make one last change to enable file
 +uploads on the web server larger than 30MB.</p>
 +<ol class="arabic">
 +<li><p class="first">Go to the start menu, and type <strong>iis manager</strong>.</p>
 +</li>
 +<li><p class="first">Open IIS Manager Select the website you want enable to accept large file
 +uploads.</p>
 +</li>
 +<li><p class="first">In the main window in the middle double click on the icon <strong>Request
 +filtering</strong>.</p>
 +</li>
 +<li><p class="first">Once the window is opened you will see a bunch of tabs across the top of the
 +far right,</p>
 +<p>Select <em class="guilabel">Edit Feature Settings</em> and modify the <em class="guilabel">Maximum
 +allowed content length (bytes)</em></p>
 +</li>
 +<li><p class="first">In here, you can change this to up to 4.1 GB.</p>
 +</li>
 +</ol>
 +<div class="admonition note">
 +<p class="first admonition-title">Note</p>
 +<p class="last">This entry is in BYTES, not KB.</p>
 +</div>
 +<p>You should now have ownCloud configured and ready for use.</p>
 +</div>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/issues/index.html
index 33a2e9d,0000000..6ed03a6
mode 100644,000000..100644
--- a/core/doc/admin/issues/index.html
+++ b/core/doc/admin/issues/index.html
@@@ -1,161 -1,0 +1,163 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
 +    <title>Issues — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
-     <link rel="prev" title="Migrating ownCloud Installations" href="../maintenance/migrating.html" />
++    <link rel="prev" title="Miscellaneous" href="../config/miscellaneous.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
 +<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../installation/index.html">Installation</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../configuration/index.html">Configuration</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1 current"><a class="current reference internal" href="">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
 +  <div class="section" id="issues">
 +<h1>Issues<a class="headerlink" href="#issues" title="Permalink to this headline">¶</a></h1>
 +<p>If you think you have found a bug in ownCloud, please:</p>
 +<ul class="simple">
 +<li>Search for a solution</li>
 +<li>Double check your configuration</li>
 +</ul>
 +<p>If you can’t find a solution, please file an issue:</p>
 +<ul class="simple">
 +<li>If the issue is with the ownCloud server, report it to the <a class="reference external" href="https://github.com/owncloud/core">GitHub core repository</a></li>
 +<li>If the issue is with the ownCloud client, report it to the <a class="reference external" href="https://github.com/owncloud/mirall">GitHub mirall repository</a></li>
 +<li>If the issue with with an ownCloud app, report it to where that app is developed<ul>
 +<li>If the app is listed <a class="reference external" href="https://github.com/owncloud">here</a> report it to the correct repository</li>
 +<li>If the app is listed <a class="reference external" href="https://github.com/owncloud/apps">here</a> report it to the apps repository</li>
 +</ul>
 +</li>
 +</ul>
 +<p>Please note that the mailing list should not be used for bug reports, as it is hard to track them there.</p>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/maintenance/backup.html
index 1c6b748,0000000..d0b7e94
mode 100644,000000..100644
--- a/core/doc/admin/maintenance/backup.html
+++ b/core/doc/admin/maintenance/backup.html
@@@ -1,189 -1,0 +1,191 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
 +    <title>Backing up ownCloud — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
 +    <link rel="up" title="Maintenance" href="index.html" />
 +    <link rel="next" title="Updating ownCloud" href="update.html" />
 +    <link rel="prev" title="Maintenance" href="index.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
 +<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../installation/index.html">Installation</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../configuration/index.html">Configuration</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
 +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Maintenance</a><ul class="current">
 +<li class="toctree-l2 current"><a class="current reference internal" href="">Backing up ownCloud</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="#backup-folders">Backup Folders</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#backup-database">Backup Database</a></li>
 +</ul>
 +</li>
 +<li class="toctree-l2"><a class="reference internal" href="update.html">Updating ownCloud</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="restore.html">Restoring ownCloud</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="migrating.html">Migrating ownCloud Installations</a></li>
 +</ul>
 +</li>
++<li class="toctree-l1"><a class="reference internal" href="../config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
 +  <div class="section" id="backing-up-owncloud">
 +<h1>Backing up ownCloud<a class="headerlink" href="#backing-up-owncloud" title="Permalink to this headline">¶</a></h1>
 +<p>To backup an ownCloud installation there are three main things you need to retain:</p>
 +<ol class="arabic simple">
 +<li>The config folder</li>
 +<li>The data folder</li>
 +<li>The database</li>
 +</ol>
 +<div class="section" id="backup-folders">
 +<h2>Backup Folders<a class="headerlink" href="#backup-folders" title="Permalink to this headline">¶</a></h2>
 +<p>Simply copy your config and data folder (or even your whole ownCloud install and data folder) to a place outside of
 +your ownCloud environment. You could use this command:</p>
 +<div class="highlight-python"><pre>rsync -Aax owncloud/ owncloud-dirbkp_`date +"%Y%m%d"`/</pre>
 +</div>
 +</div>
 +<div class="section" id="backup-database">
 +<h2>Backup Database<a class="headerlink" href="#backup-database" title="Permalink to this headline">¶</a></h2>
 +<div class="section" id="mysql">
 +<h3>MySQL<a class="headerlink" href="#mysql" title="Permalink to this headline">¶</a></h3>
 +<p>MySQL is the recommended database engine. To backup MySQL:</p>
 +<div class="highlight-python"><pre>mysqldump --lock-tables -h [server] -u [username] -p[password] > owncloud-sqlbkp_`date +"%Y%m%d"`.bak</pre>
 +</div>
 +</div>
 +<div class="section" id="sqlite">
 +<h3>SQLite<a class="headerlink" href="#sqlite" title="Permalink to this headline">¶</a></h3>
 +<div class="highlight-python"><pre>sqlite3 data/owncloud.db .dump > owncloud-sqlbkp_`date +"%Y%m%d"`.bak</pre>
 +</div>
 +</div>
 +<div class="section" id="postgresql">
 +<h3>PostgreSQL<a class="headerlink" href="#postgresql" title="Permalink to this headline">¶</a></h3>
 +<div class="highlight-python"><pre>PGPASSWORD="password" pg_dump owncloud -h [server] -U [username] -f owncloud-sqlbkp_`date +"%Y%m%d"`.bak</pre>
 +</div>
 +</div>
 +</div>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/maintenance/index.html
index bbf3838,0000000..1bb02fe
mode 100644,000000..100644
--- a/core/doc/admin/maintenance/index.html
+++ b/core/doc/admin/maintenance/index.html
@@@ -1,160 -1,0 +1,162 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
 +    <title>Maintenance — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
 +    <link rel="next" title="Backing up ownCloud" href="backup.html" />
-     <link rel="prev" title="Serving static files via web server" href="../configuration/xsendfile.html" />
++    <link rel="prev" title="File Viewers" href="../apps/viewers/index.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
 +<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../installation/index.html">Installation</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../configuration/index.html">Configuration</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
 +<li class="toctree-l1 current"><a class="current reference internal" href="">Maintenance</a><ul>
 +<li class="toctree-l2"><a class="reference internal" href="backup.html">Backing up ownCloud</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="update.html">Updating ownCloud</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="restore.html">Restoring ownCloud</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="migrating.html">Migrating ownCloud Installations</a></li>
 +</ul>
 +</li>
++<li class="toctree-l1"><a class="reference internal" href="../config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
 +  <div class="section" id="maintenance">
 +<h1>Maintenance<a class="headerlink" href="#maintenance" title="Permalink to this headline">¶</a></h1>
 +<div class="toctree-wrapper compound">
 +<ul>
 +<li class="toctree-l1"><a class="reference internal" href="backup.html">Backing up ownCloud</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="update.html">Updating ownCloud</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="restore.html">Restoring ownCloud</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="migrating.html">Migrating ownCloud Installations</a></li>
 +</ul>
 +</div>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/maintenance/migrating.html
index 841bda6,0000000..5dd243e
mode 100644,000000..100644
--- a/core/doc/admin/maintenance/migrating.html
+++ b/core/doc/admin/maintenance/migrating.html
@@@ -1,160 -1,0 +1,162 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
 +    <title>Migrating ownCloud Installations — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
 +    <link rel="up" title="Maintenance" href="index.html" />
-     <link rel="next" title="Issues" href="../issues/index.html" />
++    <link rel="next" title="The Configuration File" href="../config/index.html" />
 +    <link rel="prev" title="Restoring ownCloud" href="restore.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
 +<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../installation/index.html">Installation</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../configuration/index.html">Configuration</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
 +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Maintenance</a><ul class="current">
 +<li class="toctree-l2"><a class="reference internal" href="backup.html">Backing up ownCloud</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="update.html">Updating ownCloud</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="restore.html">Restoring ownCloud</a></li>
 +<li class="toctree-l2 current"><a class="current reference internal" href="">Migrating ownCloud Installations</a></li>
 +</ul>
 +</li>
++<li class="toctree-l1"><a class="reference internal" href="../config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
 +  <div class="section" id="migrating-owncloud-installations">
 +<h1>Migrating ownCloud Installations<a class="headerlink" href="#migrating-owncloud-installations" title="Permalink to this headline">¶</a></h1>
 +<p>To migrate an ownCloud install, follow those steps:</p>
 +<ol class="arabic simple">
 +<li>Backup data/config folders and your database (look at “Backing Up ownCloud”)</li>
 +<li>Move your data</li>
 +<li>Restore your data/config folders and your database (look at “Restore ownCloud”)</li>
 +<li>Update config.php of any changes to your database connection</li>
 +</ol>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/maintenance/restore.html
index eebd99a,0000000..4a4b580
mode 100644,000000..100644
--- a/core/doc/admin/maintenance/restore.html
+++ b/core/doc/admin/maintenance/restore.html
@@@ -1,198 -1,0 +1,200 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
 +    <title>Restoring ownCloud — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
 +    <link rel="up" title="Maintenance" href="index.html" />
 +    <link rel="next" title="Migrating ownCloud Installations" href="migrating.html" />
 +    <link rel="prev" title="Updating ownCloud" href="update.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
 +<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../installation/index.html">Installation</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../configuration/index.html">Configuration</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
 +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Maintenance</a><ul class="current">
 +<li class="toctree-l2"><a class="reference internal" href="backup.html">Backing up ownCloud</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="update.html">Updating ownCloud</a></li>
 +<li class="toctree-l2 current"><a class="current reference internal" href="">Restoring ownCloud</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="#restore-folders">Restore Folders</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#restore-database">Restore Database</a></li>
 +</ul>
 +</li>
 +<li class="toctree-l2"><a class="reference internal" href="migrating.html">Migrating ownCloud Installations</a></li>
 +</ul>
 +</li>
++<li class="toctree-l1"><a class="reference internal" href="../config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
 +  <div class="section" id="restoring-owncloud">
 +<h1>Restoring ownCloud<a class="headerlink" href="#restoring-owncloud" title="Permalink to this headline">¶</a></h1>
 +<p>To restore an ownCloud installation there are three main things you need to restore:</p>
 +<ol class="arabic simple">
 +<li>The config folder</li>
 +<li>The data folder</li>
 +<li>The database</li>
 +</ol>
 +<div class="section" id="restore-folders">
 +<h2>Restore Folders<a class="headerlink" href="#restore-folders" title="Permalink to this headline">¶</a></h2>
 +<div class="admonition note">
 +<p class="first admonition-title">Note</p>
 +<p class="last">This guide assumes that your previous backup is called “owncloud-dirbkp”</p>
 +</div>
 +<p>Simply copy your config and data folder (or even your whole ownCloud install and data folder) to a place outside of
 +your ownCloud environment. You could use this command:</p>
 +<div class="highlight-python"><pre>rsync -Aax owncloud-dirbkp/ owncloud/</pre>
 +</div>
 +</div>
 +<div class="section" id="restore-database">
 +<h2>Restore Database<a class="headerlink" href="#restore-database" title="Permalink to this headline">¶</a></h2>
 +<div class="admonition note">
 +<p class="first admonition-title">Note</p>
 +<p class="last">This guide assumes that your previous backup is called “owncloud-sqlbkp.bak”</p>
 +</div>
 +<div class="section" id="mysql">
 +<h3>MySQL<a class="headerlink" href="#mysql" title="Permalink to this headline">¶</a></h3>
 +<p>MySQL is the recommended database engine. To backup MySQL:</p>
 +<div class="highlight-python"><div class="highlight"><pre><span class="n">mysql</span> <span class="o">-</span><span class="n">h</span> <span class="p">[</span><span class="n">server</span><span class="p">]</span> <span class="o">-</span><span class="n">u</span> <span class="p">[</span><span class="n">username</span><span class="p">]</span> <span class="o">-</span><span class="n">p</span><span class="p">[</span><span class="n">password</span><span class="p">]</span> <span class="o">< [...]
 +</pre></div>
 +</div>
 +</div>
 +<div class="section" id="sqlite">
 +<h3>SQLite<a class="headerlink" href="#sqlite" title="Permalink to this headline">¶</a></h3>
 +<div class="highlight-python"><pre>sqlite3 data/owncloud.db .dump < owncloud-sqlbkp.bak</pre>
 +</div>
 +</div>
 +<div class="section" id="postgresql">
 +<h3>PostgreSQL<a class="headerlink" href="#postgresql" title="Permalink to this headline">¶</a></h3>
 +<div class="highlight-python"><pre>PGPASSWORD="password" pg_restore -c -d owncloud -h [server] -U [username] owncloud-sqlbkp.bak</pre>
 +</div>
 +</div>
 +</div>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/maintenance/update.html
index 1d0c77b,0000000..783a46f
mode 100644,000000..100644
--- a/core/doc/admin/maintenance/update.html
+++ b/core/doc/admin/maintenance/update.html
@@@ -1,215 -1,0 +1,215 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
 +    <title>Updating ownCloud — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
 +    <link rel="up" title="Maintenance" href="index.html" />
 +    <link rel="next" title="Restoring ownCloud" href="restore.html" />
 +    <link rel="prev" title="Backing up ownCloud" href="backup.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
 +<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../installation/index.html">Installation</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../configuration/index.html">Configuration</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
 +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Maintenance</a><ul class="current">
 +<li class="toctree-l2"><a class="reference internal" href="backup.html">Backing up ownCloud</a></li>
 +<li class="toctree-l2 current"><a class="current reference internal" href="">Updating ownCloud</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="#update">Update</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#upgrade">Upgrade</a></li>
 +</ul>
 +</li>
 +<li class="toctree-l2"><a class="reference internal" href="restore.html">Restoring ownCloud</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="migrating.html">Migrating ownCloud Installations</a></li>
 +</ul>
 +</li>
++<li class="toctree-l1"><a class="reference internal" href="../config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
 +  <div class="section" id="updating-owncloud">
 +<h1>Updating ownCloud<a class="headerlink" href="#updating-owncloud" title="Permalink to this headline">¶</a></h1>
 +<div class="admonition note">
 +<p class="first admonition-title">Note</p>
 +<p class="last">If you have installed ownCloud from a repository, your package management should take care of it. Probably
 +you will need to look for compatible third party applications yourself. <strong>Always do backups anyway.</strong></p>
 +</div>
 +<div class="section" id="update">
 +<h2>Update<a class="headerlink" href="#update" title="Permalink to this headline">¶</a></h2>
- <p>Updating means updating ownCloud to the latest <em>point release</em>, e.g. ownCloud 5.0.13 → 5.0.14a. This procedure uses the
++<p>Updating means updating ownCloud to the latest <em>point release</em>, e.g. ownCloud 6.0.0a → 6.0.2. This procedure uses the
 +ownCloud updater plugin called “Updater”: it’s an internal application already present in your ownCloud installation.</p>
 +<p>To update ownCloud, follow those steps:</p>
 +<ol class="arabic simple">
 +<li>Make a backup of the ownCloud folder and the database.</li>
 +<li>Make sure that updater plugin is enabled.</li>
 +<li>Navigate to the ‘Admin’ page.</li>
 +<li>Click ‘Update’.</li>
 +<li>Refresh the page with Ctrl+F5.</li>
 +</ol>
 +<p>If this procedure doesn’t work (for example, ownCloud 5.0.10 doesn’t show new any new version) you could try to perform
 +a full upgrade to update to the latest point release (see below).</p>
 +</div>
 +<div class="section" id="upgrade">
 +<h2>Upgrade<a class="headerlink" href="#upgrade" title="Permalink to this headline">¶</a></h2>
 +<p>Upgrade is to bring an ownCloud instance to a new <em>major release</em>, e.g.
 +ownCloud 5.0.14a → 6.0.2. Always do backups anyway.</p>
 +<p>To upgrade ownCloud, follow those steps:</p>
 +<ol class="arabic">
 +<li><p class="first">Make sure that you ran the latest point release of the major ownCloud
 +version, e.g. 5.0.14a in the 5.0 series. If not, update to that version first
 +(see above).</p>
 +</li>
 +<li><p class="first">Make a backup of the ownCloud folder and the database.</p>
 +</li>
 +<li><p class="first">Download the latest version to the working directory:</p>
 +<div class="highlight-python"><pre>wget http://download.owncloud.org/community/owncloud-latest.tar.bz2</pre>
 +</div>
 +</li>
 +<li><p class="first">Deactivate all third party applications.</p>
 +</li>
 +<li><p class="first">Delete everything from your ownCloud installation directory, except data and
- config. Assuming that it’s your working directory, you could execute this command:</p>
- <div class="highlight-python"><pre>ls | grep -v 'data\|config' | xargs rm -r</pre>
- </div>
++config.</p>
 +</li>
 +<li><p class="first">Unpack the release tarball in the ownCloud directory (or copy the
 +files thereto). Assuming that your installation directory is called ‘owncloud’ and that it’s inside your working
 +directory, you could execute this command:</p>
 +<div class="highlight-python"><pre>tar xfj owncloud-latest.tar.bz2</pre>
 +</div>
 +</li>
 +<li><p class="first">Set the permissions properly</p>
 +</li>
 +<li><p class="first">With the next page request the update procedures will run.</p>
 +</li>
 +<li><p class="first">If you had 3rd party applications, check if they provide versions compatible
 +with the new release. If so, install and enable them, update procedures will run if needed.</p>
 +</li>
 +</ol>
 +</div>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/quota/index.html
index 4b48e0d,0000000..9dcdc85
mode 100644,000000..100644
--- a/core/doc/admin/quota/index.html
+++ b/core/doc/admin/quota/index.html
@@@ -1,164 -1,0 +1,218 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
-     <title><no title> — ownCloud Administrators Manual 6.0 documentation</title>
++    <title>Quota Calculation — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
 +<ul>
 +<li class="toctree-l1"><a class="reference internal" href="../installation/index.html">Installation</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../configuration/index.html">Configuration</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
-   <p><strong>ownCloud Quota Calculations</strong></p>
- <div class="toctree-wrapper compound">
- <ul>
- <li class="toctree-l1"><a class="reference internal" href="Table_of_Contents.html">Table of Contents</a></li>
- <li class="toctree-l1"><a class="reference internal" href="Introduction.html">Introduction</a></li>
- <li class="toctree-l1"><a class="reference internal" href="Checking_available_space.html">Checking available space</a></li>
- <li class="toctree-l1"><a class="reference internal" href="Sharing.html">Sharing</a><ul>
- <li class="toctree-l2"><a class="reference internal" href="Sharing.html#shared-files">Shared Files</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Sharing.html#shared-directories">Shared Directories</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Sharing.html#resharing">Resharing</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Sharing.html#public-sharing-with-upload-permission">Public sharing with upload permission</a></li>
- </ul>
- </li>
- <li class="toctree-l1"><a class="reference internal" href="Excluded_from_quota.html">Excluded from quota</a><ul>
- <li class="toctree-l2"><a class="reference internal" href="Excluded_from_quota.html#metadata-and-cache">Metadata and cache</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Excluded_from_quota.html#deleted-files">Deleted Files</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Excluded_from_quota.html#version-control">Version Control</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Excluded_from_quota.html#encryption">Encryption</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Excluded_from_quota.html#external-storage">External Storage</a></li>
- </ul>
- </li>
- </ul>
++  <div class="section" id="quota-calculation">
++<h1>Quota Calculation<a class="headerlink" href="#quota-calculation" title="Permalink to this headline">¶</a></h1>
++<div class="section" id="introduction">
++<h2>Introduction<a class="headerlink" href="#introduction" title="Permalink to this headline">¶</a></h2>
++<p>ownCloud allows the admin to specify a storage quota for users.
++This quota is the maximum space a user is allowed to utilize for files located in their home storage.</p>
++<p>The users quota is set in the Users page within ownCloud when creating a user.</p>
++<p><img alt="10000000000003DF000000D953A456B6_png" src="../_images/10000000000003DF000000D953A456B6.png" style="width: 6.5in; height: 1.4228in;" /></p>
++<p>Each user can have a different quota (shown above in the Storage column).
++In addition, there is a default quota should a user not have a quota specified.</p>
++<p>It is important to note that when setting a quota, the administrator needs to be aware that it applies only to the actual files and not the metadata.
++This means when allocating a quota, the admin should make sure at least 10% more space is available for each user.</p>
++</div>
++<div class="section" id="checking-available-space">
++<h2>Checking available space<a class="headerlink" href="#checking-available-space" title="Permalink to this headline">¶</a></h2>
++<p>A user can check their available space on the Personal page.</p>
++<p><img alt="10000000000003A800000039364066E4_png" src="../_images/10000000000003A800000039364066E4.png" style="width: 6.5in; height: 0.3957in;" /></p>
++<p>The available space for a given user is calculated using the following formula:</p>
++<p><img alt="10000000000002BB000000266DB6AD1A_png" src="../_images/10000000000002BB000000266DB6AD1A.png" style="width: 6.5in; height: 0.3535in;" /></p>
++<p>Where disk_free_space is the space available on the partition where the user’s home storage is located on the server.</p>
++</div>
++<div class="section" id="sharing">
++<h2>Sharing<a class="headerlink" href="#sharing" title="Permalink to this headline">¶</a></h2>
++<p>Shared files or directories are counted against the owner’s quota and not the “shared-to” user’s quota.</p>
++<div class="section" id="shared-files">
++<h3>Shared Files<a class="headerlink" href="#shared-files" title="Permalink to this headline">¶</a></h3>
++<p>When user A shares a file with user B, the size of the file will be counted against user A’s quota.
++This is the case even if the file is modified by user B or if user B increases the file size.</p>
++</div>
++<div class="section" id="shared-directories">
++<h3>Shared Directories<a class="headerlink" href="#shared-directories" title="Permalink to this headline">¶</a></h3>
++<p>When user A shares a directory with User B, all files uploaded to that directory by user B will count against user A’s quota.
++Likewise, files within that directory which are modified by user B will count against user A’s quota.</p>
++</div>
++<div class="section" id="resharing">
++<h3>Resharing<a class="headerlink" href="#resharing" title="Permalink to this headline">¶</a></h3>
++<p>If user A shares a file with user B who then reshares a file to user C, the space occupied by that file is counted against user A’s quota.</p>
++</div>
++<div class="section" id="public-sharing-with-upload-permission">
++<h3>Public sharing with upload permission<a class="headerlink" href="#public-sharing-with-upload-permission" title="Permalink to this headline">¶</a></h3>
++<p>If user A publicly shares a directory via a link and enables “public upload” permission, files uploaded to that directory from the outside are counted against user A’s quota.
++Excluded from quota
++===================</p>
++<p>The following sections describe information which is not counted in a user’s quota.</p>
++</div>
++<div class="section" id="metadata-and-cache">
++<h3>Metadata and cache<a class="headerlink" href="#metadata-and-cache" title="Permalink to this headline">¶</a></h3>
++<p>Application metadata and cached information are excluded from total used space.
++Examples of such data are thumbnails (icon previews, pictures app), temporary files, and encryption keys.</p>
++</div>
++<div class="section" id="deleted-files">
++<h3>Deleted Files<a class="headerlink" href="#deleted-files" title="Permalink to this headline">¶</a></h3>
++<p>Files which have been moved to the trash bin do not count against a user’s quota.
++Deleted items are permanently deleted, oldest to newest, should the user run out of space to make room for new files.</p>
++<p>For example, if the user has a 10GB quota, and has used 4GB of space and 5GB in the trash bin, the user will still have 6GB available space.
++If, however, the user uploads 6GB, ownCloud will permanently delete files from the trash bin in order to make room for the new files.</p>
++</div>
++<div class="section" id="version-control">
++<h3>Version Control<a class="headerlink" href="#version-control" title="Permalink to this headline">¶</a></h3>
++<p>Older versions do not count against the user’s quota.
++The versions app will delete old versions, oldest to newest, should the user run out of space to make room for new files.</p>
++<p>For example, if the user has a 10GB quota, and has used 4GB and 5GB is used on older versions, the user will still have 6GB available space.
++If, however, the user uploads 6GB, ownCloud will discard older versions to make room for the new files.</p>
++</div>
++<div class="section" id="encryption">
++<h3>Encryption<a class="headerlink" href="#encryption" title="Permalink to this headline">¶</a></h3>
++<p>Encrypted files are slightly larger than their unencrypted equivalents.
++The unencrypted file size is used to determine the quota.</p>
++</div>
++<div class="section" id="external-storage">
++<h3>External Storage<a class="headerlink" href="#external-storage" title="Permalink to this headline">¶</a></h3>
++<p>External storage, mounted by either a user or the admin, is not taken into consideration when calculating the user’s storage.</p>
++</div>
++</div>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/search.html
index cd6fd0f,0000000..2cad2bb
mode 100644,000000..100644
--- a/core/doc/admin/search.html
+++ b/core/doc/admin/search.html
@@@ -1,169 -1,0 +1,171 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
 +    <title>Search — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="_static/jquery.js"></script>
 +    <script type="text/javascript" src="_static/underscore.js"></script>
 +    <script type="text/javascript" src="_static/doctools.js"></script>
 +    <script type="text/javascript" src="_static/searchtools.js"></script>
 +    <script type="text/javascript" src="_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="index.html" />
 +  <script type="text/javascript">
 +    jQuery(function() { Search.loadIndex("searchindex.js"); });
 +  </script>
 +  
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
 +<ul>
 +<li class="toctree-l1"><a class="reference internal" href="installation/index.html">Installation</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="configuration/index.html">Configuration</a></li>
++<li class="toctree-l1"><a class="reference internal" href="apps/index.html">Apps</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1"><a class="reference internal" href="config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
 +  <h1 id="search-documentation">Search</h1>
 +  <div id="fallback" class="admonition warning">
 +  <script type="text/javascript">$('#fallback').hide();</script>
 +  <p>
 +    Please activate JavaScript to enable the search
 +    functionality.
 +  </p>
 +  </div>
 +  <p>
 +    From here you can search these documents. Enter your search
 +    words into the box below and click "search". Note that the search
 +    function will automatically search for all of the words. Pages
 +    containing fewer words won't appear in the result list.
 +  </p>
 +  <form action="" method="get">
 +    <input type="text" name="q" value="" />
 +    <input type="submit" value="search" />
 +    <span id="search-progress" style="padding-left: 10px"></span>
 +  </form>
 +  
 +  <div id="search-results">
 +  
 +  </div>
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/sharing_api/create_a_new_share.html
index 1be6a17,0000000..914df78
mode 100644,000000..100644
--- a/core/doc/admin/sharing_api/create_a_new_share.html
+++ b/core/doc/admin/sharing_api/create_a_new_share.html
@@@ -1,408 -1,0 +1,404 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
 +    <title>Create a new Share — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
 +<ul>
 +<li class="toctree-l1"><a class="reference internal" href="../installation/index.html">Installation</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../configuration/index.html">Configuration</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
 +  <div class="section" id="create-a-new-share">
 +<h1>Create a new Share<a class="headerlink" href="#create-a-new-share" title="Permalink to this headline">¶</a></h1>
 +<p>To create a new share the following may be used.
 +This allows sharing with a user or group or as a link.</p>
 +<table border="1" class="docutils">
 +<colgroup>
 +<col width="14%" />
 +<col width="32%" />
 +<col width="6%" />
 +<col width="48%" />
 +</colgroup>
 +<tbody valign="top">
 +<tr class="row-odd"><td>Syntax</td>
 +<td><Base URL></td>
 +<td> </td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td>Method</td>
 +<td>POST</td>
 +<td> </td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td>Mandatory Argument</td>
 +<td>path</td>
 +<td>string</td>
 +<td>Full path of the file/folder being shared</td>
 +</tr>
 +<tr class="row-even"><td>Mandatory Argument</td>
 +<td>shareType</td>
 +<td>int</td>
 +<td>‘0’ = user, ‘1’ = group, ‘3’ = Public link</td>
 +</tr>
 +<tr class="row-odd"><td>Argument</td>
 +<td>shareWith</td>
 +<td>string</td>
 +<td>User/group ID with who the file should be shared.
 +This is mandatory for shareType of 0 or 1</td>
 +</tr>
 +<tr class="row-even"><td>Argument</td>
 +<td>publicUpload</td>
 +<td>boolean</td>
 +<td><p class="first">If ‘false’ (default) public cannot upload to a public shared folder</p>
 +<p>If ‘true’ public can upload to a shared folder</p>
 +<p class="last">Only available for public link shares</p>
 +</td>
 +</tr>
 +<tr class="row-odd"><td>Argument</td>
 +<td>password</td>
 +<td>string</td>
 +<td><p class="first">Password to protect a public link share</p>
 +<p class="last">Only available for public link shares</p>
 +</td>
 +</tr>
 +<tr class="row-even"><td>Argument</td>
 +<td>permissions</td>
 +<td>int</td>
 +<td>From table in section 2.2 for user or group shares</td>
 +</tr>
 +<tr class="row-odd"><td>Result</td>
 +<td>XML Code with share ID of newly created share</td>
 +<td> </td>
 +<td> </td>
 +</tr>
 +</tbody>
 +</table>
 +<p>The following is a list of returned status codes:</p>
 +<table border="1" class="docutils">
 +<colgroup>
 +<col width="35%" />
 +<col width="65%" />
 +</colgroup>
 +<tbody valign="top">
 +<tr class="row-odd"><td>HTTP Status Code</td>
 +<td>Description</td>
 +</tr>
 +<tr class="row-even"><td>100</td>
 +<td>Successful</td>
 +</tr>
 +<tr class="row-odd"><td>400</td>
 +<td>Unknown Share type</td>
 +</tr>
 +<tr class="row-even"><td>403</td>
 +<td>Public Upload disabled by admin</td>
 +</tr>
 +<tr class="row-odd"><td>404</td>
 +<td>File couldn’t be shared</td>
 +</tr>
 +</tbody>
 +</table>
 +<div class="section" id="poster-share-as-a-link">
 +<h2>Poster – Share as a link<a class="headerlink" href="#poster-share-as-a-link" title="Permalink to this headline">¶</a></h2>
 +<p>The following example shares the file “test/Lab.txt” as a public link</p>
 +<table border="1" class="docutils">
 +<colgroup>
 +<col width="25%" />
 +<col width="75%" />
 +</colgroup>
 +<tbody valign="top">
 +<tr class="row-odd"><td>Field</td>
 +<td>Value</td>
 +</tr>
 +<tr class="row-even"><td><strong>URL</strong></td>
 +<td>Base URL for the API of the ownCloud server</td>
 +</tr>
 +<tr class="row-odd"><td><strong>User Auth</strong></td>
 +<td>User ID of the file owner</td>
 +</tr>
 +<tr class="row-even"><td><strong>Password</strong></td>
 +<td>User’s Password</td>
 +</tr>
 +<tr class="row-odd"><td><strong>Name</strong></td>
 +<td>Argument being passed</td>
 +</tr>
 +<tr class="row-even"><td><strong>Value</strong></td>
 +<td>Full path of file/folder shared</td>
 +</tr>
 +</tbody>
 +</table>
 +<p><img alt="1000000000000298000001874D3CA506_png" src="../_images/1000000000000298000001874D3CA506.png" style="width: 6.5in; height: 3.828in;" /></p>
 +<p>Navigate to the “Content to Send” tab and select “Body from Parameters”</p>
 +<p><img alt="1000000000000298000001870B0581FA_png" src="../_images/1000000000000298000001870B0581FA.png" style="width: 6.5in; height: 3.828in;" /></p>
 +<p>Select POST.</p>
 +</div>
 +<div class="section" id="curl-share-as-link">
 +<h2>Curl – Share as link<a class="headerlink" href="#curl-share-as-link" title="Permalink to this headline">¶</a></h2>
- <p>#curl <a class="reference external" href="http:/">http:/</a>/<ip>/ocs/v1.php/apps/files_sharing/api/v1/shares -k -u user:password -X POST –data “path=<file>&shareType=3”</p>
- <p>#curl
- <a class="reference external" href="http://192.168.1.63/owncloud/ocs/v1.php/apps/files_sharing/api/v1/shares">http://192.168.1.63/owncloud/ocs/v1.php/apps/files_sharing/api/v1/shares</a></p>
- <p>-k -u ser72_oc6:Password01 -X POST –data “path=test/Lab.txt&shareType=3”</p>
++<p>$ curl http://<ip>/ocs/v1.php/apps/files_sharing/api/v1/shares -k -u user:password -X POST –data “path=<file>&shareType=3”</p>
 +</div>
 +<div class="section" id="output">
 +<h2>Output<a class="headerlink" href="#output" title="Permalink to this headline">¶</a></h2>
 +<table border="1" class="docutils">
 +<colgroup>
 +<col width="77%" />
 +<col width="23%" />
 +</colgroup>
 +<tbody valign="top">
 +<tr class="row-odd"><td><?xml version=”1.0”?></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td><ocs></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td><meta></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td><status>ok</status></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td><statuscode>100</statuscode></td>
 +<td>Status = 100: successful</td>
 +</tr>
 +<tr class="row-even"><td><message/></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td></meta></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td><data></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td><id>9</id></td>
 +<td>Share ID = 9</td>
 +</tr>
 +<tr class="row-even"><td><url>http://192.168.1.63/owncloud6RC3/public.php?service=files&amp;t=e1947aaeaa2b88a69cc1e90bf27ddfe2</url></td>
 +<td>Share Link.
 +Send this to the desired users</td>
 +</tr>
 +<tr class="row-odd"><td><token>e1947aaeaa2b88a69cc1e90bf27ddfe2</token></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td></data></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td><strong></ocs></strong></td>
 +<td> </td>
 +</tr>
 +</tbody>
 +</table>
 +</div>
 +<div class="section" id="poster-share-with-user">
 +<h2>Poster – Share with user<a class="headerlink" href="#poster-share-with-user" title="Permalink to this headline">¶</a></h2>
 +<p>The following example shares a file called “test/Lab.txt” with user “ser72”</p>
 +<table border="1" class="docutils">
 +<colgroup>
 +<col width="25%" />
 +<col width="75%" />
 +</colgroup>
 +<tbody valign="top">
 +<tr class="row-odd"><td>Field</td>
 +<td>Value</td>
 +</tr>
 +<tr class="row-even"><td><strong>URL</strong></td>
 +<td>Base URL for the API of the ownCloud server</td>
 +</tr>
 +<tr class="row-odd"><td><strong>User Auth</strong></td>
 +<td>User ID of the file owner</td>
 +</tr>
 +<tr class="row-even"><td><strong>Password</strong></td>
 +<td>User’s Password</td>
 +</tr>
 +<tr class="row-odd"><td><strong>Name</strong></td>
 +<td>Argument being passed</td>
 +</tr>
 +<tr class="row-even"><td><strong>Value</strong></td>
 +<td>Full path of file/folder shared</td>
 +</tr>
 +</tbody>
 +</table>
 +<p><img alt="1000000000000289000001A9D7F3941F_png" src="../_images/1000000000000289000001A9D7F3941F.png" style="width: 6.5in; height: 4.2563in;" /></p>
 +<p>Navigate to the “Content to Send Tab” and select “Body from Parameters”</p>
 +<p><img alt="10000000000002950000019EF5732E36_png" src="../_images/10000000000002950000019EF5732E36.png" style="width: 6.5in; height: 4.0701in;" /></p>
 +<p>Select POST.</p>
 +</div>
 +<div class="section" id="curl-share-with-user">
 +<h2>Curl – Share with User<a class="headerlink" href="#curl-share-with-user" title="Permalink to this headline">¶</a></h2>
- <p>#curl <a class="reference external" href="http:/">http:/</a>/<ip>/ocs/v1.php/apps/files_sharing/api/v1/shares -k -u user:password -X POST –data “path=<file>&shareType=0&shareWith=<user>”</p>
- <p>#curl
- <a class="reference external" href="http://192.168.1.63/owncloud/ocs/v1.php/apps/files_sharing/api/v1/shares">http://192.168.1.63/owncloud/ocs/v1.php/apps/files_sharing/api/v1/shares</a></p>
- <p>-k -u ser72_oc6:Password01 -X POST –data “path=test/Lab.txt&shareType=0&shareWith=ser72”</p>
++<p>$ curl http://<ip>/ocs/v1.php/apps/files_sharing/api/v1/shares -k -u user:password -X POST –data “path=<file>&shareType=0&shareWith=<user>”</p>
 +</div>
- <div class="section" id="id2">
- <h2>output<a class="headerlink" href="#id2" title="Permalink to this headline">¶</a></h2>
++<div class="section" id="id1">
++<h2>Output<a class="headerlink" href="#id1" title="Permalink to this headline">¶</a></h2>
 +<table border="1" class="docutils">
 +<colgroup>
 +<col width="55%" />
 +<col width="45%" />
 +</colgroup>
 +<tbody valign="top">
 +<tr class="row-odd"><td><?xml version=”1.0”?></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td><ocs></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td><meta></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td><status>ok</status></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td><statuscode>100</statuscode></td>
 +<td>Status: 100: Successful</td>
 +</tr>
 +<tr class="row-even"><td><message/></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td></meta></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td><data></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td><id>10</id></td>
 +<td>Share ID = 10</td>
 +</tr>
 +<tr class="row-even"><td></data></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td></ocs></td>
 +<td> </td>
 +</tr>
 +</tbody>
 +</table>
 +</div>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/sharing_api/delete_share.html
index 9e83841,0000000..10dd551
mode 100644,000000..100644
--- a/core/doc/admin/sharing_api/delete_share.html
+++ b/core/doc/admin/sharing_api/delete_share.html
@@@ -1,231 -1,0 +1,231 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
 +    <title>Delete Share — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
 +<ul>
 +<li class="toctree-l1"><a class="reference internal" href="../installation/index.html">Installation</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../configuration/index.html">Configuration</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
 +  <div class="section" id="delete-share">
 +<h1>Delete Share<a class="headerlink" href="#delete-share" title="Permalink to this headline">¶</a></h1>
 +<p>The following method should be used in the event that a file share should be removed.</p>
 +<p>Note: the share ID can be obtained from the output of any of the previous Share API calls or the creation of a new share.</p>
 +<table border="1" class="docutils">
 +<colgroup>
 +<col width="30%" />
 +<col width="70%" />
 +</colgroup>
 +<tbody valign="top">
 +<tr class="row-odd"><td>Syntax</td>
 +<td><Base URL>/<share id></td>
 +</tr>
 +<tr class="row-even"><td>Method</td>
 +<td>DELETE</td>
 +</tr>
 +<tr class="row-odd"><td>Argument</td>
 +<td>Share ID (int)</td>
 +</tr>
 +</tbody>
 +</table>
 +<p>The following is a list of returned status codes:</p>
 +<table border="1" class="docutils">
 +<colgroup>
 +<col width="41%" />
 +<col width="59%" />
 +</colgroup>
 +<tbody valign="top">
 +<tr class="row-odd"><td>HTTP Status Code</td>
 +<td>Description</td>
 +</tr>
 +<tr class="row-even"><td>100</td>
 +<td>Successful</td>
 +</tr>
 +<tr class="row-odd"><td>404</td>
 +<td>File couldn’t be deleted</td>
 +</tr>
 +</tbody>
 +</table>
 +<div class="section" id="poster">
 +<h2>Poster<a class="headerlink" href="#poster" title="Permalink to this headline">¶</a></h2>
 +<p>To remove the share identified by ID 10, use the following method.</p>
 +<p><img alt="10000000000002910000018B31D51F03_png" src="../_images/10000000000002910000018B31D51F03.png" style="width: 6.5in; height: 3.9075in;" /></p>
 +<p>Press DELETE</p>
 +</div>
 +<div class="section" id="curl">
 +<h2>Curl<a class="headerlink" href="#curl" title="Permalink to this headline">¶</a></h2>
- <p>#curl –X “DELETE” <a class="reference external" href="http:/">http:/</a>/<user>:<password>@<ip>/ocs/v1.php/apps/files_sharing/api/v1/files/<share_id></p>
- <p>#curl –X “DELETE”
- <a class="reference external" href="http://ser72_oc6:Password01@192.168.1.63/owncloud/ocs/v1.php/apps/files_sharing/api/v1/shares/10">http://ser72_oc6:Password01@192.168.1.63/owncloud/ocs/v1.php/apps/files_sharing/api/v1/shares/10</a></p>
++<p>$ curl –X “DELETE” http://<user>:<password>@<ip>/ocs/v1.php/apps/files_sharing/api/v1/files/<share_id></p>
 +</div>
 +<div class="section" id="output">
- <h2>output<a class="headerlink" href="#output" title="Permalink to this headline">¶</a></h2>
++<h2>Output<a class="headerlink" href="#output" title="Permalink to this headline">¶</a></h2>
 +<table border="1" class="docutils">
 +<colgroup>
 +<col width="56%" />
 +<col width="44%" />
 +</colgroup>
 +<tbody valign="top">
 +<tr class="row-odd"><td><?xml version=”1.0”?></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td><ocs></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td><meta></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td><status>ok</status></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td><statuscode>100</statuscode></td>
 +<td>Status=100: Successful</td>
 +</tr>
 +<tr class="row-even"><td><message/></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td></meta></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td><data/></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td></ocs></td>
 +<td> </td>
 +</tr>
 +</tbody>
 +</table>
 +</div>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/sharing_api/get_all_shares.html
index a158b57,0000000..7f457e1
mode 100644,000000..100644
--- a/core/doc/admin/sharing_api/get_all_shares.html
+++ b/core/doc/admin/sharing_api/get_all_shares.html
@@@ -1,305 -1,0 +1,305 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
 +    <title>Get All Shares — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
 +<ul>
 +<li class="toctree-l1"><a class="reference internal" href="../installation/index.html">Installation</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../configuration/index.html">Configuration</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
 +  <div class="section" id="get-all-shares">
 +<h1>Get All Shares<a class="headerlink" href="#get-all-shares" title="Permalink to this headline">¶</a></h1>
 +<p>To obtain a list of all files shared by a user, the following can be used.</p>
 +<table border="1" class="docutils">
 +<colgroup>
 +<col width="17%" />
 +<col width="83%" />
 +</colgroup>
 +<tbody valign="top">
 +<tr class="row-odd"><td>Syntax</td>
 +<td><Base URL></td>
 +</tr>
 +<tr class="row-even"><td>Method</td>
 +<td>GET</td>
 +</tr>
 +<tr class="row-odd"><td>Result</td>
 +<td>XML code with all shares by the user</td>
 +</tr>
 +</tbody>
 +</table>
 +<p>The following is a list of returned status codes:</p>
 +<table border="1" class="docutils">
 +<colgroup>
 +<col width="46%" />
 +<col width="54%" />
 +</colgroup>
 +<tbody valign="top">
 +<tr class="row-odd"><td>HTTP Status Code</td>
 +<td>Description</td>
 +</tr>
 +<tr class="row-even"><td>100</td>
 +<td>Successful</td>
 +</tr>
 +<tr class="row-odd"><td>404</td>
 +<td>Couldn’t get shares</td>
 +</tr>
 +</tbody>
 +</table>
 +<div class="section" id="poster">
- <h2>Poster:<a class="headerlink" href="#poster" title="Permalink to this headline">¶</a></h2>
++<h2>Poster<a class="headerlink" href="#poster" title="Permalink to this headline">¶</a></h2>
 +<table border="1" class="docutils">
 +<colgroup>
 +<col width="25%" />
 +<col width="75%" />
 +</colgroup>
 +<tbody valign="top">
 +<tr class="row-odd"><td>Field</td>
 +<td>Value</td>
 +</tr>
 +<tr class="row-even"><td><strong>URL</strong></td>
 +<td>Base URL for the API of the ownCloud server</td>
 +</tr>
 +<tr class="row-odd"><td><strong>User Auth</strong></td>
 +<td>User ID performing the Share</td>
 +</tr>
 +<tr class="row-even"><td><strong>Password</strong></td>
 +<td>User’s Password</td>
 +</tr>
 +</tbody>
 +</table>
 +<p><img alt="10000201000002FC000001DC2DDAD2F1_png" src="../_images/10000201000002FC000001DC2DDAD2F1.png" /></p>
 +<p>Select “GET”</p>
 +</div>
 +<div class="section" id="curl">
 +<h2>Curl<a class="headerlink" href="#curl" title="Permalink to this headline">¶</a></h2>
 +<p>The user is the id of the user who shares the files.
 +The password belongs to that user as well.</p>
- <p>#curl <a class="reference external" href="http:/">http:/</a>/<user>:<password>@<ip>/ocs/v1.php/apps/files_sharing/api/v1/shares</p>
- <p>#curl
- <a class="reference external" href="http://ser72_oc6:Password01@192.168.1.63/owncloud/ocs/v1.php/appsi/files_sharing/api/v1/shares">http://ser72_oc6:Password01@192.168.1.63/owncloud/ocs/v1.php/appsi/files_sharing/api/v1/shares</a></p>
++<p>$ curl http://<user>:<password>@<ip>/ocs/v1.php/apps/files_sharing/api/v1/shares</p>
 +</div>
 +<div class="section" id="output">
- <h2>output<a class="headerlink" href="#output" title="Permalink to this headline">¶</a></h2>
++<h2>Output<a class="headerlink" href="#output" title="Permalink to this headline">¶</a></h2>
 +<table border="1" class="docutils">
 +<colgroup>
 +<col width="55%" />
 +<col width="45%" />
 +</colgroup>
 +<tbody valign="top">
 +<tr class="row-odd"><td><?xml version=”1.0”?></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td><ocs></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td><meta></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td><status>ok</status></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td><statuscode>100</statuscode></td>
 +<td>Status = 100: Successful</td>
 +</tr>
 +<tr class="row-even"><td><message/></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td></meta></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td><data></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td><element></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td><id>6</id></td>
 +<td>Share ID = 6</td>
 +</tr>
 +<tr class="row-odd"><td><item_type>file</item_type></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td><item_source>138</item_source></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td><parent/></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td><share_type>0</share_type></td>
 +<td>Share Type = 0: User share</td>
 +</tr>
 +<tr class="row-odd"><td><share_with>ser72</share_with></td>
 +<td>File shared with user ser72</td>
 +</tr>
 +<tr class="row-even"><td><file_source>138</file_source></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td><path>/Lab.txt</path></td>
 +<td>File name /Lab.txt</td>
 +</tr>
 +<tr class="row-even"><td><permissions>27</permissions></td>
 +<td>Permissions: Re-share, Read, Delete, Update</td>
 +</tr>
 +<tr class="row-odd"><td><stime>1386697532</stime></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td><expiration/></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td><token/></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td><storage>4</storage></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td><mail_send>0</mail_send></td>
 +<td>Do not send email alerting of the share</td>
 +</tr>
 +<tr class="row-even"><td><share_with_displayname>ser72</share_with_displayname></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td></element></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td></data></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td></ocs></td>
 +<td> </td>
 +</tr>
 +</tbody>
 +</table>
 +</div>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/sharing_api/get_information_about_a_known_share.html
index 17e99ae,0000000..b502832
mode 100644,000000..100644
--- a/core/doc/admin/sharing_api/get_information_about_a_known_share.html
+++ b/core/doc/admin/sharing_api/get_information_about_a_known_share.html
@@@ -1,309 -1,0 +1,310 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
 +    <title>Get Information about a known share — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
 +<ul>
 +<li class="toctree-l1"><a class="reference internal" href="../installation/index.html">Installation</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../configuration/index.html">Configuration</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
 +  <div class="section" id="get-information-about-a-known-share">
 +<h1>Get Information about a known share<a class="headerlink" href="#get-information-about-a-known-share" title="Permalink to this headline">¶</a></h1>
 +<p>To get information about a share when the share ID is known, use the following.</p>
 +<p>Note: the share ID can be obtained from the output of any of the previous Share API calls or the creation of a new share.</p>
 +<table border="1" class="docutils">
 +<colgroup>
 +<col width="25%" />
 +<col width="75%" />
 +</colgroup>
 +<tbody valign="top">
 +<tr class="row-odd"><td>Syntax</td>
 +<td><Base URL>/<share id></td>
 +</tr>
 +<tr class="row-even"><td>Method</td>
 +<td>GET</td>
 +</tr>
 +<tr class="row-odd"><td>Arguments</td>
 +<td>Share id (int)</td>
 +</tr>
 +<tr class="row-even"><td>Result</td>
 +<td>XML code with share information</td>
 +</tr>
 +<tr class="row-odd"><td> </td>
 +<td> </td>
 +</tr>
 +</tbody>
 +</table>
 +<p>The following is a list of returned status codes:</p>
 +<table border="1" class="docutils">
 +<colgroup>
 +<col width="46%" />
 +<col width="54%" />
 +</colgroup>
 +<tbody valign="top">
 +<tr class="row-odd"><td>HTTP Status Code</td>
 +<td>Description</td>
 +</tr>
 +<tr class="row-even"><td>100</td>
 +<td>Successful</td>
 +</tr>
 +<tr class="row-odd"><td>404</td>
 +<td>Share doesn’t exist</td>
 +</tr>
 +</tbody>
 +</table>
 +<div class="section" id="poster">
 +<h2>Poster<a class="headerlink" href="#poster" title="Permalink to this headline">¶</a></h2>
 +<p>This example shows the output of share information for share ID “7”</p>
 +<table border="1" class="docutils">
 +<colgroup>
 +<col width="21%" />
 +<col width="79%" />
 +</colgroup>
 +<tbody valign="top">
 +<tr class="row-odd"><td>Field</td>
 +<td>Value</td>
 +</tr>
 +<tr class="row-even"><td><strong>URL</strong></td>
 +<td>Base URL for the API of the ownCloud server/<share id></td>
 +</tr>
 +<tr class="row-odd"><td><strong>User Auth</strong></td>
 +<td>User ID of the file owner</td>
 +</tr>
 +<tr class="row-even"><td><strong>Password</strong></td>
 +<td>User’s Password</td>
 +</tr>
 +</tbody>
 +</table>
 +<p><img alt="1000000000000288000001A1D5BE4881_png" src="../_images/1000000000000288000001A1D5BE4881.png" style="width: 6.5in; height: 4.1819in;" /></p>
 +</div>
 +<div class="section" id="curl">
 +<h2>Curl<a class="headerlink" href="#curl" title="Permalink to this headline">¶</a></h2>
- <p>#curl <a class="reference external" href="http:/">http:/</a>/<user>:<passowrd>@<ip>/ocs/v1.php/apps/files_sharing/api/v1/shares/<share_id></p>
- <p>#curl <a class="reference external" href="http://ser72_oc6:Password01@192.168.1.63/owncloud/ocs/v1.php/apps/files_sharing/api/v1/shares/7">http://ser72_oc6:Password01@192.168.1.63/owncloud/ocs/v1.php/apps/files_sharing/api/v1/shares/7</a></p>
++<p>$ curl http://<user>:<passowrd>@<ip>/ocs/v1.php/apps/files_sharing/api/v1/shares/<share_id></p>
 +</div>
 +<div class="section" id="output">
- <h2>output<a class="headerlink" href="#output" title="Permalink to this headline">¶</a></h2>
++<h2>Output<a class="headerlink" href="#output" title="Permalink to this headline">¶</a></h2>
 +<table border="1" class="docutils">
 +<colgroup>
 +<col width="70%" />
 +<col width="30%" />
 +</colgroup>
 +<tbody valign="top">
 +<tr class="row-odd"><td><?xml version=”1.0”?></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td><ocs></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td><meta></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td><status>ok</status></td>
 +<td>Status=100: successful</td>
 +</tr>
 +<tr class="row-odd"><td><statuscode>100</statuscode></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td><message/></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td></meta></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td><data></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td><element></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td><id>7</id></td>
 +<td>Share ID = 7</td>
 +</tr>
 +<tr class="row-odd"><td><item_type>file</item_type></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td><item_source>675</item_source></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td><parent/></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td><share_type>0</share_type></td>
 +<td>Share type = 0: user</td>
 +</tr>
 +<tr class="row-odd"><td><share_with>ser72</share_with></td>
 +<td>Share with user ser72</td>
 +</tr>
 +<tr class="row-even"><td><file_source>675</file_source></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td><path>/test share api/ieee.txt</path></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td><permissions>27</permissions></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td><stime>1386698116</stime></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td><expiration/></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td><token/></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td><storage>4</storage></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td><mail_send>0</mail_send></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td><share_with_displayname>ser72</share_with_displayname></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td></element></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td></data></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td></ocs></td>
 +<td> </td>
 +</tr>
 +</tbody>
 +</table>
 +</div>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/sharing_api/get_shares_from_a_specific_file_or_folder.html
index 7c2734c,0000000..f7c455e
mode 100644,000000..100644
--- a/core/doc/admin/sharing_api/get_shares_from_a_specific_file_or_folder.html
+++ b/core/doc/admin/sharing_api/get_shares_from_a_specific_file_or_folder.html
@@@ -1,500 -1,0 +1,498 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
 +    <title>Get Shares from a Specific File or Folder — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
 +<ul>
 +<li class="toctree-l1"><a class="reference internal" href="../installation/index.html">Installation</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../configuration/index.html">Configuration</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
 +  <div class="section" id="get-shares-from-a-specific-file-or-folder">
 +<h1>Get Shares from a Specific File or Folder<a class="headerlink" href="#get-shares-from-a-specific-file-or-folder" title="Permalink to this headline">¶</a></h1>
 +<p>The following will provide a list shares for a specific file.
 +The input is the full path of the desired file.
 +The output is a list of everyone who has the file shared with them.</p>
 +<table border="1" class="docutils">
 +<colgroup>
 +<col width="18%" />
 +<col width="17%" />
 +<col width="7%" />
 +<col width="58%" />
 +</colgroup>
 +<tbody valign="top">
 +<tr class="row-odd"><td><strong>Syntax</strong></td>
 +<td><Base URL></td>
 +<td> </td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td><strong>Method</strong></td>
 +<td>GET</td>
 +<td> </td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td><strong>Mandatory Argument</strong></td>
 +<td>Path</td>
 +<td>string</td>
 +<td>Path to file or folder</td>
 +</tr>
 +<tr class="row-even"><td><strong>Argument</strong></td>
 +<td>Reshares</td>
 +<td>boolean</td>
 +<td><p class="first">If set to ‘false’ (default), only shares from the current user are returned</p>
 +<p class="last">If set to ‘true’, all shares from the given file are returned</p>
 +</td>
 +</tr>
 +<tr class="row-odd"><td><strong>Argument</strong></td>
 +<td>Subfiles</td>
 +<td>boolean</td>
 +<td><p class="first">If set to ‘false’ (default), lists only the folder being shared</p>
 +<p class="last">If set to ‘true’, all shared files within the folder are returned.</p>
 +</td>
 +</tr>
 +<tr class="row-even"><td><strong>Result</strong></td>
 +<td>XML code with shares</td>
 +<td> </td>
 +<td> </td>
 +</tr>
 +</tbody>
 +</table>
 +<p>The following is a list of returned status codes:</p>
 +<table border="1" class="docutils">
 +<colgroup>
 +<col width="25%" />
 +<col width="75%" />
 +</colgroup>
 +<tbody valign="top">
 +<tr class="row-odd"><td>HTTP Status Code</td>
 +<td>Description</td>
 +</tr>
 +<tr class="row-even"><td>100</td>
 +<td>Successful</td>
 +</tr>
 +<tr class="row-odd"><td>400</td>
 +<td>Not a directory (if the ‘subfile’ argument was used)</td>
 +</tr>
 +<tr class="row-even"><td>404</td>
 +<td>File does not exist</td>
 +</tr>
 +</tbody>
 +</table>
 +<div class="section" id="poster-default-arguments">
- <h2>Poster - Default arguments<a class="headerlink" href="#poster-default-arguments" title="Permalink to this headline">¶</a></h2>
++<h2>Poster – Default arguments<a class="headerlink" href="#poster-default-arguments" title="Permalink to this headline">¶</a></h2>
 +<p>This example shows the output of share information for “test share api/ieee.txt”</p>
 +<table border="1" class="docutils">
 +<colgroup>
 +<col width="25%" />
 +<col width="75%" />
 +</colgroup>
 +<tbody valign="top">
 +<tr class="row-odd"><td>Field</td>
 +<td>Value</td>
 +</tr>
 +<tr class="row-even"><td><strong>URL</strong></td>
 +<td>Base URL for the API of the ownCloud server</td>
 +</tr>
 +<tr class="row-odd"><td><strong>User Auth</strong></td>
 +<td>User ID of the file owner</td>
 +</tr>
 +<tr class="row-even"><td><strong>Password</strong></td>
 +<td>User’s Password</td>
 +</tr>
 +<tr class="row-odd"><td><strong>Name</strong></td>
 +<td>Argument being passed</td>
 +</tr>
 +<tr class="row-even"><td><strong>Value</strong></td>
 +<td>Full path of file/folder shared</td>
 +</tr>
 +</tbody>
 +</table>
 +<p>Navigate to the “Parameters” tab and input the Name and value.</p>
 +<p><img alt="10000000000002720000013FB6EDA793_png" src="../_images/10000000000002720000013FB6EDA793.png" style="width: 6.5in; height: 3.3126in;" /></p>
 +<p>Navigate to the “Content to Send” tab and select “Body from Parameters” to move the required parameters to the query.</p>
 +<p><img alt="1000000000000291000001951B69B9A6_png" src="../_images/1000000000000291000001951B69B9A6.png" style="width: 6.5in; height: 4.0071in;" /></p>
 +<p>Select GET.</p>
 +</div>
 +<div class="section" id="curl-default-configuration">
- <h2>Curl – default configuration:<a class="headerlink" href="#curl-default-configuration" title="Permalink to this headline">¶</a></h2>
- <p>#curl –G –data “path=test_share_api/ieee.txt” <a class="reference external" href="http:/">http:/</a>/<userid>:<password>@<ip>/ocs/v1.php/apps/files_sharing/api/v1/shares</p>
- <p>#curl –G –data “path=test_share_api/ieee.txt”
- <a class="reference external" href="http://ser72_oc6:Password01@192.168.1.63/owncloud/ocs/v1.php/apps/files_sharing/api/v1/shares">http://ser72_oc6:Password01@192.168.1.63/owncloud/ocs/v1.php/apps/files_sharing/api/v1/shares</a></p>
++<h2>Curl – Default configuration<a class="headerlink" href="#curl-default-configuration" title="Permalink to this headline">¶</a></h2>
++<p>$ curl –G –data “path=test_share_api/ieee.txt” http://<userid>:<password>@<ip>/ocs/v1.php/apps/files_sharing/api/v1/shares</p>
 +</div>
 +<div class="section" id="output">
- <h2>output<a class="headerlink" href="#output" title="Permalink to this headline">¶</a></h2>
++<h2>Output<a class="headerlink" href="#output" title="Permalink to this headline">¶</a></h2>
 +<table border="1" class="docutils">
 +<colgroup>
 +<col width="64%" />
 +<col width="36%" />
 +</colgroup>
 +<tbody valign="top">
 +<tr class="row-odd"><td><?xml version=”1.0”?></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td><ocs></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td><meta></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td><status>ok</status></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td><statuscode>100</statuscode></td>
 +<td>Status=100: Successful</td>
 +</tr>
 +<tr class="row-even"><td><message/></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td></meta></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td><data></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td><element></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td><id>7</id></td>
 +<td>Share ID=7</td>
 +</tr>
 +<tr class="row-odd"><td><item_type>file</item_type></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td><item_source>675</item_source></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td><parent/></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td><share_type>0</share_type></td>
 +<td>Share Type=0: user</td>
 +</tr>
 +<tr class="row-odd"><td><share_with>ser72</share_with></td>
 +<td>Share with user ser72</td>
 +</tr>
 +<tr class="row-even"><td><file_source>675</file_source></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td><path>/test share api/ieee.txt</path></td>
 +<td>File /test share api/ieee.txt</td>
 +</tr>
 +<tr class="row-even"><td><permissions>27</permissions></td>
 +<td>Permissions 27</td>
 +</tr>
 +<tr class="row-odd"><td><stime>1386698116</stime></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td><expiration/></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td><token/></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td><storage>4</storage></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td><mail_send>0</mail_send></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td><share_with_displayname>ser72</share_with_displayname></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td></element></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td></data></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td></ocs></td>
 +<td> </td>
 +</tr>
 +</tbody>
 +</table>
 +</div>
 +<div class="section" id="poster-to-add-another-argument-such-as-re-shares">
- <h2>Poster - To add another argument, such as re-shares:<a class="headerlink" href="#poster-to-add-another-argument-such-as-re-shares" title="Permalink to this headline">¶</a></h2>
++<h2>Poster – To add another argument, such as re-shares<a class="headerlink" href="#poster-to-add-another-argument-such-as-re-shares" title="Permalink to this headline">¶</a></h2>
 +<p>This example shows the output of share information for “test share api/ieee.txt”.
 +reshares is set to true which will show output if the file is re-shared by another user.</p>
 +<p><img alt="1000000000000304000001B964698779_png" src="../_images/1000000000000304000001B964698779.png" style="width: 6.5in; height: 3.7134in;" /></p>
 +<p>Navigate to the “Content to Send” tab and select “Body from Parameters”</p>
 +<p><img alt="100000000000029B0000018885B5282E_png" src="../_images/100000000000029B0000018885B5282E.png" style="width: 6.5in; height: 3.8201in;" /></p>
 +<p>Select Get</p>
 +</div>
 +<div class="section" id="curl-to-add-another-argument-such-as-re-shares">
 +<h2>Curl – To add another argument, such as re-shares<a class="headerlink" href="#curl-to-add-another-argument-such-as-re-shares" title="Permalink to this headline">¶</a></h2>
- <p>#curl –G –data “path=test_share_api/ieee.tx&reshares=true” <a class="reference external" href="http:/">http:/</a>/<userid>:<password>@<ip>/ocs/v1.php/apps/files_sharing/api/v1/shares</p>
- <p>#curl –G –data “path=test_share_api/ieee.tx&reshares=true”
- <a class="reference external" href="http://ser72_oc6:Password01@192.168.1.63/owncloud/ocs/v1.php/apps/files_sharing/api/v1/shares">http://ser72_oc6:Password01@192.168.1.63/owncloud/ocs/v1.php/apps/files_sharing/api/v1/shares</a></p>
++<p>$ curl –G –data “path=test_share_api/ieee.tx&reshares=true” http://<userid>:<password>@<ip>/ocs/v1.php/apps/files_sharing/api/v1/shares</p>
 +</div>
- <div class="section" id="id2">
- <h2>output<a class="headerlink" href="#id2" title="Permalink to this headline">¶</a></h2>
++<div class="section" id="id1">
++<h2>Output<a class="headerlink" href="#id1" title="Permalink to this headline">¶</a></h2>
 +<table border="1" class="docutils">
 +<colgroup>
 +<col width="60%" />
 +<col width="40%" />
 +</colgroup>
 +<tbody valign="top">
 +<tr class="row-odd"><td><?xml version=”1.0”?></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td><ocs></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td><meta></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td><status>ok</status></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td><statuscode>100</statuscode></td>
 +<td>Status=100: Successful</td>
 +</tr>
 +<tr class="row-even"><td><message/></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td></meta></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td><data></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td><element></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td><id>7</id></td>
 +<td>Share id = 7</td>
 +</tr>
 +<tr class="row-odd"><td><item_type>file</item_type></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td><item_source>675</item_source></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td><parent/></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td><share_type>0</share_type></td>
 +<td>Share Type=0: User</td>
 +</tr>
 +<tr class="row-odd"><td><share_with>ser72</share_with></td>
 +<td>Share with user ser72</td>
 +</tr>
 +<tr class="row-even"><td><file_source>675</file_source></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td><path>/test share api/ieee.txt</path></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td><permissions>27</permissions></td>
 +<td>Permissions 27</td>
 +</tr>
 +<tr class="row-odd"><td><stime>1386698116</stime></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td><expiration/></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td><token/></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td><storage>4</storage></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td><mail_send>0</mail_send></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td><share_with_displayname>ser72</share_with_displayname></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td></element></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td><element></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td><id>8</id></td>
 +<td>Share id 8</td>
 +</tr>
 +<tr class="row-even"><td><item_type>file</item_type></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td><parent>7</parent></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td><share_type>0</share_type></td>
 +<td>Parent share id = 7</td>
 +</tr>
 +<tr class="row-odd"><td><share_with>ser73</share_with></td>
 +<td>Share with ser73</td>
 +</tr>
 +<tr class="row-even"><td><file_source>675</file_source></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td><path>/test share api/ieee.txt</path></td>
 +<td>Share file /test share api/ieee.txt</td>
 +</tr>
 +<tr class="row-even"><td><permissions>19</permissions></td>
 +<td>Permissions 19 – read, update, share</td>
 +</tr>
 +<tr class="row-odd"><td><stime>1386698465</stime></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td><expiration/></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td><token/></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td><storage>4</storage></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td><mail_send>0</mail_send></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td><share_with_displayname>ser73</share_with_displayname></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td></element></td>
 +<td> </td>
 +</tr>
 +<tr class="row-even"><td></data></td>
 +<td> </td>
 +</tr>
 +<tr class="row-odd"><td></ocs></td>
 +<td> </td>
 +</tr>
 +</tbody>
 +</table>
 +</div>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/admin/sharing_api/index.html
index ce22716,0000000..b871044
mode 100644,000000..100644
--- a/core/doc/admin/sharing_api/index.html
+++ b/core/doc/admin/sharing_api/index.html
@@@ -1,187 -1,0 +1,195 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
-     <title><no title> — ownCloud Administrators Manual 6.0 documentation</title>
++    <title>Sharing API — ownCloud Administrators Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud Administrators Manual 6.0 documentation" href="../index.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud Administrators Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 Admin Documentation</a></li>
 +</ul>
 +<ul>
 +<li class="toctree-l1"><a class="reference internal" href="../installation/index.html">Installation</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../configuration/index.html">Configuration</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../apps/index.html">Apps</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../maintenance/index.html">Maintenance</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../config/index.html">The Configuration File</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../issues/index.html">Issues</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
-   <p><strong>ownCloud Sharing API</strong></p>
++  <div class="section" id="sharing-api">
++<h1>Sharing API<a class="headerlink" href="#sharing-api" title="Permalink to this headline">¶</a></h1>
 +<div class="toctree-wrapper compound">
- <ul>
- <li class="toctree-l1"><a class="reference internal" href="Contents.html">Contents</a></li>
- <li class="toctree-l1"><a class="reference internal" href="Introduction.html">Introduction</a><ul>
- <li class="toctree-l2"><a class="reference internal" href="Introduction.html#permissions">Permissions</a></li>
- </ul>
- </li>
- <li class="toctree-l1"><a class="reference internal" href="Get_All_Shares.html">Get All Shares</a><ul>
- <li class="toctree-l2"><a class="reference internal" href="Get_All_Shares.html#poster">Poster:</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Get_All_Shares.html#curl">Curl</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Get_All_Shares.html#output">output</a></li>
- </ul>
- </li>
- <li class="toctree-l1"><a class="reference internal" href="Get_Shares_from_a_Specific_File_or_Folder.html">Get Shares from a Specific File or Folder</a><ul>
- <li class="toctree-l2"><a class="reference internal" href="Get_Shares_from_a_Specific_File_or_Folder.html#poster-default-arguments">Poster - Default arguments</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Get_Shares_from_a_Specific_File_or_Folder.html#curl-default-configuration">Curl – default configuration:</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Get_Shares_from_a_Specific_File_or_Folder.html#output">output</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Get_Shares_from_a_Specific_File_or_Folder.html#poster-to-add-another-argument-such-as-re-shares">Poster - To add another argument, such as re-shares:</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Get_Shares_from_a_Specific_File_or_Folder.html#curl-to-add-another-argument-such-as-re-shares">Curl – To add another argument, such as re-shares</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Get_Shares_from_a_Specific_File_or_Folder.html#id2">output</a></li>
- </ul>
- </li>
- <li class="toctree-l1"><a class="reference internal" href="Get_Information_about_a_known_share.html">Get Information about a known share</a><ul>
- <li class="toctree-l2"><a class="reference internal" href="Get_Information_about_a_known_share.html#poster">Poster</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Get_Information_about_a_known_share.html#curl">Curl</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Get_Information_about_a_known_share.html#output">output</a></li>
- </ul>
- </li>
- <li class="toctree-l1"><a class="reference internal" href="Create_a_new_Share.html">Create a new Share</a><ul>
- <li class="toctree-l2"><a class="reference internal" href="Create_a_new_Share.html#poster-share-as-a-link">Poster – Share as a link</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Create_a_new_Share.html#curl-share-as-link">Curl – Share as link</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Create_a_new_Share.html#output">Output</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Create_a_new_Share.html#poster-share-with-user">Poster – Share with user</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Create_a_new_Share.html#curl-share-with-user">Curl – Share with User</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Create_a_new_Share.html#id2">output</a></li>
- </ul>
- </li>
- <li class="toctree-l1"><a class="reference internal" href="Delete_Share.html">Delete Share</a><ul>
- <li class="toctree-l2"><a class="reference internal" href="Delete_Share.html#poster">Poster</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Delete_Share.html#curl">Curl</a></li>
- <li class="toctree-l2"><a class="reference internal" href="Delete_Share.html#output">output</a></li>
- </ul>
- </li>
- </ul>
++</div>
++<div class="section" id="introduction">
++<h2>Introduction<a class="headerlink" href="#introduction" title="Permalink to this headline">¶</a></h2>
++<p>This document will describe how to use the ownCloud Sharing API.
++The sharing API allows for the creation of new shares, obtaining a list of shares, and deleting shares.
++In addition, information such a lists of files shared to users can be obtained.</p>
++<p>In order to utilize this API, all user ID’s involved in the share, as well as full path names of files is required to be known.</p>
++<p>Two methods will be shown:
++Firefox Plugin “Poster” and Curl via the command line.</p>
++<p>The base URL for all calls to the share API is:
++owncloud_base_url>/ocs/v1.php/apps/files_sharing/api/v1/shares</p>
++<div class="section" id="permissions">
++<h3>Permissions<a class="headerlink" href="#permissions" title="Permalink to this headline">¶</a></h3>
++<p>The following table describes the Permissions of a share.
++The Permissions are contained in the XML code output of the command.</p>
++<table border="1" class="docutils">
++<colgroup>
++<col width="16%" />
++<col width="84%" />
++</colgroup>
++<tbody valign="top">
++<tr class="row-odd"><td>Value</td>
++<td>Permissions</td>
++</tr>
++<tr class="row-even"><td><strong>1</strong></td>
++<td>Read only – Default for “public” shares</td>
++</tr>
++<tr class="row-odd"><td><strong>2</strong></td>
++<td>Update</td>
++</tr>
++<tr class="row-even"><td><strong>4</strong></td>
++<td>Create</td>
++</tr>
++<tr class="row-odd"><td><strong>8</strong></td>
++<td>Delete</td>
++</tr>
++<tr class="row-even"><td><strong>16</strong></td>
++<td>Re-share</td>
++</tr>
++<tr class="row-odd"><td><strong>31</strong></td>
++<td>All above – Default for “private” shares</td>
++</tr>
++</tbody>
++</table>
++<p>To obtain combinations, add the desired values together.
++For instance, for “Re-Share”, “delete”, “read”, “update”, add 16+8+2+1 = 27.</p>
++</div>
++</div>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/user/_images/1000000000000163000000E9CDA84C92.png
index 7a16c70,0000000..7a16c70
mode 100644,000000..100644
Binary files differ
diff --cc core/doc/user/_images/1000000000000175000000FAB2A2B294.png
index 6b3f1d7,0000000..6b3f1d7
mode 100644,000000..100644
Binary files differ
diff --cc core/doc/user/_images/1000000000000195000000EF7E44082C.png
index a6506c7,0000000..a6506c7
mode 100644,000000..100644
Binary files differ
diff --cc core/doc/user/_images/10000000000001CE000000F2E2084BA1.png
index 2956d8e,0000000..2956d8e
mode 100644,000000..100644
Binary files differ
diff --cc core/doc/user/_images/100000000000041D0000003D52225C0D.png
index 4987d97,0000000..4987d97
mode 100644,000000..100644
Binary files differ
diff --cc core/doc/user/_images/1000000000000453000001BFFCF48776.png
index 8c4a6e2,0000000..8c4a6e2
mode 100644,000000..100644
Binary files differ
diff --cc core/doc/user/_images/1000000000000467000002B63162E59B.png
index 53daa91,0000000..53daa91
mode 100644,000000..100644
Binary files differ
diff --cc core/doc/user/_images/10000000000004690000026615360BEB.png
index a5ff48f,0000000..a5ff48f
mode 100644,000000..100644
Binary files differ
diff --cc core/doc/user/_images/100000000000046D0000015F4B5494A9.png
index 8805ff7,0000000..8805ff7
mode 100644,000000..100644
Binary files differ
diff --cc core/doc/user/_images/100000000000046F000000DEA2BFCD9B.png
index 958302f,0000000..958302f
mode 100644,000000..100644
Binary files differ
diff --cc core/doc/user/_images/1000000000000470000001B68AE60DD3.png
index e2d76a1,0000000..e2d76a1
mode 100644,000000..100644
Binary files differ
diff --cc core/doc/user/_images/10000000000004710000014BBC34499D.png
index 3664b3e,0000000..3664b3e
mode 100644,000000..100644
Binary files differ
diff --cc core/doc/user/_images/100000000000047200000129CB014025.png
index 9abac5a,0000000..9abac5a
mode 100644,000000..100644
Binary files differ
diff --cc core/doc/user/_images/100000000000047700000219A3013A92.png
index 191a485,0000000..191a485
mode 100644,000000..100644
Binary files differ
diff --cc core/doc/user/_images/1000000000000479000002887E7F48EA.png
index d0d1d1d,0000000..d0d1d1d
mode 100644,000000..100644
Binary files differ
diff --cc core/doc/user/_images/100000000000047A000000B727198874.png
index ec02e05,0000000..ec02e05
mode 100644,000000..100644
Binary files differ
diff --cc core/doc/user/_images/100000000000047A000000FB86FF2A9A.png
index ac169a2,0000000..ac169a2
mode 100644,000000..100644
Binary files differ
diff --cc core/doc/user/_images/100000000000047A0000011C6682A254.png
index 54484f0,0000000..54484f0
mode 100644,000000..100644
Binary files differ
diff --cc core/doc/user/_images/100000000000048100000245268CDB7A.png
index be9abd3,0000000..be9abd3
mode 100644,000000..100644
Binary files differ
diff --cc core/doc/user/_sources/files/encryption.txt
index 6cd49fc,0000000..57c7a57
mode 100644,000000..100644
--- a/core/doc/user/_sources/files/encryption.txt
+++ b/core/doc/user/_sources/files/encryption.txt
@@@ -1,65 -1,0 +1,62 @@@
 +Files Encryption
 +================
 +
- ownCloud ships a encryption app, which allows to encrypt all files stored in
- your ownCloud. Once the encryption app was enabled by the admin all your files
++ownCloud ships a encryption app, which enables encryption of all files stored in
++your ownCloud. Once the encryption app is enabled by the admin, all your files
 +will be encrypted automatically. Encryption and decryption always happens
 +server-side. This enables the user to continue to use all the other apps to
- view and edit his data. But this also means that the server administrator could
- intercept your data. Server-Side encryption is especially interesting if you
++view and edit their data. But this also means that the server administrator could
++intercept your data. Server-Side encryption is especially useful if you
 +use external storages. This way you can make sure that the storage provider is
 +not able to read your data.
 +
- Please remember. Once the encryption app is enabled you need your log-in
- password to decrypt and access your data. By default your data will be lost if
- you loss your log-in password. If you want to protect yourself against password
- loss store your log-in password on a secure place or enable the recovery key
- as described below.
++Please remember. Once the encryption app is enabled your log-in password is required
++to decrypt and access your data. By default your data will be lost if
++you lose your log-in password. If you want to protect yourself against password
++loss, store your log-in password in a secure place or enable the recovery-key
++feature as described below.
 +
 +What gets encrypted
 +-------------------
 +
- The current version encrypts all your files stored in ownCloud.
- 
- At the moment we don't encrypt:
++The current version encrypts all your files stored in ownCloud except the following:
 +
 +- old files in the trash bin (files which were deleted before the encryption app was enabled)
 +- image thumbnails from the gallery app and previews from the files app
 +- search index from the full text search app
 +
- All this data is stored directly on your ownCloud server, so you don't have to worry to expose
++All this data is stored directly on your ownCloud server, so you don't have to worry about exposing
 +your data to a third party storage provider.
 +
 +Decrypt your data again
 +-----------------------
 +
- If the encryption app was disabled users can decrypt their files again in their
- personal settings. After this was done they can continue to use their ownCloud
- without encryption.
- 
++If the encryption app is disabled after users have already stored encrypted data, users
++will be promted to decrypt their files again in their personal settings. After this is
++done, they can continue to use their ownCloud without encryption.
 +
 +Settings
 +--------
 +
- Once the encryption app is enabled you will find some additional settings on
++Once the encryption app is enabled, you will find some additional settings on
 +your personal settings page.
 +
 +Recovery Key
 +~~~~~~~~~~~~
 +
- If the admin enabled the recovery-key you can decide by your own if you
- want to use this feature for your account. If you enable "Password recovery"
++If the admin enabled the recovery-key feature you can decide for yourself if
++you want to use this feature for your account. If you enable "Password recovery"
 +the admin will be able to read your data with a special password. This allows
- him to recover your files in case of password loss. If the recovery-key is not
- enabled than there is no way to restore your files if you loss your log-in
++him to recover your files in the event you lose your password. If the recovery-key
++is not enabled than there is no way to restore your files if you lose your log-in
 +password.
 +
 +Change Private Key Password
 +~~~~~~~~~~~~~~~~~~~~~~~~~~~
 +
 +This option will be only available if your log-in password but not your
 +encryption password was changed by your admin. This can happen if your ownCloud
 +provider uses a external user back-end, e.g. LDAP, and changed your log-in
 +password there. In this case you can set your encryption password to your new
 +log-in password by providing your old and new log-in password. The encryption
 +app only works if log-in password and encryption password is identical.
diff --cc core/doc/user/_sources/files/files.txt
index 77d840b,0000000..6cabc65
mode 100644,000000..100644
--- a/core/doc/user/_sources/files/files.txt
+++ b/core/doc/user/_sources/files/files.txt
@@@ -1,253 -1,0 +1,253 @@@
 +Accessing your Files (WebDAV)
 +=============================
 +
 +Your ownCloud instance can be accessed on every platform via the web interface. There are also options to integrate it with your desktop.
 +
 +.. note:: You will have to adjust **example.org/** to the URL of your ownCloud server installation
 +
 +
 +Linux
 +-----
 +
 +Gnome 3/Nautilus
 +~~~~~~~~~~~~~~~~
 +
 +The URL that you have to use to connect to the ownCloud installation in nautilus is::
 +
 +  davs://example.org/owncloud/remote.php/webdav
 +
 +
 +.. image:: ../images/gnome3_nautilus_webdav.png
 +
 +If your server connection is not HTTPS-secured, use `dav://` instead of `davs://` .
 +
 +KDE/Dolphin
 +~~~~~~~~~~~
 +Click in the address area and enter::
 +
 +    webdav://example.org/owncloud/remote.php/webdav
 +
 +.. image:: ../images/dolphin_webdav.png
 +
 +or:
 +
 +1. Open Dolphin and click on where it says Network in the left hand Places column.
 +2. Click on the icon labeled **Add a Network Folder**.
 +3. It should come up with WebDAV already selected. Make sure it is and then click **Next**.
 +4. Enter the following settings:
 +
 +* Name: The name you’ll see in the **Places** bookmark, for example ownCloud
 +* User: Your ownCloud username you use to log in, for example admin
 +* Server: Your ownCloud domain name, for example **example.org** (without **http://** before or directories afterwards).
 +* Folder: Enter::
 +
 +        owncloud/remote.php/webdav
 +
 +5. Create icon checkbox: Tick to get a bookmark in the Places column
 +6. Port & Encrypted checkbox: Leave as it is unless you have special settings or an SSL certificate.
 +
 +Mounting from command line
 +~~~~~~~~~~~~~~~~~~~~~~~~~~
 +1. Install the WebDAV support using the davfs package. On Debian/Ubuntu, you can use::
 +
 +	sudo apt-get install davfs2
 +
 +2. Reconfigure davfs2 to allow access to normal users (select Yes when prompted)::
 +
 +        sudo dpkg-reconfigure davfs2
 +
 +3. Add the users you want to be able to mount the share to the davfs2 group::
 +
 +        sudo usermod -aG davfs2 <user>
 +
 +4. Edit :file:`/etc/fstab` and add the following line for each user who wants to mount the folder (with your details where appropriate)::
 +
 +        example.org/owncloud/remote.php/webdav /home/<username>/owncloud davfs user,rw,noauto 0 0
 +
 +Then, as each user who wants to mount the folder:
 +
 +1. Create the folders **owncloud/** and **.davfs2/** in your home directory
 +2. Create the file secrets inside **.davfs2/**, fill it with the following (with your credentials where appropriate)::
 +
 +        example.org/owncloud/remote.php/webdav <username> <password>
 +
 +3. Ensure the file is only writable by you either through the file manager, or via::
 +
 +        chmod 600 ~/.davfs2/secrets
 +
 +4. Run the command::
 +
 +        mount ~/owncloud
 +
 +5. To automatically mount the folder on login, add the command you used in step 4 to :file:`./.bashrc`
 +
 +Known Issues
 +^^^^^^^^^^^^
 +
 +**Problem:** Resource temporarily unavailable
 +
 +**Solution:** If you experience trouble when you create a file in the directory, edit :file:`/etc/davfs2/davfs2.conf` and add::
 +
 +        use_locks 0
 +
 +**Problem:** Certificate warnings
 +
 +**Solution:** If you use a self-signed certificate, you will get a warning. If you are willing to take the risk of a man in the middle attack, run this command instead::
 +
 +        echo "y" | mount ~/owncloud > /dev/null 2>&1
 +
 +MacOS
 +-----
 +
- .. note:: Finder suffers from a `series of implementation problems <http://code.google.com/p/sabredav/wiki/Finder>`_ and should only be used if the ownCloud server runs on **Apache** and **mod_php**
++.. note:: Finder suffers from a `series of implementation problems <http://sabre.io/dav/clients/finder/>`_ and should only be used if the ownCloud server runs on **Apache** and **mod_php**
 +
 +In the Finder, choose **Go > Connect to Server,** type the address of the server in the **Server Address** field, and click **Connect**.
 +
 +.. image:: ../images/osx_webdav1.png
 +
 +The URL that you have to use to connect to the ownCloud installation in finder is::
 +
 +  http://example.org/owncloud/remote.php/webdav
 +
 +.. image:: ../images/osx_webdav2.png
 +
 +For details, check the respective `vendor documentation`_ at the Apple website.
 +
 +.. _`vendor documentation`: http://docs.info.apple.com/article.html?path=Mac/10.6/en/8160.html
 +
 +Windows
 +-------
 +For Windows a seperate WebDAV client is recommended to access the files from your server. Choose one from the `WebDav Project page <http://www.webdav.org/projects/>`_
 +
 +Should you have to use the native implementation then you can assign ownCloud a drive letter. This allows you to browse files stored on an ownCloudserver the way you would files stored in a mapped network drive.
 +
 +Using this feature requires network connectivity. If you want to store
 +your files offline, use the ownCloud Client to sync all files on your
 +ownCloud to one or more directories of your local hard drive.
 +
 +
 +.. note:: Prior to mapping your drive, you will need to permit the use of Basic Authentication in the Windows Registry. The procedure is documented in KB841215_ and differs between Windows XP/Server 2003 and Windows Vista/7. Please follow the Knowledge Base article before proceeding, and follow the Vista instructions if you run Windows 7.
 +
 +.. _KB841215: http://support.microsoft.com/kb/841215
 +
 +Mapping via the command line
 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 +
 +Suppose your ownCloud is installed at **https://example.org/owncloud**,
 +that is, entering this URL in your web browser will bring up the login screen.
 +Running::
 +
 +  net use Z: https://example.org/owncloud/remote.php/webdav /user:youruser yourpassword
 +
 +will map the files of your ownCloud account to the drive letter Z:. An alternative
 +syntax is::
 +
 +  net use Z: \\example.org at ssl\owncloud\remote.php\webdav /user:youruser yourpassword
 +
 +Appending **/persistent** makes the connection persistent across reboots.
 +
 +You can also mount your ownCloud via HTTP, leaving the connection unencrypted.
 +Use either of the following syntaxes::
 +
 +  net use Z: http://example.org/owncloud/remote.php/webdav /user:youruser yourpassword
 +  net use Z: \\example.org\owncloud\remote.php\webdav /user:youruser yourpassword
 +
 +Please note that this allows anyone to sniff your ownCloud data with ease, especially on public WiFi hotspots. Plain HTTP should therefore only be used in conjunction with a VPN tunnel when used on Laptops.
 +
 +Using Windows Explorer
 +~~~~~~~~~~~~~~~~~~~~~~
 +
 +Right-click on **Computer** entry and select **Map network drive...**. Choose a local network drive to map ownCloud to. Finally, enter the address to your ownCloud instance, followed by **/remote.php/webdav**, e.g. ::
 +
 +  https://example.org/owncloud/remote.php/webdav
 +
 +for an SSL protected server. Check **Reconnect at logon** to make this mapping persistent across reboots. If you want to connect as another user, check **Connect using different credentials**.
 +
 +.. figure:: ../images/explorer_webdav.png
 +   :scale: 80%
 +
 +   Mapping WebDAV on Windows Explorer.
 +
 +After pressing **Finish**, Windows Explorer will map the network drive and your ownCloud instance should be available
 +
 +Using Cyberduck (4.2.1)
 +~~~~~~~~~~~~~~~~~~~~~~~
 +
 +Specify a server without any leading protocol information. e.g.:
 +
 +Server
 +  example.org
 +
 +The port depends on whether your ownCloud server supports SSL or not. Cyberduck requires that you select a different connection type depending on whethr SSL is to be used ('WebDAV' or 'WebDAV (HTTPS/SSL)'):
 +
 +Port
 +  80 (for WebDAV)
 +  443 (for WebDAV (HTTPS/SSL))
 +
 +Use the 'More Options' drop-down menu to add the rest of your WebDAV URL into the 'Path' field. e.g.:
 +
 +Path
 +  remote.php/webdav
 +
 +Known Problems
 +~~~~~~~~~~~~~~
 +
 +
 +Problem
 +  Windows refuses to connect via HTTPS
 +
 +Solution
 +  The Windows WebDAV Client does not support Server Name Indication (SNI) on
 +  encrypted connections. If you encounter an error mounting an SSL-encrypted
 +  ownCloud instance, please contact your provider about assigning a dedicated
 +  IP address for your SSL-based server.
 +
 +Problem
 +  I receive the error **Error 0x800700DF: The file size exceeds the limit allowed and cannot be saved.**
 +
 +Solution
 +  Windows limits the maximum size a file transferred from or to  a WebDAV
 +  share may have.  You can increase the value **FileSizeLimitInBytes** in
 +  **HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\WebClient\Parameters**.
 +  by clicking on **Modify**. In order to increase the limit to the maximum
 +  value of 4GB, pick **Decimal** and enter **4294967295** as value. Afterwards,
 +  reboot Windows or restart the **WebClient** service.
 +
 +.. todo::
 +
 +   document registry keys on file size limit and not complaining in no network cases
 +
 +
 +Sync Client
 +-----------
 +However, some applications only allow you to save to a local folder. To
 +get around this issue, you can use the `ownCloud sync clients`_
 +
 +Mobile
 +-------
 +To connect to your ownCloud server with the **ownCloud** mobile apps, use the base URL and folder only::
 +
 +    example.org/owncloud
 +
 +No need to add remote.php/webdav as you do for any other WebDAV client.
 +
 +There are apps in development for both `Android`_ and `webOS`_. Feel
 +free to `contribute, if you can`_! Right now you can use other apps to
 +connect to ownCloud from your phone via WebDAV. `WebDAV Navigator`_ is a
 +good (proprietary) app for `Android App`_ , `iPhone`_ & `BlackBerry`_.
 +
 +The URL for these is::
 +
 +    example.org/owncloud/remote.php/webdav
 +
 +.. _in your file manager: http://en.wikipedia.org/wiki/Webdav#WebDAV_client_applications
 +.. _ownCloud sync clients: http://owncloud.org/documentation/sync-clients/
 +.. _Mount ownCloud to a local folder without sync: http://owncloud.org/use/webdav/
 +.. _ownCloud Mirall repository: https://github.com/owncloud/mirall
 +.. _Android: http://github.com/owncloud/android
 +.. _webOS: http://github.com/owncloud/webos
 +.. _contribute, if you can: /contribute/
 +.. _WebDAV Navigator: http://seanashton.net/webdav/
 +.. _Android App: https://play.google.com/store/apps/details?id=com.schimera.webdavnavlite
 +.. _iPhone: https://itunes.apple.com/app/webdav-navigator/id382551345
 +.. _BlackBerry: http://appworld.blackberry.com/webstore/content/46816
diff --cc core/doc/user/_sources/files/filesweb.txt
index f87f971,0000000..a409dc2
mode 100644,000000..100644
--- a/core/doc/user/_sources/files/filesweb.txt
+++ b/core/doc/user/_sources/files/filesweb.txt
@@@ -1,85 -1,0 +1,85 @@@
 +Accessing your Files (Web Interface)
 +====================================
 +
 +Your ownCloud files can be accessed from anywhere by using your ownCloud's web interface. In the files app,
 +you can view (if a common type), move, rename, download, share and delete your files easily. If versioning app is
 +enabled, you can also revert a file to specific version. See :doc:`versioncontrol` for details.
 +
 +.. figure:: ../images/oc_filesweb.png
 +Files app on ownCloud web interface
 +
 +With ownCloud 6, you can now see file thumbnails next to the filenames. By hovering your cursor on a file, you
 +will be provided with some file operations. You can use rename, download, share buttons to perform those actions
 +or click on the cross icon at the rightmost location to remove the hovered file. If the file is an editable
 +office file, it will also show *Edit* button to open the file in documents app (if this app is enabled).
 +
 +Navigating inside your ownCloud
 +-------------------------------
 +
 +To navigate through folders in your ownCloud, you can simply click on a folder name. The navigation bar
 +will show your current directory:
 +
 +.. figure:: ../images/oc_filesweb_navigate.png
 +Navigation bar
 +
 +You can click on one of the upper directories to navigate up or use home icon to navigate back into your root
 +folder.
 +
 +
 +Creating/uploading files
 +------------------------
 +
 +You can create files by simply clicking on *New* button on files app. The *New* button will provide three
 +options to choose from:
 +
 +.. figure:: ../images/oc_filesweb_new.png
 +New button options
 +
 +* *Text file* will create a simple text file and add into the current folder in your ownCloud.
 +* *Folder* will create a folder in current folder.
 +* *From link* will download the file from the provided link and place it into the current folder.
 +
 +
 +Selecting files
 +---------------
 +
 +You can select one or more files by clicking on small thumbnails or icons of the files. To select all files in
 +the current directory, use the checkbox just above the first file/folder on the list.
 +
 +If you select multiple files, selected files can be deleted or downloaded as ZIP by using the buttons just above of the file list.
 +If download button is not visible, this means that administrator had disabled this feature.
 +
 +Viewing files
 +-------------
 +
 +ownCloud can display uncompressed text files, OpenDocument files, PDFs, and image files by simply clicking on
 +the file name. If displaying of a file is not possible, a download process will start.
 +
 +Moving files
 +------------
 +
- In ownCloud web interface, file(s) can be moved by dragging and dropping them into a sub-directory. If you would like move a directory to an upper directory, drag the file(s) into one of the folders shown in navigation bar.
++In ownCloud web interface, file(s) can be moved by dragging and dropping them into a sub-directory. If you would like to move a directory to an upper directory, drag the file(s) into one of the folders shown in navigation bar (depicted above).
 +
 +Sharing files
 +-------------
 +
 +Any file/folder on ownCloud can be shared to download with a local user, group or any person online with a public link. Shared files/folders will show a *Shared* text next to their names.
 +
 +To share a file/folder, hover your cursor on an item in the files app and click *Share*. You will be provided with some options:
 +
 +.. figure:: ../images/oc_files_share.png
 +Share dialog
 +
 +* The first field is to share this file/folder with local users/groups. This is very useful
 +  if you are in a company and want to create a quick share with a collegue.
 +* If you click on *Share link*, the other options will be visible. Since this link allows everyone
 +  to download this file/folder, you may want to protect this share with a password. To do that,
 +  click on *Password protect* and set a password.
 +* If this share is a folder, you will also have an option to enable uploads into this folder using
 +  the provided link. This is very useful to collect files from multiple users into same place easily.
 +* If your server is configured with a mail server, you can type e-mail addresses seperated with space to send the link to multiple users.
 +* Finally, setting an expiration date will expiry the share after the specified date.
 +
 +If you type a user and/or group to the *share with* field, you will be given extra sharing options such as informing via e-mail,
 +letting users edit (create, update, delete, re-share) the share. To revoke permissions from users, simply click on cross icon
 +on the same line with the users.
diff --cc core/doc/user/_sources/files/sync.txt
index 79f3957,0000000..992121f
mode 100644,000000..100644
--- a/core/doc/user/_sources/files/sync.txt
+++ b/core/doc/user/_sources/files/sync.txt
@@@ -1,22 -1,0 +1,22 @@@
 +Desktop Synchronization
 +========================
 +
 +For synchronizing files with your desktop computer, we recommend using the
 +`ownCloud Client`_ for Windows, Mac OS X and Linux.
 +
 +The ownCloud Desktop Client enables you to connect to your private ownCloud Server. 
 +You can create folders in your home directory, and keep the contents of those 
 +folders synced with your ownCloud server. Simply copy a file into the directory 
 +and the ownCloud desktop client does the rest. Make a change to the files on one 
 +computer, it will flow across the others using these desktop sync clients. Always 
 +have your latest files with you wherever you are. 
 +
 +Its usage is documented separately in the `ownCloud Desktop Client Manual`_.
 +
 +Furthermore, It is possible to synchronize your ownCloud calendar and address book
 +with a variety of different operating systems and devices. It is also possible to
 +mount your ownCloud storage via WebDAV, which is also documented in the next chapters.
 +
 +
 +.. _ownCloud Client: http://owncloud.org/sync-client/
- .. _ownCloud Desktop Client Manual:  http://doc.owncloud.com/desktop
++.. _ownCloud Desktop Client Manual:  http://doc.owncloud.org/desktop
diff --cc core/doc/user/_sources/pim/troubleshooting.txt
index 9a0285c,0000000..c608b70
mode 100644,000000..100644
--- a/core/doc/user/_sources/pim/troubleshooting.txt
+++ b/core/doc/user/_sources/pim/troubleshooting.txt
@@@ -1,86 -1,0 +1,86 @@@
 +Troubleshooting
 +===============
 +
 +Debugging the issue
 +-------------------
 +
 +In a standard ownCloud installation the log level is set to "Normal". to find any issues
 +you need to raise the log level to "All" from the Admin page.
 +Some logging - for example JavaScript console logging - needs manually editing the
 +configuration file.
 +Edit :file:`config/config.php` and add ``define('DEBUG', true);``::
 +
 +    <?php
 +    define('DEBUG',true);
 +    $CONFIG = array (
 +        ... configuration goes here ...
 +    );
 +
 +For JavaScript issues you will also need to view the javascript console. All major browsers
 +have decent developer tools for viewing the console, and you usually access them by
 +pressing F-12. For Firefox it is recommended to install the `Firebug extension <https://getfirebug.com/>`_.
 +
 +Service discovery
 +-----------------
 +
 +Some clients - especially iOS - have problems finding the proper sync URL, even when explicitly
 +configured to use it.
 +
 +There are several techniques to remedy this, which are described extensively at the
- `Sabre DAV website <http://code.google.com/p/sabredav/wiki/ServiceDiscovery>`_.
++`Sabre DAV website <http://sabre.io/dav/service-discovery/>`_.
 +
 +Apple iOS
 +`````````
 +
 +Below is what have proven to work with iOS including iOS 7.
 +
 +If your ownCloud instance is installed in a sub-folder under the web servers document root, and
 +the client has difficulties finding the Cal- or CardDAV end-points, configure your web server to
 +redirect from a "well-know" URL to the one used by ownCloud.
 +When using the Apache web server this is easily achieved using a :file:`.htaccess` file in the document
 +root of your site.
 +
 +Say your instance is located in the ``owncloud`` folder, so the URL to it is ``ADDRESS/owncloud``,
 +create or edit the :file:`.htaccess` file and add the following lines::
 +
 +    Redirect 301 /.well-known/carddav /owncloud/remote.php/carddav
 +    Redirect 301 /.well-known/caldav /owncloud/remote.php/caldav
 +
 +If you use Nginx as web server, the setting looks something like::
 +
 +    url.redirect = (
 +        "^/.well-known/carddav" => "/owncloud/remote.php/carddav",
 +        "^/.well-known/caldav" => "/owncloud/remote.php/caldav",
 +    )
 +
 +Now change the URL in the client settings to just use ``ADDRESS`` instead of e.g. ``ADDRESS/remote.php/carddav/principals/username``.
 +
 +This problem is being discussed in the `forum <http://forum.owncloud.org/viewtopic.php?f=3&t=71&p=2211#p2197>`_.
 +
 +
 +BlackBerry OS 10.2
 +``````````````````
 +
 +BlackBerry OS up to 10.2.2102 doesn't accept a URL with protocol ``https://`` in front of the server address.
 +It will always tell you, that it cannot login on your server. So instead of writing
 +
 +    https://address/remote.php/carddav/principals/username
 +    
 +in the server address field, you have to write
 +
 +    address/remote.php/carddav/principals/username
 +
 +
 +Unable to update Contacts or Events
 +-----------------------------------
 +
 +If you get an error like ``PATCH https://ADDRESS/some_url HTTP/1.0 501 Not Implemented`` it is
 +likely caused by one of the following reasons:
 +
 +Outdated lighttpd web server
 +  lighttpd in debian wheezy (1.4.31) doesn't support the PATCH HTTP verb.
 +  Upgrade to lighttpd >= 1.4.33.
 +
 +Using Pound reverse-proxy/load balancer
 +  As of writing this Pound doesn't support the HTTP/1.1 verb.
 +  Pound is easily `patched <http://www.apsis.ch/pound/pound_list/archive/2013/2013-08/1377264673000>`_ to support HTTP/1.1.
diff --cc core/doc/user/_sources/web_guide/index.txt
index 0000000,0000000..5c4608d
new file mode 100644
--- /dev/null
+++ b/core/doc/user/_sources/web_guide/index.txt
@@@ -1,0 -1,0 +1,344 @@@
++The ownCloud Web Interface
++==========================
++
++Introduction
++------------
++
++This document will discuss the ownCloud web interface from a user’s perspective.
++It will detail how to log into ownCloud, upload files, create files and folders, as well as describe the Personal Page settings.
++When possible, it will reference other more detailed documents on specific functionality.
++
++Initial Log In
++--------------
++
++The ownCloud initial login screen is as follows.
++
++|1000000000000453000001BFFCF48776_png|
++
++It should be noted, that if the instance of ownCloud is themed differently, there will be a different logo on the screen.
++
++To log into ownCloud, enter the username and password provided by your ownCloud admin.
++To remain logged into ownCloud under the same credentials, select the checkbox next to Remember.
++
++Upon initial login, the user will most likely see the “Welcome to ownCloud” banner as below.
++
++|1000000000000479000002887E7F48EA_png|
++
++This banner provides links to download the desktop sync app (see Desktop Client document), as well as the mobile apps.
++This banner will appear upon the first login only, provided the admin has not disabled it.
++To close the banner and start using ownCloud, select the ‘x’ in the upper right corner of the banner.
++
++.. |1000000000000453000001BFFCF48776_png| image:: images/1000000000000453000001BFFCF48776.png
++    :width: 6.5in
++    :height: 2.6252in
++
++
++.. |1000000000000479000002887E7F48EA_png| image:: images/1000000000000479000002887E7F48EA.png
++    :width: 6.5in
++    :height: 3.6783in
++
++Main ownCloud screen
++--------------------
++
++Once logged into ownCloud, the main screen will be displayed.
++
++|100000000000047700000219A3013A92_png|
++
++There are four sections in the main ownCloud screen
++
++#.  This is the apps bar.
++    Any user related apps will be displayed here.
++    In a default enterprise edition of ownCloud, the Files app and the Activity app are listed.
++
++
++
++#.  This section will display all data loaded into ownCloud.
++
++
++
++#.  The home button brings the user to the home directory.
++    The New button allows the user to create a file or folder, or link, and the upload arrow allows the user to upload a file.
++
++
++
++#.  The search box allows the user to search and the user name pull^down can bring the user to the Personal page for personal configurations as well as log the user out.
++
++
++
++.. |100000000000047700000219A3013A92_png| image:: images/100000000000047700000219A3013A92.png
++    :width: 6.5in
++    :height: 3.0535in
++
++Adding Data
++-----------
++
++There are a few ways to add data to the ownCloud instance.
++Files may be uploaded or text files may be created directly within ownCloud.
++Folders may also be created directly within the ownCloud web interface.
++
++Creation
++^^^^^^^^
++
++To create a file or folder, select the New button in section 3 of the main ownCloud screen.
++
++|1000000000000163000000E9CDA84C92_png|
++
++Create a text file
++~~~~~~~~~~~~~~~~~~
++
++Select “Text file” from the menu and enter the desired file name.
++
++|1000000000000175000000FAB2A2B294_png|
++
++Then press enter.
++
++|100000000000047A000000FB86FF2A9A_png|
++
++Notice the file has been placed in section 2 of the main ownCloud window.
++Since it is an empty file, the size is “0 Bytes” and it was last modified a few seconds ago.
++
++Create a folder
++~~~~~~~~~~~~~~~
++
++To create a folder within ownCloud, simply select “Folder” from the menu and enter the desired folder name.
++
++|1000000000000195000000EF7E44082C_png|
++
++Then select Enter.
++
++Notice the folder appears in the window.
++
++|100000000000047A0000011C6682A254_png|
++
++
++Adding a file from a link
++~~~~~~~~~~~~~~~~~~~~~~~~~
++
++If the desired file exists on the internet already it is possible to add the file to ownCloud using the internet link.
++To do this, select “From link” from the menu and enter the URL of the file then select enter.
++
++|10000000000001CE000000F2E2084BA1_png|
++
++|100000000000046D0000015F4B5494A9_png|
++
++
++The file contained in the link now appears in the user’s ownCloud instance.
++
++Uploading files
++^^^^^^^^^^^^^^^
++
++There are two methods possible to upload files to the ownCloud web interface.
++
++Drag and Drop
++~~~~~~~~~~~~~
++
++Simply drag and drop one or more files from the client’s
++Desktop into section 2 of the main ownCloud window.
++These files will then be uploaded to ownCloud and appear in the data window.
++
++Upload Button
++~~~~~~~~~~~~~
++
++The second method to upload a file to ownCloud is to select the upload arrow on the top left of the main ownCloud screen.
++This will being up a File Upload selection box.
++
++|100000000000048100000245268CDB7A_png|
++
++Navigate to the directory containing the desired files and select the file for uploading and press Open.
++To upload multiple files simultaneously, use either the SHIFT or CTRL key during file selection as appropriate.
++
++.. |100000000000047A000000FB86FF2A9A_png| image:: images/100000000000047A000000FB86FF2A9A.png
++    :width: 6.5in
++    :height: 1.4228in
++
++
++.. |1000000000000163000000E9CDA84C92_png| image:: images/1000000000000163000000E9CDA84C92.png
++    :width: 3.698in
++    :height: 2.4272in
++
++
++.. |10000000000001CE000000F2E2084BA1_png| image:: images/10000000000001CE000000F2E2084BA1.png
++    :width: 4.8126in
++    :height: 2.5201in
++
++
++.. |1000000000000195000000EF7E44082C_png| image:: images/1000000000000195000000EF7E44082C.png
++    :width: 4.2189in
++    :height: 2.4898in
++
++
++.. |100000000000047A0000011C6682A254_png| image:: images/100000000000047A0000011C6682A254.png
++    :width: 6.5in
++    :height: 1.611in
++
++
++.. |100000000000046D0000015F4B5494A9_png| image:: images/100000000000046D0000015F4B5494A9.png
++    :width: 6.5in
++    :height: 2.0138in
++
++
++.. |1000000000000175000000FAB2A2B294_png| image:: images/1000000000000175000000FAB2A2B294.png
++    :width: 3.8846in
++    :height: 2.6043in
++
++
++.. |100000000000048100000245268CDB7A_png| image:: images/100000000000048100000245268CDB7A.png
++    :width: 6.5in
++    :height: 3.2756in
++Navigation
++----------
++
++Changing directories
++^^^^^^^^^^^^^^^^^^^^
++
++To navigate to other folders within ownCloud, simply click on the desired folder.
++
++|1000000000000470000001B68AE60DD3_png|
++
++Notice that Section 3 shows the currently displayed directory “my_folder”.
++To navigate back to the root directly, select the “Home” button.
++
++Viewing/Editing files
++^^^^^^^^^^^^^^^^^^^^^
++
++ownCloud has the ability to view text files as well as pictures.
++To view a text file or a picture, click on the file.
++
++|10000000000004710000014BBC34499D_png|
++
++For text files, a text editor will be brought up allowing the user to modify the file as desired.
++Just type the desired text and select “Save” to commit the changes.
++Once changes have been made to the file, prior to saving, the name of the file will have an “*” next to it indicating it has yet to be saved.
++
++|100000000000046F000000DEA2BFCD9B_png|
++
++Once changes have been saved, a thumbnail of the text file will appear in the main data window.
++
++|100000000000041D0000003D52225C0D_png|
++
++Downloading a file
++^^^^^^^^^^^^^^^^^^
++
++To download a file from ownCloud to your working computer, hover over the file and then select the “Download” button.
++
++|100000000000047200000129CB014025_png|
++
++For non^text or picture files, the user may also click on the file name to download it.
++
++Renaming files or Folders
++^^^^^^^^^^^^^^^^^^^^^^^^^
++
++To rename a file or folder within ownCloud, hover over the file and select Rename.
++Then type the new name of the file or folder.
++
++Sharing, Versions, Delete, and Activity
++^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
++
++For more information on the sharing, versions, deletion or Activity features, please see the respective documents.
++
++.. |100000000000046F000000DEA2BFCD9B_png| image:: images/100000000000046F000000DEA2BFCD9B.png
++    :width: 6.5in
++    :height: 1.2717in
++
++
++.. |100000000000041D0000003D52225C0D_png| image:: images/100000000000041D0000003D52225C0D.png
++    :width: 6.5in
++    :height: 0.3764in
++
++
++.. |100000000000047200000129CB014025_png| image:: images/100000000000047200000129CB014025.png
++    :width: 6.5in
++    :height: 1.6965in
++
++
++.. |10000000000004710000014BBC34499D_png| image:: images/10000000000004710000014BBC34499D.png
++    :width: 6.5in
++    :height: 1.8925in
++
++
++.. |1000000000000470000001B68AE60DD3_png| image:: images/1000000000000470000001B68AE60DD3.png
++    :width: 6.5in
++    :height: 2.5063in
++Personal Configurations
++-----------------------
++
++Each ownCloud user may configure some personal preferences.
++To make these configurations, navigate to the Personal page.
++Select the user name and the following menu will appear.
++
++|100000000000047A000000B727198874_png|
++
++
++Select Personal to get to the configuration page.
++
++Configuration options on this page may appear or disappear depending on what the ownCloud admin has configured.
++The basic configuration parameters are as follows.
++
++|1000000000000467000002B63162E59B_png|
++
++|10000000000004690000026615360BEB_png|
++
++Important links
++^^^^^^^^^^^^^^^
++
++The top section of the Personal page contains the same links as the First Run Wizard described earlier in this document.
++For more information on this, see the document on the First Run Wizard.
++
++Quota
++^^^^^
++
++Below shows the used and remaining space for the user.
++For information as to how this is calculated, refer to the ownCloud Quota Calculations document.
++
++Password Change
++^^^^^^^^^^^^^^^
++
++If the user desires to change the password, do so in this section.
++Enter the current password followed by the new password and select “Change Password”.
++It should be noted, that when using LDAP authentication, the password is contained within the LDAP and not locally thus this field will not change the password.
++
++Change Display Name
++^^^^^^^^^^^^^^^^^^^
++
++To change the way your name is displayed within ownCloud, enter the desired name under “Full Name”.
++
++Add Email Address
++^^^^^^^^^^^^^^^^^
++
++For password recovery and share notifications, it is important for ownCloud to have an email on record.
++Enter the desired email address under the EMAIL section.
++
++Avatar
++^^^^^^
++
++ownCloud allows a user to upload an Avatar for their ownCloud instance.
++This can be done under the “Profile Picture” section of the Personal Page.
++
++To upload a new Avatar, select the “Upload new” button.
++If the desired avatar exists on the ownCloud file system, select “Select new from Files” and to remove the avatar and return to the default, select “Remove image”
++
++Language
++^^^^^^^^
++
++If English is not the user’s native language, they may change the language in this section.
++
++WebDAV
++^^^^^^
++
++This provides the address to use in order to access a user’s files via WebDav.
++
++
++
++.. |1000000000000467000002B63162E59B_png| image:: images/1000000000000467000002B63162E59B.png
++    :width: 6.5in
++    :height: 4.0028in
++
++
++.. |100000000000047A000000B727198874_png| image:: images/100000000000047A000000B727198874.png
++    :width: 6.5in
++    :height: 1.0382in
++
++
++.. |10000000000004690000026615360BEB_png| image:: images/10000000000004690000026615360BEB.png
++    :width: 6.5in
++    :height: 3.5346in
diff --cc core/doc/user/files/encryption.html
index c468f71,0000000..cb491b3
mode 100644,000000..100644
--- a/core/doc/user/files/encryption.html
+++ b/core/doc/user/files/encryption.html
@@@ -1,220 -1,0 +1,219 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
 +    <title>Files Encryption — ownCloud User Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud User Manual 6.0 documentation" href="../index.html" />
 +    <link rel="up" title="Files & Synchronization" href="index.html" />
 +    <link rel="next" title="Storage Quota" href="quota.html" />
 +    <link rel="prev" title="Desktop Synchronization" href="sync.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud User Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 User Documentation</a></li>
 +</ul>
 +<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../webinterface.html">The ownCloud Web Interface</a></li>
 +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Files & Synchronization</a><ul class="current">
 +<li class="toctree-l2"><a class="reference internal" href="filesweb.html">Accessing your Files (Web Interface)</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="files.html">Accessing your Files (WebDAV)</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="versioncontrol.html">Version Control</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="deletedfiles.html">Deleted Files</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="sync.html">Desktop Synchronization</a></li>
 +<li class="toctree-l2 current"><a class="current reference internal" href="">Files Encryption</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="#what-gets-encrypted">What gets encrypted</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#decrypt-your-data-again">Decrypt your data again</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#settings">Settings</a></li>
 +</ul>
 +</li>
 +<li class="toctree-l2"><a class="reference internal" href="quota.html">Storage Quota</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html">Big Files</a></li>
 +</ul>
 +</li>
 +<li class="toctree-l1"><a class="reference internal" href="../pim/index.html">Contacts & Calendar</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../bookmarks.html">Using the Bookmarks App</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../documents.html">Documents</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../migration.html">User Account Migration</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../userpreferences.html">Changing Preferences</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../external_storage/google_drive.html">External storage</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
 +  <div class="section" id="files-encryption">
 +<h1>Files Encryption<a class="headerlink" href="#files-encryption" title="Permalink to this headline">¶</a></h1>
- <p>ownCloud ships a encryption app, which allows to encrypt all files stored in
- your ownCloud. Once the encryption app was enabled by the admin all your files
++<p>ownCloud ships a encryption app, which enables encryption of all files stored in
++your ownCloud. Once the encryption app is enabled by the admin, all your files
 +will be encrypted automatically. Encryption and decryption always happens
 +server-side. This enables the user to continue to use all the other apps to
- view and edit his data. But this also means that the server administrator could
- intercept your data. Server-Side encryption is especially interesting if you
++view and edit their data. But this also means that the server administrator could
++intercept your data. Server-Side encryption is especially useful if you
 +use external storages. This way you can make sure that the storage provider is
 +not able to read your data.</p>
- <p>Please remember. Once the encryption app is enabled you need your log-in
- password to decrypt and access your data. By default your data will be lost if
- you loss your log-in password. If you want to protect yourself against password
- loss store your log-in password on a secure place or enable the recovery key
- as described below.</p>
++<p>Please remember. Once the encryption app is enabled your log-in password is required
++to decrypt and access your data. By default your data will be lost if
++you lose your log-in password. If you want to protect yourself against password
++loss, store your log-in password in a secure place or enable the recovery-key
++feature as described below.</p>
 +<div class="section" id="what-gets-encrypted">
 +<h2>What gets encrypted<a class="headerlink" href="#what-gets-encrypted" title="Permalink to this headline">¶</a></h2>
- <p>The current version encrypts all your files stored in ownCloud.</p>
- <p>At the moment we don’t encrypt:</p>
++<p>The current version encrypts all your files stored in ownCloud except the following:</p>
 +<ul class="simple">
 +<li>old files in the trash bin (files which were deleted before the encryption app was enabled)</li>
 +<li>image thumbnails from the gallery app and previews from the files app</li>
 +<li>search index from the full text search app</li>
 +</ul>
- <p>All this data is stored directly on your ownCloud server, so you don’t have to worry to expose
++<p>All this data is stored directly on your ownCloud server, so you don’t have to worry about exposing
 +your data to a third party storage provider.</p>
 +</div>
 +<div class="section" id="decrypt-your-data-again">
 +<h2>Decrypt your data again<a class="headerlink" href="#decrypt-your-data-again" title="Permalink to this headline">¶</a></h2>
- <p>If the encryption app was disabled users can decrypt their files again in their
- personal settings. After this was done they can continue to use their ownCloud
- without encryption.</p>
++<p>If the encryption app is disabled after users have already stored encrypted data, users
++will be promted to decrypt their files again in their personal settings. After this is
++done, they can continue to use their ownCloud without encryption.</p>
 +</div>
 +<div class="section" id="settings">
 +<h2>Settings<a class="headerlink" href="#settings" title="Permalink to this headline">¶</a></h2>
- <p>Once the encryption app is enabled you will find some additional settings on
++<p>Once the encryption app is enabled, you will find some additional settings on
 +your personal settings page.</p>
 +<div class="section" id="recovery-key">
 +<h3>Recovery Key<a class="headerlink" href="#recovery-key" title="Permalink to this headline">¶</a></h3>
- <p>If the admin enabled the recovery-key you can decide by your own if you
- want to use this feature for your account. If you enable “Password recovery”
++<p>If the admin enabled the recovery-key feature you can decide for yourself if
++you want to use this feature for your account. If you enable “Password recovery”
 +the admin will be able to read your data with a special password. This allows
- him to recover your files in case of password loss. If the recovery-key is not
- enabled than there is no way to restore your files if you loss your log-in
++him to recover your files in the event you lose your password. If the recovery-key
++is not enabled than there is no way to restore your files if you lose your log-in
 +password.</p>
 +</div>
 +<div class="section" id="change-private-key-password">
 +<h3>Change Private Key Password<a class="headerlink" href="#change-private-key-password" title="Permalink to this headline">¶</a></h3>
 +<p>This option will be only available if your log-in password but not your
 +encryption password was changed by your admin. This can happen if your ownCloud
 +provider uses a external user back-end, e.g. LDAP, and changed your log-in
 +password there. In this case you can set your encryption password to your new
 +log-in password by providing your old and new log-in password. The encryption
 +app only works if log-in password and encryption password is identical.</p>
 +</div>
 +</div>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/user/files/files.html
index 5cca451,0000000..8384aa2
mode 100644,000000..100644
--- a/core/doc/user/files/files.html
+++ b/core/doc/user/files/files.html
@@@ -1,388 -1,0 +1,388 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
 +    <title>Accessing your Files (WebDAV) — ownCloud User Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud User Manual 6.0 documentation" href="../index.html" />
 +    <link rel="up" title="Files & Synchronization" href="index.html" />
 +    <link rel="next" title="Version Control" href="versioncontrol.html" />
 +    <link rel="prev" title="Accessing your Files (Web Interface)" href="filesweb.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud User Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 User Documentation</a></li>
 +</ul>
 +<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../webinterface.html">The ownCloud Web Interface</a></li>
 +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Files & Synchronization</a><ul class="current">
 +<li class="toctree-l2"><a class="reference internal" href="filesweb.html">Accessing your Files (Web Interface)</a></li>
 +<li class="toctree-l2 current"><a class="current reference internal" href="">Accessing your Files (WebDAV)</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="#linux">Linux</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#macos">MacOS</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#windows">Windows</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#sync-client">Sync Client</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#mobile">Mobile</a></li>
 +</ul>
 +</li>
 +<li class="toctree-l2"><a class="reference internal" href="versioncontrol.html">Version Control</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="deletedfiles.html">Deleted Files</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="sync.html">Desktop Synchronization</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="encryption.html">Files Encryption</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="quota.html">Storage Quota</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html">Big Files</a></li>
 +</ul>
 +</li>
 +<li class="toctree-l1"><a class="reference internal" href="../pim/index.html">Contacts & Calendar</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../bookmarks.html">Using the Bookmarks App</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../documents.html">Documents</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../migration.html">User Account Migration</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../userpreferences.html">Changing Preferences</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../external_storage/google_drive.html">External storage</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
 +  <div class="section" id="accessing-your-files-webdav">
 +<h1>Accessing your Files (WebDAV)<a class="headerlink" href="#accessing-your-files-webdav" title="Permalink to this headline">¶</a></h1>
 +<p>Your ownCloud instance can be accessed on every platform via the web interface. There are also options to integrate it with your desktop.</p>
 +<div class="admonition note">
 +<p class="first admonition-title">Note</p>
 +<p class="last">You will have to adjust <strong>example.org/</strong> to the URL of your ownCloud server installation</p>
 +</div>
 +<div class="section" id="linux">
 +<h2>Linux<a class="headerlink" href="#linux" title="Permalink to this headline">¶</a></h2>
 +<div class="section" id="gnome-3-nautilus">
 +<h3>Gnome 3/Nautilus<a class="headerlink" href="#gnome-3-nautilus" title="Permalink to this headline">¶</a></h3>
 +<p>The URL that you have to use to connect to the ownCloud installation in nautilus is:</p>
 +<div class="highlight-python"><pre>davs://example.org/owncloud/remote.php/webdav</pre>
 +</div>
 +<img alt="../_images/gnome3_nautilus_webdav.png" src="../_images/gnome3_nautilus_webdav.png" />
 +<p>If your server connection is not HTTPS-secured, use <cite>dav://</cite> instead of <cite>davs://</cite> .</p>
 +</div>
 +<div class="section" id="kde-dolphin">
 +<h3>KDE/Dolphin<a class="headerlink" href="#kde-dolphin" title="Permalink to this headline">¶</a></h3>
 +<p>Click in the address area and enter:</p>
 +<div class="highlight-python"><pre>webdav://example.org/owncloud/remote.php/webdav</pre>
 +</div>
 +<img alt="../_images/dolphin_webdav.png" src="../_images/dolphin_webdav.png" />
 +<p>or:</p>
 +<ol class="arabic simple">
 +<li>Open Dolphin and click on where it says Network in the left hand Places column.</li>
 +<li>Click on the icon labeled <strong>Add a Network Folder</strong>.</li>
 +<li>It should come up with WebDAV already selected. Make sure it is and then click <strong>Next</strong>.</li>
 +<li>Enter the following settings:</li>
 +</ol>
 +<ul>
 +<li><p class="first">Name: The name you’ll see in the <strong>Places</strong> bookmark, for example ownCloud</p>
 +</li>
 +<li><p class="first">User: Your ownCloud username you use to log in, for example admin</p>
 +</li>
 +<li><p class="first">Server: Your ownCloud domain name, for example <strong>example.org</strong> (without <strong>http://</strong> before or directories afterwards).</p>
 +</li>
 +<li><p class="first">Folder: Enter:</p>
 +<div class="highlight-python"><div class="highlight"><pre><span class="n">owncloud</span><span class="o">/</span><span class="n">remote</span><span class="o">.</span><span class="n">php</span><span class="o">/</span><span class="n">webdav</span>
 +</pre></div>
 +</div>
 +</li>
 +</ul>
 +<ol class="arabic simple" start="5">
 +<li>Create icon checkbox: Tick to get a bookmark in the Places column</li>
 +<li>Port & Encrypted checkbox: Leave as it is unless you have special settings or an SSL certificate.</li>
 +</ol>
 +</div>
 +<div class="section" id="mounting-from-command-line">
 +<h3>Mounting from command line<a class="headerlink" href="#mounting-from-command-line" title="Permalink to this headline">¶</a></h3>
 +<ol class="arabic">
 +<li><p class="first">Install the WebDAV support using the davfs package. On Debian/Ubuntu, you can use:</p>
 +<div class="highlight-python"><pre>sudo apt-get install davfs2</pre>
 +</div>
 +</li>
 +<li><p class="first">Reconfigure davfs2 to allow access to normal users (select Yes when prompted):</p>
 +<div class="highlight-python"><pre>sudo dpkg-reconfigure davfs2</pre>
 +</div>
 +</li>
 +<li><p class="first">Add the users you want to be able to mount the share to the davfs2 group:</p>
 +<div class="highlight-python"><pre>sudo usermod -aG davfs2 <user></pre>
 +</div>
 +</li>
 +<li><p class="first">Edit <tt class="file docutils literal"><span class="pre">/etc/fstab</span></tt> and add the following line for each user who wants to mount the folder (with your details where appropriate):</p>
 +<div class="highlight-python"><pre>example.org/owncloud/remote.php/webdav /home/<username>/owncloud davfs user,rw,noauto 0 0</pre>
 +</div>
 +</li>
 +</ol>
 +<p>Then, as each user who wants to mount the folder:</p>
 +<ol class="arabic">
 +<li><p class="first">Create the folders <strong>owncloud/</strong> and <strong>.davfs2/</strong> in your home directory</p>
 +</li>
 +<li><p class="first">Create the file secrets inside <strong>.davfs2/</strong>, fill it with the following (with your credentials where appropriate):</p>
 +<div class="highlight-python"><pre>example.org/owncloud/remote.php/webdav <username> <password></pre>
 +</div>
 +</li>
 +<li><p class="first">Ensure the file is only writable by you either through the file manager, or via:</p>
 +<div class="highlight-python"><pre>chmod 600 ~/.davfs2/secrets</pre>
 +</div>
 +</li>
 +<li><p class="first">Run the command:</p>
 +<div class="highlight-python"><pre>mount ~/owncloud</pre>
 +</div>
 +</li>
 +<li><p class="first">To automatically mount the folder on login, add the command you used in step 4 to <tt class="file docutils literal"><span class="pre">./.bashrc</span></tt></p>
 +</li>
 +</ol>
 +<div class="section" id="known-issues">
 +<h4>Known Issues<a class="headerlink" href="#known-issues" title="Permalink to this headline">¶</a></h4>
 +<p><strong>Problem:</strong> Resource temporarily unavailable</p>
 +<p><strong>Solution:</strong> If you experience trouble when you create a file in the directory, edit <tt class="file docutils literal"><span class="pre">/etc/davfs2/davfs2.conf</span></tt> and add:</p>
 +<div class="highlight-python"><pre>use_locks 0</pre>
 +</div>
 +<p><strong>Problem:</strong> Certificate warnings</p>
 +<p><strong>Solution:</strong> If you use a self-signed certificate, you will get a warning. If you are willing to take the risk of a man in the middle attack, run this command instead:</p>
 +<div class="highlight-python"><pre>echo "y" | mount ~/owncloud > /dev/null 2>&1</pre>
 +</div>
 +</div>
 +</div>
 +</div>
 +<div class="section" id="macos">
 +<h2>MacOS<a class="headerlink" href="#macos" title="Permalink to this headline">¶</a></h2>
 +<div class="admonition note">
 +<p class="first admonition-title">Note</p>
- <p class="last">Finder suffers from a <a class="reference external" href="http://code.google.com/p/sabredav/wiki/Finder">series of implementation problems</a> and should only be used if the ownCloud server runs on <strong>Apache</strong> and <strong>mod_php</strong></p>
++<p class="last">Finder suffers from a <a class="reference external" href="http://sabre.io/dav/clients/finder/">series of implementation problems</a> and should only be used if the ownCloud server runs on <strong>Apache</strong> and <strong>mod_php</strong></p>
 +</div>
 +<p>In the Finder, choose <strong>Go > Connect to Server,</strong> type the address of the server in the <strong>Server Address</strong> field, and click <strong>Connect</strong>.</p>
 +<img alt="../_images/osx_webdav1.png" src="../_images/osx_webdav1.png" />
 +<p>The URL that you have to use to connect to the ownCloud installation in finder is:</p>
 +<div class="highlight-python"><pre>http://example.org/owncloud/remote.php/webdav</pre>
 +</div>
 +<img alt="../_images/osx_webdav2.png" src="../_images/osx_webdav2.png" />
 +<p>For details, check the respective <a class="reference external" href="http://docs.info.apple.com/article.html?path=Mac/10.6/en/8160.html">vendor documentation</a> at the Apple website.</p>
 +</div>
 +<div class="section" id="windows">
 +<h2>Windows<a class="headerlink" href="#windows" title="Permalink to this headline">¶</a></h2>
 +<p>For Windows a seperate WebDAV client is recommended to access the files from your server. Choose one from the <a class="reference external" href="http://www.webdav.org/projects/">WebDav Project page</a></p>
 +<p>Should you have to use the native implementation then you can assign ownCloud a drive letter. This allows you to browse files stored on an ownCloudserver the way you would files stored in a mapped network drive.</p>
 +<p>Using this feature requires network connectivity. If you want to store
 +your files offline, use the ownCloud Client to sync all files on your
 +ownCloud to one or more directories of your local hard drive.</p>
 +<div class="admonition note">
 +<p class="first admonition-title">Note</p>
 +<p class="last">Prior to mapping your drive, you will need to permit the use of Basic Authentication in the Windows Registry. The procedure is documented in <a class="reference external" href="http://support.microsoft.com/kb/841215">KB841215</a> and differs between Windows XP/Server 2003 and Windows Vista/7. Please follow the Knowledge Base article before proceeding, and follow the Vista instructions if you run Windows 7.</p>
 +</div>
 +<div class="section" id="mapping-via-the-command-line">
 +<h3>Mapping via the command line<a class="headerlink" href="#mapping-via-the-command-line" title="Permalink to this headline">¶</a></h3>
 +<p>Suppose your ownCloud is installed at <strong>https://example.org/owncloud</strong>,
 +that is, entering this URL in your web browser will bring up the login screen.
 +Running:</p>
 +<div class="highlight-python"><pre>net use Z: https://example.org/owncloud/remote.php/webdav /user:youruser yourpassword</pre>
 +</div>
 +<p>will map the files of your ownCloud account to the drive letter Z:. An alternative
 +syntax is:</p>
 +<div class="highlight-python"><pre>net use Z: \\example.org at ssl\owncloud\remote.php\webdav /user:youruser yourpassword</pre>
 +</div>
 +<p>Appending <strong>/persistent</strong> makes the connection persistent across reboots.</p>
 +<p>You can also mount your ownCloud via HTTP, leaving the connection unencrypted.
 +Use either of the following syntaxes:</p>
 +<div class="highlight-python"><pre>net use Z: http://example.org/owncloud/remote.php/webdav /user:youruser yourpassword
 +net use Z: \\example.org\owncloud\remote.php\webdav /user:youruser yourpassword</pre>
 +</div>
 +<p>Please note that this allows anyone to sniff your ownCloud data with ease, especially on public WiFi hotspots. Plain HTTP should therefore only be used in conjunction with a VPN tunnel when used on Laptops.</p>
 +</div>
 +<div class="section" id="using-windows-explorer">
 +<h3>Using Windows Explorer<a class="headerlink" href="#using-windows-explorer" title="Permalink to this headline">¶</a></h3>
 +<p>Right-click on <strong>Computer</strong> entry and select <strong>Map network drive...</strong>. Choose a local network drive to map ownCloud to. Finally, enter the address to your ownCloud instance, followed by <strong>/remote.php/webdav</strong>, e.g.</p>
 +<div class="highlight-python"><pre>https://example.org/owncloud/remote.php/webdav</pre>
 +</div>
 +<p>for an SSL protected server. Check <strong>Reconnect at logon</strong> to make this mapping persistent across reboots. If you want to connect as another user, check <strong>Connect using different credentials</strong>.</p>
 +<div class="figure">
 +<a class="reference internal image-reference" href="../_images/explorer_webdav.png"><img alt="../_images/explorer_webdav.png" src="../_images/explorer_webdav.png" style="width: 502.4px; height: 366.4px;" /></a>
 +<p class="caption">Mapping WebDAV on Windows Explorer.</p>
 +</div>
 +<p>After pressing <strong>Finish</strong>, Windows Explorer will map the network drive and your ownCloud instance should be available</p>
 +</div>
 +<div class="section" id="using-cyberduck-4-2-1">
 +<h3>Using Cyberduck (4.2.1)<a class="headerlink" href="#using-cyberduck-4-2-1" title="Permalink to this headline">¶</a></h3>
 +<p>Specify a server without any leading protocol information. e.g.:</p>
 +<dl class="docutils">
 +<dt>Server</dt>
 +<dd>example.org</dd>
 +</dl>
 +<p>The port depends on whether your ownCloud server supports SSL or not. Cyberduck requires that you select a different connection type depending on whethr SSL is to be used (‘WebDAV’ or ‘WebDAV (HTTPS/SSL)’):</p>
 +<dl class="docutils">
 +<dt>Port</dt>
 +<dd>80 (for WebDAV)
 +443 (for WebDAV (HTTPS/SSL))</dd>
 +</dl>
 +<p>Use the ‘More Options’ drop-down menu to add the rest of your WebDAV URL into the ‘Path’ field. e.g.:</p>
 +<dl class="docutils">
 +<dt>Path</dt>
 +<dd>remote.php/webdav</dd>
 +</dl>
 +</div>
 +<div class="section" id="known-problems">
 +<h3>Known Problems<a class="headerlink" href="#known-problems" title="Permalink to this headline">¶</a></h3>
 +<dl class="docutils">
 +<dt>Problem</dt>
 +<dd>Windows refuses to connect via HTTPS</dd>
 +<dt>Solution</dt>
 +<dd>The Windows WebDAV Client does not support Server Name Indication (SNI) on
 +encrypted connections. If you encounter an error mounting an SSL-encrypted
 +ownCloud instance, please contact your provider about assigning a dedicated
 +IP address for your SSL-based server.</dd>
 +<dt>Problem</dt>
 +<dd>I receive the error <strong>Error 0x800700DF: The file size exceeds the limit allowed and cannot be saved.</strong></dd>
 +<dt>Solution</dt>
 +<dd>Windows limits the maximum size a file transferred from or to  a WebDAV
 +share may have.  You can increase the value <strong>FileSizeLimitInBytes</strong> in
 +<strong>HKEY_LOCAL_MACHINESYSTEMCurrentControlSetServicesWebClientParameters</strong>.
 +by clicking on <strong>Modify</strong>. In order to increase the limit to the maximum
 +value of 4GB, pick <strong>Decimal</strong> and enter <strong>4294967295</strong> as value. Afterwards,
 +reboot Windows or restart the <strong>WebClient</strong> service.</dd>
 +</dl>
 +<div class="admonition-todo admonition" id="index-0">
 +<p class="first admonition-title">Todo</p>
 +<p class="last">document registry keys on file size limit and not complaining in no network cases</p>
 +</div>
 +</div>
 +</div>
 +<div class="section" id="sync-client">
 +<h2>Sync Client<a class="headerlink" href="#sync-client" title="Permalink to this headline">¶</a></h2>
 +<p>However, some applications only allow you to save to a local folder. To
 +get around this issue, you can use the <a class="reference external" href="http://owncloud.org/documentation/sync-clients/">ownCloud sync clients</a></p>
 +</div>
 +<div class="section" id="mobile">
 +<h2>Mobile<a class="headerlink" href="#mobile" title="Permalink to this headline">¶</a></h2>
 +<p>To connect to your ownCloud server with the <strong>ownCloud</strong> mobile apps, use the base URL and folder only:</p>
 +<div class="highlight-python"><div class="highlight"><pre><span class="n">example</span><span class="o">.</span><span class="n">org</span><span class="o">/</span><span class="n">owncloud</span>
 +</pre></div>
 +</div>
 +<p>No need to add remote.php/webdav as you do for any other WebDAV client.</p>
 +<p>There are apps in development for both <a class="reference external" href="http://github.com/owncloud/android">Android</a> and <a class="reference external" href="http://github.com/owncloud/webos">webOS</a>. Feel
 +free to <a class="reference external" href="/contribute/">contribute, if you can</a>! Right now you can use other apps to
 +connect to ownCloud from your phone via WebDAV. <a class="reference external" href="http://seanashton.net/webdav/">WebDAV Navigator</a> is a
 +good (proprietary) app for <a class="reference external" href="https://play.google.com/store/apps/details?id=com.schimera.webdavnavlite">Android App</a> , <a class="reference external" href="https://itunes.apple.com/app/webdav-navigator/id382551345">iPhone</a> & <a class="reference external" href="http://appworld.blackberry.com/webstore/content/46816">BlackBerry</a>.</p>
 +<p>The URL for these is:</p>
 +<div class="highlight-python"><div class="highlight"><pre><span class="n">example</span><span class="o">.</span><span class="n">org</span><span class="o">/</span><span class="n">owncloud</span><span class="o">/</span><span class="n">remote</span><span class="o">.</span><span class="n">php</span><span class="o">/</span><span class="n">webdav</span>
 +</pre></div>
 +</div>
 +</div>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/user/files/filesweb.html
index 8b5dd57,0000000..248a7a8
mode 100644,000000..100644
--- a/core/doc/user/files/filesweb.html
+++ b/core/doc/user/files/filesweb.html
@@@ -1,244 -1,0 +1,244 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
 +    <title>Accessing your Files (Web Interface) — ownCloud User Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud User Manual 6.0 documentation" href="../index.html" />
 +    <link rel="up" title="Files & Synchronization" href="index.html" />
 +    <link rel="next" title="Accessing your Files (WebDAV)" href="files.html" />
 +    <link rel="prev" title="Files & Synchronization" href="index.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud User Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 User Documentation</a></li>
 +</ul>
 +<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../webinterface.html">The ownCloud Web Interface</a></li>
 +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Files & Synchronization</a><ul class="current">
 +<li class="toctree-l2 current"><a class="current reference internal" href="">Accessing your Files (Web Interface)</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="#navigating-inside-your-owncloud">Navigating inside your ownCloud</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#creating-uploading-files">Creating/uploading files</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#selecting-files">Selecting files</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#viewing-files">Viewing files</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#moving-files">Moving files</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#sharing-files">Sharing files</a></li>
 +</ul>
 +</li>
 +<li class="toctree-l2"><a class="reference internal" href="files.html">Accessing your Files (WebDAV)</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="versioncontrol.html">Version Control</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="deletedfiles.html">Deleted Files</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="sync.html">Desktop Synchronization</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="encryption.html">Files Encryption</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="quota.html">Storage Quota</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html">Big Files</a></li>
 +</ul>
 +</li>
 +<li class="toctree-l1"><a class="reference internal" href="../pim/index.html">Contacts & Calendar</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../bookmarks.html">Using the Bookmarks App</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../documents.html">Documents</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../migration.html">User Account Migration</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../userpreferences.html">Changing Preferences</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../external_storage/google_drive.html">External storage</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
 +  <div class="section" id="accessing-your-files-web-interface">
 +<h1>Accessing your Files (Web Interface)<a class="headerlink" href="#accessing-your-files-web-interface" title="Permalink to this headline">¶</a></h1>
 +<p>Your ownCloud files can be accessed from anywhere by using your ownCloud’s web interface. In the files app,
 +you can view (if a common type), move, rename, download, share and delete your files easily. If versioning app is
 +enabled, you can also revert a file to specific version. See <a class="reference internal" href="versioncontrol.html"><em>Version Control</em></a> for details.</p>
 +<div class="figure">
 +<img alt="../_images/oc_filesweb.png" src="../_images/oc_filesweb.png" />
 +</div>
 +<p>Files app on ownCloud web interface</p>
 +<p>With ownCloud 6, you can now see file thumbnails next to the filenames. By hovering your cursor on a file, you
 +will be provided with some file operations. You can use rename, download, share buttons to perform those actions
 +or click on the cross icon at the rightmost location to remove the hovered file. If the file is an editable
 +office file, it will also show <em>Edit</em> button to open the file in documents app (if this app is enabled).</p>
 +<div class="section" id="navigating-inside-your-owncloud">
 +<h2>Navigating inside your ownCloud<a class="headerlink" href="#navigating-inside-your-owncloud" title="Permalink to this headline">¶</a></h2>
 +<p>To navigate through folders in your ownCloud, you can simply click on a folder name. The navigation bar
 +will show your current directory:</p>
 +<div class="figure">
 +<img alt="../_images/oc_filesweb_navigate.png" src="../_images/oc_filesweb_navigate.png" />
 +</div>
 +<p>Navigation bar</p>
 +<p>You can click on one of the upper directories to navigate up or use home icon to navigate back into your root
 +folder.</p>
 +</div>
 +<div class="section" id="creating-uploading-files">
 +<h2>Creating/uploading files<a class="headerlink" href="#creating-uploading-files" title="Permalink to this headline">¶</a></h2>
 +<p>You can create files by simply clicking on <em>New</em> button on files app. The <em>New</em> button will provide three
 +options to choose from:</p>
 +<div class="figure">
 +<img alt="../_images/oc_filesweb_new.png" src="../_images/oc_filesweb_new.png" />
 +</div>
 +<p>New button options</p>
 +<ul class="simple">
 +<li><em>Text file</em> will create a simple text file and add into the current folder in your ownCloud.</li>
 +<li><em>Folder</em> will create a folder in current folder.</li>
 +<li><em>From link</em> will download the file from the provided link and place it into the current folder.</li>
 +</ul>
 +</div>
 +<div class="section" id="selecting-files">
 +<h2>Selecting files<a class="headerlink" href="#selecting-files" title="Permalink to this headline">¶</a></h2>
 +<p>You can select one or more files by clicking on small thumbnails or icons of the files. To select all files in
 +the current directory, use the checkbox just above the first file/folder on the list.</p>
 +<p>If you select multiple files, selected files can be deleted or downloaded as ZIP by using the buttons just above of the file list.
 +If download button is not visible, this means that administrator had disabled this feature.</p>
 +</div>
 +<div class="section" id="viewing-files">
 +<h2>Viewing files<a class="headerlink" href="#viewing-files" title="Permalink to this headline">¶</a></h2>
 +<p>ownCloud can display uncompressed text files, OpenDocument files, PDFs, and image files by simply clicking on
 +the file name. If displaying of a file is not possible, a download process will start.</p>
 +</div>
 +<div class="section" id="moving-files">
 +<h2>Moving files<a class="headerlink" href="#moving-files" title="Permalink to this headline">¶</a></h2>
- <p>In ownCloud web interface, file(s) can be moved by dragging and dropping them into a sub-directory. If you would like move a directory to an upper directory, drag the file(s) into one of the folders shown in navigation bar.</p>
++<p>In ownCloud web interface, file(s) can be moved by dragging and dropping them into a sub-directory. If you would like to move a directory to an upper directory, drag the file(s) into one of the folders shown in navigation bar (depicted above).</p>
 +</div>
 +<div class="section" id="sharing-files">
 +<h2>Sharing files<a class="headerlink" href="#sharing-files" title="Permalink to this headline">¶</a></h2>
 +<p>Any file/folder on ownCloud can be shared to download with a local user, group or any person online with a public link. Shared files/folders will show a <em>Shared</em> text next to their names.</p>
 +<p>To share a file/folder, hover your cursor on an item in the files app and click <em>Share</em>. You will be provided with some options:</p>
 +<div class="figure">
 +<img alt="../_images/oc_files_share.png" src="../_images/oc_files_share.png" />
 +</div>
 +<p>Share dialog</p>
 +<ul class="simple">
 +<li>The first field is to share this file/folder with local users/groups. This is very useful
 +if you are in a company and want to create a quick share with a collegue.</li>
 +<li>If you click on <em>Share link</em>, the other options will be visible. Since this link allows everyone
 +to download this file/folder, you may want to protect this share with a password. To do that,
 +click on <em>Password protect</em> and set a password.</li>
 +<li>If this share is a folder, you will also have an option to enable uploads into this folder using
 +the provided link. This is very useful to collect files from multiple users into same place easily.</li>
 +<li>If your server is configured with a mail server, you can type e-mail addresses seperated with space to send the link to multiple users.</li>
 +<li>Finally, setting an expiration date will expiry the share after the specified date.</li>
 +</ul>
 +<p>If you type a user and/or group to the <em>share with</em> field, you will be given extra sharing options such as informing via e-mail,
 +letting users edit (create, update, delete, re-share) the share. To revoke permissions from users, simply click on cross icon
 +on the same line with the users.</p>
 +</div>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/user/files/sync.html
index 497f7dc,0000000..77a257f
mode 100644,000000..100644
--- a/core/doc/user/files/sync.html
+++ b/core/doc/user/files/sync.html
@@@ -1,173 -1,0 +1,173 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
 +    <title>Desktop Synchronization — ownCloud User Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud User Manual 6.0 documentation" href="../index.html" />
 +    <link rel="up" title="Files & Synchronization" href="index.html" />
 +    <link rel="next" title="Files Encryption" href="encryption.html" />
 +    <link rel="prev" title="Deleted Files" href="deletedfiles.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud User Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 User Documentation</a></li>
 +</ul>
 +<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../webinterface.html">The ownCloud Web Interface</a></li>
 +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Files & Synchronization</a><ul class="current">
 +<li class="toctree-l2"><a class="reference internal" href="filesweb.html">Accessing your Files (Web Interface)</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="files.html">Accessing your Files (WebDAV)</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="versioncontrol.html">Version Control</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="deletedfiles.html">Deleted Files</a></li>
 +<li class="toctree-l2 current"><a class="current reference internal" href="">Desktop Synchronization</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="encryption.html">Files Encryption</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="quota.html">Storage Quota</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="configuring_big_file_upload.html">Big Files</a></li>
 +</ul>
 +</li>
 +<li class="toctree-l1"><a class="reference internal" href="../pim/index.html">Contacts & Calendar</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../bookmarks.html">Using the Bookmarks App</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../documents.html">Documents</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../migration.html">User Account Migration</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../userpreferences.html">Changing Preferences</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../external_storage/google_drive.html">External storage</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
 +  <div class="section" id="desktop-synchronization">
 +<h1>Desktop Synchronization<a class="headerlink" href="#desktop-synchronization" title="Permalink to this headline">¶</a></h1>
 +<p>For synchronizing files with your desktop computer, we recommend using the
 +<a class="reference external" href="http://owncloud.org/sync-client/">ownCloud Client</a> for Windows, Mac OS X and Linux.</p>
 +<p>The ownCloud Desktop Client enables you to connect to your private ownCloud Server.
 +You can create folders in your home directory, and keep the contents of those
 +folders synced with your ownCloud server. Simply copy a file into the directory
 +and the ownCloud desktop client does the rest. Make a change to the files on one
 +computer, it will flow across the others using these desktop sync clients. Always
 +have your latest files with you wherever you are.</p>
- <p>Its usage is documented separately in the <a class="reference external" href="http://doc.owncloud.com/desktop">ownCloud Desktop Client Manual</a>.</p>
++<p>Its usage is documented separately in the <a class="reference external" href="http://doc.owncloud.org/desktop">ownCloud Desktop Client Manual</a>.</p>
 +<p>Furthermore, It is possible to synchronize your ownCloud calendar and address book
 +with a variety of different operating systems and devices. It is also possible to
 +mount your ownCloud storage via WebDAV, which is also documented in the next chapters.</p>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/user/pim/troubleshooting.html
index 0f83a5a,0000000..0599001
mode 100644,000000..100644
--- a/core/doc/user/pim/troubleshooting.html
+++ b/core/doc/user/pim/troubleshooting.html
@@@ -1,234 -1,0 +1,234 @@@
 +
 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 +  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 +
 +
 +<html xmlns="http://www.w3.org/1999/xhtml">
 +  <head>
 +    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +    
 +    <title>Troubleshooting — ownCloud User Manual 6.0 documentation</title>
 +    
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
 +    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
 +    
 +    <script type="text/javascript">
 +      var DOCUMENTATION_OPTIONS = {
 +        URL_ROOT:    '../',
 +        VERSION:     '6.0',
 +        COLLAPSE_INDEX: false,
 +        FILE_SUFFIX: '.html',
 +        HAS_SOURCE:  true
 +      };
 +    </script>
 +    <script type="text/javascript" src="../_static/jquery.js"></script>
 +    <script type="text/javascript" src="../_static/underscore.js"></script>
 +    <script type="text/javascript" src="../_static/doctools.js"></script>
 +    <script type="text/javascript" src="../_static/bootstrap.js"></script>
 +    <link rel="top" title="ownCloud User Manual 6.0 documentation" href="../index.html" />
 +    <link rel="up" title="Contacts & Calendar" href="index.html" />
 +    <link rel="next" title="Using the Bookmarks App" href="../bookmarks.html" />
 +    <link rel="prev" title="Synchronizing with KDE SC" href="sync_kde.html" />
 +<script type="text/javascript">
 +(function () {
 +  /**
 +   * Patch TOC list.
 +   *
 +   * Will mutate the underlying span to have a correct ul for nav.
 +   *
 +   * @param $span: Span containing nested UL's to mutate.
 +   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
 +   */
 +  var patchToc = function ($ul, minLevel) {
 +    var findA;
 +
 +    // Find all a "internal" tags, traversing recursively.
 +    findA = function ($elem, level) {
 +      var level = level || 0,
 +        $items = $elem.find("> li > a.internal, > ul, > li > ul");
 +
 +      // Iterate everything in order.
 +      $items.each(function (index, item) {
 +        var $item = $(item),
 +          tag = item.tagName.toLowerCase(),
 +          pad = 15 + ((level - minLevel) * 10);
 +
 +        if (tag === 'a' && level >= minLevel) {
 +          // Add to existing padding.
 +          $item.css('padding-left', pad + "px");
 +          console.log(level, $item, 'padding-left', pad + "px");
 +        } else if (tag === 'ul') {
 +          // Recurse.
 +          findA($item, level + 1);
 +        }
 +      });
 +    };
 +
 +    console.log("HERE");
 +    findA($ul);
 +  };
 +
 +  $(document).ready(function () {
 +    // Add styling, structure to TOC's.
 +    $(".dropdown-menu").each(function () {
 +      $(this).find("ul").each(function (index, item){
 +        var $item = $(item);
 +        $item.addClass('unstyled');
 +      });
 +      $(this).find("li").each(function () {
 +        $(this).parent().append(this);
 +      });
 +    });
 +
 +    // Patch in level.
 +    patchToc($("ul.globaltoc"), 2);
 +    patchToc($("ul.localtoc"), 2);
 +
 +    // Enable dropdown.
 +    $('.dropdown-toggle').dropdown();
 +  });
 +}());
 +</script>
 +
 +  </head>
 +  <body>
 +  
 +
 +<div class="container">
 +  <div class="content">
 +    <div class="page-header">
 +      <h1><a href="../contents.html">ownCloud User Manual</a></h1>
 +
 +    </div>
 +    
 +			<div class="row">
 +				<div class="span3">
 +					<div class="sidebar">
 +						<div class="well">
 +							<div class="menu-support-container">
 +								<ul id="menu-support" class="menu">
 +									<ul>
 +										<li><a href="../contents.html">Overview</a></li>
 +									</ul>
 +                  <ul>
 +<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 User Documentation</a></li>
 +</ul>
 +<ul class="current">
 +<li class="toctree-l1"><a class="reference internal" href="../webinterface.html">The ownCloud Web Interface</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../files/index.html">Files & Synchronization</a></li>
 +<li class="toctree-l1 current"><a class="reference internal" href="index.html">Contacts & Calendar</a><ul class="current">
 +<li class="toctree-l2"><a class="reference internal" href="contacts.html">Using the Contacts App</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="calendar.html">Using the Calendar App</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="sync_ios.html">iOS - Synchronize iPhone/iPad</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="sync_osx.html">Synchronizing with OS X</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="sync_thunderbird.html">Thunderbird - Synchronize Addressbook</a></li>
 +<li class="toctree-l2"><a class="reference internal" href="sync_kde.html">Synchronizing with KDE SC</a></li>
 +<li class="toctree-l2 current"><a class="current reference internal" href="">Troubleshooting</a><ul>
 +<li class="toctree-l3"><a class="reference internal" href="#debugging-the-issue">Debugging the issue</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#service-discovery">Service discovery</a></li>
 +<li class="toctree-l3"><a class="reference internal" href="#unable-to-update-contacts-or-events">Unable to update Contacts or Events</a></li>
 +</ul>
 +</li>
 +</ul>
 +</li>
 +<li class="toctree-l1"><a class="reference internal" href="../bookmarks.html">Using the Bookmarks App</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../documents.html">Documents</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../migration.html">User Account Migration</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../userpreferences.html">Changing Preferences</a></li>
 +<li class="toctree-l1"><a class="reference internal" href="../external_storage/google_drive.html">External storage</a></li>
 +</ul>
 +
 +								</ul>
 +							</div>
 +						</div>
 +					</div>
 +				</div>
 +        
 +
 +				<div class="span9">
 +					<div class="page-content">
 +						
 +  <div class="section" id="troubleshooting">
 +<h1>Troubleshooting<a class="headerlink" href="#troubleshooting" title="Permalink to this headline">¶</a></h1>
 +<div class="section" id="debugging-the-issue">
 +<h2>Debugging the issue<a class="headerlink" href="#debugging-the-issue" title="Permalink to this headline">¶</a></h2>
 +<p>In a standard ownCloud installation the log level is set to “Normal”. to find any issues
 +you need to raise the log level to “All” from the Admin page.
 +Some logging - for example JavaScript console logging - needs manually editing the
 +configuration file.
 +Edit <tt class="file docutils literal"><span class="pre">config/config.php</span></tt> and add <tt class="docutils literal"><span class="pre">define('DEBUG',</span> <span class="pre">true);</span></tt>:</p>
 +<div class="highlight-python"><pre><?php
 +define('DEBUG',true);
 +$CONFIG = array (
 +    ... configuration goes here ...
 +);</pre>
 +</div>
 +<p>For JavaScript issues you will also need to view the javascript console. All major browsers
 +have decent developer tools for viewing the console, and you usually access them by
 +pressing F-12. For Firefox it is recommended to install the <a class="reference external" href="https://getfirebug.com/">Firebug extension</a>.</p>
 +</div>
 +<div class="section" id="service-discovery">
 +<h2>Service discovery<a class="headerlink" href="#service-discovery" title="Permalink to this headline">¶</a></h2>
 +<p>Some clients - especially iOS - have problems finding the proper sync URL, even when explicitly
 +configured to use it.</p>
 +<p>There are several techniques to remedy this, which are described extensively at the
- <a class="reference external" href="http://code.google.com/p/sabredav/wiki/ServiceDiscovery">Sabre DAV website</a>.</p>
++<a class="reference external" href="http://sabre.io/dav/service-discovery/">Sabre DAV website</a>.</p>
 +<div class="section" id="apple-ios">
 +<h3>Apple iOS<a class="headerlink" href="#apple-ios" title="Permalink to this headline">¶</a></h3>
 +<p>Below is what have proven to work with iOS including iOS 7.</p>
 +<p>If your ownCloud instance is installed in a sub-folder under the web servers document root, and
 +the client has difficulties finding the Cal- or CardDAV end-points, configure your web server to
 +redirect from a “well-know” URL to the one used by ownCloud.
 +When using the Apache web server this is easily achieved using a <tt class="file docutils literal"><span class="pre">.htaccess</span></tt> file in the document
 +root of your site.</p>
 +<p>Say your instance is located in the <tt class="docutils literal"><span class="pre">owncloud</span></tt> folder, so the URL to it is <tt class="docutils literal"><span class="pre">ADDRESS/owncloud</span></tt>,
 +create or edit the <tt class="file docutils literal"><span class="pre">.htaccess</span></tt> file and add the following lines:</p>
 +<div class="highlight-python"><pre>Redirect 301 /.well-known/carddav /owncloud/remote.php/carddav
 +Redirect 301 /.well-known/caldav /owncloud/remote.php/caldav</pre>
 +</div>
 +<p>If you use Nginx as web server, the setting looks something like:</p>
 +<div class="highlight-python"><pre>url.redirect = (
 +    "^/.well-known/carddav" => "/owncloud/remote.php/carddav",
 +    "^/.well-known/caldav" => "/owncloud/remote.php/caldav",
 +)</pre>
 +</div>
 +<p>Now change the URL in the client settings to just use <tt class="docutils literal"><span class="pre">ADDRESS</span></tt> instead of e.g. <tt class="docutils literal"><span class="pre">ADDRESS/remote.php/carddav/principals/username</span></tt>.</p>
 +<p>This problem is being discussed in the <a class="reference external" href="http://forum.owncloud.org/viewtopic.php?f=3&t=71&p=2211#p2197">forum</a>.</p>
 +</div>
 +<div class="section" id="blackberry-os-10-2">
 +<h3>BlackBerry OS 10.2<a class="headerlink" href="#blackberry-os-10-2" title="Permalink to this headline">¶</a></h3>
 +<p>BlackBerry OS up to 10.2.2102 doesn’t accept a URL with protocol <tt class="docutils literal"><span class="pre">https://</span></tt> in front of the server address.
 +It will always tell you, that it cannot login on your server. So instead of writing</p>
 +<blockquote>
 +<div><a class="reference external" href="https://address/remote.php/carddav/principals/username">https://address/remote.php/carddav/principals/username</a></div></blockquote>
 +<p>in the server address field, you have to write</p>
 +<blockquote>
 +<div>address/remote.php/carddav/principals/username</div></blockquote>
 +</div>
 +</div>
 +<div class="section" id="unable-to-update-contacts-or-events">
 +<h2>Unable to update Contacts or Events<a class="headerlink" href="#unable-to-update-contacts-or-events" title="Permalink to this headline">¶</a></h2>
 +<p>If you get an error like <tt class="docutils literal"><span class="pre">PATCH</span> <span class="pre">https://ADDRESS/some_url</span> <span class="pre">HTTP/1.0</span> <span class="pre">501</span> <span class="pre">Not</span> <span class="pre">Implemented</span></tt> it is
 +likely caused by one of the following reasons:</p>
 +<dl class="docutils">
 +<dt>Outdated lighttpd web server</dt>
 +<dd>lighttpd in debian wheezy (1.4.31) doesn’t support the PATCH HTTP verb.
 +Upgrade to lighttpd >= 1.4.33.</dd>
 +<dt>Using Pound reverse-proxy/load balancer</dt>
 +<dd>As of writing this Pound doesn’t support the HTTP/1.1 verb.
 +Pound is easily <a class="reference external" href="http://www.apsis.ch/pound/pound_list/archive/2013/2013-08/1377264673000">patched</a> to support HTTP/1.1.</dd>
 +</dl>
 +</div>
 +</div>
 +
 +
 +					</div>
 +				</div>
 +			</div>
 +    
 +  </div>
 +</div>
 +  </body>
 +</html>
diff --cc core/doc/user/web_guide/index.html
index 0000000,0000000..50b69c2
new file mode 100644
--- /dev/null
+++ b/core/doc/user/web_guide/index.html
@@@ -1,0 -1,0 +1,325 @@@
++
++<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
++  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
++
++
++<html xmlns="http://www.w3.org/1999/xhtml">
++  <head>
++    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
++    
++    <title>The ownCloud Web Interface — ownCloud User Manual 6.0 documentation</title>
++    
++    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
++    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
++    <link rel="stylesheet" href="../_static/style.css" type="text/css" />
++    <link rel="stylesheet" href="../_static/bootstrap-sphinx.css" type="text/css" />
++    
++    <script type="text/javascript">
++      var DOCUMENTATION_OPTIONS = {
++        URL_ROOT:    '../',
++        VERSION:     '6.0',
++        COLLAPSE_INDEX: false,
++        FILE_SUFFIX: '.html',
++        HAS_SOURCE:  true
++      };
++    </script>
++    <script type="text/javascript" src="../_static/jquery.js"></script>
++    <script type="text/javascript" src="../_static/underscore.js"></script>
++    <script type="text/javascript" src="../_static/doctools.js"></script>
++    <script type="text/javascript" src="../_static/bootstrap.js"></script>
++    <link rel="top" title="ownCloud User Manual 6.0 documentation" href="../index.html" />
++<script type="text/javascript">
++(function () {
++  /**
++   * Patch TOC list.
++   *
++   * Will mutate the underlying span to have a correct ul for nav.
++   *
++   * @param $span: Span containing nested UL's to mutate.
++   * @param minLevel: Starting level for nested lists. (1: global, 2: local).
++   */
++  var patchToc = function ($ul, minLevel) {
++    var findA;
++
++    // Find all a "internal" tags, traversing recursively.
++    findA = function ($elem, level) {
++      var level = level || 0,
++        $items = $elem.find("> li > a.internal, > ul, > li > ul");
++
++      // Iterate everything in order.
++      $items.each(function (index, item) {
++        var $item = $(item),
++          tag = item.tagName.toLowerCase(),
++          pad = 15 + ((level - minLevel) * 10);
++
++        if (tag === 'a' && level >= minLevel) {
++          // Add to existing padding.
++          $item.css('padding-left', pad + "px");
++          console.log(level, $item, 'padding-left', pad + "px");
++        } else if (tag === 'ul') {
++          // Recurse.
++          findA($item, level + 1);
++        }
++      });
++    };
++
++    console.log("HERE");
++    findA($ul);
++  };
++
++  $(document).ready(function () {
++    // Add styling, structure to TOC's.
++    $(".dropdown-menu").each(function () {
++      $(this).find("ul").each(function (index, item){
++        var $item = $(item);
++        $item.addClass('unstyled');
++      });
++      $(this).find("li").each(function () {
++        $(this).parent().append(this);
++      });
++    });
++
++    // Patch in level.
++    patchToc($("ul.globaltoc"), 2);
++    patchToc($("ul.localtoc"), 2);
++
++    // Enable dropdown.
++    $('.dropdown-toggle').dropdown();
++  });
++}());
++</script>
++
++  </head>
++  <body>
++  
++
++<div class="container">
++  <div class="content">
++    <div class="page-header">
++      <h1><a href="../contents.html">ownCloud User Manual</a></h1>
++
++    </div>
++    
++			<div class="row">
++				<div class="span3">
++					<div class="sidebar">
++						<div class="well">
++							<div class="menu-support-container">
++								<ul id="menu-support" class="menu">
++									<ul>
++										<li><a href="../contents.html">Overview</a></li>
++									</ul>
++                  <ul>
++<li class="toctree-l1"><a class="reference internal" href="../index.html">ownCloud 6.0 User Documentation</a></li>
++</ul>
++<ul>
++<li class="toctree-l1"><a class="reference internal" href="../webinterface.html">The ownCloud Web Interface</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../files/index.html">Files & Synchronization</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../pim/index.html">Contacts & Calendar</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../bookmarks.html">Using the Bookmarks App</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../documents.html">Documents</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../migration.html">User Account Migration</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../userpreferences.html">Changing Preferences</a></li>
++<li class="toctree-l1"><a class="reference internal" href="../external_storage/google_drive.html">External storage</a></li>
++</ul>
++
++								</ul>
++							</div>
++						</div>
++					</div>
++				</div>
++        
++
++				<div class="span9">
++					<div class="page-content">
++						
++  <div class="section" id="the-owncloud-web-interface">
++<h1>The ownCloud Web Interface<a class="headerlink" href="#the-owncloud-web-interface" title="Permalink to this headline">¶</a></h1>
++<div class="section" id="introduction">
++<h2>Introduction<a class="headerlink" href="#introduction" title="Permalink to this headline">¶</a></h2>
++<p>This document will discuss the ownCloud web interface from a user’s perspective.
++It will detail how to log into ownCloud, upload files, create files and folders, as well as describe the Personal Page settings.
++When possible, it will reference other more detailed documents on specific functionality.</p>
++</div>
++<div class="section" id="initial-log-in">
++<h2>Initial Log In<a class="headerlink" href="#initial-log-in" title="Permalink to this headline">¶</a></h2>
++<p>The ownCloud initial login screen is as follows.</p>
++<p><img alt="1000000000000453000001BFFCF48776_png" src="../_images/1000000000000453000001BFFCF48776.png" style="width: 6.5in; height: 2.6252in;" /></p>
++<p>It should be noted, that if the instance of ownCloud is themed differently, there will be a different logo on the screen.</p>
++<p>To log into ownCloud, enter the username and password provided by your ownCloud admin.
++To remain logged into ownCloud under the same credentials, select the checkbox next to Remember.</p>
++<p>Upon initial login, the user will most likely see the “Welcome to ownCloud” banner as below.</p>
++<p><img alt="1000000000000479000002887E7F48EA_png" src="../_images/1000000000000479000002887E7F48EA.png" style="width: 6.5in; height: 3.6783in;" /></p>
++<p>This banner provides links to download the desktop sync app (see Desktop Client document), as well as the mobile apps.
++This banner will appear upon the first login only, provided the admin has not disabled it.
++To close the banner and start using ownCloud, select the ‘x’ in the upper right corner of the banner.</p>
++</div>
++<div class="section" id="main-owncloud-screen">
++<h2>Main ownCloud screen<a class="headerlink" href="#main-owncloud-screen" title="Permalink to this headline">¶</a></h2>
++<p>Once logged into ownCloud, the main screen will be displayed.</p>
++<p><img alt="100000000000047700000219A3013A92_png" src="../_images/100000000000047700000219A3013A92.png" style="width: 6.5in; height: 3.0535in;" /></p>
++<p>There are four sections in the main ownCloud screen</p>
++<ol class="arabic simple">
++<li>This is the apps bar.
++Any user related apps will be displayed here.
++In a default enterprise edition of ownCloud, the Files app and the Activity app are listed.</li>
++<li>This section will display all data loaded into ownCloud.</li>
++<li>The home button brings the user to the home directory.
++The New button allows the user to create a file or folder, or link, and the upload arrow allows the user to upload a file.</li>
++<li>The search box allows the user to search and the user name pull^down can bring the user to the Personal page for personal configurations as well as log the user out.</li>
++</ol>
++</div>
++<div class="section" id="adding-data">
++<h2>Adding Data<a class="headerlink" href="#adding-data" title="Permalink to this headline">¶</a></h2>
++<p>There are a few ways to add data to the ownCloud instance.
++Files may be uploaded or text files may be created directly within ownCloud.
++Folders may also be created directly within the ownCloud web interface.</p>
++<div class="section" id="creation">
++<h3>Creation<a class="headerlink" href="#creation" title="Permalink to this headline">¶</a></h3>
++<p>To create a file or folder, select the New button in section 3 of the main ownCloud screen.</p>
++<p><img alt="1000000000000163000000E9CDA84C92_png" src="../_images/1000000000000163000000E9CDA84C92.png" style="width: 3.698in; height: 2.4272in;" /></p>
++<div class="section" id="create-a-text-file">
++<h4>Create a text file<a class="headerlink" href="#create-a-text-file" title="Permalink to this headline">¶</a></h4>
++<p>Select “Text file” from the menu and enter the desired file name.</p>
++<p><img alt="1000000000000175000000FAB2A2B294_png" src="../_images/1000000000000175000000FAB2A2B294.png" style="width: 3.8846in; height: 2.6043in;" /></p>
++<p>Then press enter.</p>
++<p><img alt="100000000000047A000000FB86FF2A9A_png" src="../_images/100000000000047A000000FB86FF2A9A.png" style="width: 6.5in; height: 1.4228in;" /></p>
++<p>Notice the file has been placed in section 2 of the main ownCloud window.
++Since it is an empty file, the size is “0 Bytes” and it was last modified a few seconds ago.</p>
++</div>
++<div class="section" id="create-a-folder">
++<h4>Create a folder<a class="headerlink" href="#create-a-folder" title="Permalink to this headline">¶</a></h4>
++<p>To create a folder within ownCloud, simply select “Folder” from the menu and enter the desired folder name.</p>
++<p><img alt="1000000000000195000000EF7E44082C_png" src="../_images/1000000000000195000000EF7E44082C.png" style="width: 4.2189in; height: 2.4898in;" /></p>
++<p>Then select Enter.</p>
++<p>Notice the folder appears in the window.</p>
++<p><img alt="100000000000047A0000011C6682A254_png" src="../_images/100000000000047A0000011C6682A254.png" style="width: 6.5in; height: 1.611in;" /></p>
++</div>
++<div class="section" id="adding-a-file-from-a-link">
++<h4>Adding a file from a link<a class="headerlink" href="#adding-a-file-from-a-link" title="Permalink to this headline">¶</a></h4>
++<p>If the desired file exists on the internet already it is possible to add the file to ownCloud using the internet link.
++To do this, select “From link” from the menu and enter the URL of the file then select enter.</p>
++<p><img alt="10000000000001CE000000F2E2084BA1_png" src="../_images/10000000000001CE000000F2E2084BA1.png" style="width: 4.8126in; height: 2.5201in;" /></p>
++<p><img alt="100000000000046D0000015F4B5494A9_png" src="../_images/100000000000046D0000015F4B5494A9.png" style="width: 6.5in; height: 2.0138in;" /></p>
++<p>The file contained in the link now appears in the user’s ownCloud instance.</p>
++</div>
++</div>
++<div class="section" id="uploading-files">
++<h3>Uploading files<a class="headerlink" href="#uploading-files" title="Permalink to this headline">¶</a></h3>
++<p>There are two methods possible to upload files to the ownCloud web interface.</p>
++<div class="section" id="drag-and-drop">
++<h4>Drag and Drop<a class="headerlink" href="#drag-and-drop" title="Permalink to this headline">¶</a></h4>
++<p>Simply drag and drop one or more files from the client’s
++Desktop into section 2 of the main ownCloud window.
++These files will then be uploaded to ownCloud and appear in the data window.</p>
++</div>
++<div class="section" id="upload-button">
++<h4>Upload Button<a class="headerlink" href="#upload-button" title="Permalink to this headline">¶</a></h4>
++<p>The second method to upload a file to ownCloud is to select the upload arrow on the top left of the main ownCloud screen.
++This will being up a File Upload selection box.</p>
++<p><img alt="100000000000048100000245268CDB7A_png" src="../_images/100000000000048100000245268CDB7A.png" style="width: 6.5in; height: 3.2756in;" /></p>
++<p>Navigate to the directory containing the desired files and select the file for uploading and press Open.
++To upload multiple files simultaneously, use either the SHIFT or CTRL key during file selection as appropriate.</p>
++</div>
++</div>
++</div>
++<div class="section" id="navigation">
++<h2>Navigation<a class="headerlink" href="#navigation" title="Permalink to this headline">¶</a></h2>
++<div class="section" id="changing-directories">
++<h3>Changing directories<a class="headerlink" href="#changing-directories" title="Permalink to this headline">¶</a></h3>
++<p>To navigate to other folders within ownCloud, simply click on the desired folder.</p>
++<p><img alt="1000000000000470000001B68AE60DD3_png" src="../_images/1000000000000470000001B68AE60DD3.png" style="width: 6.5in; height: 2.5063in;" /></p>
++<p>Notice that Section 3 shows the currently displayed directory “my_folder”.
++To navigate back to the root directly, select the “Home” button.</p>
++</div>
++<div class="section" id="viewing-editing-files">
++<h3>Viewing/Editing files<a class="headerlink" href="#viewing-editing-files" title="Permalink to this headline">¶</a></h3>
++<p>ownCloud has the ability to view text files as well as pictures.
++To view a text file or a picture, click on the file.</p>
++<p><img alt="10000000000004710000014BBC34499D_png" src="../_images/10000000000004710000014BBC34499D.png" style="width: 6.5in; height: 1.8925in;" /></p>
++<p>For text files, a text editor will be brought up allowing the user to modify the file as desired.
++Just type the desired text and select “Save” to commit the changes.
++Once changes have been made to the file, prior to saving, the name of the file will have an “*” next to it indicating it has yet to be saved.</p>
++<p><img alt="100000000000046F000000DEA2BFCD9B_png" src="../_images/100000000000046F000000DEA2BFCD9B.png" style="width: 6.5in; height: 1.2717in;" /></p>
++<p>Once changes have been saved, a thumbnail of the text file will appear in the main data window.</p>
++<p><img alt="100000000000041D0000003D52225C0D_png" src="../_images/100000000000041D0000003D52225C0D.png" style="width: 6.5in; height: 0.3764in;" /></p>
++</div>
++<div class="section" id="downloading-a-file">
++<h3>Downloading a file<a class="headerlink" href="#downloading-a-file" title="Permalink to this headline">¶</a></h3>
++<p>To download a file from ownCloud to your working computer, hover over the file and then select the “Download” button.</p>
++<p><img alt="100000000000047200000129CB014025_png" src="../_images/100000000000047200000129CB014025.png" style="width: 6.5in; height: 1.6965in;" /></p>
++<p>For non^text or picture files, the user may also click on the file name to download it.</p>
++</div>
++<div class="section" id="renaming-files-or-folders">
++<h3>Renaming files or Folders<a class="headerlink" href="#renaming-files-or-folders" title="Permalink to this headline">¶</a></h3>
++<p>To rename a file or folder within ownCloud, hover over the file and select Rename.
++Then type the new name of the file or folder.</p>
++</div>
++<div class="section" id="sharing-versions-delete-and-activity">
++<h3>Sharing, Versions, Delete, and Activity<a class="headerlink" href="#sharing-versions-delete-and-activity" title="Permalink to this headline">¶</a></h3>
++<p>For more information on the sharing, versions, deletion or Activity features, please see the respective documents.</p>
++</div>
++</div>
++<div class="section" id="personal-configurations">
++<h2>Personal Configurations<a class="headerlink" href="#personal-configurations" title="Permalink to this headline">¶</a></h2>
++<p>Each ownCloud user may configure some personal preferences.
++To make these configurations, navigate to the Personal page.
++Select the user name and the following menu will appear.</p>
++<p><img alt="100000000000047A000000B727198874_png" src="../_images/100000000000047A000000B727198874.png" style="width: 6.5in; height: 1.0382in;" /></p>
++<p>Select Personal to get to the configuration page.</p>
++<p>Configuration options on this page may appear or disappear depending on what the ownCloud admin has configured.
++The basic configuration parameters are as follows.</p>
++<p><img alt="1000000000000467000002B63162E59B_png" src="../_images/1000000000000467000002B63162E59B.png" style="width: 6.5in; height: 4.0028in;" /></p>
++<p><img alt="10000000000004690000026615360BEB_png" src="../_images/10000000000004690000026615360BEB.png" style="width: 6.5in; height: 3.5346in;" /></p>
++<div class="section" id="important-links">
++<h3>Important links<a class="headerlink" href="#important-links" title="Permalink to this headline">¶</a></h3>
++<p>The top section of the Personal page contains the same links as the First Run Wizard described earlier in this document.
++For more information on this, see the document on the First Run Wizard.</p>
++</div>
++<div class="section" id="quota">
++<h3>Quota<a class="headerlink" href="#quota" title="Permalink to this headline">¶</a></h3>
++<p>Below shows the used and remaining space for the user.
++For information as to how this is calculated, refer to the ownCloud Quota Calculations document.</p>
++</div>
++<div class="section" id="password-change">
++<h3>Password Change<a class="headerlink" href="#password-change" title="Permalink to this headline">¶</a></h3>
++<p>If the user desires to change the password, do so in this section.
++Enter the current password followed by the new password and select “Change Password”.
++It should be noted, that when using LDAP authentication, the password is contained within the LDAP and not locally thus this field will not change the password.</p>
++</div>
++<div class="section" id="change-display-name">
++<h3>Change Display Name<a class="headerlink" href="#change-display-name" title="Permalink to this headline">¶</a></h3>
++<p>To change the way your name is displayed within ownCloud, enter the desired name under “Full Name”.</p>
++</div>
++<div class="section" id="add-email-address">
++<h3>Add Email Address<a class="headerlink" href="#add-email-address" title="Permalink to this headline">¶</a></h3>
++<p>For password recovery and share notifications, it is important for ownCloud to have an email on record.
++Enter the desired email address under the EMAIL section.</p>
++</div>
++<div class="section" id="avatar">
++<h3>Avatar<a class="headerlink" href="#avatar" title="Permalink to this headline">¶</a></h3>
++<p>ownCloud allows a user to upload an Avatar for their ownCloud instance.
++This can be done under the “Profile Picture” section of the Personal Page.</p>
++<p>To upload a new Avatar, select the “Upload new” button.
++If the desired avatar exists on the ownCloud file system, select “Select new from Files” and to remove the avatar and return to the default, select “Remove image”</p>
++</div>
++<div class="section" id="language">
++<h3>Language<a class="headerlink" href="#language" title="Permalink to this headline">¶</a></h3>
++<p>If English is not the user’s native language, they may change the language in this section.</p>
++</div>
++<div class="section" id="webdav">
++<h3>WebDAV<a class="headerlink" href="#webdav" title="Permalink to this headline">¶</a></h3>
++<p>This provides the address to use in order to access a user’s files via WebDav.</p>
++</div>
++</div>
++</div>
++
++
++					</div>
++				</div>
++			</div>
++    
++  </div>
++</div>
++  </body>
++</html>
diff --cc core/skeleton/ownCloudUserManual.pdf
index 00e436f,0000000..f883ee7
mode 100644,000000..100644
Binary files differ
diff --cc lib/private/request.php
index f5b5aa0,f4ab76b..f4ab76b
mode 100644,100755..100644
--- a/lib/private/request.php
+++ b/lib/private/request.php
diff --cc lib/private/util.php
index 7b9d223,6db1727..6db1727
mode 100644,100755..100644
--- a/lib/private/util.php
+++ b/lib/private/util.php
diff --cc version.php
index e84bbde,b26d336..31c9a1b
--- a/version.php
+++ b/version.php
@@@ -1,6 -1,17 +1,6 @@@
 -<?php
 -
 -// We only can count up. The 4. digit is only for the internal patchlevel to trigger DB upgrades between betas, final and RCs. This is _not_ the public version number. Reset minor/patchlevel when updating major/minor version number.
 -$OC_Version=array(6, 0, 2, 5);
 -
 -// The human readable string
 -$OC_VersionString='6.0.2';
 -
 -// The ownCloud edition
 -$OC_Edition='';
 -
 -// The ownCloud channel
 -$OC_Channel='git';
 -
 -// The build number
 -$OC_Build='';
 -
 +<?php 
- $OC_Version = array(6,0,2,2);
++$OC_Version = array(6,0,2,5);
 +$OC_VersionString = '6.0.2';
 +$OC_Edition = '';
- $OC_Channel = 'stable';
- $OC_Build = '2014-03-03T14:12:38+00:00';
++$OC_Channel = 'daily';
++$OC_Build = '2014-04-18T03:13:40+00:00';

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-owncloud/owncloud.git



More information about the Pkg-owncloud-commits mailing list