[tarent-useful-scripts SCM] {mirkarte} branch master updated. b3da28b7027458ad7aae36de9e85874ef6282003

mirabilos at evolvis.org mirabilos at evolvis.org
Fri Jun 13 14:17:07 CEST 2014


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Supplemental git repository mirkarte for Evolvis project useful-scripts".

The branch, master has been updated
       via  b3da28b7027458ad7aae36de9e85874ef6282003 (commit)
       via  863eecc372e5b1c6bea8d8b8c8a82fed5a7e46de (commit)
       via  83ad2670ce91be3a1f70c83b79a90517164bd919 (commit)
       via  4c93974e90e8bf9405bc72e139436325f2caf954 (commit)
       via  ce88e6aeb3e1b2432f8647c17f220f025c8f7661 (commit)
       via  595393b09bf8096fe5b69ce94cb51b09f8619e85 (commit)
       via  a46c00b5db15ea929177c3153d3faf008b398b47 (commit)
       via  26b27d4cf044f7be0398a06a8419e62e41aeb2bb (commit)
       via  647175074b2293968016b98f92b42ea6384f1cc5 (commit)
       via  e9a4ea5be69762f4177fbed8b0a89b1f4bb15506 (commit)
       via  731c61c4f52e083bc9aa9ebe9c1951de47131044 (commit)
       via  c89853b38473bed9ac3eb4c8dba9258024ec25d2 (commit)
       via  aa740a3fe9932109e93732cd031b2a99a7bbc0e0 (commit)
       via  9cbeaeccc2194e6297fa13997ec203883c4f59c1 (commit)
       via  25daed2c31529c297d43b0b3a78b4f41b2e4f56e (commit)
       via  5080ef7b1bcbe7a1442bf7624db9e0da5603058d (commit)
       via  333e3faebd521ca5bf3a2ac869cab2b4d54664c9 (commit)
       via  591c1ffe1b1de0eb56d11b970b5e6b46f2fffd04 (commit)
       via  6bbd666b61f18fa0e981e4a5b4fa3ecc985aca38 (commit)
       via  0c11ec6a2c18cbc2c2fb13c58e905bfea7e998d8 (commit)
       via  c32fc310d17c6edbf89b866622527459ec52d6d7 (commit)
       via  cff4d4f94ba7667812ed3016ef617611777d5528 (commit)
       via  e5d10d8fc84d2221eda59139de1e3f32a9993946 (commit)
       via  a30a60307c6dc9e9f6b0965cf915e75c99bbb364 (commit)
       via  75e8b36b46e5d450f803128ec7a0b1c10091344b (commit)
       via  33d86dbc1508ac217ebd9895732619872d893b23 (commit)
       via  301dc930e04ea800353a158fbb2c054a275cfb95 (commit)
       via  1fcafe6c2a680deff01eca890b8371f0315ced7b (commit)
       via  ba165115cf348eea00e9d19f93c1faca57c81548 (commit)
       via  956b9885bea830c37a7713c1ef637242ffbd0e61 (commit)
       via  e5bc8cf2a401142652881e18e57ba9877c6133ad (commit)
       via  3d3c6fcbf338221f5753e4923e16edb9e902f3ac (commit)
       via  b428c0d534eae9583fb6e70f98d323e5deb9c79a (commit)
       via  e4aabedea80a9059de3054ce09cd5fa39f73d8ce (commit)
       via  f4b6ffbe0b1a503730e9a5b20eda287812b9df87 (commit)
       via  981e2ae5051745fae0bdd689a32e3fa9e39c3aea (commit)
       via  0d247c95396e7686652a35b6d04b1fbb5cbdf670 (commit)
       via  7e8fc2bfd4a68e9528566fdc85758cf5155528b9 (commit)
       via  272ede16ac2f231dc8193452136db1e45b3b48c9 (commit)
       via  bc7be190f0e640008e0f04a5ed588540960fde8c (commit)
       via  eea42f11e3f78d4121455303b0759e57fb37fbf0 (commit)
       via  b3b75b13400c66be3eed75861f8403c881c350ea (commit)
       via  bb09d7213b5456bc29ce72889326eb8acf685ea5 (commit)
       via  b723700bdae482e3f209fab535e96f9c452fc40d (commit)
       via  d87cfb0664a95ac092bf43e2d80d706a5e5e318b (commit)
       via  81dd134d80ed3050acf403c762d8c73bb490ea6d (commit)
       via  ebb2216232c0d28a6e0322f97f30a5ce979930b4 (commit)
       via  20f50339f621980a4457643568dfd9ebba6016e4 (commit)
       via  e1c195f01ceaa71cd59b2b33f021a2e84415f6f4 (commit)
       via  cd653ffbc5503c9f7929c9ff20bdbc02f467dda3 (commit)
       via  48dc2439855775610399823fd7ca20fddffac761 (commit)
       via  e26da42b8e024fa393ede06cd47a0a2cff8b93dd (commit)
       via  0b9acf53f4ca6cda071ea89cd80e613661bc0508 (commit)
       via  80f59c74baede4020da7be2eeb7fc5be388b934b (commit)
       via  b86e51d1accc9929b6326bc8ef46b5a764109f01 (commit)
       via  6260f0d5a06820984ae3e22628083f43f24a4162 (commit)
       via  401ff262f07357d95777df61c947de949299beed (commit)
       via  88fef8373f65beba9c4c136eb65b066ffe472468 (commit)
       via  1f910f2e853d60e9aafbf694b82e1f63c0662f63 (commit)
       via  cd6243e0144a8799063a0f12881ec28fe6232529 (commit)
       via  24079d6249fb04cc250563a6413a1a2cb281385b (commit)
       via  96011fc9cc3a8e672949a3283284e70154cba445 (commit)
       via  6f6407580d1c21d78d4afd49884b7d9fa5f93923 (commit)
       via  fb2c63fb5ac8393d4e0f5f97ecbe68a6d1d46457 (commit)
       via  05048682aa23d8c593a35b814e926bd583ebbe94 (commit)
       via  f5b4df8cae80ffe95013eb297d593140f8ce3669 (commit)
       via  234504b25cfae973aa6f4ea5ca9503ad9c1051f6 (commit)
       via  3cc3c2732f0b9e3aa635a1680e1736c1b9dd3ff9 (commit)
       via  2fb658f8d42dfdcf37ea11b450d4adbcde56b1c9 (commit)
       via  e07693b01243547344cd76a8bc59b45d1cc19112 (commit)
       via  bf614462b9af54fb585dc14a9c7f728698a281e9 (commit)
       via  62fd2368525a513259d7d8576cd81811decaafcf (commit)
       via  609ca2595c1d008640b0cf79e80c5b8bb9c642b0 (commit)
       via  c68f030686bb11c25d2366b8a1fda17103daaa41 (commit)
       via  eb349c693e56888d9c8421dff9a343042e2dd31c (commit)
       via  781e5bffbdb22447ba10bd5c40603281470046b3 (commit)
       via  0b347faa8e598cbcff1a8de568b1e1661e3b53db (commit)
       via  7350b97ed00a520d7a44556a15d6330c0262bcf1 (commit)
       via  d53e0a41fd3500c002b0368078d3c828d011dc51 (commit)
       via  e65f08f60c3297fb6191de44ccf2fa5ff6cecbe7 (commit)
       via  f0a4093822a0347ca20dd36fdc68c71fe33cddf0 (commit)
       via  d6356af2cf8e496f567e69a0b0cb4f197a2466cf (commit)
       via  3042757383fd2e0654ce0aef23f54005bbc68df9 (commit)
       via  22cb76333da2c0a36c9d9492d92c6027728d33ca (commit)
       via  a63e6dc8d8aa1f87be765bf96281b2dcc910e582 (commit)
       via  d09edfd2a7ec617e4520eb36228cb1ba677fa0a6 (commit)
       via  a41f4c9d75f1d6547b1b715b385afcad2b774fae (commit)
       via  f3603ee5ed6020f70fae1027b94d4cd7606f41a0 (commit)
       via  a9490a4d1c64a4c02818d2375ae042a4b44eb831 (commit)
       via  caab022620eed11bc3834ff717b383b44e203077 (commit)
       via  faa8f83dc7173c422758517034d68e87f8d0eb66 (commit)
       via  983f255fdd89666d6f917a9c82638c786326be73 (commit)
       via  e917ec43f4dc17dc5ed2167fa59253c3e176b389 (commit)
       via  61c0c8e046c7c92396199ce58acdbfc8ca614d85 (commit)
       via  142d8e87c022d81ce5b0f7ffe2e7798d8658431c (commit)
       via  c7e9d098fe1c6ee54dfaac51e3541543ddb3d8e4 (commit)
       via  95873cf8d74fdd848aa250082736ae91fb7a3b97 (commit)
       via  f6cff0f9a2d239ce4db2ba7fa19d233d13568158 (commit)
       via  ed5c790deffa526360c643acd3c41e716d9189ff (commit)
       via  dc86eda4e5064da30eb20c11bdf64f92f20b42a6 (commit)
       via  8564a16a11e7e1448fcf92f98d16b87bc4e5a7b9 (commit)
       via  b6d27e13730bd01caabe6b2c4b809ee44d7515dd (commit)
       via  f6717a11d5f03563ba44164f7f4347dcbfe68996 (commit)
       via  25f5e6af8859bf19a3aa40dd8c2d5bba8f32cf73 (commit)
       via  63ac7584ad0636c3810b45acc302af8f7d79fa33 (commit)
       via  62e614702e1ebf7cb5417206eb4503af0e160129 (commit)
       via  fb677d8fda1381599731c84845504c68da2946d9 (commit)
       via  11cca65d7fdf6f1c355b2b148335d8d76b00a010 (commit)
       via  dae44b666f423a3e7226ea2ca62a36cae9be5743 (commit)
       via  1b0fe8c7a52ac8a74a914e5fbdce335a59432491 (commit)
       via  4dac7a97a1db657285de80e03b48fcd9d9ce8677 (commit)
       via  fd04a1c19b476582a933e2c9b771a056420b13f8 (commit)
       via  9cf99b6b5ee62d740e154bfd4013640ac7960af1 (commit)
       via  260ded4e5ff1294e89f669c876b57c8d52e005a4 (commit)
       via  f93037957b59be8da27e029161af71ac870ebf82 (commit)
       via  59f9f69da1ea1ee4d6a8d944c10d348be9d03512 (commit)
       via  948734f98ab77d82c09aec35914d957d3b8132ba (commit)
       via  c19672fc4efe58839acb323481f8fbec326f046d (commit)
       via  687e7cbc46485d43072d8a655214d01336abe541 (commit)
       via  2e4c8462c6b2c18bd9973fede1599e5bec370db8 (commit)
       via  d649b50bd0572ef7c624c93d58e86b294b8f0747 (commit)
       via  c25498e4743bececf73c01518c026f1666547d24 (commit)
       via  ecb4e50d574bf685b8fd416d48f511819497ef9c (commit)
       via  b54c00ee26d3fb3f5fbc532efeae1d13d5850b7b (commit)
       via  c66b0b8245b58c28e67ac63ce55ee5798b7ba5e2 (commit)
       via  f3b4c06ab9ad98e2865ed894d369b3e09d9c5f0b (commit)
       via  4985a2594c5ecdf5bf99595ed9317b1670c8de75 (commit)
       via  9d7ea75874077f8a74864cef79b263f24b2bc756 (commit)
       via  840699b4ae892bda2ab4a69beda10f5d63182508 (commit)
       via  7ee96a347e29f3893ca3b0bc4f145349a540fa24 (commit)
       via  b635fa7ef31761f7a3714f3015dce0689d2eed7b (commit)
       via  50fec109c12cdbd996f5f9067f118c689fc53c3d (commit)
       via  04d981a71ac5920c5abc86ebcf42d2deea8392aa (commit)
       via  4ae28b7c3e19c8f825439820d3198209fd559d1f (commit)
       via  a08fd5729ba1dcecc9c505ea59e196dcac67bb74 (commit)
       via  fc395a34a1db25420664aefb5a79ad60aac9332b (commit)
       via  5e6679d8b443d30f74163ad3b9c1ae8a55e7fead (commit)
       via  a3a8f52c6b3a79f38c3a0901927f7fea6f8d6753 (commit)
       via  e1ec03e680b2cee8174cee21a6dd1c0ecc619a54 (commit)
       via  ebf0c57dae8b7f097b34a5686b510305c1cf2e0c (commit)
       via  502aca9e6cea1be99ed3a30ed511bc49cd189160 (commit)
       via  d288d74d07b7e3806cd6da0b61e3e8924fbff280 (commit)
       via  f268312bad8bcb45b1e4ea72b893b3e92ca8bb2d (commit)
       via  08b4e2ce0e20fe9cd9dfd5d7344aa2541f6952bf (commit)
       via  0636d1545941e12daa16a7896eb2b011f1a560ce (commit)
       via  3c7d135c84df375f02b7e137ad03e4c932d1efe9 (commit)
       via  4561b24adc92097e543c446dfa34481d74555e0d (commit)
       via  08abfe1c7005f43806dd8c5ddaa0c9b0d159c514 (commit)
       via  fdfecb87d722c45c24ed7d65df723a2c2ae4105b (commit)
       via  4b5532b15a82d2c8cbbdbd767409479454d6c55d (commit)
       via  dec674fb07ff23a700831898c8b7617f9f0b881b (commit)
       via  578b89ae981bc79131bb93fe87d1d042b430084e (commit)
       via  392eadeb998f093ff87400db8951777c65ae9667 (commit)
       via  a0766a3e7a89d34709cae64740d3f5d88f58f817 (commit)
       via  673e5b589679eb38a878e8b2e90cebf879f400b1 (commit)
       via  8bb89400cf4c81cb871cfcda4054a598532821de (commit)
       via  d4a815a6cafd93d26b4a60f0528b8dd020d4b344 (commit)
       via  443bf806caa11990f6794eb45ac8350f0cbadb1a (commit)
       via  0eadb44e6b30ec2b513b0dcc7287c044c3254545 (commit)
       via  be20fd77f6043d14844448f7921cdbc4e39a85a2 (commit)
       via  93bdd331a6e462e13fbe5b2d75ef0ba6b45ff66e (commit)
       via  9600cdc2309450cd862c83a285087743913a912a (commit)
       via  0e05bf6d0684034bcae23684b0cd6905c9043f41 (commit)
       via  de845594cf69932c20556c7d9b79a265ff0e49cb (commit)
       via  306f82d546f58d8036312034a74fe70b07fe04b2 (commit)
       via  5be95d5b672b66b00588803383c4940fc195758b (commit)
       via  966071e1f89c59080059fcdb7562f3048a04dcee (commit)
       via  a60b199e887428be8956823c47b01ae63183f8b0 (commit)
       via  e131cc92c9b3564732ed9086f420783527769a7e (commit)
       via  5bffb6bfb58c72e67e040cf057e9ccfcee2e2d24 (commit)
       via  38f12692370ccc0e4a7a659eb6d46f2bff4ed251 (commit)
       via  53c21ebab07b80a0c395f40c574a50710c950850 (commit)
       via  7983a5eb26bb783b2990d38b9e1a55307d4ee387 (commit)
       via  3ab3fc38040e3990dbf58445e50d46291d794d30 (commit)
       via  6d499cd874428a7c2e5bac94ef631e6fdb8e041f (commit)
       via  6cc3de26a90a2a2fbcaf372b90e2fef918b16a65 (commit)
       via  4485fb950fa8bd8f3387d2dc0ba6d5d298028ea7 (commit)
       via  5795c0dcd7fc880807e9f7e60a1267b9ec2c05d5 (commit)
       via  23d57b8dca18dd48e1a28284ed8d2b53a5f02b04 (commit)
       via  7474b95fa770e2d735fabb5e99fb5bf90e26d589 (commit)
       via  0db340823d8501d3fd84e3f6742ee067c98f4426 (commit)
       via  ec5850c1003fc26727308a4c9771cdf0f449ab98 (commit)
       via  c51dd793b285c3bf63e8542e713b11e1f9ee5e07 (commit)
       via  99e5c8cef1bb87a45a103972092e6eb7b2aa21cc (commit)
       via  0bd785752432d4b665e0799cdc619d35eac0d114 (commit)
       via  b1fcbdde0119dfc45479ab554fabeb74794b65a4 (commit)
       via  d8de0e11bb0c895167b79bb1f5830befc3582424 (commit)
       via  5d6dd6a23b56bdd8c41432c8e0c1d6903cab6d93 (commit)
       via  cac3278a0db79c001b522caf3e6336f75f1db888 (commit)
       via  63cf7e888a2f26e80dc528e017a971adbe3b9e9c (commit)
       via  c75caa7661d698f39dc6d916511ef2294c2b66d1 (commit)
       via  7d05694bb7cbb315e2ddd08e2a8c9d4ec8290459 (commit)
       via  76d151df0038392b08d309187eeb8b2c83ec984f (commit)
       via  74d156c465146515123295ba6b019f634cf3c15f (commit)
       via  768a1963d538ad944c2fb9b971d625912f0d3147 (commit)
       via  988f43b0a3e23eb2137a36c89aaf7614a887942c (commit)
       via  bb40591e37c7e3a8ca6bcfc5c10c07212671eed7 (commit)
       via  ad7f3783d95f3b51925098fa86cfb175d2cf0e8c (commit)
       via  88d8a7ac54812fdd373a1c806b35be46159c96f2 (commit)
       via  fa048ba6908dbed75d43a10d26d43d1e610fc23c (commit)
       via  040de16ddaaa72d9e4c91455ff9e9360c8ba4dff (commit)
       via  242e717a864030f3466d024b4ddc6ffcbba9f7bd (commit)
       via  b712bbca0519df5b57de07814500273777ff1e1e (commit)
       via  a9d0e75a7add2b9f292d8f918181e5522c0a9636 (commit)
       via  881d694d7299ea30671c6aba63a78306000d2340 (commit)
       via  a4e70e1d26fd7fc987763fa55c177dfd13774655 (commit)
       via  767b47c98486ede93f96ffdc47fab3e0b2bc1ddc (commit)
       via  ce9fdac7400cfd5a2cb4b79451ba5338fea5d376 (commit)
       via  a16bc9d786f989d4d0e6e41a565cba3cab3eae21 (commit)
       via  59624bae85dc46fe708b54df5d0426bb8f9fac27 (commit)
       via  8eca4b387ffbb4b4528fc40ecfa01a29e3ccef67 (commit)
       via  bf16b55d684af57b4166e1430c8433e604364e36 (commit)
       via  fca850bf219ef01bdb2384ef75f23a1f6d91da7d (commit)
       via  0f92bd45859c53be37c6577672a71e6e2be393aa (commit)
       via  2737502b61e77a62db689b2061d17bc511a53f0f (commit)
       via  6e25bf1d05bbe152339370b88e5b12874c952592 (commit)
       via  e1b0eef56c88244bcda24cd0d73b4552acfe571f (commit)
       via  ac4386c2ab18cf03a34cbb751480d35fc6b1e98c (commit)
       via  95370bf1f655c2ba079f256644687c291313e40e (commit)
       via  82457ad3d8e016c36820188b9e63ae012bc81751 (commit)
       via  ce9a31d814e4d3b8eef27cb71b1604fa0ac8db15 (commit)
       via  dc11ae773f4d1c98804395ee01afb60191c5b0d2 (commit)
       via  7d80f77e65dc5336de22950206cefbfec1231de9 (commit)
       via  f55c22c482984bf3b9830d096e40c3f26fb68e79 (commit)
       via  1e3941dfed4508dcdd5de44073d99704e6e9049d (commit)
       via  96a111ccf74dcc1fe07d60b72c135d5c481d7ce3 (commit)
       via  edf2380390f187cdbb66c70c2fbc2f2ad2f05164 (commit)
       via  9873225ff2e8581900e9d5bcceff5cb4ad9f46c5 (commit)
       via  cc53921a8b4283781acaf110d6f6c83436ad48b4 (commit)
       via  b0ee8921ec74149217222884a25b2cbe22c63aa0 (commit)
       via  a9e63e001705bfea51dc4cd802c2accf72496a17 (commit)
       via  6150e6c3d894d351fe31f5b232840628c736e69c (commit)
       via  1757ce8b1e1b128e67f80eaf6d0cade20d80479b (commit)
       via  0218f024584170a58c00ad711034ca1bddd088ed (commit)
       via  d4610a3ac21d3a6b3b8c232317bc99d8785b2ac1 (commit)
       via  fe36a6905d9f586f079142f9f0d26c8ae0982aa0 (commit)
       via  370ac9d4b7b8274baec9549aea7ae0baacbd2316 (commit)
       via  5eb685439ee2a3edd7330121955f69f9412250d6 (commit)
       via  7199e8c90a1e62e7f5837d771ca25aa9d7226835 (commit)
       via  ad26769b1fcd491f47c694cec1e7a6ebdcb94c56 (commit)
       via  fd7cb354d1c9326ba09bf44592f0c244a5e44519 (commit)
       via  1408c1854024d9bbd05784aec653d9ce72397999 (commit)
      from  d50c17928e1bb801fc0716dae19ba7a69974244b (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit b3da28b7027458ad7aae36de9e85874ef6282003
Author: Thorsten Glaser <tg at mirbsd.org>
Date:   Fri Jun 13 14:16:43 2014 +0200

    very rudimentary GPX loading (plain and zipped), not parsing yet

commit 863eecc372e5b1c6bea8d8b8c8a82fed5a7e46de
Merge: 83ad267 4c93974
Author: Thorsten Glaser <tg at mirbsd.org>
Date:   Fri Jun 13 14:16:22 2014 +0200

    Merge remote-tracking branch 'zipjs/master' as subtree
    
    git://github.com/gildas-lormeau/zip.js

commit 83ad2670ce91be3a1f70c83b79a90517164bd919
Author: Thorsten Glaser <tg at mirbsd.org>
Date:   Fri Jun 13 12:37:28 2014 +0200

    initial menu

commit 4c93974e90e8bf9405bc72e139436325f2caf954
Merge: 595393b ce88e6a
Author: gildas-lormeau <gildas.lormeau at gmail.com>
Date:   Thu Apr 4 07:38:33 2013 -0700

    Merge pull request #43 from Rob--W/master
    
    Case-insentivity for MIME-type mapping

commit ce88e6aeb3e1b2432f8647c17f220f025c8f7661
Author: Rob Wu <gwnRob at gmail.com>
Date:   Thu Apr 4 16:25:13 2013 +0200

    Case-insentivity for MIME-type mapping

commit 595393b09bf8096fe5b69ce94cb51b09f8619e85
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sun Mar 17 02:56:55 2013 +0100

    fixed issue when using FileWriter

commit a46c00b5db15ea929177c3153d3faf008b398b47
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sun Mar 17 02:48:36 2013 +0100

    minor fix

commit 26b27d4cf044f7be0398a06a8419e62e41aeb2bb
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sun Mar 17 02:41:40 2013 +0100

    added constants

commit 647175074b2293968016b98f92b42ea6384f1cc5
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sun Mar 17 02:34:41 2013 +0100

    removed Array#forEach calls

commit e9a4ea5be69762f4177fbed8b0a89b1f4bb15506
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sun Mar 17 02:25:05 2013 +0100

    fixed minor issue about file names

commit 731c61c4f52e083bc9aa9ebe9c1951de47131044
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sun Mar 17 02:22:15 2013 +0100

    simplified error callback call

commit c89853b38473bed9ac3eb4c8dba9258024ec25d2
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sun Mar 17 02:20:35 2013 +0100

    don't throw exception when adding duplicated filename in a zip file

commit aa740a3fe9932109e93732cd031b2a99a7bbc0e0
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sun Mar 17 02:12:46 2013 +0100

    moved FileWriter into zip-ext.js

commit 9cbeaeccc2194e6297fa13997ec203883c4f59c1
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sun Mar 17 01:50:50 2013 +0100

    fixed zip-fs.js (zip-ext.js is now optional)

commit 25daed2c31529c297d43b0b3a78b4f41b2e4f56e
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sun Mar 17 01:16:00 2013 +0100

    moved ArrayBufferReader and ArrayBufferWriter in zip-ext.js

commit 5080ef7b1bcbe7a1442bf7624db9e0da5603058d
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sun Mar 17 01:04:16 2013 +0100

    updated license year

commit 333e3faebd521ca5bf3a2ac869cab2b4d54664c9
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sun Mar 17 00:56:52 2013 +0100

    moved ERR_HTTP_RANGE var

commit 591c1ffe1b1de0eb56d11b970b5e6b46f2fffd04
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sun Mar 17 00:50:31 2013 +0100

    moved HttpReader and HttpRangeReader into the new optional zip-ext.js
    file

commit 6bbd666b61f18fa0e981e4a5b4fa3ecc985aca38
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sat Mar 16 00:40:12 2013 +0100

    fixed jshint warnings

commit 0c11ec6a2c18cbc2c2fb13c58e905bfea7e998d8
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sat Mar 16 00:34:31 2013 +0100

    removed irrelevant code

commit c32fc310d17c6edbf89b866622527459ec52d6d7
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Mon Mar 11 20:47:44 2013 +0100

    stupid commit

commit cff4d4f94ba7667812ed3016ef617611777d5528
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Tue Mar 5 16:09:58 2013 +0100

    Fixed issue #39 : added optional encoding parameter to zip.TextWriter.

commit e5d10d8fc84d2221eda59139de1e3f32a9993946
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Tue Mar 5 16:01:28 2013 +0100

    fixed issue #40 (thanks to @Jacob-Christian-Munch-Andersen)

commit a30a60307c6dc9e9f6b0965cf915e75c99bbb364
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sun Feb 24 20:55:37 2013 +0100

    added missing parameter

commit 75e8b36b46e5d450f803128ec7a0b1c10091344b
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sat Feb 23 17:53:02 2013 +0100

    fixed issue #29

commit 33d86dbc1508ac217ebd9895732619872d893b23
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Fri Feb 8 01:43:08 2013 +0100

    removed obsolete hack

commit 301dc930e04ea800353a158fbb2c054a275cfb95
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Fri Feb 8 01:35:33 2013 +0100

    simplified code

commit 1fcafe6c2a680deff01eca890b8371f0315ced7b
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Thu Feb 7 21:50:30 2013 +0100

    fixed issue with IE10

commit ba165115cf348eea00e9d19f93c1faca57c81548
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Thu Feb 7 21:06:18 2013 +0100

    formatted code

commit 956b9885bea830c37a7713c1ef637242ffbd0e61
Author: Dāvis <davispuh at gmail.com>
Date:   Wed Jan 30 18:33:25 2013 +0200

    Replace BlobBuilder with Blob constructor

commit e5bc8cf2a401142652881e18e57ba9877c6133ad
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Thu Feb 7 20:40:30 2013 +0100

    fixed missing variable declarations

commit 3d3c6fcbf338221f5753e4923e16edb9e902f3ac
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Tue Jan 29 22:37:29 2013 +0100

    ZInputStream.read method return sometimes zero instead
    of -1 at the end of stream.

commit b428c0d534eae9583fb6e70f98d323e5deb9c79a
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Thu Nov 15 23:33:22 2012 +0100

    fixed issue when an empty filename is given to zip.getMimeType

commit e4aabedea80a9059de3054ce09cd5fa39f73d8ce
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Mon Nov 12 22:14:15 2012 +0100

    linted code #2

commit f4b6ffbe0b1a503730e9a5b20eda287812b9df87
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Mon Nov 12 22:09:17 2012 +0100

    linted code

commit 981e2ae5051745fae0bdd689a32e3fa9e39c3aea
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Tue Oct 30 00:28:34 2012 +0100

    fixed test

commit 0d247c95396e7686652a35b6d04b1fbb5cbdf670
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Mon Oct 29 23:43:20 2012 +0100

    added ArrayBufferReader/ArrayBufferWriter example

commit 7e8fc2bfd4a68e9528566fdc85758cf5155528b9
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Mon Oct 29 23:21:51 2012 +0100

    added missing parameter

commit 272ede16ac2f231dc8193452136db1e45b3b48c9
Merge: eea42f1 bc7be19
Author: gildas-lormeau <gildas.lormeau at gmail.com>
Date:   Mon Oct 29 14:54:11 2012 -0700

    Merge pull request #23 from Renanse/master
    
    Handling non-zero length comments

commit bc7be190f0e640008e0f04a5ed588540960fde8c
Author: Joshua Slack <renanse at gmail.com>
Date:   Tue Oct 16 13:12:52 2012 -0500

    Updated to handle zip files with non-zero length comments.
    
    The "End of central directory record" is only 22 bytes from the end if the comment length is 0.  This change handles situations where that is not the case.

commit eea42f11e3f78d4121455303b0759e57fb37fbf0
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Wed Sep 19 01:55:51 2012 +0200

    fixed issue #19

commit b3b75b13400c66be3eed75861f8403c881c350ea
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Wed Sep 19 01:43:25 2012 +0200

    fixed issue 19

commit bb09d7213b5456bc29ce72889326eb8acf685ea5
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sun Sep 16 01:56:32 2012 +0200

    added mime types

commit b723700bdae482e3f209fab535e96f9c452fc40d
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sat Sep 15 21:17:48 2012 +0200

    added default zip.getMimeType function used in getFileEntry function

commit d87cfb0664a95ac092bf43e2d80d706a5e5e318b
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sat Sep 15 20:58:26 2012 +0200

    added jshint validation

commit 81dd134d80ed3050acf403c762d8c73bb490ea6d
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sat Sep 15 02:32:14 2012 +0200

    formatted code

commit ebb2216232c0d28a6e0322f97f30a5ce979930b4
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sat Sep 15 02:27:46 2012 +0200

    fixed regression

commit 20f50339f621980a4457643568dfd9ebba6016e4
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sat Sep 15 01:44:22 2012 +0200

    added missing file

commit e1c195f01ceaa71cd59b2b33f021a2e84415f6f4
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sat Sep 15 01:28:10 2012 +0200

    added zip.getMimeType() use

commit cd653ffbc5503c9f7929c9ff20bdbc02f467dda3
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sat Sep 15 01:24:31 2012 +0200

    added mime type parameters

commit 48dc2439855775610399823fd7ca20fddffac761
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sat Sep 15 01:17:16 2012 +0200

    removed BlobBuilder use from tests

commit e26da42b8e024fa393ede06cd47a0a2cff8b93dd
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sat Sep 15 00:59:38 2012 +0200

    removed obsolete onerror parameter

commit 0b9acf53f4ca6cda071ea89cd80e613661bc0508
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sat Sep 15 00:47:51 2012 +0200

    added optional mime-type.js

commit 80f59c74baede4020da7be2eeb7fc5be388b934b
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sat Sep 15 00:26:22 2012 +0200

    removed global object reference

commit b86e51d1accc9929b6326bc8ef46b5a764109f01
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Thu Sep 13 02:07:19 2012 +0200

    added mimeType parameter in ZipFileEntry.prototype.getBlob

commit 6260f0d5a06820984ae3e22628083f43f24a4162
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Thu Sep 13 00:32:40 2012 +0200

    fixed issue #17

commit 401ff262f07357d95777df61c947de949299beed
Author: gildas-lormeau <gildas.lormeau at gmail.com>
Date:   Mon Aug 20 12:37:57 2012 +0300

    Update WebContent/zip.js
    
    removed not-working test

commit 88fef8373f65beba9c4c136eb65b066ffe472468
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sun Aug 19 13:18:29 2012 +0200

    Added info about license (issue #10)

commit 1f910f2e853d60e9aafbf694b82e1f63c0662f63
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sun Aug 19 12:45:26 2012 +0200

    fixed issue #14

commit cd6243e0144a8799063a0f12881ec28fe6232529
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sun Aug 19 12:01:41 2012 +0200

    fixed minor issue with onprogress parameter values

commit 24079d6249fb04cc250563a6413a1a2cb281385b
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Tue Jun 5 21:56:06 2012 +0200

    use unicode notation for ASCII extended table

commit 96011fc9cc3a8e672949a3283284e70154cba445
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Tue Apr 10 23:05:27 2012 +0200

    fixed some issues with objects content type

commit 6f6407580d1c21d78d4afd49884b7d9fa5f93923
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Wed Mar 14 23:25:33 2012 +0100

    fixed a bug with pending bytes in Data64URIWriter

commit fb2c63fb5ac8393d4e0f5f97ecbe68a6d1d46457
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sun Mar 11 23:26:58 2012 +0100

    moved crc32Table into Crc32 prototype

commit 05048682aa23d8c593a35b814e926bd583ebbe94
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sun Mar 11 23:10:13 2012 +0100

    removed obsolete code

commit f5b4df8cae80ffe95013eb297d593140f8ce3669
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sat Mar 10 23:40:39 2012 +0100

    added URL source code

commit 234504b25cfae973aa6f4ea5ca9503ad9c1051f6
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sat Mar 10 23:33:42 2012 +0100

    removed unneeded script (dataview.js)

commit 3cc3c2732f0b9e3aa635a1680e1736c1b9dd3ff9
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Thu Mar 8 22:26:26 2012 +0100

    make the demo compatible with IE9, Firefox, Chrome, and Safari

commit 2fb658f8d42dfdcf37ea11b450d4adbcde56b1c9
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Thu Mar 8 01:35:43 2012 +0100

    set zipped data URI mime type from "text/plain" to "application/zip"

commit e07693b01243547344cd76a8bc59b45d1cc19112
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Thu Mar 8 01:34:17 2012 +0100

    bad crc32 fixed

commit bf614462b9af54fb585dc14a9c7f728698a281e9
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Thu Mar 8 01:26:29 2012 +0100

    minor fixes

commit 62fd2368525a513259d7d8576cd81811decaafcf
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Thu Mar 8 01:18:13 2012 +0100

    fixed variable/parameter/function names

commit 609ca2595c1d008640b0cf79e80c5b8bb9c642b0
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Thu Mar 8 01:15:24 2012 +0100

    removed obsolete code

commit c68f030686bb11c25d2366b8a1fda17103daaa41
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Thu Mar 8 01:10:14 2012 +0100

    Demo without web workers and using DataURIReader/DataURIWriter

commit eb349c693e56888d9c8421dff9a343042e2dd31c
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Thu Mar 8 00:50:40 2012 +0100

    added a test for zip.useWebWorkers

commit 781e5bffbdb22447ba10bd5c40603281470046b3
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Thu Mar 8 00:48:19 2012 +0100

    added zip.useWebWorkers attribute: if zip.useWebWorkers = false then zip.js will not use web workers to inflate/deflate data

commit 0b347faa8e598cbcff1a8de568b1e1661e3b53db
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Thu Mar 8 00:45:05 2012 +0100

    if the script detects window.zip object then it adds the Deflater/Inflater constructor into window.zip else it adds the message event listener

commit 7350b97ed00a520d7a44556a15d6330c0262bcf1
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Tue Mar 6 22:12:29 2012 +0100

    added checkCrc32 parameter to ZipEntry.prototype.getFileEntry

commit d53e0a41fd3500c002b0368078d3c828d011dc51
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Tue Mar 6 20:00:42 2012 +0100

    fixed MSBlobBuilder typo (IE10 support)

commit e65f08f60c3297fb6191de44ccf2fa5ff6cecbe7
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Tue Mar 6 00:58:07 2012 +0100

    UTF-8 support for TextWriter/TextReader implementation

commit f0a4093822a0347ca20dd36fdc68c71fe33cddf0
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Tue Mar 6 00:20:50 2012 +0100

    removed unneeded test

commit d6356af2cf8e496f567e69a0b0cb4f197a2466cf
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Mon Mar 5 23:24:36 2012 +0100

    enabled crc32 checking test

commit 3042757383fd2e0654ce0aef23f54005bbc68df9
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Mon Mar 5 23:24:00 2012 +0100

    added a checkCrc32 parameter on ZipFileEntryProto.get*

commit 22cb76333da2c0a36c9d9492d92c6027728d33ca
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Mon Mar 5 23:23:36 2012 +0100

    DRYier worker management & added a checkCrc32 parameter on Entry.prototype.getData

commit a63e6dc8d8aa1f87be765bf96281b2dcc910e582
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sun Mar 4 00:34:42 2012 +0100

    refactored imported entries management

commit d09edfd2a7ec617e4520eb36228cb1ba677fa0a6
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sat Mar 3 22:53:24 2012 +0100

    refactored some code

commit a41f4c9d75f1d6547b1b715b385afcad2b774fae
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Fri Mar 2 23:53:51 2012 +0100

    added comment entry support

commit f3603ee5ed6020f70fae1027b94d4cd7606f41a0
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Fri Mar 2 23:38:17 2012 +0100

    fixed possible issue with filename when adding a directory

commit a9490a4d1c64a4c02818d2375ae042a4b44eb831
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Fri Mar 2 23:25:46 2012 +0100

    updated FIXME label

commit caab022620eed11bc3834ff717b383b44e203077
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Fri Mar 2 23:24:59 2012 +0100

    added option to set last modification date

commit faa8f83dc7173c422758517034d68e87f8d0eb66
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Fri Mar 2 23:16:00 2012 +0100

    added comment entry support

commit 983f255fdd89666d6f917a9c82638c786326be73
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Tue Feb 28 21:32:12 2012 +0100

    added missing onerror parameter

commit e917ec43f4dc17dc5ed2167fa59253c3e176b389
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Mon Feb 27 23:22:25 2012 +0100

    set a Reader object (reader property) into each ZipFileEntry object for reuse

commit 61c0c8e046c7c92396199ce58acdbfc8ca614d85
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Mon Feb 27 01:26:11 2012 +0100

    temporary rollback

commit 142d8e87c022d81ce5b0f7ffe2e7798d8658431c
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Mon Feb 27 01:05:36 2012 +0100

    attach reader to child

commit c7e9d098fe1c6ee54dfaac51e3541543ddb3d8e4
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Mon Feb 27 00:59:58 2012 +0100

    added ZipFileEntry and ZipDirectoryEntry constructors

commit 95873cf8d74fdd848aa250082736ae91fb7a3b97
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sun Feb 26 21:17:47 2012 +0100

    added a test

commit f6cff0f9a2d239ce4db2ba7fa19d233d13568158
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sun Feb 26 21:12:50 2012 +0100

    minor fixes

commit ed5c790deffa526360c643acd3c41e716d9189ff
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sun Feb 26 20:49:15 2012 +0100

    added some tests

commit dc86eda4e5064da30eb20c11bdf64f92f20b42a6
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sun Feb 26 20:44:10 2012 +0100

    fixed issue in addFileEntry function when passing a FileEntry object

commit 8564a16a11e7e1448fcf92f98d16b87bc4e5a7b9
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sun Feb 26 20:16:26 2012 +0100

    minor fix

commit b6d27e13730bd01caabe6b2c4b809ee44d7515dd
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sun Feb 26 20:10:36 2012 +0100

    fixed issue with currentIndex into getFileEntry and exportZip

commit f6717a11d5f03563ba44164f7f4347dcbfe68996
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sun Feb 26 19:40:51 2012 +0100

    - renamed ZipEntry.prototype.getFile to ZipEntry.prototype.getFileEntry
    - ZipEntry.prototype.getFileEntry allows getting all files recursively from a ZipEntry object into a FileEntry object
    - added ZipEntry.prototype.addFileEntry to add a all files recursively from a FileEntry object into a ZipEntry object

commit 25f5e6af8859bf19a3aa40dd8c2d5bba8f32cf73
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sun Feb 26 19:24:08 2012 +0100

    added constructor attribute in the prototype of *Reader and *Writer functions

commit 63ac7584ad0636c3810b45acc302af8f7d79fa33
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sat Feb 25 01:15:01 2012 +0100

    expose Reader and Writer constructors

commit 62e614702e1ebf7cb5417206eb4503af0e160129
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Fri Feb 24 20:17:41 2012 +0100

    rollback

commit fb677d8fda1381599731c84845504c68da2946d9
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Wed Feb 22 22:08:19 2012 +0100

    issue #6 fixed: changed default zip version from 1.0 to 2.0 (zip.js uses "Data descriptor")

commit 11cca65d7fdf6f1c355b2b148335d8d76b00a010
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Wed Feb 22 00:15:54 2012 +0100

    removed directory entry creation from exportZip function

commit dae44b666f423a3e7226ea2ca62a36cae9be5743
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sun Feb 19 23:24:25 2012 +0100

    fixed minor regression

commit 1b0fe8c7a52ac8a74a914e5fbdce335a59432491
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sun Feb 19 23:10:01 2012 +0100

    added zipVersion attribute to ZipEntry to force zip version

commit 4dac7a97a1db657285de80e03b48fcd9d9ce8677
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sun Feb 19 23:00:27 2012 +0100

    invalid data descriptor header fixed

commit fd04a1c19b476582a933e2c9b771a056420b13f8
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Fri Feb 17 00:10:09 2012 +0100

    removed obsolete code

commit 9cf99b6b5ee62d740e154bfd4013640ac7960af1
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Thu Feb 16 01:11:41 2012 +0100

    fixed issue #5

commit 260ded4e5ff1294e89f669c876b57c8d52e005a4
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sun Feb 12 01:56:01 2012 +0100

    updated dataview.js

commit f93037957b59be8da27e029161af71ac870ebf82
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Wed Feb 8 00:21:19 2012 +0100

    removed unused error messages

commit 59f9f69da1ea1ee4d6a8d944c10d348be9d03512
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Wed Feb 8 00:04:29 2012 +0100

    minor optimizations for obfuscation

commit 948734f98ab77d82c09aec35914d957d3b8132ba
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Tue Feb 7 23:17:39 2012 +0100

    fixed issue when copying uncompressed data

commit c19672fc4efe58839acb323481f8fbec326f046d
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Tue Feb 7 22:57:10 2012 +0100

    fixed support for level compression when zipping

commit 687e7cbc46485d43072d8a655214d01336abe541
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Tue Feb 7 01:17:57 2012 +0100

    added support for future IE

commit 2e4c8462c6b2c18bd9973fede1599e5bec370db8
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Tue Feb 7 01:16:17 2012 +0100

    extracted worker script names

commit d649b50bd0572ef7c624c93d58e86b294b8f0747
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Tue Feb 7 01:08:34 2012 +0100

    removed useless function params

commit c25498e4743bececf73c01518c026f1666547d24
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Tue Feb 7 00:49:27 2012 +0100

    added bufferedCopy function into Entry.prototype.getData function

commit ecb4e50d574bf685b8fd416d48f511819497ef9c
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Mon Feb 6 21:30:59 2012 +0100

    removed File related constructors

commit b54c00ee26d3fb3f5fbc532efeae1d13d5850b7b
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Mon Feb 6 21:16:26 2012 +0100

    added simple test: read a zip with an uncompressed entry

commit c66b0b8245b58c28e67ac63ce55ee5798b7ba5e2
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Mon Feb 6 21:12:22 2012 +0100

    fixed issue when reading uncompressed file

commit f3b4c06ab9ad98e2865ed894d369b3e09d9c5f0b
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Mon Feb 6 01:22:30 2012 +0100

    fixed issue #4

commit 4985a2594c5ecdf5bf99595ed9317b1670c8de75
Author: muffindespair <github.20.muffindespair at spamgourmet.com>
Date:   Sun Feb 5 17:28:36 2012 -0500

    it seemed to be discarding store-compressed data

commit 9d7ea75874077f8a74864cef79b263f24b2bc756
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sat Feb 4 23:43:26 2012 +0100

    new TextReader implementation

commit 840699b4ae892bda2ab4a69beda10f5d63182508
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sat Feb 4 23:43:07 2012 +0100

    removed extra semicolumn

commit 7ee96a347e29f3893ca3b0bc4f145349a540fa24
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sat Feb 4 22:32:44 2012 +0100

    fixed getTotalSize function (worked correctly only at the first call)

commit b635fa7ef31761f7a3714f3015dce0689d2eed7b
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sat Feb 4 21:31:43 2012 +0100

    fixed issue #3

commit 50fec109c12cdbd996f5f9067f118c689fc53c3d
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Fri Feb 3 01:37:17 2012 +0100

    removed obsolete onprogress parameter on import* methods

commit 04d981a71ac5920c5abc86ebcf42d2deea8392aa
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Fri Feb 3 01:19:25 2012 +0100

    removed obselete parameter for InfBlocks constructor

commit 4ae28b7c3e19c8f825439820d3198209fd559d1f
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Fri Feb 3 01:15:58 2012 +0100

    removed obsolete code

commit a08fd5729ba1dcecc9c505ea59e196dcac67bb74
Author: check_ca <gildas.lormeau at gmail.com>
Date:   Thu Feb 2 19:50:26 2012 +0100

    rollback, the right var name is "workerScriptsPath" (everywhere ...)

commit fc395a34a1db25420664aefb5a79ad60aac9332b
Merge: a3a8f52 5e6679d
Author: check_ca <gildas.lormeau at gmail.com>
Date:   Thu Feb 2 09:37:03 2012 -0800

    Merge pull request #2 from spacemunkay/master
    
    website should say "workerScriptsPath" instead of "workersScriptPath"

commit 5e6679d8b443d30f74163ad3b9c1ae8a55e7fead
Author: Jason Denney <jdenney at lgscout.com>
Date:   Thu Feb 2 12:06:21 2012 -0500

    Fixed workerSriptsPath to match website documentation "workersScriptPath"

commit a3a8f52c6b3a79f38c3a0901927f7fea6f8d6753
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Wed Feb 1 00:01:43 2012 +0100

    removed adler32 related code

commit e1ec03e680b2cee8174cee21a6dd1c0ecc619a54
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Tue Jan 31 00:50:58 2012 +0100

    simplified adler32 function (thanks to WebReflection)

commit ebf0c57dae8b7f097b34a5686b510305c1cf2e0c
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Mon Jan 30 22:06:54 2012 +0100

    renamed ERR_WRITE_ZIP to ERR_WRITE

commit 502aca9e6cea1be99ed3a30ed511bc49cd189160
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Mon Jan 30 21:52:16 2012 +0100

    removed size and *Getter parameters from ZipEntry.prototype.add* functions

commit d288d74d07b7e3806cd6da0b61e3e8924fbff280
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Mon Jan 30 21:24:37 2012 +0100

    removed timeouted callbacks

commit f268312bad8bcb45b1e4ea72b893b3e92ca8bb2d
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sun Jan 29 23:40:04 2012 +0100

    data read with HttpReader is now deffered

commit 08b4e2ce0e20fe9cd9dfd5d7344aa2541f6952bf
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sun Jan 29 23:12:23 2012 +0100

    added Reader and Writer constructors

commit 0636d1545941e12daa16a7896eb2b011f1a560ce
Merge: 3c7d135 4561b24
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sun Jan 29 22:35:18 2012 +0100

    Merge remote branch 'origin/master'

commit 3c7d135c84df375f02b7e137ad03e4c932d1efe9
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sun Jan 29 22:26:58 2012 +0100

    new Data64URIReader and Data64URIWriter implementations

commit 4561b24adc92097e543c446dfa34481d74555e0d
Author: check_ca <gildas.lormeau at gmail.com>
Date:   Sun Jan 29 01:12:01 2012 +0100

    fixed typo

commit 08abfe1c7005f43806dd8c5ddaa0c9b0d159c514
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sun Jan 29 01:03:43 2012 +0100

    fixed typo

commit fdfecb87d722c45c24ed7d65df723a2c2ae4105b
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sat Jan 28 22:28:03 2012 +0100

    fixed jshint issues

commit 4b5532b15a82d2c8cbbdbd767409479454d6c55d
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Fri Jan 27 00:19:08 2012 +0100

    moved import and export methods into ZipEntry prototype + new test

commit dec674fb07ff23a700831898c8b7617f9f0b881b
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Thu Jan 26 23:49:43 2012 +0100

    check if entry file is defined when calling data getter

commit 578b89ae981bc79131bb93fe87d1d042b430084e
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Thu Jan 26 23:39:55 2012 +0100

    added missing onprogress parameter on data getters of ZipEntry prototype

commit 392eadeb998f093ff87400db8951777c65ae9667
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Thu Jan 26 22:18:11 2012 +0100

    added data getters in ZipEntry prototype

commit a0766a3e7a89d34709cae64740d3f5d88f58f817
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Thu Jan 26 21:10:28 2012 +0100

    added BSD license

commit 673e5b589679eb38a878e8b2e90cebf879f400b1
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Thu Jan 26 01:03:26 2012 +0100

    minor refactoring

commit 8bb89400cf4c81cb871cfcda4054a598532821de
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Thu Jan 26 00:14:32 2012 +0100

    minor fix

commit d4a815a6cafd93d26b4a60f0528b8dd020d4b344
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Wed Jan 25 23:30:29 2012 +0100

    added "helper" methods

commit 443bf806caa11990f6794eb45ac8350f0cbadb1a
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Wed Jan 25 23:08:25 2012 +0100

    read local file header when extracting data

commit 0eadb44e6b30ec2b513b0dcc7287c044c3254545
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Tue Jan 24 23:38:13 2012 +0100

    better test

commit be20fd77f6043d14844448f7921cdbc4e39a85a2
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Tue Jan 24 23:37:31 2012 +0100

    size parameter is optional for FileData64URI constructor

commit 93bdd331a6e462e13fbe5b2d75ef0ba6b45ff66e
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sun Jan 22 23:02:03 2012 +0100

    compute crc32 after the message is sent to deflate worker

commit 9600cdc2309450cd862c83a285087743913a912a
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sat Jan 21 22:32:46 2012 +0100

    added FileHTTP test

commit 0e05bf6d0684034bcae23684b0cd6905c9043f41
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sat Jan 21 22:31:20 2012 +0100

    added zip.fs.FileHTTP and zip.fs.FileHTTPRange constructors

commit de845594cf69932c20556c7d9b79a265ff0e49cb
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sat Jan 21 21:59:33 2012 +0100

    fixed bug: onprogress currentIndex wasn't correct when exporting zip

commit 306f82d546f58d8036312034a74fe70b07fe04b2
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sat Jan 21 21:58:27 2012 +0100

    added zip example

commit 5be95d5b672b66b00588803383c4940fc195758b
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sat Jan 21 21:37:08 2012 +0100

    added HttpReader test

commit 966071e1f89c59080059fcdb7562f3048a04dcee
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sat Jan 21 21:35:56 2012 +0100

    added HttpReader implementation

commit a60b199e887428be8956823c47b01ae63183f8b0
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sat Jan 21 20:16:01 2012 +0100

    removed optional parameter

commit e131cc92c9b3564732ed9086f420783527769a7e
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sat Jan 21 20:15:36 2012 +0100

    refactored export function

commit 5bffb6bfb58c72e67e040cf057e9ccfcee2e2d24
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sat Jan 21 20:13:58 2012 +0100

    minor fix

commit 38f12692370ccc0e4a7a659eb6d46f2bff4ed251
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Fri Jan 20 22:17:11 2012 +0100

    better fix

commit 53c21ebab07b80a0c395f40c574a50710c950850
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Fri Jan 20 01:27:49 2012 +0100

    workaround with FileDeflated entries export issue

commit 7983a5eb26bb783b2990d38b9e1a55307d4ee387
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Fri Jan 20 00:34:59 2012 +0100

    removed dead code

commit 3ab3fc38040e3990dbf58445e50d46291d794d30
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Fri Jan 20 00:30:32 2012 +0100

    use only data URI Readers/Writers

commit 6d499cd874428a7c2e5bac94ef631e6fdb8e041f
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Fri Jan 20 00:29:35 2012 +0100

    bug fixed in DataURIReader.readBlob and DataURIReader.readUint8Array simplified

commit 6cc3de26a90a2a2fbcaf372b90e2fef918b16a65
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Thu Jan 19 23:26:09 2012 +0100

    added Text I/O support and added FileDeflated constructor

commit 4485fb950fa8bd8f3387d2dc0ba6d5d298028ea7
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Thu Jan 19 02:02:02 2012 +0100

    improved filesystem API

commit 5795c0dcd7fc880807e9f7e60a1267b9ec2c05d5
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Wed Jan 18 01:53:31 2012 +0100

    minor fix

commit 23d57b8dca18dd48e1a28284ed8d2b53a5f02b04
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Wed Jan 18 01:44:09 2012 +0100

    basic test for zip.Data64URIReader and zip.Data64URIWriter

commit 7474b95fa770e2d735fabb5e99fb5bf90e26d589
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Wed Jan 18 01:43:09 2012 +0100

    fixed title

commit 0db340823d8501d3fd84e3f6742ee067c98f4426
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Wed Jan 18 01:42:46 2012 +0100

    added zip.Data64URIReader and zip.Data64URIWriter constructors

commit ec5850c1003fc26727308a4c9771cdf0f449ab98
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Tue Jan 17 23:33:11 2012 +0100

    basic test for filesystem API

commit c51dd793b285c3bf63e8542e713b11e1f9ee5e07
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Tue Jan 17 23:14:00 2012 +0100

    removed unneeded closures

commit 99e5c8cef1bb87a45a103972092e6eb7b2aa21cc
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Tue Jan 17 22:28:23 2012 +0100

    new OO version of filesystem API

commit 0bd785752432d4b665e0799cdc619d35eac0d114
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Tue Jan 17 00:33:21 2012 +0100

    new high level API

commit b1fcbdde0119dfc45479ab554fabeb74794b65a4
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Mon Jan 16 21:46:36 2012 +0100

    yet another fix for directories support!

commit d8de0e11bb0c895167b79bb1f5830befc3582424
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Mon Jan 16 01:34:34 2012 +0100

    ...

commit 5d6dd6a23b56bdd8c41432c8e0c1d6903cab6d93
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Mon Jan 16 01:23:31 2012 +0100

    fixed a bug with header entry reading

commit cac3278a0db79c001b522caf3e6336f75f1db888
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sun Jan 15 22:19:48 2012 +0100

    removed debug code

commit 63cf7e888a2f26e80dc528e017a971adbe3b9e9c
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sun Jan 15 21:57:56 2012 +0100

    added constants for error messages

commit c75caa7661d698f39dc6d916511ef2294c2b66d1
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sun Jan 15 21:38:15 2012 +0100

    added signature check when reading zip entries

commit 7d05694bb7cbb315e2ddd08e2a8c9d4ec8290459
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sun Jan 15 21:36:14 2012 +0100

    minor refactoring

commit 76d151df0038392b08d309187eeb8b2c83ec984f
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sun Jan 15 01:53:07 2012 +0100

    fixed minor issue when writing file entry header

commit 74d156c465146515123295ba6b019f634cf3c15f
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sat Jan 14 23:58:19 2012 +0100

    removed seek method from BlobWriter and FileWriter, added support for folder entries

commit 768a1963d538ad944c2fb9b971d625912f0d3147
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sat Jan 14 23:57:49 2012 +0100

    fixed typo in test pages

commit 988f43b0a3e23eb2137a36c89aaf7614a887942c
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sat Jan 7 23:25:24 2012 +0100

    set zip.workerScriptsPath default value to empty string

commit bb40591e37c7e3a8ca6bcfc5c10c07212671eed7
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sat Jan 7 23:03:58 2012 +0100

    fixed minor scope issue

commit ad7f3783d95f3b51925098fa86cfb175d2cf0e8c
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Fri Jan 6 01:39:00 2012 +0100

    removed unneeded variable

commit 88d8a7ac54812fdd373a1c806b35be46159c96f2
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Fri Jan 6 01:27:59 2012 +0100

    added basic tests

commit fa048ba6908dbed75d43a10d26d43d1e610fc23c
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Fri Jan 6 01:27:17 2012 +0100

    removed WORKER_SCRIPTS_PATH constant, use zip.workerScriptsPath instead

commit 040de16ddaaa72d9e4c91455ff9e9360c8ba4dff
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Fri Jan 6 01:17:42 2012 +0100

    minor refactoring on API

commit 242e717a864030f3466d024b4ddc6ffcbba9f7bd
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Fri Jan 6 01:16:28 2012 +0100

    removed dead code

commit b712bbca0519df5b57de07814500273777ff1e1e
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Thu Oct 6 01:25:35 2011 +0200

    simpler Writer class API in zip.js
    added the onprogress callback called during deflate or inflate
    inflate and deflate produce ArrayBuffers instead of Blobs
    updated adler32 function (unused)
    code refactoring in zip.js to reduce large indentations

commit a9d0e75a7add2b9f292d8f918181e5522c0a9636
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sun Sep 18 22:42:28 2011 +0200

    new API (based on Readers and Writers) and new implementation

commit 881d694d7299ea30671c6aba63a78306000d2340
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Fri Sep 9 23:29:31 2011 +0200

    simpler API

commit a4e70e1d26fd7fc987763fa55c177dfd13774655
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Wed Sep 7 00:02:23 2011 +0200

    bad copy/paste ...

commit 767b47c98486ede93f96ffdc47fab3e0b2bc1ddc
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Tue Sep 6 00:58:48 2011 +0200

    added forgotten support for firefox Blob.mozSlice and future Blob.slice

commit ce9fdac7400cfd5a2cb4b79451ba5338fea5d376
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Tue Sep 6 00:43:28 2011 +0200

    renamed BlobResourceWriter
 to FileResourceWriter
    Uint8Array support for reading/writing file added

commit a16bc9d786f989d4d0e6e41a565cba3cab3eae21
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Tue Sep 6 00:41:38 2011 +0200

    new inflate implementation

commit 59624bae85dc46fe708b54df5d0426bb8f9fac27
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Fri Sep 2 22:03:15 2011 +0200

    extracted ResourceReader/Writer classes

commit 8eca4b387ffbb4b4528fc40ecfa01a29e3ccef67
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Fri Sep 2 22:01:46 2011 +0200

    added global object as parameter for the global closure.

commit bf16b55d684af57b4166e1430c8433e604364e36
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Mon Aug 29 01:15:12 2011 +0200

    removed demo files

commit fca850bf219ef01bdb2384ef75f23a1f6d91da7d
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Mon Aug 29 01:12:14 2011 +0200

    link to project homepage

commit 0f92bd45859c53be37c6577672a71e6e2be393aa
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Mon Aug 29 00:52:49 2011 +0200

    obsolete file

commit 2737502b61e77a62db689b2061d17bc511a53f0f
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sun Aug 28 21:50:45 2011 +0200

    progress bar is displayed next to the file being compressed

commit 6e25bf1d05bbe152339370b88e5b12874c952592
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sun Aug 28 20:34:04 2011 +0200

    better buffer management

commit e1b0eef56c88244bcda24cd0d73b4552acfe571f
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sun Aug 28 18:00:32 2011 +0200

    workaround: create the zip worker for each file to zip since it makes
    chrome to crash with big files

commit ac4386c2ab18cf03a34cbb751480d35fc6b1e98c
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sun Aug 28 01:15:42 2011 +0200

    workaround: inflate.js can't be used more than twice: worker is created
    each time inflate is used

commit 95370bf1f655c2ba079f256644687c291313e40e
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sun Aug 28 00:18:55 2011 +0200

    bug fixed: bad feature test

commit 82457ad3d8e016c36820188b9e63ae012bc81751
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sat Aug 27 23:47:12 2011 +0200

    removed obsolete line of code

commit ce9a31d814e4d3b8eef27cb71b1604fa0ac8db15
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sat Aug 27 23:45:09 2011 +0200

    minor refactoring: moved all variable declarations at the top of
    function
    block

commit dc11ae773f4d1c98804395ee01afb60191c5b0d2
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sat Aug 27 23:31:49 2011 +0200

    removed arraycopy function

commit 7d80f77e65dc5336de22950206cefbfec1231de9
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sat Aug 27 23:19:32 2011 +0200

    removed anonymous function created in a loop

commit f55c22c482984bf3b9830d096e40c3f26fb68e79
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sat Aug 27 23:08:57 2011 +0200

    jshint fixes

commit 1e3941dfed4508dcdd5de44073d99704e6e9049d
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sat Aug 27 22:29:45 2011 +0200

    mozilla support added (not tested)

commit 96a111ccf74dcc1fe07d60b72c135d5c481d7ce3
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sat Aug 27 22:09:50 2011 +0200

    new deflate implementation

commit edf2380390f187cdbb66c70c2fbc2f2ad2f05164
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Tue Aug 23 22:14:54 2011 +0200

    use subarray method instead of creating a new Uint8Array object

commit 9873225ff2e8581900e9d5bcceff5cb4ad9f46c5
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Sun Aug 21 01:27:00 2011 +0200

    use Blob objects to add or read files

commit cc53921a8b4283781acaf110d6f6c83436ad48b4
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Tue Aug 16 01:01:28 2011 +0200

    new web demo without css

commit b0ee8921ec74149217222884a25b2cbe22c63aa0
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Mon Aug 15 21:03:29 2011 +0200

    bad copy/paste

commit a9e63e001705bfea51dc4cd802c2accf72496a17
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Mon Aug 15 20:29:55 2011 +0200

    added an accept parameter on file input

commit 6150e6c3d894d351fe31f5b232840628c736e69c
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Mon Aug 15 20:29:11 2011 +0200

    updated README

commit 1757ce8b1e1b128e67f80eaf6d0cade20d80479b
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Mon Aug 15 20:27:12 2011 +0200

    added a close method into the zip reader object

commit 0218f024584170a58c00ad711034ca1bddd088ed
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Mon Aug 15 17:35:19 2011 +0200

    better usage of DataView methods

commit d4610a3ac21d3a6b3b8c232317bc99d8785b2ac1
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Mon Aug 15 01:31:16 2011 +0200

    typo fixed

commit fe36a6905d9f586f079142f9f0d26c8ae0982aa0
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Mon Aug 15 01:29:43 2011 +0200

    README updated

commit 370ac9d4b7b8274baec9549aea7ae0baacbd2316
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Mon Aug 15 00:57:46 2011 +0200

    header comments updated

commit 5eb685439ee2a3edd7330121955f69f9412250d6
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Mon Aug 15 00:50:10 2011 +0200

    manifest updated

commit 7199e8c90a1e62e7f5837d771ca25aa9d7226835
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Mon Aug 15 00:29:31 2011 +0200

    remove obsolete comments

commit ad26769b1fcd491f47c694cec1e7a6ebdcb94c56
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Mon Aug 15 00:27:19 2011 +0200

    add HOWTO section

commit fd7cb354d1c9326ba09bf44592f0c244a5e44519
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Mon Aug 15 00:11:10 2011 +0200

    add README

commit 1408c1854024d9bbd05784aec653d9ce72397999
Author: Gildas Lormeau <gildas.lormeau at gmail.com>
Date:   Mon Aug 15 00:02:32 2011 +0200

    first commit

-----------------------------------------------------------------------

Summary of changes:
 index.htm                               |    4 +
 mirkarte.js                             |  107 +-
 zip.js/.project                         |   34 +
 zip.js/README                           |    4 +
 zip.js/WebContent/deflate.js            | 2088 +++++++++++++++++++++++++++++
 zip.js/WebContent/inflate.js            | 2163 +++++++++++++++++++++++++++++++
 zip.js/WebContent/mime-types.js         | 1001 ++++++++++++++
 zip.js/WebContent/tests/arraybuffer.js  |  760 +++++++++++
 zip.js/WebContent/tests/base64.js       |   58 +
 zip.js/WebContent/tests/dataview.js     |  212 +++
 zip.js/WebContent/tests/lorem.txt       |    1 +
 zip.js/WebContent/tests/lorem.zip       |  Bin 0 -> 739 bytes
 zip.js/WebContent/tests/lorem2.zip      |  Bin 0 -> 1023 bytes
 zip.js/WebContent/tests/lorem_store.zip |  Bin 0 -> 1278 bytes
 zip.js/WebContent/tests/test1.html      |   13 +
 zip.js/WebContent/tests/test1.js        |   46 +
 zip.js/WebContent/tests/test10.html     |   14 +
 zip.js/WebContent/tests/test10.js       |   34 +
 zip.js/WebContent/tests/test11.html     |   14 +
 zip.js/WebContent/tests/test11.js       |   67 +
 zip.js/WebContent/tests/test12.html     |   14 +
 zip.js/WebContent/tests/test12.js       |   66 +
 zip.js/WebContent/tests/test13.html     |   13 +
 zip.js/WebContent/tests/test13.js       |   74 ++
 zip.js/WebContent/tests/test14.html     |   13 +
 zip.js/WebContent/tests/test14.js       |   80 ++
 zip.js/WebContent/tests/test15.html     |   12 +
 zip.js/WebContent/tests/test15.js       |   60 +
 zip.js/WebContent/tests/test16.html     |   14 +
 zip.js/WebContent/tests/test16.js       |   46 +
 zip.js/WebContent/tests/test17.html     |   15 +
 zip.js/WebContent/tests/test17.js       |   41 +
 zip.js/WebContent/tests/test18.html     |   16 +
 zip.js/WebContent/tests/test18.js       |   46 +
 zip.js/WebContent/tests/test2.html      |   14 +
 zip.js/WebContent/tests/test2.js        |   49 +
 zip.js/WebContent/tests/test3.html      |   14 +
 zip.js/WebContent/tests/test3.js        |   40 +
 zip.js/WebContent/tests/test4.html      |   12 +
 zip.js/WebContent/tests/test4.js        |   40 +
 zip.js/WebContent/tests/test5.html      |   13 +
 zip.js/WebContent/tests/test5.js        |   33 +
 zip.js/WebContent/tests/test6.html      |   13 +
 zip.js/WebContent/tests/test6.js        |   33 +
 zip.js/WebContent/tests/test7.html      |   14 +
 zip.js/WebContent/tests/test7.js        |   18 +
 zip.js/WebContent/tests/test8.html      |   14 +
 zip.js/WebContent/tests/test8.js        |   31 +
 zip.js/WebContent/tests/test9.html      |   14 +
 zip.js/WebContent/tests/test9.js        |   34 +
 zip.js/WebContent/tests/util.js         |   16 +
 zip.js/WebContent/zip-ext.js            |  241 ++++
 zip.js/WebContent/zip-fs.js             |  538 ++++++++
 zip.js/WebContent/zip.js                |  801 ++++++++++++
 54 files changed, 9109 insertions(+), 3 deletions(-)
 create mode 100644 zip.js/.project
 create mode 100644 zip.js/README
 create mode 100644 zip.js/WebContent/deflate.js
 create mode 100644 zip.js/WebContent/inflate.js
 create mode 100644 zip.js/WebContent/mime-types.js
 create mode 100644 zip.js/WebContent/tests/arraybuffer.js
 create mode 100644 zip.js/WebContent/tests/base64.js
 create mode 100644 zip.js/WebContent/tests/dataview.js
 create mode 100644 zip.js/WebContent/tests/lorem.txt
 create mode 100644 zip.js/WebContent/tests/lorem.zip
 create mode 100644 zip.js/WebContent/tests/lorem2.zip
 create mode 100644 zip.js/WebContent/tests/lorem_store.zip
 create mode 100644 zip.js/WebContent/tests/test1.html
 create mode 100644 zip.js/WebContent/tests/test1.js
 create mode 100644 zip.js/WebContent/tests/test10.html
 create mode 100644 zip.js/WebContent/tests/test10.js
 create mode 100644 zip.js/WebContent/tests/test11.html
 create mode 100644 zip.js/WebContent/tests/test11.js
 create mode 100644 zip.js/WebContent/tests/test12.html
 create mode 100644 zip.js/WebContent/tests/test12.js
 create mode 100644 zip.js/WebContent/tests/test13.html
 create mode 100644 zip.js/WebContent/tests/test13.js
 create mode 100644 zip.js/WebContent/tests/test14.html
 create mode 100644 zip.js/WebContent/tests/test14.js
 create mode 100644 zip.js/WebContent/tests/test15.html
 create mode 100644 zip.js/WebContent/tests/test15.js
 create mode 100644 zip.js/WebContent/tests/test16.html
 create mode 100644 zip.js/WebContent/tests/test16.js
 create mode 100644 zip.js/WebContent/tests/test17.html
 create mode 100644 zip.js/WebContent/tests/test17.js
 create mode 100644 zip.js/WebContent/tests/test18.html
 create mode 100644 zip.js/WebContent/tests/test18.js
 create mode 100644 zip.js/WebContent/tests/test2.html
 create mode 100644 zip.js/WebContent/tests/test2.js
 create mode 100644 zip.js/WebContent/tests/test3.html
 create mode 100644 zip.js/WebContent/tests/test3.js
 create mode 100644 zip.js/WebContent/tests/test4.html
 create mode 100644 zip.js/WebContent/tests/test4.js
 create mode 100644 zip.js/WebContent/tests/test5.html
 create mode 100644 zip.js/WebContent/tests/test5.js
 create mode 100644 zip.js/WebContent/tests/test6.html
 create mode 100644 zip.js/WebContent/tests/test6.js
 create mode 100644 zip.js/WebContent/tests/test7.html
 create mode 100644 zip.js/WebContent/tests/test7.js
 create mode 100644 zip.js/WebContent/tests/test8.html
 create mode 100644 zip.js/WebContent/tests/test8.js
 create mode 100644 zip.js/WebContent/tests/test9.html
 create mode 100644 zip.js/WebContent/tests/test9.js
 create mode 100644 zip.js/WebContent/tests/util.js
 create mode 100644 zip.js/WebContent/zip-ext.js
 create mode 100644 zip.js/WebContent/zip-fs.js
 create mode 100644 zip.js/WebContent/zip.js

diff --git a/index.htm b/index.htm
index 2ba96a3..2bb8418 100644
--- a/index.htm
+++ b/index.htm
@@ -34,6 +34,10 @@
  /*]]>*/--></style>
  <script type="text/javascript" src="/javascript/leaflet/leaflet-src.js"></script>
  <script type="text/javascript" src="/javascript/prototype/prototype.js"></script>
+ <script type="text/javascript" src="zip.js/WebContent/zip.js"></script>
+ <script type="text/javascript"><!--//--><![CDATA[//><!--
+  zip.workerScriptsPath = "zip.js/WebContent/";
+ //--><!]]></script>
  <script type="text/javascript" src="mirkarte.js"></script>
 </head><body>
 <div id="map_wrapper">
diff --git a/mirkarte.js b/mirkarte.js
index b425938..a12fe75 100644
--- a/mirkarte.js
+++ b/mirkarte.js
@@ -76,6 +76,107 @@ function nuke_marker() {
 	update_hash();
 }
 
+var show_menu_marker = (function () {
+	var hasfile = false;
+	var filestr = "Your browser does not support the File API";
+
+	if (window.File && window.FileList && window.FileReader && window.Blob) {
+		hasfile = true;
+		filestr = '<fieldset><legend>GPX upload</legend>' +
+		    '<div id="gpxupload"><table>' +
+		    '<tr><th>*.gpx:</th><td><input type="file" id="files" name="files[]" /></td></tr>' +
+		    '<tr><th>*.zip:</th><td><input type="file" id="filez" name="filez[]" /></td></tr>' +
+		    '</table></div></fieldset>';
+	}
+
+	var handleGpxFileLoaded = function (e) {
+		$("gpxupload").update("GPX loaded.");
+		if (!/<gpx/.test(e.target.result))
+			$("gpxupload").update("Not a valid GPX file.");
+		alert(e.target.result);
+	};
+
+	var handleZipExtraction = function (entry) {
+		$("gpxupload").update("Extracting");
+		entry.getData(new zip.BlobWriter(), function (asblob) {
+			$("gpxupload").update("Extracted");
+			var reader = new FileReader();
+			reader.onload = handleGpxFileLoaded;
+			reader.readAsText(asblob);
+		    }, function (current, total) {
+			$("gpxupload").update("Extracting... " +
+			    current + "/" + total);
+		    }, true);
+	};
+
+	var handleZipFileLoaded = function (entries) {
+		var ents = new Element("ul");
+		entries.forEach(function(entry) {
+			var a = new Element("a",
+			    {"href": "#"}).update(entry.filename);
+			a.addEventListener("click", function(event) {
+				handleZipExtraction(entry);
+				event.preventDefault();
+				return (false);
+			    }, false);
+			ents.appendChild(new Element("li").update(a));
+		    });
+		if (ents.empty())
+			ents = "Empty ZIP file.";
+		$("gpxupload").update(ents);
+	};
+
+	var handleFileSelect = function (e, filetype, cb) {
+		var reader, f = e.target.files[0];
+
+		if (!f) {
+			$("gpxupload").update("No file found.");
+			return;
+		}
+		$("gpxupload").update("Loading…");
+		if (filetype == 'zip') {
+			zip.createReader(new zip.BlobReader(f),
+			    function (zipReader) {
+				zipReader.getEntries(cb);
+			    }, function (message) {
+				$("gpxupload").update("ZIP error: " +
+				    ("" + message).escapeHTML());
+			    });
+		} else {
+			reader = new FileReader();
+			reader.onload = cb;
+			if (filetype == 'text')
+				reader.readAsText(f);
+			else
+				reader.readAsBinaryString(f);
+		}
+	};
+
+	var handleGpxFileSelect = function (e) {
+		handleFileSelect(e, 'text', handleGpxFileLoaded);
+	};
+
+	var handleZipFileSelect = function (e) {
+		handleFileSelect(e, 'zip', handleZipFileLoaded);
+	};
+
+	var res = function () {
+		var s, pos = map.getCenter(), f = llformat(pos.lat, pos.lng);
+
+		s = "Current centre: " + f[0] + " " + f[1] + "<hr />" +
+		    filestr;
+		L.popup().setLatLng(pos).setContent(s).openOn(map);
+		if (hasfile) {
+			document.getElementById("files").addEventListener("change",
+			    handleGpxFileSelect, false);
+			document.getElementById("filez").addEventListener("change",
+			    handleZipFileSelect, false);
+		}
+	};
+
+	return (res);
+    })();
+
 if (typeof(window.onhashchange) !== "undefined" &&
     (document.documentMode === undefined || document.documentMode > 7)) {
 	(function () {
@@ -273,9 +374,9 @@ $(document).observe("dom:loaded", function () {
 		onAdd: function (map) {
 			var container = L.Control.Zoom.prototype.onAdd.apply(this, [map]);
 
-			myzoomcontrol_text = L.DomUtil.create("a",
-			    "myzoomcontrol-text", false);
-			myzoomcontrol_text.innerHTML = "-";
+			myzoomcontrol_text = this._createButton("-",
+			    "Menu", "myzoomcontrol-text", false,
+			    show_menu_marker, false);
 			container.insertBefore(myzoomcontrol_text,
 			    this._zoomOutButton);
 
diff --git a/zip.js/.project b/zip.js/.project
new file mode 100644
index 0000000..291535a
--- /dev/null
+++ b/zip.js/.project
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>zip.js</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.wst.jsdt.core.javascriptValidator</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.wst.common.project.facet.core.builder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.wst.validation.validationbuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>com.eclipsesource.jshint.ui.builder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.wst.common.project.facet.core.nature</nature>
+		<nature>org.eclipse.wst.common.modulecore.ModuleCoreNature</nature>
+		<nature>org.eclipse.wst.jsdt.core.jsNature</nature>
+	</natures>
+</projectDescription>
diff --git a/zip.js/README b/zip.js/README
new file mode 100644
index 0000000..4be207d
--- /dev/null
+++ b/zip.js/README
@@ -0,0 +1,4 @@
+zip.js is an open-source library (BSD license) for zipping and unzipping files.
+
+See here for more info:
+http://gildas-lormeau.github.com/zip.js/
diff --git a/zip.js/WebContent/deflate.js b/zip.js/WebContent/deflate.js
new file mode 100644
index 0000000..82544e5
--- /dev/null
+++ b/zip.js/WebContent/deflate.js
@@ -0,0 +1,2088 @@
+/*
+ Copyright (c) 2013 Gildas Lormeau. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright 
+ notice, this list of conditions and the following disclaimer in 
+ the documentation and/or other materials provided with the distribution.
+
+ 3. The names of the authors may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
+ INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This program is based on JZlib 1.0.2 ymnk, JCraft,Inc.
+ * JZlib is based on zlib-1.1.3, so all credit should go authors
+ * Jean-loup Gailly(jloup at gzip.org) and Mark Adler(madler at alumni.caltech.edu)
+ * and contributors of zlib.
+ */
+
+(function(obj) {
+
+	// Global
+
+	var MAX_BITS = 15;
+	var D_CODES = 30;
+	var BL_CODES = 19;
+
+	var LENGTH_CODES = 29;
+	var LITERALS = 256;
+	var L_CODES = (LITERALS + 1 + LENGTH_CODES);
+	var HEAP_SIZE = (2 * L_CODES + 1);
+
+	var END_BLOCK = 256;
+
+	// Bit length codes must not exceed MAX_BL_BITS bits
+	var MAX_BL_BITS = 7;
+
+	// repeat previous bit length 3-6 times (2 bits of repeat count)
+	var REP_3_6 = 16;
+
+	// repeat a zero length 3-10 times (3 bits of repeat count)
+	var REPZ_3_10 = 17;
+
+	// repeat a zero length 11-138 times (7 bits of repeat count)
+	var REPZ_11_138 = 18;
+
+	// The lengths of the bit length codes are sent in order of decreasing
+	// probability, to avoid transmitting the lengths for unused bit
+	// length codes.
+
+	var Buf_size = 8 * 2;
+
+	// JZlib version : "1.0.2"
+	var Z_DEFAULT_COMPRESSION = -1;
+
+	// compression strategy
+	var Z_FILTERED = 1;
+	var Z_HUFFMAN_ONLY = 2;
+	var Z_DEFAULT_STRATEGY = 0;
+
+	var Z_NO_FLUSH = 0;
+	var Z_PARTIAL_FLUSH = 1;
+	var Z_FULL_FLUSH = 3;
+	var Z_FINISH = 4;
+
+	var Z_OK = 0;
+	var Z_STREAM_END = 1;
+	var Z_NEED_DICT = 2;
+	var Z_STREAM_ERROR = -2;
+	var Z_DATA_ERROR = -3;
+	var Z_BUF_ERROR = -5;
+
+	// Tree
+
+	// see definition of array dist_code below
+	var _dist_code = [ 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+			10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+			12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+			13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+			14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+			14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+			15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, 18, 18, 19, 19,
+			20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+			24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+			26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+			27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+			28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29,
+			29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+			29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 ];
+
+	function Tree() {
+		var that = this;
+
+		// dyn_tree; // the dynamic tree
+		// max_code; // largest code with non zero frequency
+		// stat_desc; // the corresponding static tree
+
+		// Compute the optimal bit lengths for a tree and update the total bit
+		// length
+		// for the current block.
+		// IN assertion: the fields freq and dad are set, heap[heap_max] and
+		// above are the tree nodes sorted by increasing frequency.
+		// OUT assertions: the field len is set to the optimal bit length, the
+		// array bl_count contains the frequencies for each bit length.
+		// The length opt_len is updated; static_len is also updated if stree is
+		// not null.
+		function gen_bitlen(s) {
+			var tree = that.dyn_tree;
+			var stree = that.stat_desc.static_tree;
+			var extra = that.stat_desc.extra_bits;
+			var base = that.stat_desc.extra_base;
+			var max_length = that.stat_desc.max_length;
+			var h; // heap index
+			var n, m; // iterate over the tree elements
+			var bits; // bit length
+			var xbits; // extra bits
+			var f; // frequency
+			var overflow = 0; // number of elements with bit length too large
+
+			for (bits = 0; bits <= MAX_BITS; bits++)
+				s.bl_count[bits] = 0;
+
+			// In a first pass, compute the optimal bit lengths (which may
+			// overflow in the case of the bit length tree).
+			tree[s.heap[s.heap_max] * 2 + 1] = 0; // root of the heap
+
+			for (h = s.heap_max + 1; h < HEAP_SIZE; h++) {
+				n = s.heap[h];
+				bits = tree[tree[n * 2 + 1] * 2 + 1] + 1;
+				if (bits > max_length) {
+					bits = max_length;
+					overflow++;
+				}
+				tree[n * 2 + 1] = bits;
+				// We overwrite tree[n*2+1] which is no longer needed
+
+				if (n > that.max_code)
+					continue; // not a leaf node
+
+				s.bl_count[bits]++;
+				xbits = 0;
+				if (n >= base)
+					xbits = extra[n - base];
+				f = tree[n * 2];
+				s.opt_len += f * (bits + xbits);
+				if (stree)
+					s.static_len += f * (stree[n * 2 + 1] + xbits);
+			}
+			if (overflow === 0)
+				return;
+
+			// This happens for example on obj2 and pic of the Calgary corpus
+			// Find the first bit length which could increase:
+			do {
+				bits = max_length - 1;
+				while (s.bl_count[bits] === 0)
+					bits--;
+				s.bl_count[bits]--; // move one leaf down the tree
+				s.bl_count[bits + 1] += 2; // move one overflow item as its brother
+				s.bl_count[max_length]--;
+				// The brother of the overflow item also moves one step up,
+				// but this does not affect bl_count[max_length]
+				overflow -= 2;
+			} while (overflow > 0);
+
+			for (bits = max_length; bits !== 0; bits--) {
+				n = s.bl_count[bits];
+				while (n !== 0) {
+					m = s.heap[--h];
+					if (m > that.max_code)
+						continue;
+					if (tree[m * 2 + 1] != bits) {
+						s.opt_len += (bits - tree[m * 2 + 1]) * tree[m * 2];
+						tree[m * 2 + 1] = bits;
+					}
+					n--;
+				}
+			}
+		}
+
+		// Reverse the first len bits of a code, using straightforward code (a
+		// faster
+		// method would use a table)
+		// IN assertion: 1 <= len <= 15
+		function bi_reverse(code, // the value to invert
+		len // its bit length
+		) {
+			var res = 0;
+			do {
+				res |= code & 1;
+				code >>>= 1;
+				res <<= 1;
+			} while (--len > 0);
+			return res >>> 1;
+		}
+
+		// Generate the codes for a given tree and bit counts (which need not be
+		// optimal).
+		// IN assertion: the array bl_count contains the bit length statistics for
+		// the given tree and the field len is set for all tree elements.
+		// OUT assertion: the field code is set for all tree elements of non
+		// zero code length.
+		function gen_codes(tree, // the tree to decorate
+		max_code, // largest code with non zero frequency
+		bl_count // number of codes at each bit length
+		) {
+			var next_code = []; // next code value for each
+			// bit length
+			var code = 0; // running code value
+			var bits; // bit index
+			var n; // code index
+			var len;
+
+			// The distribution counts are first used to generate the code values
+			// without bit reversal.
+			for (bits = 1; bits <= MAX_BITS; bits++) {
+				next_code[bits] = code = ((code + bl_count[bits - 1]) << 1);
+			}
+
+			// Check that the bit counts in bl_count are consistent. The last code
+			// must be all ones.
+			// Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
+			// "inconsistent bit counts");
+			// Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
+
+			for (n = 0; n <= max_code; n++) {
+				len = tree[n * 2 + 1];
+				if (len === 0)
+					continue;
+				// Now reverse the bits
+				tree[n * 2] = bi_reverse(next_code[len]++, len);
+			}
+		}
+
+		// Construct one Huffman tree and assigns the code bit strings and lengths.
+		// Update the total bit length for the current block.
+		// IN assertion: the field freq is set for all tree elements.
+		// OUT assertions: the fields len and code are set to the optimal bit length
+		// and corresponding code. The length opt_len is updated; static_len is
+		// also updated if stree is not null. The field max_code is set.
+		that.build_tree = function(s) {
+			var tree = that.dyn_tree;
+			var stree = that.stat_desc.static_tree;
+			var elems = that.stat_desc.elems;
+			var n, m; // iterate over heap elements
+			var max_code = -1; // largest code with non zero frequency
+			var node; // new node being created
+
+			// Construct the initial heap, with least frequent element in
+			// heap[1]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
+			// heap[0] is not used.
+			s.heap_len = 0;
+			s.heap_max = HEAP_SIZE;
+
+			for (n = 0; n < elems; n++) {
+				if (tree[n * 2] !== 0) {
+					s.heap[++s.heap_len] = max_code = n;
+					s.depth[n] = 0;
+				} else {
+					tree[n * 2 + 1] = 0;
+				}
+			}
+
+			// The pkzip format requires that at least one distance code exists,
+			// and that at least one bit should be sent even if there is only one
+			// possible code. So to avoid special checks later on we force at least
+			// two codes of non zero frequency.
+			while (s.heap_len < 2) {
+				node = s.heap[++s.heap_len] = max_code < 2 ? ++max_code : 0;
+				tree[node * 2] = 1;
+				s.depth[node] = 0;
+				s.opt_len--;
+				if (stree)
+					s.static_len -= stree[node * 2 + 1];
+				// node is 0 or 1 so it does not have extra bits
+			}
+			that.max_code = max_code;
+
+			// The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
+			// establish sub-heaps of increasing lengths:
+
+			for (n = Math.floor(s.heap_len / 2); n >= 1; n--)
+				s.pqdownheap(tree, n);
+
+			// Construct the Huffman tree by repeatedly combining the least two
+			// frequent nodes.
+
+			node = elems; // next internal node of the tree
+			do {
+				// n = node of least frequency
+				n = s.heap[1];
+				s.heap[1] = s.heap[s.heap_len--];
+				s.pqdownheap(tree, 1);
+				m = s.heap[1]; // m = node of next least frequency
+
+				s.heap[--s.heap_max] = n; // keep the nodes sorted by frequency
+				s.heap[--s.heap_max] = m;
+
+				// Create a new node father of n and m
+				tree[node * 2] = (tree[n * 2] + tree[m * 2]);
+				s.depth[node] = Math.max(s.depth[n], s.depth[m]) + 1;
+				tree[n * 2 + 1] = tree[m * 2 + 1] = node;
+
+				// and insert the new node in the heap
+				s.heap[1] = node++;
+				s.pqdownheap(tree, 1);
+			} while (s.heap_len >= 2);
+
+			s.heap[--s.heap_max] = s.heap[1];
+
+			// At this point, the fields freq and dad are set. We can now
+			// generate the bit lengths.
+
+			gen_bitlen(s);
+
+			// The field len is now set, we can generate the bit codes
+			gen_codes(tree, that.max_code, s.bl_count);
+		};
+
+	}
+
+	Tree._length_code = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16,
+			16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+			20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+			22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+			24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+			25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+			26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 ];
+
+	Tree.base_length = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 0 ];
+
+	Tree.base_dist = [ 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384,
+			24576 ];
+
+	// Mapping from a distance to a distance code. dist is the distance - 1 and
+	// must not have side effects. _dist_code[256] and _dist_code[257] are never
+	// used.
+	Tree.d_code = function(dist) {
+		return ((dist) < 256 ? _dist_code[dist] : _dist_code[256 + ((dist) >>> 7)]);
+	};
+
+	// extra bits for each length code
+	Tree.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 ];
+
+	// extra bits for each distance code
+	Tree.extra_dbits = [ 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 ];
+
+	// extra bits for each bit length code
+	Tree.extra_blbits = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7 ];
+
+	Tree.bl_order = [ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 ];
+
+	// StaticTree
+
+	function StaticTree(static_tree, extra_bits, extra_base, elems, max_length) {
+		var that = this;
+		that.static_tree = static_tree;
+		that.extra_bits = extra_bits;
+		that.extra_base = extra_base;
+		that.elems = elems;
+		that.max_length = max_length;
+	}
+
+	StaticTree.static_ltree = [ 12, 8, 140, 8, 76, 8, 204, 8, 44, 8, 172, 8, 108, 8, 236, 8, 28, 8, 156, 8, 92, 8, 220, 8, 60, 8, 188, 8, 124, 8, 252, 8, 2, 8,
+			130, 8, 66, 8, 194, 8, 34, 8, 162, 8, 98, 8, 226, 8, 18, 8, 146, 8, 82, 8, 210, 8, 50, 8, 178, 8, 114, 8, 242, 8, 10, 8, 138, 8, 74, 8, 202, 8, 42,
+			8, 170, 8, 106, 8, 234, 8, 26, 8, 154, 8, 90, 8, 218, 8, 58, 8, 186, 8, 122, 8, 250, 8, 6, 8, 134, 8, 70, 8, 198, 8, 38, 8, 166, 8, 102, 8, 230, 8,
+			22, 8, 150, 8, 86, 8, 214, 8, 54, 8, 182, 8, 118, 8, 246, 8, 14, 8, 142, 8, 78, 8, 206, 8, 46, 8, 174, 8, 110, 8, 238, 8, 30, 8, 158, 8, 94, 8,
+			222, 8, 62, 8, 190, 8, 126, 8, 254, 8, 1, 8, 129, 8, 65, 8, 193, 8, 33, 8, 161, 8, 97, 8, 225, 8, 17, 8, 145, 8, 81, 8, 209, 8, 49, 8, 177, 8, 113,
+			8, 241, 8, 9, 8, 137, 8, 73, 8, 201, 8, 41, 8, 169, 8, 105, 8, 233, 8, 25, 8, 153, 8, 89, 8, 217, 8, 57, 8, 185, 8, 121, 8, 249, 8, 5, 8, 133, 8,
+			69, 8, 197, 8, 37, 8, 165, 8, 101, 8, 229, 8, 21, 8, 149, 8, 85, 8, 213, 8, 53, 8, 181, 8, 117, 8, 245, 8, 13, 8, 141, 8, 77, 8, 205, 8, 45, 8,
+			173, 8, 109, 8, 237, 8, 29, 8, 157, 8, 93, 8, 221, 8, 61, 8, 189, 8, 125, 8, 253, 8, 19, 9, 275, 9, 147, 9, 403, 9, 83, 9, 339, 9, 211, 9, 467, 9,
+			51, 9, 307, 9, 179, 9, 435, 9, 115, 9, 371, 9, 243, 9, 499, 9, 11, 9, 267, 9, 139, 9, 395, 9, 75, 9, 331, 9, 203, 9, 459, 9, 43, 9, 299, 9, 171, 9,
+			427, 9, 107, 9, 363, 9, 235, 9, 491, 9, 27, 9, 283, 9, 155, 9, 411, 9, 91, 9, 347, 9, 219, 9, 475, 9, 59, 9, 315, 9, 187, 9, 443, 9, 123, 9, 379,
+			9, 251, 9, 507, 9, 7, 9, 263, 9, 135, 9, 391, 9, 71, 9, 327, 9, 199, 9, 455, 9, 39, 9, 295, 9, 167, 9, 423, 9, 103, 9, 359, 9, 231, 9, 487, 9, 23,
+			9, 279, 9, 151, 9, 407, 9, 87, 9, 343, 9, 215, 9, 471, 9, 55, 9, 311, 9, 183, 9, 439, 9, 119, 9, 375, 9, 247, 9, 503, 9, 15, 9, 271, 9, 143, 9,
+			399, 9, 79, 9, 335, 9, 207, 9, 463, 9, 47, 9, 303, 9, 175, 9, 431, 9, 111, 9, 367, 9, 239, 9, 495, 9, 31, 9, 287, 9, 159, 9, 415, 9, 95, 9, 351, 9,
+			223, 9, 479, 9, 63, 9, 319, 9, 191, 9, 447, 9, 127, 9, 383, 9, 255, 9, 511, 9, 0, 7, 64, 7, 32, 7, 96, 7, 16, 7, 80, 7, 48, 7, 112, 7, 8, 7, 72, 7,
+			40, 7, 104, 7, 24, 7, 88, 7, 56, 7, 120, 7, 4, 7, 68, 7, 36, 7, 100, 7, 20, 7, 84, 7, 52, 7, 116, 7, 3, 8, 131, 8, 67, 8, 195, 8, 35, 8, 163, 8,
+			99, 8, 227, 8 ];
+
+	StaticTree.static_dtree = [ 0, 5, 16, 5, 8, 5, 24, 5, 4, 5, 20, 5, 12, 5, 28, 5, 2, 5, 18, 5, 10, 5, 26, 5, 6, 5, 22, 5, 14, 5, 30, 5, 1, 5, 17, 5, 9, 5,
+			25, 5, 5, 5, 21, 5, 13, 5, 29, 5, 3, 5, 19, 5, 11, 5, 27, 5, 7, 5, 23, 5 ];
+
+	StaticTree.static_l_desc = new StaticTree(StaticTree.static_ltree, Tree.extra_lbits, LITERALS + 1, L_CODES, MAX_BITS);
+
+	StaticTree.static_d_desc = new StaticTree(StaticTree.static_dtree, Tree.extra_dbits, 0, D_CODES, MAX_BITS);
+
+	StaticTree.static_bl_desc = new StaticTree(null, Tree.extra_blbits, 0, BL_CODES, MAX_BL_BITS);
+
+	// Deflate
+
+	var MAX_MEM_LEVEL = 9;
+	var DEF_MEM_LEVEL = 8;
+
+	function Config(good_length, max_lazy, nice_length, max_chain, func) {
+		var that = this;
+		that.good_length = good_length;
+		that.max_lazy = max_lazy;
+		that.nice_length = nice_length;
+		that.max_chain = max_chain;
+		that.func = func;
+	}
+
+	var STORED = 0;
+	var FAST = 1;
+	var SLOW = 2;
+	var config_table = [ new Config(0, 0, 0, 0, STORED), new Config(4, 4, 8, 4, FAST), new Config(4, 5, 16, 8, FAST), new Config(4, 6, 32, 32, FAST),
+			new Config(4, 4, 16, 16, SLOW), new Config(8, 16, 32, 32, SLOW), new Config(8, 16, 128, 128, SLOW), new Config(8, 32, 128, 256, SLOW),
+			new Config(32, 128, 258, 1024, SLOW), new Config(32, 258, 258, 4096, SLOW) ];
+
+	var z_errmsg = [ "need dictionary", // Z_NEED_DICT
+	// 2
+	"stream end", // Z_STREAM_END 1
+	"", // Z_OK 0
+	"", // Z_ERRNO (-1)
+	"stream error", // Z_STREAM_ERROR (-2)
+	"data error", // Z_DATA_ERROR (-3)
+	"", // Z_MEM_ERROR (-4)
+	"buffer error", // Z_BUF_ERROR (-5)
+	"",// Z_VERSION_ERROR (-6)
+	"" ];
+
+	// block not completed, need more input or more output
+	var NeedMore = 0;
+
+	// block flush performed
+	var BlockDone = 1;
+
+	// finish started, need only more output at next deflate
+	var FinishStarted = 2;
+
+	// finish done, accept no more input or output
+	var FinishDone = 3;
+
+	// preset dictionary flag in zlib header
+	var PRESET_DICT = 0x20;
+
+	var INIT_STATE = 42;
+	var BUSY_STATE = 113;
+	var FINISH_STATE = 666;
+
+	// The deflate compression method
+	var Z_DEFLATED = 8;
+
+	var STORED_BLOCK = 0;
+	var STATIC_TREES = 1;
+	var DYN_TREES = 2;
+
+	var MIN_MATCH = 3;
+	var MAX_MATCH = 258;
+	var MIN_LOOKAHEAD = (MAX_MATCH + MIN_MATCH + 1);
+
+	function smaller(tree, n, m, depth) {
+		var tn2 = tree[n * 2];
+		var tm2 = tree[m * 2];
+		return (tn2 < tm2 || (tn2 == tm2 && depth[n] <= depth[m]));
+	}
+
+	function Deflate() {
+
+		var that = this;
+		var strm; // pointer back to this zlib stream
+		var status; // as the name implies
+		// pending_buf; // output still pending
+		var pending_buf_size; // size of pending_buf
+		// pending_out; // next pending byte to output to the stream
+		// pending; // nb of bytes in the pending buffer
+		var method; // STORED (for zip only) or DEFLATED
+		var last_flush; // value of flush param for previous deflate call
+
+		var w_size; // LZ77 window size (32K by default)
+		var w_bits; // log2(w_size) (8..16)
+		var w_mask; // w_size - 1
+
+		var window;
+		// Sliding window. Input bytes are read into the second half of the window,
+		// and move to the first half later to keep a dictionary of at least wSize
+		// bytes. With this organization, matches are limited to a distance of
+		// wSize-MAX_MATCH bytes, but this ensures that IO is always
+		// performed with a length multiple of the block size. Also, it limits
+		// the window size to 64K, which is quite useful on MSDOS.
+		// To do: use the user input buffer as sliding window.
+
+		var window_size;
+		// Actual size of window: 2*wSize, except when the user input buffer
+		// is directly used as sliding window.
+
+		var prev;
+		// Link to older string with same hash index. To limit the size of this
+		// array to 64K, this link is maintained only for the last 32K strings.
+		// An index in this array is thus a window index modulo 32K.
+
+		var head; // Heads of the hash chains or NIL.
+
+		var ins_h; // hash index of string to be inserted
+		var hash_size; // number of elements in hash table
+		var hash_bits; // log2(hash_size)
+		var hash_mask; // hash_size-1
+
+		// Number of bits by which ins_h must be shifted at each input
+		// step. It must be such that after MIN_MATCH steps, the oldest
+		// byte no longer takes part in the hash key, that is:
+		// hash_shift * MIN_MATCH >= hash_bits
+		var hash_shift;
+
+		// Window position at the beginning of the current output block. Gets
+		// negative when the window is moved backwards.
+
+		var block_start;
+
+		var match_length; // length of best match
+		var prev_match; // previous match
+		var match_available; // set if previous match exists
+		var strstart; // start of string to insert
+		var match_start; // start of matching string
+		var lookahead; // number of valid bytes ahead in window
+
+		// Length of the best match at previous step. Matches not greater than this
+		// are discarded. This is used in the lazy match evaluation.
+		var prev_length;
+
+		// To speed up deflation, hash chains are never searched beyond this
+		// length. A higher limit improves compression ratio but degrades the speed.
+		var max_chain_length;
+
+		// Attempt to find a better match only when the current match is strictly
+		// smaller than this value. This mechanism is used only for compression
+		// levels >= 4.
+		var max_lazy_match;
+
+		// Insert new strings in the hash table only if the match length is not
+		// greater than this length. This saves time but degrades compression.
+		// max_insert_length is used only for compression levels <= 3.
+
+		var level; // compression level (1..9)
+		var strategy; // favor or force Huffman coding
+
+		// Use a faster search when the previous match is longer than this
+		var good_match;
+
+		// Stop searching when current match exceeds this
+		var nice_match;
+
+		var dyn_ltree; // literal and length tree
+		var dyn_dtree; // distance tree
+		var bl_tree; // Huffman tree for bit lengths
+
+		var l_desc = new Tree(); // desc for literal tree
+		var d_desc = new Tree(); // desc for distance tree
+		var bl_desc = new Tree(); // desc for bit length tree
+
+		// that.heap_len; // number of elements in the heap
+		// that.heap_max; // element of largest frequency
+		// The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
+		// The same heap array is used to build all trees.
+
+		// Depth of each subtree used as tie breaker for trees of equal frequency
+		that.depth = [];
+
+		var l_buf; // index for literals or lengths */
+
+		// Size of match buffer for literals/lengths. There are 4 reasons for
+		// limiting lit_bufsize to 64K:
+		// - frequencies can be kept in 16 bit counters
+		// - if compression is not successful for the first block, all input
+		// data is still in the window so we can still emit a stored block even
+		// when input comes from standard input. (This can also be done for
+		// all blocks if lit_bufsize is not greater than 32K.)
+		// - if compression is not successful for a file smaller than 64K, we can
+		// even emit a stored file instead of a stored block (saving 5 bytes).
+		// This is applicable only for zip (not gzip or zlib).
+		// - creating new Huffman trees less frequently may not provide fast
+		// adaptation to changes in the input data statistics. (Take for
+		// example a binary file with poorly compressible code followed by
+		// a highly compressible string table.) Smaller buffer sizes give
+		// fast adaptation but have of course the overhead of transmitting
+		// trees more frequently.
+		// - I can't count above 4
+		var lit_bufsize;
+
+		var last_lit; // running index in l_buf
+
+		// Buffer for distances. To simplify the code, d_buf and l_buf have
+		// the same number of elements. To use different lengths, an extra flag
+		// array would be necessary.
+
+		var d_buf; // index of pendig_buf
+
+		// that.opt_len; // bit length of current block with optimal trees
+		// that.static_len; // bit length of current block with static trees
+		var matches; // number of string matches in current block
+		var last_eob_len; // bit length of EOB code for last block
+
+		// Output buffer. bits are inserted starting at the bottom (least
+		// significant bits).
+		var bi_buf;
+
+		// Number of valid bits in bi_buf. All bits above the last valid bit
+		// are always zero.
+		var bi_valid;
+
+		// number of codes at each bit length for an optimal tree
+		that.bl_count = [];
+
+		// heap used to build the Huffman trees
+		that.heap = [];
+
+		dyn_ltree = [];
+		dyn_dtree = [];
+		bl_tree = [];
+
+		function lm_init() {
+			var i;
+			window_size = 2 * w_size;
+
+			head[hash_size - 1] = 0;
+			for (i = 0; i < hash_size - 1; i++) {
+				head[i] = 0;
+			}
+
+			// Set the default configuration parameters:
+			max_lazy_match = config_table[level].max_lazy;
+			good_match = config_table[level].good_length;
+			nice_match = config_table[level].nice_length;
+			max_chain_length = config_table[level].max_chain;
+
+			strstart = 0;
+			block_start = 0;
+			lookahead = 0;
+			match_length = prev_length = MIN_MATCH - 1;
+			match_available = 0;
+			ins_h = 0;
+		}
+
+		function init_block() {
+			var i;
+			// Initialize the trees.
+			for (i = 0; i < L_CODES; i++)
+				dyn_ltree[i * 2] = 0;
+			for (i = 0; i < D_CODES; i++)
+				dyn_dtree[i * 2] = 0;
+			for (i = 0; i < BL_CODES; i++)
+				bl_tree[i * 2] = 0;
+
+			dyn_ltree[END_BLOCK * 2] = 1;
+			that.opt_len = that.static_len = 0;
+			last_lit = matches = 0;
+		}
+
+		// Initialize the tree data structures for a new zlib stream.
+		function tr_init() {
+
+			l_desc.dyn_tree = dyn_ltree;
+			l_desc.stat_desc = StaticTree.static_l_desc;
+
+			d_desc.dyn_tree = dyn_dtree;
+			d_desc.stat_desc = StaticTree.static_d_desc;
+
+			bl_desc.dyn_tree = bl_tree;
+			bl_desc.stat_desc = StaticTree.static_bl_desc;
+
+			bi_buf = 0;
+			bi_valid = 0;
+			last_eob_len = 8; // enough lookahead for inflate
+
+			// Initialize the first block of the first file:
+			init_block();
+		}
+
+		// Restore the heap property by moving down the tree starting at node k,
+		// exchanging a node with the smallest of its two sons if necessary,
+		// stopping
+		// when the heap property is re-established (each father smaller than its
+		// two sons).
+		that.pqdownheap = function(tree, // the tree to restore
+		k // node to move down
+		) {
+			var heap = that.heap;
+			var v = heap[k];
+			var j = k << 1; // left son of k
+			while (j <= that.heap_len) {
+				// Set j to the smallest of the two sons:
+				if (j < that.heap_len && smaller(tree, heap[j + 1], heap[j], that.depth)) {
+					j++;
+				}
+				// Exit if v is smaller than both sons
+				if (smaller(tree, v, heap[j], that.depth))
+					break;
+
+				// Exchange v with the smallest son
+				heap[k] = heap[j];
+				k = j;
+				// And continue down the tree, setting j to the left son of k
+				j <<= 1;
+			}
+			heap[k] = v;
+		};
+
+		// Scan a literal or distance tree to determine the frequencies of the codes
+		// in the bit length tree.
+		function scan_tree(tree,// the tree to be scanned
+		max_code // and its largest code of non zero frequency
+		) {
+			var n; // iterates over all tree elements
+			var prevlen = -1; // last emitted length
+			var curlen; // length of current code
+			var nextlen = tree[0 * 2 + 1]; // length of next code
+			var count = 0; // repeat count of the current code
+			var max_count = 7; // max repeat count
+			var min_count = 4; // min repeat count
+
+			if (nextlen === 0) {
+				max_count = 138;
+				min_count = 3;
+			}
+			tree[(max_code + 1) * 2 + 1] = 0xffff; // guard
+
+			for (n = 0; n <= max_code; n++) {
+				curlen = nextlen;
+				nextlen = tree[(n + 1) * 2 + 1];
+				if (++count < max_count && curlen == nextlen) {
+					continue;
+				} else if (count < min_count) {
+					bl_tree[curlen * 2] += count;
+				} else if (curlen !== 0) {
+					if (curlen != prevlen)
+						bl_tree[curlen * 2]++;
+					bl_tree[REP_3_6 * 2]++;
+				} else if (count <= 10) {
+					bl_tree[REPZ_3_10 * 2]++;
+				} else {
+					bl_tree[REPZ_11_138 * 2]++;
+				}
+				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;
+				}
+			}
+		}
+
+		// Construct the Huffman tree for the bit lengths and return the index in
+		// bl_order of the last bit length code to send.
+		function build_bl_tree() {
+			var max_blindex; // index of last bit length code of non zero freq
+
+			// Determine the bit length frequencies for literal and distance trees
+			scan_tree(dyn_ltree, l_desc.max_code);
+			scan_tree(dyn_dtree, d_desc.max_code);
+
+			// Build the bit length tree:
+			bl_desc.build_tree(that);
+			// opt_len now includes the length of the tree representations, except
+			// the lengths of the bit lengths codes and the 5+5+4 bits for the
+			// counts.
+
+			// Determine the number of bit length codes to send. The pkzip format
+			// requires that at least 4 bit length codes be sent. (appnote.txt says
+			// 3 but the actual value used is 4.)
+			for (max_blindex = BL_CODES - 1; max_blindex >= 3; max_blindex--) {
+				if (bl_tree[Tree.bl_order[max_blindex] * 2 + 1] !== 0)
+					break;
+			}
+			// Update opt_len to include the bit length tree and counts
+			that.opt_len += 3 * (max_blindex + 1) + 5 + 5 + 4;
+
+			return max_blindex;
+		}
+
+		// Output a byte on the stream.
+		// IN assertion: there is enough room in pending_buf.
+		function put_byte(p) {
+			that.pending_buf[that.pending++] = p;
+		}
+
+		function put_short(w) {
+			put_byte(w & 0xff);
+			put_byte((w >>> 8) & 0xff);
+		}
+
+		function putShortMSB(b) {
+			put_byte((b >> 8) & 0xff);
+			put_byte((b & 0xff) & 0xff);
+		}
+
+		function send_bits(value, length) {
+			var val, len = length;
+			if (bi_valid > Buf_size - len) {
+				val = value;
+				// bi_buf |= (val << bi_valid);
+				bi_buf |= ((val << bi_valid) & 0xffff);
+				put_short(bi_buf);
+				bi_buf = val >>> (Buf_size - bi_valid);
+				bi_valid += len - Buf_size;
+			} else {
+				// bi_buf |= (value) << bi_valid;
+				bi_buf |= (((value) << bi_valid) & 0xffff);
+				bi_valid += len;
+			}
+		}
+
+		function send_code(c, tree) {
+			var c2 = c * 2;
+			send_bits(tree[c2] & 0xffff, tree[c2 + 1] & 0xffff);
+		}
+
+		// Send a literal or distance tree in compressed form, using the codes in
+		// bl_tree.
+		function send_tree(tree,// the tree to be sent
+		max_code // and its largest code of non zero frequency
+		) {
+			var n; // iterates over all tree elements
+			var prevlen = -1; // last emitted length
+			var curlen; // length of current code
+			var nextlen = tree[0 * 2 + 1]; // length of next code
+			var count = 0; // repeat count of the current code
+			var max_count = 7; // max repeat count
+			var min_count = 4; // min repeat count
+
+			if (nextlen === 0) {
+				max_count = 138;
+				min_count = 3;
+			}
+
+			for (n = 0; n <= max_code; n++) {
+				curlen = nextlen;
+				nextlen = tree[(n + 1) * 2 + 1];
+				if (++count < max_count && curlen == nextlen) {
+					continue;
+				} else if (count < min_count) {
+					do {
+						send_code(curlen, bl_tree);
+					} while (--count !== 0);
+				} else if (curlen !== 0) {
+					if (curlen != prevlen) {
+						send_code(curlen, bl_tree);
+						count--;
+					}
+					send_code(REP_3_6, bl_tree);
+					send_bits(count - 3, 2);
+				} else if (count <= 10) {
+					send_code(REPZ_3_10, bl_tree);
+					send_bits(count - 3, 3);
+				} else {
+					send_code(REPZ_11_138, bl_tree);
+					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;
+				}
+			}
+		}
+
+		// Send the header for a block using dynamic Huffman trees: the counts, the
+		// lengths of the bit length codes, the literal tree and the distance tree.
+		// IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
+		function send_all_trees(lcodes, dcodes, blcodes) {
+			var rank; // index in bl_order
+
+			send_bits(lcodes - 257, 5); // not +255 as stated in appnote.txt
+			send_bits(dcodes - 1, 5);
+			send_bits(blcodes - 4, 4); // not -3 as stated in appnote.txt
+			for (rank = 0; rank < blcodes; rank++) {
+				send_bits(bl_tree[Tree.bl_order[rank] * 2 + 1], 3);
+			}
+			send_tree(dyn_ltree, lcodes - 1); // literal tree
+			send_tree(dyn_dtree, dcodes - 1); // distance tree
+		}
+
+		// Flush the bit buffer, keeping at most 7 bits in it.
+		function bi_flush() {
+			if (bi_valid == 16) {
+				put_short(bi_buf);
+				bi_buf = 0;
+				bi_valid = 0;
+			} else if (bi_valid >= 8) {
+				put_byte(bi_buf & 0xff);
+				bi_buf >>>= 8;
+				bi_valid -= 8;
+			}
+		}
+
+		// Send one empty static block to give enough lookahead for inflate.
+		// This takes 10 bits, of which 7 may remain in the bit buffer.
+		// The current inflate code requires 9 bits of lookahead. If the
+		// last two codes for the previous block (real code plus EOB) were coded
+		// on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode
+		// the last real code. In this case we send two empty static blocks instead
+		// of one. (There are no problems if the previous block is stored or fixed.)
+		// To simplify the code, we assume the worst case of last real code encoded
+		// on one bit only.
+		function _tr_align() {
+			send_bits(STATIC_TREES << 1, 3);
+			send_code(END_BLOCK, StaticTree.static_ltree);
+
+			bi_flush();
+
+			// Of the 10 bits for the empty block, we have already sent
+			// (10 - bi_valid) bits. The lookahead for the last real code (before
+			// the EOB of the previous block) was thus at least one plus the length
+			// of the EOB plus what we have just sent of the empty static block.
+			if (1 + last_eob_len + 10 - bi_valid < 9) {
+				send_bits(STATIC_TREES << 1, 3);
+				send_code(END_BLOCK, StaticTree.static_ltree);
+				bi_flush();
+			}
+			last_eob_len = 7;
+		}
+
+		// Save the match info and tally the frequency counts. Return true if
+		// the current block must be flushed.
+		function _tr_tally(dist, // distance of matched string
+		lc // match length-MIN_MATCH or unmatched char (if dist==0)
+		) {
+			var out_length, in_length, dcode;
+			that.pending_buf[d_buf + last_lit * 2] = (dist >>> 8) & 0xff;
+			that.pending_buf[d_buf + last_lit * 2 + 1] = dist & 0xff;
+
+			that.pending_buf[l_buf + last_lit] = lc & 0xff;
+			last_lit++;
+
+			if (dist === 0) {
+				// lc is the unmatched char
+				dyn_ltree[lc * 2]++;
+			} else {
+				matches++;
+				// Here, lc is the match length - MIN_MATCH
+				dist--; // dist = match distance - 1
+				dyn_ltree[(Tree._length_code[lc] + LITERALS + 1) * 2]++;
+				dyn_dtree[Tree.d_code(dist) * 2]++;
+			}
+
+			if ((last_lit & 0x1fff) === 0 && level > 2) {
+				// Compute an upper bound for the compressed length
+				out_length = last_lit * 8;
+				in_length = strstart - block_start;
+				for (dcode = 0; dcode < D_CODES; dcode++) {
+					out_length += dyn_dtree[dcode * 2] * (5 + Tree.extra_dbits[dcode]);
+				}
+				out_length >>>= 3;
+				if ((matches < Math.floor(last_lit / 2)) && out_length < Math.floor(in_length / 2))
+					return true;
+			}
+
+			return (last_lit == lit_bufsize - 1);
+			// We avoid equality with lit_bufsize because of wraparound at 64K
+			// on 16 bit machines and because stored blocks are restricted to
+			// 64K-1 bytes.
+		}
+
+		// Send the block data compressed using the given Huffman trees
+		function compress_block(ltree, dtree) {
+			var dist; // distance of matched string
+			var lc; // match length or unmatched char (if dist === 0)
+			var lx = 0; // running index in l_buf
+			var code; // the code to send
+			var extra; // number of extra bits to send
+
+			if (last_lit !== 0) {
+				do {
+					dist = ((that.pending_buf[d_buf + lx * 2] << 8) & 0xff00) | (that.pending_buf[d_buf + lx * 2 + 1] & 0xff);
+					lc = (that.pending_buf[l_buf + lx]) & 0xff;
+					lx++;
+
+					if (dist === 0) {
+						send_code(lc, ltree); // send a literal byte
+					} else {
+						// Here, lc is the match length - MIN_MATCH
+						code = Tree._length_code[lc];
+
+						send_code(code + LITERALS + 1, ltree); // send the length
+						// code
+						extra = Tree.extra_lbits[code];
+						if (extra !== 0) {
+							lc -= Tree.base_length[code];
+							send_bits(lc, extra); // send the extra length bits
+						}
+						dist--; // dist is now the match distance - 1
+						code = Tree.d_code(dist);
+
+						send_code(code, dtree); // send the distance code
+						extra = Tree.extra_dbits[code];
+						if (extra !== 0) {
+							dist -= Tree.base_dist[code];
+							send_bits(dist, extra); // send the extra distance bits
+						}
+					} // literal or match pair ?
+
+					// Check that the overlay between pending_buf and d_buf+l_buf is
+					// ok:
+				} while (lx < last_lit);
+			}
+
+			send_code(END_BLOCK, ltree);
+			last_eob_len = ltree[END_BLOCK * 2 + 1];
+		}
+
+		// Flush the bit buffer and align the output on a byte boundary
+		function bi_windup() {
+			if (bi_valid > 8) {
+				put_short(bi_buf);
+			} else if (bi_valid > 0) {
+				put_byte(bi_buf & 0xff);
+			}
+			bi_buf = 0;
+			bi_valid = 0;
+		}
+
+		// Copy a stored block, storing first the length and its
+		// one's complement if requested.
+		function copy_block(buf, // the input data
+		len, // its length
+		header // true if block header must be written
+		) {
+			bi_windup(); // align on byte boundary
+			last_eob_len = 8; // enough lookahead for inflate
+
+			if (header) {
+				put_short(len);
+				put_short(~len);
+			}
+
+			that.pending_buf.set(window.subarray(buf, buf + len), that.pending);
+			that.pending += len;
+		}
+
+		// Send a stored block
+		function _tr_stored_block(buf, // input block
+		stored_len, // length of input block
+		eof // true if this is the last block for a file
+		) {
+			send_bits((STORED_BLOCK << 1) + (eof ? 1 : 0), 3); // send block type
+			copy_block(buf, stored_len, true); // with header
+		}
+
+		// Determine the best encoding for the current block: dynamic trees, static
+		// trees or store, and output the encoded block to the zip file.
+		function _tr_flush_block(buf, // input block, or NULL if too old
+		stored_len, // length of input block
+		eof // true if this is the last block for a file
+		) {
+			var opt_lenb, static_lenb;// opt_len and static_len in bytes
+			var max_blindex = 0; // index of last bit length code of non zero freq
+
+			// Build the Huffman trees unless a stored block is forced
+			if (level > 0) {
+				// Construct the literal and distance trees
+				l_desc.build_tree(that);
+
+				d_desc.build_tree(that);
+
+				// At this point, opt_len and static_len are the total bit lengths
+				// of
+				// the compressed block data, excluding the tree representations.
+
+				// Build the bit length tree for the above two trees, and get the
+				// index
+				// in bl_order of the last bit length code to send.
+				max_blindex = build_bl_tree();
+
+				// Determine the best encoding. Compute first the block length in
+				// bytes
+				opt_lenb = (that.opt_len + 3 + 7) >>> 3;
+				static_lenb = (that.static_len + 3 + 7) >>> 3;
+
+				if (static_lenb <= opt_lenb)
+					opt_lenb = static_lenb;
+			} else {
+				opt_lenb = static_lenb = stored_len + 5; // force a stored block
+			}
+
+			if ((stored_len + 4 <= opt_lenb) && buf != -1) {
+				// 4: two words for the lengths
+				// The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
+				// Otherwise we can't have processed more than WSIZE input bytes
+				// since
+				// the last block flush, because compression would have been
+				// successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
+				// transform a block into a stored block.
+				_tr_stored_block(buf, stored_len, eof);
+			} else if (static_lenb == opt_lenb) {
+				send_bits((STATIC_TREES << 1) + (eof ? 1 : 0), 3);
+				compress_block(StaticTree.static_ltree, StaticTree.static_dtree);
+			} else {
+				send_bits((DYN_TREES << 1) + (eof ? 1 : 0), 3);
+				send_all_trees(l_desc.max_code + 1, d_desc.max_code + 1, max_blindex + 1);
+				compress_block(dyn_ltree, dyn_dtree);
+			}
+
+			// The above check is made mod 2^32, for files larger than 512 MB
+			// and uLong implemented on 32 bits.
+
+			init_block();
+
+			if (eof) {
+				bi_windup();
+			}
+		}
+
+		function flush_block_only(eof) {
+			_tr_flush_block(block_start >= 0 ? block_start : -1, strstart - block_start, eof);
+			block_start = strstart;
+			strm.flush_pending();
+		}
+
+		// Fill the window when the lookahead becomes insufficient.
+		// Updates strstart and lookahead.
+		//
+		// IN assertion: lookahead < MIN_LOOKAHEAD
+		// OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
+		// At least one byte has been read, or avail_in === 0; reads are
+		// performed for at least two bytes (required for the zip translate_eol
+		// option -- not supported here).
+		function fill_window() {
+			var n, m;
+			var p;
+			var more; // Amount of free space at the end of the window.
+
+			do {
+				more = (window_size - lookahead - strstart);
+
+				// Deal with !@#$% 64K limit:
+				if (more === 0 && strstart === 0 && lookahead === 0) {
+					more = w_size;
+				} else if (more == -1) {
+					// Very unlikely, but possible on 16 bit machine if strstart ==
+					// 0
+					// and lookahead == 1 (input done one byte at time)
+					more--;
+
+					// If the window is almost full and there is insufficient
+					// lookahead,
+					// move the upper half to the lower one to make room in the
+					// upper half.
+				} else if (strstart >= w_size + w_size - MIN_LOOKAHEAD) {
+					window.set(window.subarray(w_size, w_size + w_size), 0);
+
+					match_start -= w_size;
+					strstart -= w_size; // we now have strstart >= MAX_DIST
+					block_start -= w_size;
+
+					// Slide the hash table (could be avoided with 32 bit values
+					// at the expense of memory usage). We slide even when level ==
+					// 0
+					// to keep the hash table consistent if we switch back to level
+					// > 0
+					// later. (Using level 0 permanently is not an optimal usage of
+					// zlib, so we don't care about this pathological case.)
+
+					n = hash_size;
+					p = n;
+					do {
+						m = (head[--p] & 0xffff);
+						head[p] = (m >= w_size ? m - w_size : 0);
+					} while (--n !== 0);
+
+					n = w_size;
+					p = n;
+					do {
+						m = (prev[--p] & 0xffff);
+						prev[p] = (m >= w_size ? m - w_size : 0);
+						// If n is not on any hash chain, prev[n] is garbage but
+						// its value will never be used.
+					} while (--n !== 0);
+					more += w_size;
+				}
+
+				if (strm.avail_in === 0)
+					return;
+
+				// If there was no sliding:
+				// strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
+				// more == window_size - lookahead - strstart
+				// => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
+				// => more >= window_size - 2*WSIZE + 2
+				// In the BIG_MEM or MMAP case (not yet supported),
+				// window_size == input_size + MIN_LOOKAHEAD &&
+				// strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
+				// Otherwise, window_size == 2*WSIZE so more >= 2.
+				// If there was sliding, more >= WSIZE. So in all cases, more >= 2.
+
+				n = strm.read_buf(window, strstart + lookahead, more);
+				lookahead += n;
+
+				// Initialize the hash value now that we have some input:
+				if (lookahead >= MIN_MATCH) {
+					ins_h = window[strstart] & 0xff;
+					ins_h = (((ins_h) << hash_shift) ^ (window[strstart + 1] & 0xff)) & hash_mask;
+				}
+				// If the whole input has less than MIN_MATCH bytes, ins_h is
+				// garbage,
+				// but this is not important since only literal bytes will be
+				// emitted.
+			} while (lookahead < MIN_LOOKAHEAD && strm.avail_in !== 0);
+		}
+
+		// Copy without compression as much as possible from the input stream,
+		// return
+		// the current block state.
+		// This function does not insert new strings in the dictionary since
+		// uncompressible data is probably not useful. This function is used
+		// only for the level=0 compression option.
+		// NOTE: this function should be optimized to avoid extra copying from
+		// window to pending_buf.
+		function deflate_stored(flush) {
+			// Stored blocks are limited to 0xffff bytes, pending_buf is limited
+			// to pending_buf_size, and each stored block has a 5 byte header:
+
+			var max_block_size = 0xffff;
+			var max_start;
+
+			if (max_block_size > pending_buf_size - 5) {
+				max_block_size = pending_buf_size - 5;
+			}
+
+			// Copy as much as possible from input to output:
+			while (true) {
+				// Fill the window as much as possible:
+				if (lookahead <= 1) {
+					fill_window();
+					if (lookahead === 0 && flush == Z_NO_FLUSH)
+						return NeedMore;
+					if (lookahead === 0)
+						break; // flush the current block
+				}
+
+				strstart += lookahead;
+				lookahead = 0;
+
+				// Emit a stored block if pending_buf will be full:
+				max_start = block_start + max_block_size;
+				if (strstart === 0 || strstart >= max_start) {
+					// strstart === 0 is possible when wraparound on 16-bit machine
+					lookahead = (strstart - max_start);
+					strstart = max_start;
+
+					flush_block_only(false);
+					if (strm.avail_out === 0)
+						return NeedMore;
+
+				}
+
+				// Flush if we may have to slide, otherwise block_start may become
+				// negative and the data will be gone:
+				if (strstart - block_start >= w_size - MIN_LOOKAHEAD) {
+					flush_block_only(false);
+					if (strm.avail_out === 0)
+						return NeedMore;
+				}
+			}
+
+			flush_block_only(flush == Z_FINISH);
+			if (strm.avail_out === 0)
+				return (flush == Z_FINISH) ? FinishStarted : NeedMore;
+
+			return flush == Z_FINISH ? FinishDone : BlockDone;
+		}
+
+		function longest_match(cur_match) {
+			var chain_length = max_chain_length; // max hash chain length
+			var scan = strstart; // current string
+			var match; // matched string
+			var len; // length of current match
+			var best_len = prev_length; // best match length so far
+			var limit = strstart > (w_size - MIN_LOOKAHEAD) ? strstart - (w_size - MIN_LOOKAHEAD) : 0;
+			var _nice_match = nice_match;
+
+			// Stop when cur_match becomes <= limit. To simplify the code,
+			// we prevent matches with the string of window index 0.
+
+			var wmask = w_mask;
+
+			var strend = strstart + MAX_MATCH;
+			var scan_end1 = window[scan + best_len - 1];
+			var scan_end = window[scan + best_len];
+
+			// The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of
+			// 16.
+			// It is easy to get rid of this optimization if necessary.
+
+			// Do not waste too much time if we already have a good match:
+			if (prev_length >= good_match) {
+				chain_length >>= 2;
+			}
+
+			// Do not look for matches beyond the end of the input. This is
+			// necessary
+			// to make deflate deterministic.
+			if (_nice_match > lookahead)
+				_nice_match = lookahead;
+
+			do {
+				match = cur_match;
+
+				// Skip to next match if the match length cannot increase
+				// or if the match length is less than 2:
+				if (window[match + best_len] != scan_end || window[match + best_len - 1] != scan_end1 || window[match] != window[scan]
+						|| window[++match] != window[scan + 1])
+					continue;
+
+				// The check at best_len-1 can be removed because it will be made
+				// again later. (This heuristic is not always a win.)
+				// It is not necessary to compare scan[2] and match[2] since they
+				// are always equal when the other bytes match, given that
+				// the hash keys are equal and that HASH_BITS >= 8.
+				scan += 2;
+				match++;
+
+				// We check for insufficient lookahead only every 8th comparison;
+				// the 256th check will be made at strstart+258.
+				do {
+				} while (window[++scan] == window[++match] && window[++scan] == window[++match] && window[++scan] == window[++match]
+						&& window[++scan] == window[++match] && window[++scan] == window[++match] && window[++scan] == window[++match]
+						&& window[++scan] == window[++match] && window[++scan] == window[++match] && scan < strend);
+
+				len = MAX_MATCH - (strend - scan);
+				scan = strend - MAX_MATCH;
+
+				if (len > best_len) {
+					match_start = cur_match;
+					best_len = len;
+					if (len >= _nice_match)
+						break;
+					scan_end1 = window[scan + best_len - 1];
+					scan_end = window[scan + best_len];
+				}
+
+			} while ((cur_match = (prev[cur_match & wmask] & 0xffff)) > limit && --chain_length !== 0);
+
+			if (best_len <= lookahead)
+				return best_len;
+			return lookahead;
+		}
+
+		// Compress as much as possible from the input stream, return the current
+		// block state.
+		// This function does not perform lazy evaluation of matches and inserts
+		// new strings in the dictionary only for unmatched strings or for short
+		// matches. It is used only for the fast compression options.
+		function deflate_fast(flush) {
+			// short hash_head = 0; // head of the hash chain
+			var hash_head = 0; // head of the hash chain
+			var bflush; // set if current block must be flushed
+
+			while (true) {
+				// Make sure that we always have enough lookahead, except
+				// at the end of the input file. We need MAX_MATCH bytes
+				// for the next match, plus MIN_MATCH bytes to insert the
+				// string following the next match.
+				if (lookahead < MIN_LOOKAHEAD) {
+					fill_window();
+					if (lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+						return NeedMore;
+					}
+					if (lookahead === 0)
+						break; // flush the current block
+				}
+
+				// Insert the string window[strstart .. strstart+2] in the
+				// dictionary, and set hash_head to the head of the hash chain:
+				if (lookahead >= MIN_MATCH) {
+					ins_h = (((ins_h) << hash_shift) ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff)) & hash_mask;
+
+					// prev[strstart&w_mask]=hash_head=head[ins_h];
+					hash_head = (head[ins_h] & 0xffff);
+					prev[strstart & w_mask] = head[ins_h];
+					head[ins_h] = strstart;
+				}
+
+				// Find the longest match, discarding those <= prev_length.
+				// At this point we have always match_length < MIN_MATCH
+
+				if (hash_head !== 0 && ((strstart - hash_head) & 0xffff) <= w_size - MIN_LOOKAHEAD) {
+					// To simplify the code, we prevent matches with the string
+					// of window index 0 (in particular we have to avoid a match
+					// of the string with itself at the start of the input file).
+					if (strategy != Z_HUFFMAN_ONLY) {
+						match_length = longest_match(hash_head);
+					}
+					// longest_match() sets match_start
+				}
+				if (match_length >= MIN_MATCH) {
+					// check_match(strstart, match_start, match_length);
+
+					bflush = _tr_tally(strstart - match_start, match_length - MIN_MATCH);
+
+					lookahead -= match_length;
+
+					// Insert new strings in the hash table only if the match length
+					// is not too large. This saves time but degrades compression.
+					if (match_length <= max_lazy_match && lookahead >= MIN_MATCH) {
+						match_length--; // string at strstart already in hash table
+						do {
+							strstart++;
+
+							ins_h = ((ins_h << hash_shift) ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff)) & hash_mask;
+							// prev[strstart&w_mask]=hash_head=head[ins_h];
+							hash_head = (head[ins_h] & 0xffff);
+							prev[strstart & w_mask] = head[ins_h];
+							head[ins_h] = strstart;
+
+							// strstart never exceeds WSIZE-MAX_MATCH, so there are
+							// always MIN_MATCH bytes ahead.
+						} while (--match_length !== 0);
+						strstart++;
+					} else {
+						strstart += match_length;
+						match_length = 0;
+						ins_h = window[strstart] & 0xff;
+
+						ins_h = (((ins_h) << hash_shift) ^ (window[strstart + 1] & 0xff)) & hash_mask;
+						// If lookahead < MIN_MATCH, ins_h is garbage, but it does
+						// not
+						// matter since it will be recomputed at next deflate call.
+					}
+				} else {
+					// No match, output a literal byte
+
+					bflush = _tr_tally(0, window[strstart] & 0xff);
+					lookahead--;
+					strstart++;
+				}
+				if (bflush) {
+
+					flush_block_only(false);
+					if (strm.avail_out === 0)
+						return NeedMore;
+				}
+			}
+
+			flush_block_only(flush == Z_FINISH);
+			if (strm.avail_out === 0) {
+				if (flush == Z_FINISH)
+					return FinishStarted;
+				else
+					return NeedMore;
+			}
+			return flush == Z_FINISH ? FinishDone : BlockDone;
+		}
+
+		// Same as above, but achieves better compression. We use a lazy
+		// evaluation for matches: a match is finally adopted only if there is
+		// no better match at the next window position.
+		function deflate_slow(flush) {
+			// short hash_head = 0; // head of hash chain
+			var hash_head = 0; // head of hash chain
+			var bflush; // set if current block must be flushed
+			var max_insert;
+
+			// Process the input block.
+			while (true) {
+				// Make sure that we always have enough lookahead, except
+				// at the end of the input file. We need MAX_MATCH bytes
+				// for the next match, plus MIN_MATCH bytes to insert the
+				// string following the next match.
+
+				if (lookahead < MIN_LOOKAHEAD) {
+					fill_window();
+					if (lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+						return NeedMore;
+					}
+					if (lookahead === 0)
+						break; // flush the current block
+				}
+
+				// Insert the string window[strstart .. strstart+2] in the
+				// dictionary, and set hash_head to the head of the hash chain:
+
+				if (lookahead >= MIN_MATCH) {
+					ins_h = (((ins_h) << hash_shift) ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff)) & hash_mask;
+					// prev[strstart&w_mask]=hash_head=head[ins_h];
+					hash_head = (head[ins_h] & 0xffff);
+					prev[strstart & w_mask] = head[ins_h];
+					head[ins_h] = strstart;
+				}
+
+				// Find the longest match, discarding those <= prev_length.
+				prev_length = match_length;
+				prev_match = match_start;
+				match_length = MIN_MATCH - 1;
+
+				if (hash_head !== 0 && prev_length < max_lazy_match && ((strstart - hash_head) & 0xffff) <= w_size - MIN_LOOKAHEAD) {
+					// To simplify the code, we prevent matches with the string
+					// of window index 0 (in particular we have to avoid a match
+					// of the string with itself at the start of the input file).
+
+					if (strategy != Z_HUFFMAN_ONLY) {
+						match_length = longest_match(hash_head);
+					}
+					// longest_match() sets match_start
+
+					if (match_length <= 5 && (strategy == Z_FILTERED || (match_length == MIN_MATCH && strstart - match_start > 4096))) {
+
+						// If prev_match is also MIN_MATCH, match_start is garbage
+						// but we will ignore the current match anyway.
+						match_length = MIN_MATCH - 1;
+					}
+				}
+
+				// If there was a match at the previous step and the current
+				// match is not better, output the previous match:
+				if (prev_length >= MIN_MATCH && match_length <= prev_length) {
+					max_insert = strstart + lookahead - MIN_MATCH;
+					// Do not insert strings in hash table beyond this.
+
+					// check_match(strstart-1, prev_match, prev_length);
+
+					bflush = _tr_tally(strstart - 1 - prev_match, prev_length - MIN_MATCH);
+
+					// Insert in hash table all strings up to the end of the match.
+					// strstart-1 and strstart are already inserted. If there is not
+					// enough lookahead, the last two strings are not inserted in
+					// the hash table.
+					lookahead -= prev_length - 1;
+					prev_length -= 2;
+					do {
+						if (++strstart <= max_insert) {
+							ins_h = (((ins_h) << hash_shift) ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff)) & hash_mask;
+							// prev[strstart&w_mask]=hash_head=head[ins_h];
+							hash_head = (head[ins_h] & 0xffff);
+							prev[strstart & w_mask] = head[ins_h];
+							head[ins_h] = strstart;
+						}
+					} while (--prev_length !== 0);
+					match_available = 0;
+					match_length = MIN_MATCH - 1;
+					strstart++;
+
+					if (bflush) {
+						flush_block_only(false);
+						if (strm.avail_out === 0)
+							return NeedMore;
+					}
+				} else if (match_available !== 0) {
+
+					// If there was no match at the previous position, output a
+					// single literal. If there was a match but the current match
+					// is longer, truncate the previous match to a single literal.
+
+					bflush = _tr_tally(0, window[strstart - 1] & 0xff);
+
+					if (bflush) {
+						flush_block_only(false);
+					}
+					strstart++;
+					lookahead--;
+					if (strm.avail_out === 0)
+						return NeedMore;
+				} else {
+					// There is no previous match to compare with, wait for
+					// the next step to decide.
+
+					match_available = 1;
+					strstart++;
+					lookahead--;
+				}
+			}
+
+			if (match_available !== 0) {
+				bflush = _tr_tally(0, window[strstart - 1] & 0xff);
+				match_available = 0;
+			}
+			flush_block_only(flush == Z_FINISH);
+
+			if (strm.avail_out === 0) {
+				if (flush == Z_FINISH)
+					return FinishStarted;
+				else
+					return NeedMore;
+			}
+
+			return flush == Z_FINISH ? FinishDone : BlockDone;
+		}
+
+		function deflateReset(strm) {
+			strm.total_in = strm.total_out = 0;
+			strm.msg = null; //
+			
+			that.pending = 0;
+			that.pending_out = 0;
+
+			status = BUSY_STATE;
+
+			last_flush = Z_NO_FLUSH;
+
+			tr_init();
+			lm_init();
+			return Z_OK;
+		}
+
+		that.deflateInit = function(strm, _level, bits, _method, memLevel, _strategy) {
+			if (!_method)
+				_method = Z_DEFLATED;
+			if (!memLevel)
+				memLevel = DEF_MEM_LEVEL;
+			if (!_strategy)
+				_strategy = Z_DEFAULT_STRATEGY;
+
+			// byte[] my_version=ZLIB_VERSION;
+
+			//
+			// if (!version || version[0] != my_version[0]
+			// || stream_size != sizeof(z_stream)) {
+			// return Z_VERSION_ERROR;
+			// }
+
+			strm.msg = null;
+
+			if (_level == Z_DEFAULT_COMPRESSION)
+				_level = 6;
+
+			if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || _method != Z_DEFLATED || bits < 9 || bits > 15 || _level < 0 || _level > 9 || _strategy < 0
+					|| _strategy > Z_HUFFMAN_ONLY) {
+				return Z_STREAM_ERROR;
+			}
+
+			strm.dstate = that;
+
+			w_bits = bits;
+			w_size = 1 << w_bits;
+			w_mask = w_size - 1;
+
+			hash_bits = memLevel + 7;
+			hash_size = 1 << hash_bits;
+			hash_mask = hash_size - 1;
+			hash_shift = Math.floor((hash_bits + MIN_MATCH - 1) / MIN_MATCH);
+
+			window = new Uint8Array(w_size * 2);
+			prev = [];
+			head = [];
+
+			lit_bufsize = 1 << (memLevel + 6); // 16K elements by default
+
+			// We overlay pending_buf and d_buf+l_buf. This works since the average
+			// output size for (length,distance) codes is <= 24 bits.
+			that.pending_buf = new Uint8Array(lit_bufsize * 4);
+			pending_buf_size = lit_bufsize * 4;
+
+			d_buf = Math.floor(lit_bufsize / 2);
+			l_buf = (1 + 2) * lit_bufsize;
+
+			level = _level;
+
+			strategy = _strategy;
+			method = _method & 0xff;
+
+			return deflateReset(strm);
+		};
+
+		that.deflateEnd = function() {
+			if (status != INIT_STATE && status != BUSY_STATE && status != FINISH_STATE) {
+				return Z_STREAM_ERROR;
+			}
+			// Deallocate in reverse order of allocations:
+			that.pending_buf = null;
+			head = null;
+			prev = null;
+			window = null;
+			// free
+			that.dstate = null;
+			return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;
+		};
+
+		that.deflateParams = function(strm, _level, _strategy) {
+			var err = Z_OK;
+
+			if (_level == Z_DEFAULT_COMPRESSION) {
+				_level = 6;
+			}
+			if (_level < 0 || _level > 9 || _strategy < 0 || _strategy > Z_HUFFMAN_ONLY) {
+				return Z_STREAM_ERROR;
+			}
+
+			if (config_table[level].func != config_table[_level].func && strm.total_in !== 0) {
+				// Flush the last buffer:
+				err = strm.deflate(Z_PARTIAL_FLUSH);
+			}
+
+			if (level != _level) {
+				level = _level;
+				max_lazy_match = config_table[level].max_lazy;
+				good_match = config_table[level].good_length;
+				nice_match = config_table[level].nice_length;
+				max_chain_length = config_table[level].max_chain;
+			}
+			strategy = _strategy;
+			return err;
+		};
+
+		that.deflateSetDictionary = function(strm, dictionary, dictLength) {
+			var length = dictLength;
+			var n, index = 0;
+
+			if (!dictionary || status != INIT_STATE)
+				return Z_STREAM_ERROR;
+
+			if (length < MIN_MATCH)
+				return Z_OK;
+			if (length > w_size - MIN_LOOKAHEAD) {
+				length = w_size - MIN_LOOKAHEAD;
+				index = dictLength - length; // use the tail of the dictionary
+			}
+			window.set(dictionary.subarray(index, index + length), 0);
+
+			strstart = length;
+			block_start = length;
+
+			// Insert all strings in the hash table (except for the last two bytes).
+			// s->lookahead stays null, so s->ins_h will be recomputed at the next
+			// call of fill_window.
+
+			ins_h = window[0] & 0xff;
+			ins_h = (((ins_h) << hash_shift) ^ (window[1] & 0xff)) & hash_mask;
+
+			for (n = 0; n <= length - MIN_MATCH; n++) {
+				ins_h = (((ins_h) << hash_shift) ^ (window[(n) + (MIN_MATCH - 1)] & 0xff)) & hash_mask;
+				prev[n & w_mask] = head[ins_h];
+				head[ins_h] = n;
+			}
+			return Z_OK;
+		};
+
+		that.deflate = function(_strm, flush) {
+			var i, header, level_flags, old_flush, bstate;
+
+			if (flush > Z_FINISH || flush < 0) {
+				return Z_STREAM_ERROR;
+			}
+
+			if (!_strm.next_out || (!_strm.next_in && _strm.avail_in !== 0) || (status == FINISH_STATE && flush != Z_FINISH)) {
+				_strm.msg = z_errmsg[Z_NEED_DICT - (Z_STREAM_ERROR)];
+				return Z_STREAM_ERROR;
+			}
+			if (_strm.avail_out === 0) {
+				_strm.msg = z_errmsg[Z_NEED_DICT - (Z_BUF_ERROR)];
+				return Z_BUF_ERROR;
+			}
+
+			strm = _strm; // just in case
+			old_flush = last_flush;
+			last_flush = flush;
+
+			// Write the zlib header
+			if (status == INIT_STATE) {
+				header = (Z_DEFLATED + ((w_bits - 8) << 4)) << 8;
+				level_flags = ((level - 1) & 0xff) >> 1;
+
+				if (level_flags > 3)
+					level_flags = 3;
+				header |= (level_flags << 6);
+				if (strstart !== 0)
+					header |= PRESET_DICT;
+				header += 31 - (header % 31);
+
+				status = BUSY_STATE;
+				putShortMSB(header);
+			}
+
+			// Flush as much pending output as possible
+			if (that.pending !== 0) {
+				strm.flush_pending();
+				if (strm.avail_out === 0) {
+					// console.log(" avail_out==0");
+					// Since avail_out is 0, deflate will be called again with
+					// more output space, but possibly with both pending and
+					// avail_in equal to zero. There won't be anything to do,
+					// but this is not an error situation so make sure we
+					// return OK instead of BUF_ERROR at next call of deflate:
+					last_flush = -1;
+					return Z_OK;
+				}
+
+				// Make sure there is something to do and avoid duplicate
+				// consecutive
+				// flushes. For repeated and useless calls with Z_FINISH, we keep
+				// returning Z_STREAM_END instead of Z_BUFF_ERROR.
+			} else if (strm.avail_in === 0 && flush <= old_flush && flush != Z_FINISH) {
+				strm.msg = z_errmsg[Z_NEED_DICT - (Z_BUF_ERROR)];
+				return Z_BUF_ERROR;
+			}
+
+			// User must not provide more input after the first FINISH:
+			if (status == FINISH_STATE && strm.avail_in !== 0) {
+				_strm.msg = z_errmsg[Z_NEED_DICT - (Z_BUF_ERROR)];
+				return Z_BUF_ERROR;
+			}
+
+			// Start a new block or continue the current one.
+			if (strm.avail_in !== 0 || lookahead !== 0 || (flush != Z_NO_FLUSH && status != FINISH_STATE)) {
+				bstate = -1;
+				switch (config_table[level].func) {
+				case STORED:
+					bstate = deflate_stored(flush);
+					break;
+				case FAST:
+					bstate = deflate_fast(flush);
+					break;
+				case SLOW:
+					bstate = deflate_slow(flush);
+					break;
+				default:
+				}
+
+				if (bstate == FinishStarted || bstate == FinishDone) {
+					status = FINISH_STATE;
+				}
+				if (bstate == NeedMore || bstate == FinishStarted) {
+					if (strm.avail_out === 0) {
+						last_flush = -1; // avoid BUF_ERROR next call, see above
+					}
+					return Z_OK;
+					// If flush != Z_NO_FLUSH && avail_out === 0, the next call
+					// of deflate should use the same flush parameter to make sure
+					// that the flush is complete. So we don't have to output an
+					// empty block here, this will be done at next call. This also
+					// ensures that for a very small output buffer, we emit at most
+					// one empty block.
+				}
+
+				if (bstate == BlockDone) {
+					if (flush == Z_PARTIAL_FLUSH) {
+						_tr_align();
+					} else { // FULL_FLUSH or SYNC_FLUSH
+						_tr_stored_block(0, 0, false);
+						// For a full flush, this empty block will be recognized
+						// as a special marker by inflate_sync().
+						if (flush == Z_FULL_FLUSH) {
+							// state.head[s.hash_size-1]=0;
+							for (i = 0; i < hash_size/*-1*/; i++)
+								// forget history
+								head[i] = 0;
+						}
+					}
+					strm.flush_pending();
+					if (strm.avail_out === 0) {
+						last_flush = -1; // avoid BUF_ERROR at next call, see above
+						return Z_OK;
+					}
+				}
+			}
+
+			if (flush != Z_FINISH)
+				return Z_OK;
+			return Z_STREAM_END;
+		};
+	}
+
+	// ZStream
+
+	function ZStream() {
+		var that = this;
+		that.next_in_index = 0;
+		that.next_out_index = 0;
+		// that.next_in; // next input byte
+		that.avail_in = 0; // number of bytes available at next_in
+		that.total_in = 0; // total nb of input bytes read so far
+		// that.next_out; // next output byte should be put there
+		that.avail_out = 0; // remaining free space at next_out
+		that.total_out = 0; // total nb of bytes output so far
+		// that.msg;
+		// that.dstate;
+	}
+
+	ZStream.prototype = {
+		deflateInit : function(level, bits) {
+			var that = this;
+			that.dstate = new Deflate();
+			if (!bits)
+				bits = MAX_BITS;
+			return that.dstate.deflateInit(that, level, bits);
+		},
+
+		deflate : function(flush) {
+			var that = this;
+			if (!that.dstate) {
+				return Z_STREAM_ERROR;
+			}
+			return that.dstate.deflate(that, flush);
+		},
+
+		deflateEnd : function() {
+			var that = this;
+			if (!that.dstate)
+				return Z_STREAM_ERROR;
+			var ret = that.dstate.deflateEnd();
+			that.dstate = null;
+			return ret;
+		},
+
+		deflateParams : function(level, strategy) {
+			var that = this;
+			if (!that.dstate)
+				return Z_STREAM_ERROR;
+			return that.dstate.deflateParams(that, level, strategy);
+		},
+
+		deflateSetDictionary : function(dictionary, dictLength) {
+			var that = this;
+			if (!that.dstate)
+				return Z_STREAM_ERROR;
+			return that.dstate.deflateSetDictionary(that, dictionary, dictLength);
+		},
+
+		// Read a new buffer from the current input stream, update the
+		// total number of bytes read. All deflate() input goes through
+		// this function so some applications may wish to modify it to avoid
+		// allocating a large strm->next_in buffer and copying from it.
+		// (See also flush_pending()).
+		read_buf : function(buf, start, size) {
+			var that = this;
+			var len = that.avail_in;
+			if (len > size)
+				len = size;
+			if (len === 0)
+				return 0;
+			that.avail_in -= len;
+			buf.set(that.next_in.subarray(that.next_in_index, that.next_in_index + len), start);
+			that.next_in_index += len;
+			that.total_in += len;
+			return len;
+		},
+
+		// Flush as much pending output as possible. All deflate() output goes
+		// through this function so some applications may wish to modify it
+		// to avoid allocating a large strm->next_out buffer and copying into it.
+		// (See also read_buf()).
+		flush_pending : function() {
+			var that = this;
+			var len = that.dstate.pending;
+
+			if (len > that.avail_out)
+				len = that.avail_out;
+			if (len === 0)
+				return;
+
+			// if (that.dstate.pending_buf.length <= that.dstate.pending_out || that.next_out.length <= that.next_out_index
+			// || that.dstate.pending_buf.length < (that.dstate.pending_out + len) || that.next_out.length < (that.next_out_index +
+			// len)) {
+			// console.log(that.dstate.pending_buf.length + ", " + that.dstate.pending_out + ", " + that.next_out.length + ", " +
+			// that.next_out_index + ", " + len);
+			// console.log("avail_out=" + that.avail_out);
+			// }
+
+			that.next_out.set(that.dstate.pending_buf.subarray(that.dstate.pending_out, that.dstate.pending_out + len), that.next_out_index);
+
+			that.next_out_index += len;
+			that.dstate.pending_out += len;
+			that.total_out += len;
+			that.avail_out -= len;
+			that.dstate.pending -= len;
+			if (that.dstate.pending === 0) {
+				that.dstate.pending_out = 0;
+			}
+		}
+	};
+
+	// Deflater
+
+	function Deflater(level) {
+		var that = this;
+		var z = new ZStream();
+		var bufsize = 512;
+		var flush = Z_NO_FLUSH;
+		var buf = new Uint8Array(bufsize);
+
+		if (typeof level == "undefined")
+			level = Z_DEFAULT_COMPRESSION;
+		z.deflateInit(level);
+		z.next_out = buf;
+
+		that.append = function(data, onprogress) {
+			var err, buffers = [], lastIndex = 0, bufferIndex = 0, bufferSize = 0, array;
+			if (!data.length)
+				return;
+			z.next_in_index = 0;
+			z.next_in = data;
+			z.avail_in = data.length;
+			do {
+				z.next_out_index = 0;
+				z.avail_out = bufsize;
+				err = z.deflate(flush);
+				if (err != Z_OK)
+					throw "deflating: " + z.msg;
+				if (z.next_out_index)
+					if (z.next_out_index == bufsize)
+						buffers.push(new Uint8Array(buf));
+					else
+						buffers.push(new Uint8Array(buf.subarray(0, z.next_out_index)));
+				bufferSize += z.next_out_index;
+				if (onprogress && z.next_in_index > 0 && z.next_in_index != lastIndex) {
+					onprogress(z.next_in_index);
+					lastIndex = z.next_in_index;
+				}
+			} while (z.avail_in > 0 || z.avail_out === 0);
+			array = new Uint8Array(bufferSize);
+			buffers.forEach(function(chunk) {
+				array.set(chunk, bufferIndex);
+				bufferIndex += chunk.length;
+			});
+			return array;
+		};
+		that.flush = function() {
+			var err, buffers = [], bufferIndex = 0, bufferSize = 0, array;
+			do {
+				z.next_out_index = 0;
+				z.avail_out = bufsize;
+				err = z.deflate(Z_FINISH);
+				if (err != Z_STREAM_END && err != Z_OK)
+					throw "deflating: " + z.msg;
+				if (bufsize - z.avail_out > 0)
+					buffers.push(new Uint8Array(buf.subarray(0, z.next_out_index)));
+				bufferSize += z.next_out_index;
+			} while (z.avail_in > 0 || z.avail_out === 0);
+			z.deflateEnd();
+			array = new Uint8Array(bufferSize);
+			buffers.forEach(function(chunk) {
+				array.set(chunk, bufferIndex);
+				bufferIndex += chunk.length;
+			});
+			return array;
+		};
+	}
+
+	var deflater;
+
+	if (obj.zip)
+		obj.zip.Deflater = Deflater;
+	else {
+		deflater = new Deflater();
+		obj.addEventListener("message", function(event) {
+			var message = event.data;
+			if (message.init) {
+				deflater = new Deflater(message.level);
+				obj.postMessage({
+					oninit : true
+				});
+			}
+			if (message.append)
+				obj.postMessage({
+					onappend : true,
+					data : deflater.append(message.data, function(current) {
+						obj.postMessage({
+							progress : true,
+							current : current
+						});
+					})
+				});
+			if (message.flush)
+				obj.postMessage({
+					onflush : true,
+					data : deflater.flush()
+				});
+		}, false);
+	}
+
+})(this);
diff --git a/zip.js/WebContent/inflate.js b/zip.js/WebContent/inflate.js
new file mode 100644
index 0000000..cc0e012
--- /dev/null
+++ b/zip.js/WebContent/inflate.js
@@ -0,0 +1,2163 @@
+/*
+ Copyright (c) 2013 Gildas Lormeau. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright 
+ notice, this list of conditions and the following disclaimer in 
+ the documentation and/or other materials provided with the distribution.
+
+ 3. The names of the authors may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
+ INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This program is based on JZlib 1.0.2 ymnk, JCraft,Inc.
+ * JZlib is based on zlib-1.1.3, so all credit should go authors
+ * Jean-loup Gailly(jloup at gzip.org) and Mark Adler(madler at alumni.caltech.edu)
+ * and contributors of zlib.
+ */
+
+(function(obj) {
+
+	// Global
+	var MAX_BITS = 15;
+
+	var Z_OK = 0;
+	var Z_STREAM_END = 1;
+	var Z_NEED_DICT = 2;
+	var Z_STREAM_ERROR = -2;
+	var Z_DATA_ERROR = -3;
+	var Z_MEM_ERROR = -4;
+	var Z_BUF_ERROR = -5;
+
+	var inflate_mask = [ 0x00000000, 0x00000001, 0x00000003, 0x00000007, 0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff, 0x000001ff, 0x000003ff,
+			0x000007ff, 0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff ];
+
+	var MANY = 1440;
+
+	// JZlib version : "1.0.2"
+	var Z_NO_FLUSH = 0;
+	var Z_FINISH = 4;
+
+	// InfTree
+	var fixed_bl = 9;
+	var fixed_bd = 5;
+
+	var fixed_tl = [ 96, 7, 256, 0, 8, 80, 0, 8, 16, 84, 8, 115, 82, 7, 31, 0, 8, 112, 0, 8, 48, 0, 9, 192, 80, 7, 10, 0, 8, 96, 0, 8, 32, 0, 9, 160, 0, 8, 0,
+			0, 8, 128, 0, 8, 64, 0, 9, 224, 80, 7, 6, 0, 8, 88, 0, 8, 24, 0, 9, 144, 83, 7, 59, 0, 8, 120, 0, 8, 56, 0, 9, 208, 81, 7, 17, 0, 8, 104, 0, 8, 40,
+			0, 9, 176, 0, 8, 8, 0, 8, 136, 0, 8, 72, 0, 9, 240, 80, 7, 4, 0, 8, 84, 0, 8, 20, 85, 8, 227, 83, 7, 43, 0, 8, 116, 0, 8, 52, 0, 9, 200, 81, 7, 13,
+			0, 8, 100, 0, 8, 36, 0, 9, 168, 0, 8, 4, 0, 8, 132, 0, 8, 68, 0, 9, 232, 80, 7, 8, 0, 8, 92, 0, 8, 28, 0, 9, 152, 84, 7, 83, 0, 8, 124, 0, 8, 60,
+			0, 9, 216, 82, 7, 23, 0, 8, 108, 0, 8, 44, 0, 9, 184, 0, 8, 12, 0, 8, 140, 0, 8, 76, 0, 9, 248, 80, 7, 3, 0, 8, 82, 0, 8, 18, 85, 8, 163, 83, 7,
+			35, 0, 8, 114, 0, 8, 50, 0, 9, 196, 81, 7, 11, 0, 8, 98, 0, 8, 34, 0, 9, 164, 0, 8, 2, 0, 8, 130, 0, 8, 66, 0, 9, 228, 80, 7, 7, 0, 8, 90, 0, 8,
+			26, 0, 9, 148, 84, 7, 67, 0, 8, 122, 0, 8, 58, 0, 9, 212, 82, 7, 19, 0, 8, 106, 0, 8, 42, 0, 9, 180, 0, 8, 10, 0, 8, 138, 0, 8, 74, 0, 9, 244, 80,
+			7, 5, 0, 8, 86, 0, 8, 22, 192, 8, 0, 83, 7, 51, 0, 8, 118, 0, 8, 54, 0, 9, 204, 81, 7, 15, 0, 8, 102, 0, 8, 38, 0, 9, 172, 0, 8, 6, 0, 8, 134, 0,
+			8, 70, 0, 9, 236, 80, 7, 9, 0, 8, 94, 0, 8, 30, 0, 9, 156, 84, 7, 99, 0, 8, 126, 0, 8, 62, 0, 9, 220, 82, 7, 27, 0, 8, 110, 0, 8, 46, 0, 9, 188, 0,
+			8, 14, 0, 8, 142, 0, 8, 78, 0, 9, 252, 96, 7, 256, 0, 8, 81, 0, 8, 17, 85, 8, 131, 82, 7, 31, 0, 8, 113, 0, 8, 49, 0, 9, 194, 80, 7, 10, 0, 8, 97,
+			0, 8, 33, 0, 9, 162, 0, 8, 1, 0, 8, 129, 0, 8, 65, 0, 9, 226, 80, 7, 6, 0, 8, 89, 0, 8, 25, 0, 9, 146, 83, 7, 59, 0, 8, 121, 0, 8, 57, 0, 9, 210,
+			81, 7, 17, 0, 8, 105, 0, 8, 41, 0, 9, 178, 0, 8, 9, 0, 8, 137, 0, 8, 73, 0, 9, 242, 80, 7, 4, 0, 8, 85, 0, 8, 21, 80, 8, 258, 83, 7, 43, 0, 8, 117,
+			0, 8, 53, 0, 9, 202, 81, 7, 13, 0, 8, 101, 0, 8, 37, 0, 9, 170, 0, 8, 5, 0, 8, 133, 0, 8, 69, 0, 9, 234, 80, 7, 8, 0, 8, 93, 0, 8, 29, 0, 9, 154,
+			84, 7, 83, 0, 8, 125, 0, 8, 61, 0, 9, 218, 82, 7, 23, 0, 8, 109, 0, 8, 45, 0, 9, 186, 0, 8, 13, 0, 8, 141, 0, 8, 77, 0, 9, 250, 80, 7, 3, 0, 8, 83,
+			0, 8, 19, 85, 8, 195, 83, 7, 35, 0, 8, 115, 0, 8, 51, 0, 9, 198, 81, 7, 11, 0, 8, 99, 0, 8, 35, 0, 9, 166, 0, 8, 3, 0, 8, 131, 0, 8, 67, 0, 9, 230,
+			80, 7, 7, 0, 8, 91, 0, 8, 27, 0, 9, 150, 84, 7, 67, 0, 8, 123, 0, 8, 59, 0, 9, 214, 82, 7, 19, 0, 8, 107, 0, 8, 43, 0, 9, 182, 0, 8, 11, 0, 8, 139,
+			0, 8, 75, 0, 9, 246, 80, 7, 5, 0, 8, 87, 0, 8, 23, 192, 8, 0, 83, 7, 51, 0, 8, 119, 0, 8, 55, 0, 9, 206, 81, 7, 15, 0, 8, 103, 0, 8, 39, 0, 9, 174,
+			0, 8, 7, 0, 8, 135, 0, 8, 71, 0, 9, 238, 80, 7, 9, 0, 8, 95, 0, 8, 31, 0, 9, 158, 84, 7, 99, 0, 8, 127, 0, 8, 63, 0, 9, 222, 82, 7, 27, 0, 8, 111,
+			0, 8, 47, 0, 9, 190, 0, 8, 15, 0, 8, 143, 0, 8, 79, 0, 9, 254, 96, 7, 256, 0, 8, 80, 0, 8, 16, 84, 8, 115, 82, 7, 31, 0, 8, 112, 0, 8, 48, 0, 9,
+			193, 80, 7, 10, 0, 8, 96, 0, 8, 32, 0, 9, 161, 0, 8, 0, 0, 8, 128, 0, 8, 64, 0, 9, 225, 80, 7, 6, 0, 8, 88, 0, 8, 24, 0, 9, 145, 83, 7, 59, 0, 8,
+			120, 0, 8, 56, 0, 9, 209, 81, 7, 17, 0, 8, 104, 0, 8, 40, 0, 9, 177, 0, 8, 8, 0, 8, 136, 0, 8, 72, 0, 9, 241, 80, 7, 4, 0, 8, 84, 0, 8, 20, 85, 8,
+			227, 83, 7, 43, 0, 8, 116, 0, 8, 52, 0, 9, 201, 81, 7, 13, 0, 8, 100, 0, 8, 36, 0, 9, 169, 0, 8, 4, 0, 8, 132, 0, 8, 68, 0, 9, 233, 80, 7, 8, 0, 8,
+			92, 0, 8, 28, 0, 9, 153, 84, 7, 83, 0, 8, 124, 0, 8, 60, 0, 9, 217, 82, 7, 23, 0, 8, 108, 0, 8, 44, 0, 9, 185, 0, 8, 12, 0, 8, 140, 0, 8, 76, 0, 9,
+			249, 80, 7, 3, 0, 8, 82, 0, 8, 18, 85, 8, 163, 83, 7, 35, 0, 8, 114, 0, 8, 50, 0, 9, 197, 81, 7, 11, 0, 8, 98, 0, 8, 34, 0, 9, 165, 0, 8, 2, 0, 8,
+			130, 0, 8, 66, 0, 9, 229, 80, 7, 7, 0, 8, 90, 0, 8, 26, 0, 9, 149, 84, 7, 67, 0, 8, 122, 0, 8, 58, 0, 9, 213, 82, 7, 19, 0, 8, 106, 0, 8, 42, 0, 9,
+			181, 0, 8, 10, 0, 8, 138, 0, 8, 74, 0, 9, 245, 80, 7, 5, 0, 8, 86, 0, 8, 22, 192, 8, 0, 83, 7, 51, 0, 8, 118, 0, 8, 54, 0, 9, 205, 81, 7, 15, 0, 8,
+			102, 0, 8, 38, 0, 9, 173, 0, 8, 6, 0, 8, 134, 0, 8, 70, 0, 9, 237, 80, 7, 9, 0, 8, 94, 0, 8, 30, 0, 9, 157, 84, 7, 99, 0, 8, 126, 0, 8, 62, 0, 9,
+			221, 82, 7, 27, 0, 8, 110, 0, 8, 46, 0, 9, 189, 0, 8, 14, 0, 8, 142, 0, 8, 78, 0, 9, 253, 96, 7, 256, 0, 8, 81, 0, 8, 17, 85, 8, 131, 82, 7, 31, 0,
+			8, 113, 0, 8, 49, 0, 9, 195, 80, 7, 10, 0, 8, 97, 0, 8, 33, 0, 9, 163, 0, 8, 1, 0, 8, 129, 0, 8, 65, 0, 9, 227, 80, 7, 6, 0, 8, 89, 0, 8, 25, 0, 9,
+			147, 83, 7, 59, 0, 8, 121, 0, 8, 57, 0, 9, 211, 81, 7, 17, 0, 8, 105, 0, 8, 41, 0, 9, 179, 0, 8, 9, 0, 8, 137, 0, 8, 73, 0, 9, 243, 80, 7, 4, 0, 8,
+			85, 0, 8, 21, 80, 8, 258, 83, 7, 43, 0, 8, 117, 0, 8, 53, 0, 9, 203, 81, 7, 13, 0, 8, 101, 0, 8, 37, 0, 9, 171, 0, 8, 5, 0, 8, 133, 0, 8, 69, 0, 9,
+			235, 80, 7, 8, 0, 8, 93, 0, 8, 29, 0, 9, 155, 84, 7, 83, 0, 8, 125, 0, 8, 61, 0, 9, 219, 82, 7, 23, 0, 8, 109, 0, 8, 45, 0, 9, 187, 0, 8, 13, 0, 8,
+			141, 0, 8, 77, 0, 9, 251, 80, 7, 3, 0, 8, 83, 0, 8, 19, 85, 8, 195, 83, 7, 35, 0, 8, 115, 0, 8, 51, 0, 9, 199, 81, 7, 11, 0, 8, 99, 0, 8, 35, 0, 9,
+			167, 0, 8, 3, 0, 8, 131, 0, 8, 67, 0, 9, 231, 80, 7, 7, 0, 8, 91, 0, 8, 27, 0, 9, 151, 84, 7, 67, 0, 8, 123, 0, 8, 59, 0, 9, 215, 82, 7, 19, 0, 8,
+			107, 0, 8, 43, 0, 9, 183, 0, 8, 11, 0, 8, 139, 0, 8, 75, 0, 9, 247, 80, 7, 5, 0, 8, 87, 0, 8, 23, 192, 8, 0, 83, 7, 51, 0, 8, 119, 0, 8, 55, 0, 9,
+			207, 81, 7, 15, 0, 8, 103, 0, 8, 39, 0, 9, 175, 0, 8, 7, 0, 8, 135, 0, 8, 71, 0, 9, 239, 80, 7, 9, 0, 8, 95, 0, 8, 31, 0, 9, 159, 84, 7, 99, 0, 8,
+			127, 0, 8, 63, 0, 9, 223, 82, 7, 27, 0, 8, 111, 0, 8, 47, 0, 9, 191, 0, 8, 15, 0, 8, 143, 0, 8, 79, 0, 9, 255 ];
+	var fixed_td = [ 80, 5, 1, 87, 5, 257, 83, 5, 17, 91, 5, 4097, 81, 5, 5, 89, 5, 1025, 85, 5, 65, 93, 5, 16385, 80, 5, 3, 88, 5, 513, 84, 5, 33, 92, 5,
+			8193, 82, 5, 9, 90, 5, 2049, 86, 5, 129, 192, 5, 24577, 80, 5, 2, 87, 5, 385, 83, 5, 25, 91, 5, 6145, 81, 5, 7, 89, 5, 1537, 85, 5, 97, 93, 5,
+			24577, 80, 5, 4, 88, 5, 769, 84, 5, 49, 92, 5, 12289, 82, 5, 13, 90, 5, 3073, 86, 5, 193, 192, 5, 24577 ];
+
+	// Tables for deflate from PKZIP's appnote.txt.
+	var cplens = [ // Copy lengths for literal codes 257..285
+	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 ];
+
+	// see note #13 above about 258
+	var cplext = [ // Extra bits for literal codes 257..285
+	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, 112, 112 // 112==invalid
+	];
+
+	var cpdist = [ // Copy offsets for distance codes 0..29
+	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 cpdext = [ // Extra bits for distance codes
+	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 ];
+
+	// If BMAX needs to be larger than 16, then h and x[] should be uLong.
+	var BMAX = 15; // maximum bit length of any code
+
+	function InfTree() {
+		var that = this;
+
+		var hn; // hufts used in space
+		var v; // work area for huft_build
+		var c; // bit length count table
+		var r; // table entry for structure assignment
+		var u; // table stack
+		var x; // bit offsets, then code stack
+
+		function huft_build(b, // code lengths in bits (all assumed <=
+		// BMAX)
+		bindex, n, // number of codes (assumed <= 288)
+		s, // number of simple-valued codes (0..s-1)
+		d, // list of base values for non-simple codes
+		e, // list of extra bits for non-simple codes
+		t, // result: starting table
+		m, // maximum lookup bits, returns actual
+		hp,// space for trees
+		hn,// hufts used in space
+		v // working area: values in order of bit length
+		) {
+			// Given a list of code lengths and a maximum table size, make a set of
+			// tables to decode that set of codes. Return Z_OK on success,
+			// Z_BUF_ERROR
+			// if the given code set is incomplete (the tables are still built in
+			// this
+			// case), Z_DATA_ERROR if the input is invalid (an over-subscribed set
+			// of
+			// lengths), or Z_MEM_ERROR if not enough memory.
+
+			var a; // counter for codes of length k
+			var f; // i repeats in table every f entries
+			var g; // maximum code length
+			var h; // table level
+			var i; // counter, current code
+			var j; // counter
+			var k; // number of bits in current code
+			var l; // bits per table (returned in m)
+			var mask; // (1 << w) - 1, to avoid cc -O bug on HP
+			var p; // pointer into c[], b[], or v[]
+			var q; // points to current table
+			var w; // bits before this table == (l * h)
+			var xp; // pointer into x
+			var y; // number of dummy codes added
+			var z; // number of entries in current table
+
+			// Generate counts for each bit length
+
+			p = 0;
+			i = n;
+			do {
+				c[b[bindex + p]]++;
+				p++;
+				i--; // assume all entries <= BMAX
+			} while (i !== 0);
+
+			if (c[0] == n) { // null input--all zero length codes
+				t[0] = -1;
+				m[0] = 0;
+				return Z_OK;
+			}
+
+			// Find minimum and maximum length, bound *m by those
+			l = m[0];
+			for (j = 1; j <= BMAX; j++)
+				if (c[j] !== 0)
+					break;
+			k = j; // minimum code length
+			if (l < j) {
+				l = j;
+			}
+			for (i = BMAX; i !== 0; i--) {
+				if (c[i] !== 0)
+					break;
+			}
+			g = i; // maximum code length
+			if (l > i) {
+				l = i;
+			}
+			m[0] = l;
+
+			// Adjust last length count to fill out codes, if needed
+			for (y = 1 << j; j < i; j++, y <<= 1) {
+				if ((y -= c[j]) < 0) {
+					return Z_DATA_ERROR;
+				}
+			}
+			if ((y -= c[i]) < 0) {
+				return Z_DATA_ERROR;
+			}
+			c[i] += y;
+
+			// Generate starting offsets into the value table for each length
+			x[1] = j = 0;
+			p = 1;
+			xp = 2;
+			while (--i !== 0) { // note that i == g from above
+				x[xp] = (j += c[p]);
+				xp++;
+				p++;
+			}
+
+			// Make a table of values in order of bit lengths
+			i = 0;
+			p = 0;
+			do {
+				if ((j = b[bindex + p]) !== 0) {
+					v[x[j]++] = i;
+				}
+				p++;
+			} while (++i < n);
+			n = x[g]; // set n to length of v
+
+			// Generate the Huffman codes and for each, make the table entries
+			x[0] = i = 0; // first Huffman code is zero
+			p = 0; // grab values in bit order
+			h = -1; // no tables yet--level -1
+			w = -l; // bits decoded == (l * h)
+			u[0] = 0; // just to keep compilers happy
+			q = 0; // ditto
+			z = 0; // ditto
+
+			// go through the bit lengths (k already is bits in shortest code)
+			for (; k <= g; k++) {
+				a = c[k];
+				while (a-- !== 0) {
+					// here i is the Huffman code of length k bits for value *p
+					// make tables up to required level
+					while (k > w + l) {
+						h++;
+						w += l; // previous table always l bits
+						// compute minimum size table less than or equal to l bits
+						z = g - w;
+						z = (z > l) ? l : z; // table size upper limit
+						if ((f = 1 << (j = k - w)) > a + 1) { // try a k-w bit table
+							// too few codes for
+							// k-w bit table
+							f -= a + 1; // deduct codes from patterns left
+							xp = k;
+							if (j < z) {
+								while (++j < z) { // try smaller tables up to z bits
+									if ((f <<= 1) <= c[++xp])
+										break; // enough codes to use up j bits
+									f -= c[xp]; // else deduct codes from patterns
+								}
+							}
+						}
+						z = 1 << j; // table entries for j-bit table
+
+						// allocate new table
+						if (hn[0] + z > MANY) { // (note: doesn't matter for fixed)
+							return Z_DATA_ERROR; // overflow of MANY
+						}
+						u[h] = q = /* hp+ */hn[0]; // DEBUG
+						hn[0] += z;
+
+						// connect to last table, if there is one
+						if (h !== 0) {
+							x[h] = i; // save pattern for backing up
+							r[0] = /* (byte) */j; // bits in this table
+							r[1] = /* (byte) */l; // bits to dump before this table
+							j = i >>> (w - l);
+							r[2] = /* (int) */(q - u[h - 1] - j); // offset to this table
+							hp.set(r, (u[h - 1] + j) * 3);
+							// to
+							// last
+							// table
+						} else {
+							t[0] = q; // first table is returned result
+						}
+					}
+
+					// set up table entry in r
+					r[1] = /* (byte) */(k - w);
+					if (p >= n) {
+						r[0] = 128 + 64; // out of values--invalid code
+					} else if (v[p] < s) {
+						r[0] = /* (byte) */(v[p] < 256 ? 0 : 32 + 64); // 256 is
+						// end-of-block
+						r[2] = v[p++]; // simple code is just the value
+					} else {
+						r[0] = /* (byte) */(e[v[p] - s] + 16 + 64); // non-simple--look
+						// up in lists
+						r[2] = d[v[p++] - s];
+					}
+
+					// fill code-like entries with r
+					f = 1 << (k - w);
+					for (j = i >>> w; j < z; j += f) {
+						hp.set(r, (q + j) * 3);
+					}
+
+					// backwards increment the k-bit code i
+					for (j = 1 << (k - 1); (i & j) !== 0; j >>>= 1) {
+						i ^= j;
+					}
+					i ^= j;
+
+					// backup over finished tables
+					mask = (1 << w) - 1; // needed on HP, cc -O bug
+					while ((i & mask) != x[h]) {
+						h--; // don't need to update q
+						w -= l;
+						mask = (1 << w) - 1;
+					}
+				}
+			}
+			// Return Z_BUF_ERROR if we were given an incomplete table
+			return y !== 0 && g != 1 ? Z_BUF_ERROR : Z_OK;
+		}
+
+		function initWorkArea(vsize) {
+			var i;
+			if (!hn) {
+				hn = []; // []; //new Array(1);
+				v = []; // new Array(vsize);
+				c = new Int32Array(BMAX + 1); // new Array(BMAX + 1);
+				r = []; // new Array(3);
+				u = new Int32Array(BMAX); // new Array(BMAX);
+				x = new Int32Array(BMAX + 1); // new Array(BMAX + 1);
+			}
+			if (v.length < vsize) {
+				v = []; // new Array(vsize);
+			}
+			for (i = 0; i < vsize; i++) {
+				v[i] = 0;
+			}
+			for (i = 0; i < BMAX + 1; i++) {
+				c[i] = 0;
+			}
+			for (i = 0; i < 3; i++) {
+				r[i] = 0;
+			}
+			// for(int i=0; i<BMAX; i++){u[i]=0;}
+			u.set(c.subarray(0, BMAX), 0);
+			// for(int i=0; i<BMAX+1; i++){x[i]=0;}
+			x.set(c.subarray(0, BMAX + 1), 0);
+		}
+
+		that.inflate_trees_bits = function(c, // 19 code lengths
+		bb, // bits tree desired/actual depth
+		tb, // bits tree result
+		hp, // space for trees
+		z // for messages
+		) {
+			var result;
+			initWorkArea(19);
+			hn[0] = 0;
+			result = huft_build(c, 0, 19, 19, null, null, tb, bb, hp, hn, v);
+
+			if (result == Z_DATA_ERROR) {
+				z.msg = "oversubscribed dynamic bit lengths tree";
+			} else if (result == Z_BUF_ERROR || bb[0] === 0) {
+				z.msg = "incomplete dynamic bit lengths tree";
+				result = Z_DATA_ERROR;
+			}
+			return result;
+		};
+
+		that.inflate_trees_dynamic = function(nl, // number of literal/length codes
+		nd, // number of distance codes
+		c, // that many (total) code lengths
+		bl, // literal desired/actual bit depth
+		bd, // distance desired/actual bit depth
+		tl, // literal/length tree result
+		td, // distance tree result
+		hp, // space for trees
+		z // for messages
+		) {
+			var result;
+
+			// build literal/length tree
+			initWorkArea(288);
+			hn[0] = 0;
+			result = huft_build(c, 0, nl, 257, cplens, cplext, tl, bl, hp, hn, v);
+			if (result != Z_OK || bl[0] === 0) {
+				if (result == Z_DATA_ERROR) {
+					z.msg = "oversubscribed literal/length tree";
+				} else if (result != Z_MEM_ERROR) {
+					z.msg = "incomplete literal/length tree";
+					result = Z_DATA_ERROR;
+				}
+				return result;
+			}
+
+			// build distance tree
+			initWorkArea(288);
+			result = huft_build(c, nl, nd, 0, cpdist, cpdext, td, bd, hp, hn, v);
+
+			if (result != Z_OK || (bd[0] === 0 && nl > 257)) {
+				if (result == Z_DATA_ERROR) {
+					z.msg = "oversubscribed distance tree";
+				} else if (result == Z_BUF_ERROR) {
+					z.msg = "incomplete distance tree";
+					result = Z_DATA_ERROR;
+				} else if (result != Z_MEM_ERROR) {
+					z.msg = "empty distance tree with lengths";
+					result = Z_DATA_ERROR;
+				}
+				return result;
+			}
+
+			return Z_OK;
+		};
+
+	}
+
+	InfTree.inflate_trees_fixed = function(bl, // literal desired/actual bit depth
+	bd, // distance desired/actual bit depth
+	tl,// literal/length tree result
+	td// distance tree result
+	) {
+		bl[0] = fixed_bl;
+		bd[0] = fixed_bd;
+		tl[0] = fixed_tl;
+		td[0] = fixed_td;
+		return Z_OK;
+	};
+
+	// InfCodes
+
+	// waiting for "i:"=input,
+	// "o:"=output,
+	// "x:"=nothing
+	var START = 0; // x: set up for LEN
+	var LEN = 1; // i: get length/literal/eob next
+	var LENEXT = 2; // i: getting length extra (have base)
+	var DIST = 3; // i: get distance next
+	var DISTEXT = 4;// i: getting distance extra
+	var COPY = 5; // o: copying bytes in window, waiting
+	// for space
+	var LIT = 6; // o: got literal, waiting for output
+	// space
+	var WASH = 7; // o: got eob, possibly still output
+	// waiting
+	var END = 8; // x: got eob and all data flushed
+	var BADCODE = 9;// x: got error
+
+	function InfCodes() {
+		var that = this;
+
+		var mode; // current inflate_codes mode
+
+		// mode dependent information
+		var len = 0;
+
+		var tree; // pointer into tree
+		var tree_index = 0;
+		var need = 0; // bits needed
+
+		var lit = 0;
+
+		// if EXT or COPY, where and how much
+		var get = 0; // bits to get for extra
+		var dist = 0; // distance back to copy from
+
+		var lbits = 0; // ltree bits decoded per branch
+		var dbits = 0; // dtree bits decoder per branch
+		var ltree; // literal/length/eob tree
+		var ltree_index = 0; // literal/length/eob tree
+		var dtree; // distance tree
+		var dtree_index = 0; // distance tree
+
+		// Called with number of bytes left to write in window at least 258
+		// (the maximum string length) and number of input bytes available
+		// at least ten. The ten bytes are six bytes for the longest length/
+		// distance pair plus four bytes for overloading the bit buffer.
+
+		function inflate_fast(bl, bd, tl, tl_index, td, td_index, s, z) {
+			var t; // temporary pointer
+			var tp; // temporary pointer
+			var tp_index; // temporary pointer
+			var e; // extra bits or operation
+			var b; // bit buffer
+			var k; // bits in bit buffer
+			var p; // input data pointer
+			var n; // bytes available there
+			var q; // output window write pointer
+			var m; // bytes to end of window or read pointer
+			var ml; // mask for literal/length tree
+			var md; // mask for distance tree
+			var c; // bytes to copy
+			var d; // distance back to copy from
+			var r; // copy source pointer
+
+			var tp_index_t_3; // (tp_index+t)*3
+
+			// load input, output, bit values
+			p = z.next_in_index;
+			n = z.avail_in;
+			b = s.bitb;
+			k = s.bitk;
+			q = s.write;
+			m = q < s.read ? s.read - q - 1 : s.end - q;
+
+			// initialize masks
+			ml = inflate_mask[bl];
+			md = inflate_mask[bd];
+
+			// do until not enough input or output space for fast loop
+			do { // assume called with m >= 258 && n >= 10
+				// get literal/length code
+				while (k < (20)) { // max bits for literal/length code
+					n--;
+					b |= (z.read_byte(p++) & 0xff) << k;
+					k += 8;
+				}
+
+				t = b & ml;
+				tp = tl;
+				tp_index = tl_index;
+				tp_index_t_3 = (tp_index + t) * 3;
+				if ((e = tp[tp_index_t_3]) === 0) {
+					b >>= (tp[tp_index_t_3 + 1]);
+					k -= (tp[tp_index_t_3 + 1]);
+
+					s.window[q++] = /* (byte) */tp[tp_index_t_3 + 2];
+					m--;
+					continue;
+				}
+				do {
+
+					b >>= (tp[tp_index_t_3 + 1]);
+					k -= (tp[tp_index_t_3 + 1]);
+
+					if ((e & 16) !== 0) {
+						e &= 15;
+						c = tp[tp_index_t_3 + 2] + (/* (int) */b & inflate_mask[e]);
+
+						b >>= e;
+						k -= e;
+
+						// decode distance base of block to copy
+						while (k < (15)) { // max bits for distance code
+							n--;
+							b |= (z.read_byte(p++) & 0xff) << k;
+							k += 8;
+						}
+
+						t = b & md;
+						tp = td;
+						tp_index = td_index;
+						tp_index_t_3 = (tp_index + t) * 3;
+						e = tp[tp_index_t_3];
+
+						do {
+
+							b >>= (tp[tp_index_t_3 + 1]);
+							k -= (tp[tp_index_t_3 + 1]);
+
+							if ((e & 16) !== 0) {
+								// get extra bits to add to distance base
+								e &= 15;
+								while (k < (e)) { // get extra bits (up to 13)
+									n--;
+									b |= (z.read_byte(p++) & 0xff) << k;
+									k += 8;
+								}
+
+								d = tp[tp_index_t_3 + 2] + (b & inflate_mask[e]);
+
+								b >>= (e);
+								k -= (e);
+
+								// do the copy
+								m -= c;
+								if (q >= d) { // offset before dest
+									// just copy
+									r = q - d;
+									if (q - r > 0 && 2 > (q - r)) {
+										s.window[q++] = s.window[r++]; // minimum
+										// count is
+										// three,
+										s.window[q++] = s.window[r++]; // so unroll
+										// loop a
+										// little
+										c -= 2;
+									} else {
+										s.window.set(s.window.subarray(r, r + 2), q);
+										q += 2;
+										r += 2;
+										c -= 2;
+									}
+								} else { // else offset after destination
+									r = q - d;
+									do {
+										r += s.end; // force pointer in window
+									} while (r < 0); // covers invalid distances
+									e = s.end - r;
+									if (c > e) { // if source crosses,
+										c -= e; // wrapped copy
+										if (q - r > 0 && e > (q - r)) {
+											do {
+												s.window[q++] = s.window[r++];
+											} while (--e !== 0);
+										} else {
+											s.window.set(s.window.subarray(r, r + e), q);
+											q += e;
+											r += e;
+											e = 0;
+										}
+										r = 0; // copy rest from start of window
+									}
+
+								}
+
+								// copy all or what's left
+								if (q - r > 0 && c > (q - r)) {
+									do {
+										s.window[q++] = s.window[r++];
+									} while (--c !== 0);
+								} else {
+									s.window.set(s.window.subarray(r, r + c), q);
+									q += c;
+									r += c;
+									c = 0;
+								}
+								break;
+							} else if ((e & 64) === 0) {
+								t += tp[tp_index_t_3 + 2];
+								t += (b & inflate_mask[e]);
+								tp_index_t_3 = (tp_index + t) * 3;
+								e = tp[tp_index_t_3];
+							} else {
+								z.msg = "invalid distance code";
+
+								c = z.avail_in - n;
+								c = (k >> 3) < c ? k >> 3 : c;
+								n += c;
+								p -= c;
+								k -= c << 3;
+
+								s.bitb = b;
+								s.bitk = k;
+								z.avail_in = n;
+								z.total_in += p - z.next_in_index;
+								z.next_in_index = p;
+								s.write = q;
+
+								return Z_DATA_ERROR;
+							}
+						} while (true);
+						break;
+					}
+
+					if ((e & 64) === 0) {
+						t += tp[tp_index_t_3 + 2];
+						t += (b & inflate_mask[e]);
+						tp_index_t_3 = (tp_index + t) * 3;
+						if ((e = tp[tp_index_t_3]) === 0) {
+
+							b >>= (tp[tp_index_t_3 + 1]);
+							k -= (tp[tp_index_t_3 + 1]);
+
+							s.window[q++] = /* (byte) */tp[tp_index_t_3 + 2];
+							m--;
+							break;
+						}
+					} else if ((e & 32) !== 0) {
+
+						c = z.avail_in - n;
+						c = (k >> 3) < c ? k >> 3 : c;
+						n += c;
+						p -= c;
+						k -= c << 3;
+
+						s.bitb = b;
+						s.bitk = k;
+						z.avail_in = n;
+						z.total_in += p - z.next_in_index;
+						z.next_in_index = p;
+						s.write = q;
+
+						return Z_STREAM_END;
+					} else {
+						z.msg = "invalid literal/length code";
+
+						c = z.avail_in - n;
+						c = (k >> 3) < c ? k >> 3 : c;
+						n += c;
+						p -= c;
+						k -= c << 3;
+
+						s.bitb = b;
+						s.bitk = k;
+						z.avail_in = n;
+						z.total_in += p - z.next_in_index;
+						z.next_in_index = p;
+						s.write = q;
+
+						return Z_DATA_ERROR;
+					}
+				} while (true);
+			} while (m >= 258 && n >= 10);
+
+			// not enough input or output--restore pointers and return
+			c = z.avail_in - n;
+			c = (k >> 3) < c ? k >> 3 : c;
+			n += c;
+			p -= c;
+			k -= c << 3;
+
+			s.bitb = b;
+			s.bitk = k;
+			z.avail_in = n;
+			z.total_in += p - z.next_in_index;
+			z.next_in_index = p;
+			s.write = q;
+
+			return Z_OK;
+		}
+
+		that.init = function(bl, bd, tl, tl_index, td, td_index) {
+			mode = START;
+			lbits = /* (byte) */bl;
+			dbits = /* (byte) */bd;
+			ltree = tl;
+			ltree_index = tl_index;
+			dtree = td;
+			dtree_index = td_index;
+			tree = null;
+		};
+
+		that.proc = function(s, z, r) {
+			var j; // temporary storage
+			var tindex; // temporary pointer
+			var e; // extra bits or operation
+			var b = 0; // bit buffer
+			var k = 0; // bits in bit buffer
+			var p = 0; // input data pointer
+			var n; // bytes available there
+			var q; // output window write pointer
+			var m; // bytes to end of window or read pointer
+			var f; // pointer to copy strings from
+
+			// copy input/output information to locals (UPDATE macro restores)
+			p = z.next_in_index;
+			n = z.avail_in;
+			b = s.bitb;
+			k = s.bitk;
+			q = s.write;
+			m = q < s.read ? s.read - q - 1 : s.end - q;
+
+			// process input and output based on current state
+			while (true) {
+				switch (mode) {
+				// waiting for "i:"=input, "o:"=output, "x:"=nothing
+				case START: // x: set up for LEN
+					if (m >= 258 && n >= 10) {
+
+						s.bitb = b;
+						s.bitk = k;
+						z.avail_in = n;
+						z.total_in += p - z.next_in_index;
+						z.next_in_index = p;
+						s.write = q;
+						r = inflate_fast(lbits, dbits, ltree, ltree_index, dtree, dtree_index, s, z);
+
+						p = z.next_in_index;
+						n = z.avail_in;
+						b = s.bitb;
+						k = s.bitk;
+						q = s.write;
+						m = q < s.read ? s.read - q - 1 : s.end - q;
+
+						if (r != Z_OK) {
+							mode = r == Z_STREAM_END ? WASH : BADCODE;
+							break;
+						}
+					}
+					need = lbits;
+					tree = ltree;
+					tree_index = ltree_index;
+
+					mode = LEN;
+				case LEN: // i: get length/literal/eob next
+					j = need;
+
+					while (k < (j)) {
+						if (n !== 0)
+							r = Z_OK;
+						else {
+
+							s.bitb = b;
+							s.bitk = k;
+							z.avail_in = n;
+							z.total_in += p - z.next_in_index;
+							z.next_in_index = p;
+							s.write = q;
+							return s.inflate_flush(z, r);
+						}
+						n--;
+						b |= (z.read_byte(p++) & 0xff) << k;
+						k += 8;
+					}
+
+					tindex = (tree_index + (b & inflate_mask[j])) * 3;
+
+					b >>>= (tree[tindex + 1]);
+					k -= (tree[tindex + 1]);
+
+					e = tree[tindex];
+
+					if (e === 0) { // literal
+						lit = tree[tindex + 2];
+						mode = LIT;
+						break;
+					}
+					if ((e & 16) !== 0) { // length
+						get = e & 15;
+						len = tree[tindex + 2];
+						mode = LENEXT;
+						break;
+					}
+					if ((e & 64) === 0) { // next table
+						need = e;
+						tree_index = tindex / 3 + tree[tindex + 2];
+						break;
+					}
+					if ((e & 32) !== 0) { // end of block
+						mode = WASH;
+						break;
+					}
+					mode = BADCODE; // invalid code
+					z.msg = "invalid literal/length code";
+					r = Z_DATA_ERROR;
+
+					s.bitb = b;
+					s.bitk = k;
+					z.avail_in = n;
+					z.total_in += p - z.next_in_index;
+					z.next_in_index = p;
+					s.write = q;
+					return s.inflate_flush(z, r);
+
+				case LENEXT: // i: getting length extra (have base)
+					j = get;
+
+					while (k < (j)) {
+						if (n !== 0)
+							r = Z_OK;
+						else {
+
+							s.bitb = b;
+							s.bitk = k;
+							z.avail_in = n;
+							z.total_in += p - z.next_in_index;
+							z.next_in_index = p;
+							s.write = q;
+							return s.inflate_flush(z, r);
+						}
+						n--;
+						b |= (z.read_byte(p++) & 0xff) << k;
+						k += 8;
+					}
+
+					len += (b & inflate_mask[j]);
+
+					b >>= j;
+					k -= j;
+
+					need = dbits;
+					tree = dtree;
+					tree_index = dtree_index;
+					mode = DIST;
+				case DIST: // i: get distance next
+					j = need;
+
+					while (k < (j)) {
+						if (n !== 0)
+							r = Z_OK;
+						else {
+
+							s.bitb = b;
+							s.bitk = k;
+							z.avail_in = n;
+							z.total_in += p - z.next_in_index;
+							z.next_in_index = p;
+							s.write = q;
+							return s.inflate_flush(z, r);
+						}
+						n--;
+						b |= (z.read_byte(p++) & 0xff) << k;
+						k += 8;
+					}
+
+					tindex = (tree_index + (b & inflate_mask[j])) * 3;
+
+					b >>= tree[tindex + 1];
+					k -= tree[tindex + 1];
+
+					e = (tree[tindex]);
+					if ((e & 16) !== 0) { // distance
+						get = e & 15;
+						dist = tree[tindex + 2];
+						mode = DISTEXT;
+						break;
+					}
+					if ((e & 64) === 0) { // next table
+						need = e;
+						tree_index = tindex / 3 + tree[tindex + 2];
+						break;
+					}
+					mode = BADCODE; // invalid code
+					z.msg = "invalid distance code";
+					r = Z_DATA_ERROR;
+
+					s.bitb = b;
+					s.bitk = k;
+					z.avail_in = n;
+					z.total_in += p - z.next_in_index;
+					z.next_in_index = p;
+					s.write = q;
+					return s.inflate_flush(z, r);
+
+				case DISTEXT: // i: getting distance extra
+					j = get;
+
+					while (k < (j)) {
+						if (n !== 0)
+							r = Z_OK;
+						else {
+
+							s.bitb = b;
+							s.bitk = k;
+							z.avail_in = n;
+							z.total_in += p - z.next_in_index;
+							z.next_in_index = p;
+							s.write = q;
+							return s.inflate_flush(z, r);
+						}
+						n--;
+						b |= (z.read_byte(p++) & 0xff) << k;
+						k += 8;
+					}
+
+					dist += (b & inflate_mask[j]);
+
+					b >>= j;
+					k -= j;
+
+					mode = COPY;
+				case COPY: // o: copying bytes in window, waiting for space
+					f = q - dist;
+					while (f < 0) { // modulo window size-"while" instead
+						f += s.end; // of "if" handles invalid distances
+					}
+					while (len !== 0) {
+
+						if (m === 0) {
+							if (q == s.end && s.read !== 0) {
+								q = 0;
+								m = q < s.read ? s.read - q - 1 : s.end - q;
+							}
+							if (m === 0) {
+								s.write = q;
+								r = s.inflate_flush(z, r);
+								q = s.write;
+								m = q < s.read ? s.read - q - 1 : s.end - q;
+
+								if (q == s.end && s.read !== 0) {
+									q = 0;
+									m = q < s.read ? s.read - q - 1 : s.end - q;
+								}
+
+								if (m === 0) {
+									s.bitb = b;
+									s.bitk = k;
+									z.avail_in = n;
+									z.total_in += p - z.next_in_index;
+									z.next_in_index = p;
+									s.write = q;
+									return s.inflate_flush(z, r);
+								}
+							}
+						}
+
+						s.window[q++] = s.window[f++];
+						m--;
+
+						if (f == s.end)
+							f = 0;
+						len--;
+					}
+					mode = START;
+					break;
+				case LIT: // o: got literal, waiting for output space
+					if (m === 0) {
+						if (q == s.end && s.read !== 0) {
+							q = 0;
+							m = q < s.read ? s.read - q - 1 : s.end - q;
+						}
+						if (m === 0) {
+							s.write = q;
+							r = s.inflate_flush(z, r);
+							q = s.write;
+							m = q < s.read ? s.read - q - 1 : s.end - q;
+
+							if (q == s.end && s.read !== 0) {
+								q = 0;
+								m = q < s.read ? s.read - q - 1 : s.end - q;
+							}
+							if (m === 0) {
+								s.bitb = b;
+								s.bitk = k;
+								z.avail_in = n;
+								z.total_in += p - z.next_in_index;
+								z.next_in_index = p;
+								s.write = q;
+								return s.inflate_flush(z, r);
+							}
+						}
+					}
+					r = Z_OK;
+
+					s.window[q++] = /* (byte) */lit;
+					m--;
+
+					mode = START;
+					break;
+				case WASH: // o: got eob, possibly more output
+					if (k > 7) { // return unused byte, if any
+						k -= 8;
+						n++;
+						p--; // can always return one
+					}
+
+					s.write = q;
+					r = s.inflate_flush(z, r);
+					q = s.write;
+					m = q < s.read ? s.read - q - 1 : s.end - q;
+
+					if (s.read != s.write) {
+						s.bitb = b;
+						s.bitk = k;
+						z.avail_in = n;
+						z.total_in += p - z.next_in_index;
+						z.next_in_index = p;
+						s.write = q;
+						return s.inflate_flush(z, r);
+					}
+					mode = END;
+				case END:
+					r = Z_STREAM_END;
+					s.bitb = b;
+					s.bitk = k;
+					z.avail_in = n;
+					z.total_in += p - z.next_in_index;
+					z.next_in_index = p;
+					s.write = q;
+					return s.inflate_flush(z, r);
+
+				case BADCODE: // x: got error
+
+					r = Z_DATA_ERROR;
+
+					s.bitb = b;
+					s.bitk = k;
+					z.avail_in = n;
+					z.total_in += p - z.next_in_index;
+					z.next_in_index = p;
+					s.write = q;
+					return s.inflate_flush(z, r);
+
+				default:
+					r = Z_STREAM_ERROR;
+
+					s.bitb = b;
+					s.bitk = k;
+					z.avail_in = n;
+					z.total_in += p - z.next_in_index;
+					z.next_in_index = p;
+					s.write = q;
+					return s.inflate_flush(z, r);
+				}
+			}
+		};
+
+		that.free = function() {
+			// ZFREE(z, c);
+		};
+
+	}
+
+	// InfBlocks
+
+	// Table for deflate from PKZIP's appnote.txt.
+	var border = [ // Order of the bit length code lengths
+	16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 ];
+
+	var TYPE = 0; // get type bits (3, including end bit)
+	var LENS = 1; // get lengths for stored
+	var STORED = 2;// processing stored block
+	var TABLE = 3; // get table lengths
+	var BTREE = 4; // get bit lengths tree for a dynamic
+	// block
+	var DTREE = 5; // get length, distance trees for a
+	// dynamic block
+	var CODES = 6; // processing fixed or dynamic block
+	var DRY = 7; // output remaining window bytes
+	var DONELOCKS = 8; // finished last block, done
+	var BADBLOCKS = 9; // ot a data error--stuck here
+
+	function InfBlocks(z, w) {
+		var that = this;
+
+		var mode = TYPE; // current inflate_block mode
+
+		var left = 0; // if STORED, bytes left to copy
+
+		var table = 0; // table lengths (14 bits)
+		var index = 0; // index into blens (or border)
+		var blens; // bit lengths of codes
+		var bb = [ 0 ]; // bit length tree depth
+		var tb = [ 0 ]; // bit length decoding tree
+
+		var codes = new InfCodes(); // if CODES, current state
+
+		var last = 0; // true if this block is the last block
+
+		var hufts = new Int32Array(MANY * 3); // single malloc for tree space
+		var check = 0; // check on output
+		var inftree = new InfTree();
+
+		that.bitk = 0; // bits in bit buffer
+		that.bitb = 0; // bit buffer
+		that.window = new Uint8Array(w); // sliding window
+		that.end = w; // one byte after sliding window
+		that.read = 0; // window read pointer
+		that.write = 0; // window write pointer
+
+		that.reset = function(z, c) {
+			if (c)
+				c[0] = check;
+			// if (mode == BTREE || mode == DTREE) {
+			// }
+			if (mode == CODES) {
+				codes.free(z);
+			}
+			mode = TYPE;
+			that.bitk = 0;
+			that.bitb = 0;
+			that.read = that.write = 0;
+		};
+
+		that.reset(z, null);
+
+		// copy as much as possible from the sliding window to the output area
+		that.inflate_flush = function(z, r) {
+			var n;
+			var p;
+			var q;
+
+			// local copies of source and destination pointers
+			p = z.next_out_index;
+			q = that.read;
+
+			// compute number of bytes to copy as far as end of window
+			n = /* (int) */((q <= that.write ? that.write : that.end) - q);
+			if (n > z.avail_out)
+				n = z.avail_out;
+			if (n !== 0 && r == Z_BUF_ERROR)
+				r = Z_OK;
+
+			// update counters
+			z.avail_out -= n;
+			z.total_out += n;
+
+			// copy as far as end of window
+			z.next_out.set(that.window.subarray(q, q + n), p);
+			p += n;
+			q += n;
+
+			// see if more to copy at beginning of window
+			if (q == that.end) {
+				// wrap pointers
+				q = 0;
+				if (that.write == that.end)
+					that.write = 0;
+
+				// compute bytes to copy
+				n = that.write - q;
+				if (n > z.avail_out)
+					n = z.avail_out;
+				if (n !== 0 && r == Z_BUF_ERROR)
+					r = Z_OK;
+
+				// update counters
+				z.avail_out -= n;
+				z.total_out += n;
+
+				// copy
+				z.next_out.set(that.window.subarray(q, q + n), p);
+				p += n;
+				q += n;
+			}
+
+			// update pointers
+			z.next_out_index = p;
+			that.read = q;
+
+			// done
+			return r;
+		};
+
+		that.proc = function(z, r) {
+			var t; // temporary storage
+			var b; // bit buffer
+			var k; // bits in bit buffer
+			var p; // input data pointer
+			var n; // bytes available there
+			var q; // output window write pointer
+			var m; // bytes to end of window or read pointer
+
+			var i;
+
+			// copy input/output information to locals (UPDATE macro restores)
+			// {
+			p = z.next_in_index;
+			n = z.avail_in;
+			b = that.bitb;
+			k = that.bitk;
+			// }
+			// {
+			q = that.write;
+			m = /* (int) */(q < that.read ? that.read - q - 1 : that.end - q);
+			// }
+
+			// process input based on current state
+			// DEBUG dtree
+			while (true) {
+				switch (mode) {
+				case TYPE:
+
+					while (k < (3)) {
+						if (n !== 0) {
+							r = Z_OK;
+						} else {
+							that.bitb = b;
+							that.bitk = k;
+							z.avail_in = n;
+							z.total_in += p - z.next_in_index;
+							z.next_in_index = p;
+							that.write = q;
+							return that.inflate_flush(z, r);
+						}
+						n--;
+						b |= (z.read_byte(p++) & 0xff) << k;
+						k += 8;
+					}
+					t = /* (int) */(b & 7);
+					last = t & 1;
+
+					switch (t >>> 1) {
+					case 0: // stored
+						// {
+						b >>>= (3);
+						k -= (3);
+						// }
+						t = k & 7; // go to byte boundary
+
+						// {
+						b >>>= (t);
+						k -= (t);
+						// }
+						mode = LENS; // get length of stored block
+						break;
+					case 1: // fixed
+						// {
+						var bl = []; // new Array(1);
+						var bd = []; // new Array(1);
+						var tl = [ [] ]; // new Array(1);
+						var td = [ [] ]; // new Array(1);
+
+						InfTree.inflate_trees_fixed(bl, bd, tl, td);
+						codes.init(bl[0], bd[0], tl[0], 0, td[0], 0);
+						// }
+
+						// {
+						b >>>= (3);
+						k -= (3);
+						// }
+
+						mode = CODES;
+						break;
+					case 2: // dynamic
+
+						// {
+						b >>>= (3);
+						k -= (3);
+						// }
+
+						mode = TABLE;
+						break;
+					case 3: // illegal
+
+						// {
+						b >>>= (3);
+						k -= (3);
+						// }
+						mode = BADBLOCKS;
+						z.msg = "invalid block type";
+						r = Z_DATA_ERROR;
+
+						that.bitb = b;
+						that.bitk = k;
+						z.avail_in = n;
+						z.total_in += p - z.next_in_index;
+						z.next_in_index = p;
+						that.write = q;
+						return that.inflate_flush(z, r);
+					}
+					break;
+				case LENS:
+
+					while (k < (32)) {
+						if (n !== 0) {
+							r = Z_OK;
+						} else {
+							that.bitb = b;
+							that.bitk = k;
+							z.avail_in = n;
+							z.total_in += p - z.next_in_index;
+							z.next_in_index = p;
+							that.write = q;
+							return that.inflate_flush(z, r);
+						}
+						n--;
+						b |= (z.read_byte(p++) & 0xff) << k;
+						k += 8;
+					}
+
+					if ((((~b) >>> 16) & 0xffff) != (b & 0xffff)) {
+						mode = BADBLOCKS;
+						z.msg = "invalid stored block lengths";
+						r = Z_DATA_ERROR;
+
+						that.bitb = b;
+						that.bitk = k;
+						z.avail_in = n;
+						z.total_in += p - z.next_in_index;
+						z.next_in_index = p;
+						that.write = q;
+						return that.inflate_flush(z, r);
+					}
+					left = (b & 0xffff);
+					b = k = 0; // dump bits
+					mode = left !== 0 ? STORED : (last !== 0 ? DRY : TYPE);
+					break;
+				case STORED:
+					if (n === 0) {
+						that.bitb = b;
+						that.bitk = k;
+						z.avail_in = n;
+						z.total_in += p - z.next_in_index;
+						z.next_in_index = p;
+						that.write = q;
+						return that.inflate_flush(z, r);
+					}
+
+					if (m === 0) {
+						if (q == that.end && that.read !== 0) {
+							q = 0;
+							m = /* (int) */(q < that.read ? that.read - q - 1 : that.end - q);
+						}
+						if (m === 0) {
+							that.write = q;
+							r = that.inflate_flush(z, r);
+							q = that.write;
+							m = /* (int) */(q < that.read ? that.read - q - 1 : that.end - q);
+							if (q == that.end && that.read !== 0) {
+								q = 0;
+								m = /* (int) */(q < that.read ? that.read - q - 1 : that.end - q);
+							}
+							if (m === 0) {
+								that.bitb = b;
+								that.bitk = k;
+								z.avail_in = n;
+								z.total_in += p - z.next_in_index;
+								z.next_in_index = p;
+								that.write = q;
+								return that.inflate_flush(z, r);
+							}
+						}
+					}
+					r = Z_OK;
+
+					t = left;
+					if (t > n)
+						t = n;
+					if (t > m)
+						t = m;
+					that.window.set(z.read_buf(p, t), q);
+					p += t;
+					n -= t;
+					q += t;
+					m -= t;
+					if ((left -= t) !== 0)
+						break;
+					mode = last !== 0 ? DRY : TYPE;
+					break;
+				case TABLE:
+
+					while (k < (14)) {
+						if (n !== 0) {
+							r = Z_OK;
+						} else {
+							that.bitb = b;
+							that.bitk = k;
+							z.avail_in = n;
+							z.total_in += p - z.next_in_index;
+							z.next_in_index = p;
+							that.write = q;
+							return that.inflate_flush(z, r);
+						}
+
+						n--;
+						b |= (z.read_byte(p++) & 0xff) << k;
+						k += 8;
+					}
+
+					table = t = (b & 0x3fff);
+					if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29) {
+						mode = BADBLOCKS;
+						z.msg = "too many length or distance symbols";
+						r = Z_DATA_ERROR;
+
+						that.bitb = b;
+						that.bitk = k;
+						z.avail_in = n;
+						z.total_in += p - z.next_in_index;
+						z.next_in_index = p;
+						that.write = q;
+						return that.inflate_flush(z, r);
+					}
+					t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f);
+					if (!blens || blens.length < t) {
+						blens = []; // new Array(t);
+					} else {
+						for (i = 0; i < t; i++) {
+							blens[i] = 0;
+						}
+					}
+
+					// {
+					b >>>= (14);
+					k -= (14);
+					// }
+
+					index = 0;
+					mode = BTREE;
+				case BTREE:
+					while (index < 4 + (table >>> 10)) {
+						while (k < (3)) {
+							if (n !== 0) {
+								r = Z_OK;
+							} else {
+								that.bitb = b;
+								that.bitk = k;
+								z.avail_in = n;
+								z.total_in += p - z.next_in_index;
+								z.next_in_index = p;
+								that.write = q;
+								return that.inflate_flush(z, r);
+							}
+							n--;
+							b |= (z.read_byte(p++) & 0xff) << k;
+							k += 8;
+						}
+
+						blens[border[index++]] = b & 7;
+
+						// {
+						b >>>= (3);
+						k -= (3);
+						// }
+					}
+
+					while (index < 19) {
+						blens[border[index++]] = 0;
+					}
+
+					bb[0] = 7;
+					t = inftree.inflate_trees_bits(blens, bb, tb, hufts, z);
+					if (t != Z_OK) {
+						r = t;
+						if (r == Z_DATA_ERROR) {
+							blens = null;
+							mode = BADBLOCKS;
+						}
+
+						that.bitb = b;
+						that.bitk = k;
+						z.avail_in = n;
+						z.total_in += p - z.next_in_index;
+						z.next_in_index = p;
+						that.write = q;
+						return that.inflate_flush(z, r);
+					}
+
+					index = 0;
+					mode = DTREE;
+				case DTREE:
+					while (true) {
+						t = table;
+						if (!(index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f))) {
+							break;
+						}
+
+						var j, c;
+
+						t = bb[0];
+
+						while (k < (t)) {
+							if (n !== 0) {
+								r = Z_OK;
+							} else {
+								that.bitb = b;
+								that.bitk = k;
+								z.avail_in = n;
+								z.total_in += p - z.next_in_index;
+								z.next_in_index = p;
+								that.write = q;
+								return that.inflate_flush(z, r);
+							}
+							n--;
+							b |= (z.read_byte(p++) & 0xff) << k;
+							k += 8;
+						}
+
+						// if (tb[0] == -1) {
+						// System.err.println("null...");
+						// }
+
+						t = hufts[(tb[0] + (b & inflate_mask[t])) * 3 + 1];
+						c = hufts[(tb[0] + (b & inflate_mask[t])) * 3 + 2];
+
+						if (c < 16) {
+							b >>>= (t);
+							k -= (t);
+							blens[index++] = c;
+						} else { // c == 16..18
+							i = c == 18 ? 7 : c - 14;
+							j = c == 18 ? 11 : 3;
+
+							while (k < (t + i)) {
+								if (n !== 0) {
+									r = Z_OK;
+								} else {
+									that.bitb = b;
+									that.bitk = k;
+									z.avail_in = n;
+									z.total_in += p - z.next_in_index;
+									z.next_in_index = p;
+									that.write = q;
+									return that.inflate_flush(z, r);
+								}
+								n--;
+								b |= (z.read_byte(p++) & 0xff) << k;
+								k += 8;
+							}
+
+							b >>>= (t);
+							k -= (t);
+
+							j += (b & inflate_mask[i]);
+
+							b >>>= (i);
+							k -= (i);
+
+							i = index;
+							t = table;
+							if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) || (c == 16 && i < 1)) {
+								blens = null;
+								mode = BADBLOCKS;
+								z.msg = "invalid bit length repeat";
+								r = Z_DATA_ERROR;
+
+								that.bitb = b;
+								that.bitk = k;
+								z.avail_in = n;
+								z.total_in += p - z.next_in_index;
+								z.next_in_index = p;
+								that.write = q;
+								return that.inflate_flush(z, r);
+							}
+
+							c = c == 16 ? blens[i - 1] : 0;
+							do {
+								blens[i++] = c;
+							} while (--j !== 0);
+							index = i;
+						}
+					}
+
+					tb[0] = -1;
+					// {
+					var bl_ = []; // new Array(1);
+					var bd_ = []; // new Array(1);
+					var tl_ = []; // new Array(1);
+					var td_ = []; // new Array(1);
+					bl_[0] = 9; // must be <= 9 for lookahead assumptions
+					bd_[0] = 6; // must be <= 9 for lookahead assumptions
+
+					t = table;
+					t = inftree.inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f), blens, bl_, bd_, tl_, td_, hufts, z);
+
+					if (t != Z_OK) {
+						if (t == Z_DATA_ERROR) {
+							blens = null;
+							mode = BADBLOCKS;
+						}
+						r = t;
+
+						that.bitb = b;
+						that.bitk = k;
+						z.avail_in = n;
+						z.total_in += p - z.next_in_index;
+						z.next_in_index = p;
+						that.write = q;
+						return that.inflate_flush(z, r);
+					}
+					codes.init(bl_[0], bd_[0], hufts, tl_[0], hufts, td_[0]);
+					// }
+					mode = CODES;
+				case CODES:
+					that.bitb = b;
+					that.bitk = k;
+					z.avail_in = n;
+					z.total_in += p - z.next_in_index;
+					z.next_in_index = p;
+					that.write = q;
+
+					if ((r = codes.proc(that, z, r)) != Z_STREAM_END) {
+						return that.inflate_flush(z, r);
+					}
+					r = Z_OK;
+					codes.free(z);
+
+					p = z.next_in_index;
+					n = z.avail_in;
+					b = that.bitb;
+					k = that.bitk;
+					q = that.write;
+					m = /* (int) */(q < that.read ? that.read - q - 1 : that.end - q);
+
+					if (last === 0) {
+						mode = TYPE;
+						break;
+					}
+					mode = DRY;
+				case DRY:
+					that.write = q;
+					r = that.inflate_flush(z, r);
+					q = that.write;
+					m = /* (int) */(q < that.read ? that.read - q - 1 : that.end - q);
+					if (that.read != that.write) {
+						that.bitb = b;
+						that.bitk = k;
+						z.avail_in = n;
+						z.total_in += p - z.next_in_index;
+						z.next_in_index = p;
+						that.write = q;
+						return that.inflate_flush(z, r);
+					}
+					mode = DONELOCKS;
+				case DONELOCKS:
+					r = Z_STREAM_END;
+
+					that.bitb = b;
+					that.bitk = k;
+					z.avail_in = n;
+					z.total_in += p - z.next_in_index;
+					z.next_in_index = p;
+					that.write = q;
+					return that.inflate_flush(z, r);
+				case BADBLOCKS:
+					r = Z_DATA_ERROR;
+
+					that.bitb = b;
+					that.bitk = k;
+					z.avail_in = n;
+					z.total_in += p - z.next_in_index;
+					z.next_in_index = p;
+					that.write = q;
+					return that.inflate_flush(z, r);
+
+				default:
+					r = Z_STREAM_ERROR;
+
+					that.bitb = b;
+					that.bitk = k;
+					z.avail_in = n;
+					z.total_in += p - z.next_in_index;
+					z.next_in_index = p;
+					that.write = q;
+					return that.inflate_flush(z, r);
+				}
+			}
+		};
+
+		that.free = function(z) {
+			that.reset(z, null);
+			that.window = null;
+			hufts = null;
+			// ZFREE(z, s);
+		};
+
+		that.set_dictionary = function(d, start, n) {
+			that.window.set(d.subarray(start, start + n), 0);
+			that.read = that.write = n;
+		};
+
+		// Returns true if inflate is currently at the end of a block generated
+		// by Z_SYNC_FLUSH or Z_FULL_FLUSH.
+		that.sync_point = function() {
+			return mode == LENS ? 1 : 0;
+		};
+
+	}
+
+	// Inflate
+
+	// preset dictionary flag in zlib header
+	var PRESET_DICT = 0x20;
+
+	var Z_DEFLATED = 8;
+
+	var METHOD = 0; // waiting for method byte
+	var FLAG = 1; // waiting for flag byte
+	var DICT4 = 2; // four dictionary check bytes to go
+	var DICT3 = 3; // three dictionary check bytes to go
+	var DICT2 = 4; // two dictionary check bytes to go
+	var DICT1 = 5; // one dictionary check byte to go
+	var DICT0 = 6; // waiting for inflateSetDictionary
+	var BLOCKS = 7; // decompressing blocks
+	var DONE = 12; // finished check, done
+	var BAD = 13; // got an error--stay here
+
+	var mark = [ 0, 0, 0xff, 0xff ];
+
+	function Inflate() {
+		var that = this;
+
+		that.mode = 0; // current inflate mode
+
+		// mode dependent information
+		that.method = 0; // if FLAGS, method byte
+
+		// if CHECK, check values to compare
+		that.was = [ 0 ]; // new Array(1); // computed check value
+		that.need = 0; // stream check value
+
+		// if BAD, inflateSync's marker bytes count
+		that.marker = 0;
+
+		// mode independent information
+		that.wbits = 0; // log2(window size) (8..15, defaults to 15)
+
+		// this.blocks; // current inflate_blocks state
+
+		function inflateReset(z) {
+			if (!z || !z.istate)
+				return Z_STREAM_ERROR;
+
+			z.total_in = z.total_out = 0;
+			z.msg = null;
+			z.istate.mode = BLOCKS;
+			z.istate.blocks.reset(z, null);
+			return Z_OK;
+		}
+
+		that.inflateEnd = function(z) {
+			if (that.blocks)
+				that.blocks.free(z);
+			that.blocks = null;
+			// ZFREE(z, z->state);
+			return Z_OK;
+		};
+
+		that.inflateInit = function(z, w) {
+			z.msg = null;
+			that.blocks = null;
+
+			// set window size
+			if (w < 8 || w > 15) {
+				that.inflateEnd(z);
+				return Z_STREAM_ERROR;
+			}
+			that.wbits = w;
+
+			z.istate.blocks = new InfBlocks(z, 1 << w);
+
+			// reset state
+			inflateReset(z);
+			return Z_OK;
+		};
+
+		that.inflate = function(z, f) {
+			var r;
+			var b;
+
+			if (!z || !z.istate || !z.next_in)
+				return Z_STREAM_ERROR;
+			f = f == Z_FINISH ? Z_BUF_ERROR : Z_OK;
+			r = Z_BUF_ERROR;
+			while (true) {
+				// System.out.println("mode: "+z.istate.mode);
+				switch (z.istate.mode) {
+				case METHOD:
+
+					if (z.avail_in === 0)
+						return r;
+					r = f;
+
+					z.avail_in--;
+					z.total_in++;
+					if (((z.istate.method = z.read_byte(z.next_in_index++)) & 0xf) != Z_DEFLATED) {
+						z.istate.mode = BAD;
+						z.msg = "unknown compression method";
+						z.istate.marker = 5; // can't try inflateSync
+						break;
+					}
+					if ((z.istate.method >> 4) + 8 > z.istate.wbits) {
+						z.istate.mode = BAD;
+						z.msg = "invalid window size";
+						z.istate.marker = 5; // can't try inflateSync
+						break;
+					}
+					z.istate.mode = FLAG;
+				case FLAG:
+
+					if (z.avail_in === 0)
+						return r;
+					r = f;
+
+					z.avail_in--;
+					z.total_in++;
+					b = (z.read_byte(z.next_in_index++)) & 0xff;
+
+					if ((((z.istate.method << 8) + b) % 31) !== 0) {
+						z.istate.mode = BAD;
+						z.msg = "incorrect header check";
+						z.istate.marker = 5; // can't try inflateSync
+						break;
+					}
+
+					if ((b & PRESET_DICT) === 0) {
+						z.istate.mode = BLOCKS;
+						break;
+					}
+					z.istate.mode = DICT4;
+				case DICT4:
+
+					if (z.avail_in === 0)
+						return r;
+					r = f;
+
+					z.avail_in--;
+					z.total_in++;
+					z.istate.need = ((z.read_byte(z.next_in_index++) & 0xff) << 24) & 0xff000000;
+					z.istate.mode = DICT3;
+				case DICT3:
+
+					if (z.avail_in === 0)
+						return r;
+					r = f;
+
+					z.avail_in--;
+					z.total_in++;
+					z.istate.need += ((z.read_byte(z.next_in_index++) & 0xff) << 16) & 0xff0000;
+					z.istate.mode = DICT2;
+				case DICT2:
+
+					if (z.avail_in === 0)
+						return r;
+					r = f;
+
+					z.avail_in--;
+					z.total_in++;
+					z.istate.need += ((z.read_byte(z.next_in_index++) & 0xff) << 8) & 0xff00;
+					z.istate.mode = DICT1;
+				case DICT1:
+
+					if (z.avail_in === 0)
+						return r;
+					r = f;
+
+					z.avail_in--;
+					z.total_in++;
+					z.istate.need += (z.read_byte(z.next_in_index++) & 0xff);
+					z.istate.mode = DICT0;
+					return Z_NEED_DICT;
+				case DICT0:
+					z.istate.mode = BAD;
+					z.msg = "need dictionary";
+					z.istate.marker = 0; // can try inflateSync
+					return Z_STREAM_ERROR;
+				case BLOCKS:
+
+					r = z.istate.blocks.proc(z, r);
+					if (r == Z_DATA_ERROR) {
+						z.istate.mode = BAD;
+						z.istate.marker = 0; // can try inflateSync
+						break;
+					}
+					if (r == Z_OK) {
+						r = f;
+					}
+					if (r != Z_STREAM_END) {
+						return r;
+					}
+					r = f;
+					z.istate.blocks.reset(z, z.istate.was);
+					z.istate.mode = DONE;
+				case DONE:
+					return Z_STREAM_END;
+				case BAD:
+					return Z_DATA_ERROR;
+				default:
+					return Z_STREAM_ERROR;
+				}
+			}
+		};
+
+		that.inflateSetDictionary = function(z, dictionary, dictLength) {
+			var index = 0;
+			var length = dictLength;
+			if (!z || !z.istate || z.istate.mode != DICT0)
+				return Z_STREAM_ERROR;
+
+			if (length >= (1 << z.istate.wbits)) {
+				length = (1 << z.istate.wbits) - 1;
+				index = dictLength - length;
+			}
+			z.istate.blocks.set_dictionary(dictionary, index, length);
+			z.istate.mode = BLOCKS;
+			return Z_OK;
+		};
+
+		that.inflateSync = function(z) {
+			var n; // number of bytes to look at
+			var p; // pointer to bytes
+			var m; // number of marker bytes found in a row
+			var r, w; // temporaries to save total_in and total_out
+
+			// set up
+			if (!z || !z.istate)
+				return Z_STREAM_ERROR;
+			if (z.istate.mode != BAD) {
+				z.istate.mode = BAD;
+				z.istate.marker = 0;
+			}
+			if ((n = z.avail_in) === 0)
+				return Z_BUF_ERROR;
+			p = z.next_in_index;
+			m = z.istate.marker;
+
+			// search
+			while (n !== 0 && m < 4) {
+				if (z.read_byte(p) == mark[m]) {
+					m++;
+				} else if (z.read_byte(p) !== 0) {
+					m = 0;
+				} else {
+					m = 4 - m;
+				}
+				p++;
+				n--;
+			}
+
+			// restore
+			z.total_in += p - z.next_in_index;
+			z.next_in_index = p;
+			z.avail_in = n;
+			z.istate.marker = m;
+
+			// return no joy or set up to restart on a new block
+			if (m != 4) {
+				return Z_DATA_ERROR;
+			}
+			r = z.total_in;
+			w = z.total_out;
+			inflateReset(z);
+			z.total_in = r;
+			z.total_out = w;
+			z.istate.mode = BLOCKS;
+			return Z_OK;
+		};
+
+		// Returns true if inflate is currently at the end of a block generated
+		// by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
+		// implementation to provide an additional safety check. PPP uses
+		// Z_SYNC_FLUSH
+		// but removes the length bytes of the resulting empty stored block. When
+		// decompressing, PPP checks that at the end of input packet, inflate is
+		// waiting for these length bytes.
+		that.inflateSyncPoint = function(z) {
+			if (!z || !z.istate || !z.istate.blocks)
+				return Z_STREAM_ERROR;
+			return z.istate.blocks.sync_point();
+		};
+	}
+
+	// ZStream
+
+	function ZStream() {
+	}
+
+	ZStream.prototype = {
+		inflateInit : function(bits) {
+			var that = this;
+			that.istate = new Inflate();
+			if (!bits)
+				bits = MAX_BITS;
+			return that.istate.inflateInit(that, bits);
+		},
+
+		inflate : function(f) {
+			var that = this;
+			if (!that.istate)
+				return Z_STREAM_ERROR;
+			return that.istate.inflate(that, f);
+		},
+
+		inflateEnd : function() {
+			var that = this;
+			if (!that.istate)
+				return Z_STREAM_ERROR;
+			var ret = that.istate.inflateEnd(that);
+			that.istate = null;
+			return ret;
+		},
+
+		inflateSync : function() {
+			var that = this;
+			if (!that.istate)
+				return Z_STREAM_ERROR;
+			return that.istate.inflateSync(that);
+		},
+		inflateSetDictionary : function(dictionary, dictLength) {
+			var that = this;
+			if (!that.istate)
+				return Z_STREAM_ERROR;
+			return that.istate.inflateSetDictionary(that, dictionary, dictLength);
+		},
+		read_byte : function(start) {
+			var that = this;
+			return that.next_in.subarray(start, start + 1)[0];
+		},
+		read_buf : function(start, size) {
+			var that = this;
+			return that.next_in.subarray(start, start + size);
+		}
+	};
+
+	// Inflater
+
+	function Inflater() {
+		var that = this;
+		var z = new ZStream();
+		var bufsize = 512;
+		var flush = Z_NO_FLUSH;
+		var buf = new Uint8Array(bufsize);
+		var nomoreinput = false;
+
+		z.inflateInit();
+		z.next_out = buf;
+
+		that.append = function(data, onprogress) {
+			var err, buffers = [], lastIndex = 0, bufferIndex = 0, bufferSize = 0, array;
+			if (data.length === 0)
+				return;
+			z.next_in_index = 0;
+			z.next_in = data;
+			z.avail_in = data.length;
+			do {
+				z.next_out_index = 0;
+				z.avail_out = bufsize;
+				if ((z.avail_in === 0) && (!nomoreinput)) { // if buffer is empty and more input is available, refill it
+					z.next_in_index = 0;
+					nomoreinput = true;
+				}
+				err = z.inflate(flush);
+				if (nomoreinput && (err == Z_BUF_ERROR))
+					return -1;
+				if (err != Z_OK && err != Z_STREAM_END)
+					throw "inflating: " + z.msg;
+				if ((nomoreinput || err == Z_STREAM_END) && (z.avail_in == data.length))
+					return -1;
+				if (z.next_out_index)
+					if (z.next_out_index == bufsize)
+						buffers.push(new Uint8Array(buf));
+					else
+						buffers.push(new Uint8Array(buf.subarray(0, z.next_out_index)));
+				bufferSize += z.next_out_index;
+				if (onprogress && z.next_in_index > 0 && z.next_in_index != lastIndex) {
+					onprogress(z.next_in_index);
+					lastIndex = z.next_in_index;
+				}
+			} while (z.avail_in > 0 || z.avail_out === 0);
+			array = new Uint8Array(bufferSize);
+			buffers.forEach(function(chunk) {
+				array.set(chunk, bufferIndex);
+				bufferIndex += chunk.length;
+			});
+			return array;
+		};
+		that.flush = function() {
+			z.inflateEnd();
+		};
+	}
+
+	var inflater;
+
+	if (obj.zip)
+		obj.zip.Inflater = Inflater;
+	else {
+		inflater = new Inflater();
+		obj.addEventListener("message", function(event) {
+			var message = event.data;
+
+			if (message.append)
+				obj.postMessage({
+					onappend : true,
+					data : inflater.append(message.data, function(current) {
+						obj.postMessage({
+							progress : true,
+							current : current
+						});
+					})
+				});
+			if (message.flush) {
+				inflater.flush();
+				obj.postMessage({
+					onflush : true
+				});
+			}
+		}, false);
+	}
+
+})(this);
diff --git a/zip.js/WebContent/mime-types.js b/zip.js/WebContent/mime-types.js
new file mode 100644
index 0000000..382dfc4
--- /dev/null
+++ b/zip.js/WebContent/mime-types.js
@@ -0,0 +1,1001 @@
+/*
+ Copyright (c) 2013 Gildas Lormeau. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright 
+ notice, this list of conditions and the following disclaimer in 
+ the documentation and/or other materials provided with the distribution.
+
+ 3. The names of the authors may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
+ INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+(function() {
+	var table = {
+		"application" : {
+			"andrew-inset" : "ez",
+			"annodex" : "anx",
+			"atom+xml" : "atom",
+			"atomcat+xml" : "atomcat",
+			"atomserv+xml" : "atomsrv",
+			"bbolin" : "lin",
+			"cap" : [ "cap", "pcap" ],
+			"cu-seeme" : "cu",
+			"davmount+xml" : "davmount",
+			"dsptype" : "tsp",
+			"ecmascript" : [ "es", "ecma" ],
+			"futuresplash" : "spl",
+			"hta" : "hta",
+			"java-archive" : "jar",
+			"java-serialized-object" : "ser",
+			"java-vm" : "class",
+			"javascript" : "js",
+			"m3g" : "m3g",
+			"mac-binhex40" : "hqx",
+			"mathematica" : [ "nb", "ma", "mb" ],
+			"msaccess" : "mdb",
+			"msword" : [ "doc", "dot" ],
+			"mxf" : "mxf",
+			"oda" : "oda",
+			"ogg" : "ogx",
+			"pdf" : "pdf",
+			"pgp-keys" : "key",
+			"pgp-signature" : [ "asc", "sig" ],
+			"pics-rules" : "prf",
+			"postscript" : [ "ps", "ai", "eps", "epsi", "epsf", "eps2", "eps3" ],
+			"rar" : "rar",
+			"rdf+xml" : "rdf",
+			"rss+xml" : "rss",
+			"rtf" : "rtf",
+			"smil" : [ "smi", "smil" ],
+			"xhtml+xml" : [ "xhtml", "xht" ],
+			"xml" : [ "xml", "xsl", "xsd" ],
+			"xspf+xml" : "xspf",
+			"zip" : "zip",
+			"vnd.android.package-archive" : "apk",
+			"vnd.cinderella" : "cdy",
+			"vnd.google-earth.kml+xml" : "kml",
+			"vnd.google-earth.kmz" : "kmz",
+			"vnd.mozilla.xul+xml" : "xul",
+			"vnd.ms-excel" : [ "xls", "xlb", "xlt", "xlm", "xla", "xlc", "xlw" ],
+			"vnd.ms-pki.seccat" : "cat",
+			"vnd.ms-pki.stl" : "stl",
+			"vnd.ms-powerpoint" : [ "ppt", "pps", "pot" ],
+			"vnd.oasis.opendocument.chart" : "odc",
+			"vnd.oasis.opendocument.database" : "odb",
+			"vnd.oasis.opendocument.formula" : "odf",
+			"vnd.oasis.opendocument.graphics" : "odg",
+			"vnd.oasis.opendocument.graphics-template" : "otg",
+			"vnd.oasis.opendocument.image" : "odi",
+			"vnd.oasis.opendocument.presentation" : "odp",
+			"vnd.oasis.opendocument.presentation-template" : "otp",
+			"vnd.oasis.opendocument.spreadsheet" : "ods",
+			"vnd.oasis.opendocument.spreadsheet-template" : "ots",
+			"vnd.oasis.opendocument.text" : "odt",
+			"vnd.oasis.opendocument.text-master" : "odm",
+			"vnd.oasis.opendocument.text-template" : "ott",
+			"vnd.oasis.opendocument.text-web" : "oth",
+			"vnd.openxmlformats-officedocument.spreadsheetml.sheet" : "xlsx",
+			"vnd.openxmlformats-officedocument.spreadsheetml.template" : "xltx",
+			"vnd.openxmlformats-officedocument.presentationml.presentation" : "pptx",
+			"vnd.openxmlformats-officedocument.presentationml.slideshow" : "ppsx",
+			"vnd.openxmlformats-officedocument.presentationml.template" : "potx",
+			"vnd.openxmlformats-officedocument.wordprocessingml.document" : "docx",
+			"vnd.openxmlformats-officedocument.wordprocessingml.template" : "dotx",
+			"vnd.smaf" : "mmf",
+			"vnd.stardivision.calc" : "sdc",
+			"vnd.stardivision.chart" : "sds",
+			"vnd.stardivision.draw" : "sda",
+			"vnd.stardivision.impress" : "sdd",
+			"vnd.stardivision.math" : [ "sdf", "smf" ],
+			"vnd.stardivision.writer" : [ "sdw", "vor" ],
+			"vnd.stardivision.writer-global" : "sgl",
+			"vnd.sun.xml.calc" : "sxc",
+			"vnd.sun.xml.calc.template" : "stc",
+			"vnd.sun.xml.draw" : "sxd",
+			"vnd.sun.xml.draw.template" : "std",
+			"vnd.sun.xml.impress" : "sxi",
+			"vnd.sun.xml.impress.template" : "sti",
+			"vnd.sun.xml.math" : "sxm",
+			"vnd.sun.xml.writer" : "sxw",
+			"vnd.sun.xml.writer.global" : "sxg",
+			"vnd.sun.xml.writer.template" : "stw",
+			"vnd.symbian.install" : [ "sis", "sisx" ],
+			"vnd.visio" : [ "vsd", "vst", "vss", "vsw" ],
+			"vnd.wap.wbxml" : "wbxml",
+			"vnd.wap.wmlc" : "wmlc",
+			"vnd.wap.wmlscriptc" : "wmlsc",
+			"vnd.wordperfect" : "wpd",
+			"vnd.wordperfect5.1" : "wp5",
+			"x-123" : "wk",
+			"x-7z-compressed" : "7z",
+			"x-abiword" : "abw",
+			"x-apple-diskimage" : "dmg",
+			"x-bcpio" : "bcpio",
+			"x-bittorrent" : "torrent",
+			"x-cbr" : [ "cbr", "cba", "cbt", "cb7" ],
+			"x-cbz" : "cbz",
+			"x-cdf" : [ "cdf", "cda" ],
+			"x-cdlink" : "vcd",
+			"x-chess-pgn" : "pgn",
+			"x-cpio" : "cpio",
+			"x-csh" : "csh",
+			"x-debian-package" : [ "deb", "udeb" ],
+			"x-director" : [ "dcr", "dir", "dxr", "cst", "cct", "cxt", "w3d", "fgd", "swa" ],
+			"x-dms" : "dms",
+			"x-doom" : "wad",
+			"x-dvi" : "dvi",
+			"x-httpd-eruby" : "rhtml",
+			"x-font" : "pcf.Z",
+			"x-freemind" : "mm",
+			"x-gnumeric" : "gnumeric",
+			"x-go-sgf" : "sgf",
+			"x-graphing-calculator" : "gcf",
+			"x-gtar" : [ "gtar", "taz" ],
+			"x-hdf" : "hdf",
+			"x-httpd-php" : [ "phtml", "pht", "php" ],
+			"x-httpd-php-source" : "phps",
+			"x-httpd-php3" : "php3",
+			"x-httpd-php3-preprocessed" : "php3p",
+			"x-httpd-php4" : "php4",
+			"x-httpd-php5" : "php5",
+			"x-ica" : "ica",
+			"x-info" : "info",
+			"x-internet-signup" : [ "ins", "isp" ],
+			"x-iphone" : "iii",
+			"x-iso9660-image" : "iso",
+			"x-java-jnlp-file" : "jnlp",
+			"x-jmol" : "jmz",
+			"x-killustrator" : "kil",
+			"x-koan" : [ "skp", "skd", "skt", "skm" ],
+			"x-kpresenter" : [ "kpr", "kpt" ],
+			"x-kword" : [ "kwd", "kwt" ],
+			"x-latex" : "latex",
+			"x-lha" : "lha",
+			"x-lyx" : "lyx",
+			"x-lzh" : "lzh",
+			"x-lzx" : "lzx",
+			"x-maker" : [ "frm", "maker", "frame", "fm", "fb", "book", "fbdoc" ],
+			"x-ms-wmd" : "wmd",
+			"x-ms-wmz" : "wmz",
+			"x-msdos-program" : [ "com", "exe", "bat", "dll" ],
+			"x-msi" : "msi",
+			"x-netcdf" : [ "nc", "cdf" ],
+			"x-ns-proxy-autoconfig" : [ "pac", "dat" ],
+			"x-nwc" : "nwc",
+			"x-object" : "o",
+			"x-oz-application" : "oza",
+			"x-pkcs7-certreqresp" : "p7r",
+			"x-python-code" : [ "pyc", "pyo" ],
+			"x-qgis" : [ "qgs", "shp", "shx" ],
+			"x-quicktimeplayer" : "qtl",
+			"x-redhat-package-manager" : "rpm",
+			"x-ruby" : "rb",
+			"x-sh" : "sh",
+			"x-shar" : "shar",
+			"x-shockwave-flash" : [ "swf", "swfl" ],
+			"x-silverlight" : "scr",
+			"x-stuffit" : "sit",
+			"x-sv4cpio" : "sv4cpio",
+			"x-sv4crc" : "sv4crc",
+			"x-tar" : "tar",
+			"x-tcl" : "tcl",
+			"x-tex-gf" : "gf",
+			"x-tex-pk" : "pk",
+			"x-texinfo" : [ "texinfo", "texi" ],
+			"x-trash" : [ "~", "%", "bak", "old", "sik" ],
+			"x-troff" : [ "t", "tr", "roff" ],
+			"x-troff-man" : "man",
+			"x-troff-me" : "me",
+			"x-troff-ms" : "ms",
+			"x-ustar" : "ustar",
+			"x-wais-source" : "src",
+			"x-wingz" : "wz",
+			"x-x509-ca-cert" : [ "crt", "der", "cer" ],
+			"x-xcf" : "xcf",
+			"x-xfig" : "fig",
+			"x-xpinstall" : "xpi",
+			"applixware" : "aw",
+			"atomsvc+xml" : "atomsvc",
+			"ccxml+xml" : "ccxml",
+			"cdmi-capability" : "cdmia",
+			"cdmi-container" : "cdmic",
+			"cdmi-domain" : "cdmid",
+			"cdmi-object" : "cdmio",
+			"cdmi-queue" : "cdmiq",
+			"docbook+xml" : "dbk",
+			"dssc+der" : "dssc",
+			"dssc+xml" : "xdssc",
+			"emma+xml" : "emma",
+			"epub+zip" : "epub",
+			"exi" : "exi",
+			"font-tdpfr" : "pfr",
+			"gml+xml" : "gml",
+			"gpx+xml" : "gpx",
+			"gxf" : "gxf",
+			"hyperstudio" : "stk",
+			"inkml+xml" : [ "ink", "inkml" ],
+			"ipfix" : "ipfix",
+			"json" : "json",
+			"jsonml+json" : "jsonml",
+			"lost+xml" : "lostxml",
+			"mads+xml" : "mads",
+			"marc" : "mrc",
+			"marcxml+xml" : "mrcx",
+			"mathml+xml" : "mathml",
+			"mbox" : "mbox",
+			"mediaservercontrol+xml" : "mscml",
+			"metalink+xml" : "metalink",
+			"metalink4+xml" : "meta4",
+			"mets+xml" : "mets",
+			"mods+xml" : "mods",
+			"mp21" : [ "m21", "mp21" ],
+			"mp4" : "mp4s",
+			"oebps-package+xml" : "opf",
+			"omdoc+xml" : "omdoc",
+			"onenote" : [ "onetoc", "onetoc2", "onetmp", "onepkg" ],
+			"oxps" : "oxps",
+			"patch-ops-error+xml" : "xer",
+			"pgp-encrypted" : "pgp",
+			"pkcs10" : "p10",
+			"pkcs7-mime" : [ "p7m", "p7c" ],
+			"pkcs7-signature" : "p7s",
+			"pkcs8" : "p8",
+			"pkix-attr-cert" : "ac",
+			"pkix-crl" : "crl",
+			"pkix-pkipath" : "pkipath",
+			"pkixcmp" : "pki",
+			"pls+xml" : "pls",
+			"prs.cww" : "cww",
+			"pskc+xml" : "pskcxml",
+			"reginfo+xml" : "rif",
+			"relax-ng-compact-syntax" : "rnc",
+			"resource-lists+xml" : "rl",
+			"resource-lists-diff+xml" : "rld",
+			"rls-services+xml" : "rs",
+			"rpki-ghostbusters" : "gbr",
+			"rpki-manifest" : "mft",
+			"rpki-roa" : "roa",
+			"rsd+xml" : "rsd",
+			"sbml+xml" : "sbml",
+			"scvp-cv-request" : "scq",
+			"scvp-cv-response" : "scs",
+			"scvp-vp-request" : "spq",
+			"scvp-vp-response" : "spp",
+			"sdp" : "sdp",
+			"set-payment-initiation" : "setpay",
+			"set-registration-initiation" : "setreg",
+			"shf+xml" : "shf",
+			"sparql-query" : "rq",
+			"sparql-results+xml" : "srx",
+			"srgs" : "gram",
+			"srgs+xml" : "grxml",
+			"sru+xml" : "sru",
+			"ssdl+xml" : "ssdl",
+			"ssml+xml" : "ssml",
+			"tei+xml" : [ "tei", "teicorpus" ],
+			"thraud+xml" : "tfi",
+			"timestamped-data" : "tsd",
+			"vnd.3gpp.pic-bw-large" : "plb",
+			"vnd.3gpp.pic-bw-small" : "psb",
+			"vnd.3gpp.pic-bw-var" : "pvb",
+			"vnd.3gpp2.tcap" : "tcap",
+			"vnd.3m.post-it-notes" : "pwn",
+			"vnd.accpac.simply.aso" : "aso",
+			"vnd.accpac.simply.imp" : "imp",
+			"vnd.acucobol" : "acu",
+			"vnd.acucorp" : [ "atc", "acutc" ],
+			"vnd.adobe.air-application-installer-package+zip" : "air",
+			"vnd.adobe.formscentral.fcdt" : "fcdt",
+			"vnd.adobe.fxp" : [ "fxp", "fxpl" ],
+			"vnd.adobe.xdp+xml" : "xdp",
+			"vnd.adobe.xfdf" : "xfdf",
+			"vnd.ahead.space" : "ahead",
+			"vnd.airzip.filesecure.azf" : "azf",
+			"vnd.airzip.filesecure.azs" : "azs",
+			"vnd.amazon.ebook" : "azw",
+			"vnd.americandynamics.acc" : "acc",
+			"vnd.amiga.ami" : "ami",
+			"vnd.anser-web-certificate-issue-initiation" : "cii",
+			"vnd.anser-web-funds-transfer-initiation" : "fti",
+			"vnd.antix.game-component" : "atx",
+			"vnd.apple.installer+xml" : "mpkg",
+			"vnd.apple.mpegurl" : "m3u8",
+			"vnd.aristanetworks.swi" : "swi",
+			"vnd.astraea-software.iota" : "iota",
+			"vnd.audiograph" : "aep",
+			"vnd.blueice.multipass" : "mpm",
+			"vnd.bmi" : "bmi",
+			"vnd.businessobjects" : "rep",
+			"vnd.chemdraw+xml" : "cdxml",
+			"vnd.chipnuts.karaoke-mmd" : "mmd",
+			"vnd.claymore" : "cla",
+			"vnd.cloanto.rp9" : "rp9",
+			"vnd.clonk.c4group" : [ "c4g", "c4d", "c4f", "c4p", "c4u" ],
+			"vnd.cluetrust.cartomobile-config" : "c11amc",
+			"vnd.cluetrust.cartomobile-config-pkg" : "c11amz",
+			"vnd.commonspace" : "csp",
+			"vnd.contact.cmsg" : "cdbcmsg",
+			"vnd.cosmocaller" : "cmc",
+			"vnd.crick.clicker" : "clkx",
+			"vnd.crick.clicker.keyboard" : "clkk",
+			"vnd.crick.clicker.palette" : "clkp",
+			"vnd.crick.clicker.template" : "clkt",
+			"vnd.crick.clicker.wordbank" : "clkw",
+			"vnd.criticaltools.wbs+xml" : "wbs",
+			"vnd.ctc-posml" : "pml",
+			"vnd.cups-ppd" : "ppd",
+			"vnd.curl.car" : "car",
+			"vnd.curl.pcurl" : "pcurl",
+			"vnd.dart" : "dart",
+			"vnd.data-vision.rdz" : "rdz",
+			"vnd.dece.data" : [ "uvf", "uvvf", "uvd", "uvvd" ],
+			"vnd.dece.ttml+xml" : [ "uvt", "uvvt" ],
+			"vnd.dece.unspecified" : [ "uvx", "uvvx" ],
+			"vnd.dece.zip" : [ "uvz", "uvvz" ],
+			"vnd.denovo.fcselayout-link" : "fe_launch",
+			"vnd.dna" : "dna",
+			"vnd.dolby.mlp" : "mlp",
+			"vnd.dpgraph" : "dpg",
+			"vnd.dreamfactory" : "dfac",
+			"vnd.ds-keypoint" : "kpxx",
+			"vnd.dvb.ait" : "ait",
+			"vnd.dvb.service" : "svc",
+			"vnd.dynageo" : "geo",
+			"vnd.ecowin.chart" : "mag",
+			"vnd.enliven" : "nml",
+			"vnd.epson.esf" : "esf",
+			"vnd.epson.msf" : "msf",
+			"vnd.epson.quickanime" : "qam",
+			"vnd.epson.salt" : "slt",
+			"vnd.epson.ssf" : "ssf",
+			"vnd.eszigno3+xml" : [ "es3", "et3" ],
+			"vnd.ezpix-album" : "ez2",
+			"vnd.ezpix-package" : "ez3",
+			"vnd.fdf" : "fdf",
+			"vnd.fdsn.mseed" : "mseed",
+			"vnd.fdsn.seed" : [ "seed", "dataless" ],
+			"vnd.flographit" : "gph",
+			"vnd.fluxtime.clip" : "ftc",
+			"vnd.framemaker" : [ "fm", "frame", "maker", "book" ],
+			"vnd.frogans.fnc" : "fnc",
+			"vnd.frogans.ltf" : "ltf",
+			"vnd.fsc.weblaunch" : "fsc",
+			"vnd.fujitsu.oasys" : "oas",
+			"vnd.fujitsu.oasys2" : "oa2",
+			"vnd.fujitsu.oasys3" : "oa3",
+			"vnd.fujitsu.oasysgp" : "fg5",
+			"vnd.fujitsu.oasysprs" : "bh2",
+			"vnd.fujixerox.ddd" : "ddd",
+			"vnd.fujixerox.docuworks" : "xdw",
+			"vnd.fujixerox.docuworks.binder" : "xbd",
+			"vnd.fuzzysheet" : "fzs",
+			"vnd.genomatix.tuxedo" : "txd",
+			"vnd.geogebra.file" : "ggb",
+			"vnd.geogebra.tool" : "ggt",
+			"vnd.geometry-explorer" : [ "gex", "gre" ],
+			"vnd.geonext" : "gxt",
+			"vnd.geoplan" : "g2w",
+			"vnd.geospace" : "g3w",
+			"vnd.gmx" : "gmx",
+			"vnd.grafeq" : [ "gqf", "gqs" ],
+			"vnd.groove-account" : "gac",
+			"vnd.groove-help" : "ghf",
+			"vnd.groove-identity-message" : "gim",
+			"vnd.groove-injector" : "grv",
+			"vnd.groove-tool-message" : "gtm",
+			"vnd.groove-tool-template" : "tpl",
+			"vnd.groove-vcard" : "vcg",
+			"vnd.hal+xml" : "hal",
+			"vnd.handheld-entertainment+xml" : "zmm",
+			"vnd.hbci" : "hbci",
+			"vnd.hhe.lesson-player" : "les",
+			"vnd.hp-hpgl" : "hpgl",
+			"vnd.hp-hpid" : "hpid",
+			"vnd.hp-hps" : "hps",
+			"vnd.hp-jlyt" : "jlt",
+			"vnd.hp-pcl" : "pcl",
+			"vnd.hp-pclxl" : "pclxl",
+			"vnd.hydrostatix.sof-data" : "sfd-hdstx",
+			"vnd.ibm.minipay" : "mpy",
+			"vnd.ibm.modcap" : [ "afp", "listafp", "list3820" ],
+			"vnd.ibm.rights-management" : "irm",
+			"vnd.ibm.secure-container" : "sc",
+			"vnd.iccprofile" : [ "icc", "icm" ],
+			"vnd.igloader" : "igl",
+			"vnd.immervision-ivp" : "ivp",
+			"vnd.immervision-ivu" : "ivu",
+			"vnd.insors.igm" : "igm",
+			"vnd.intercon.formnet" : [ "xpw", "xpx" ],
+			"vnd.intergeo" : "i2g",
+			"vnd.intu.qbo" : "qbo",
+			"vnd.intu.qfx" : "qfx",
+			"vnd.ipunplugged.rcprofile" : "rcprofile",
+			"vnd.irepository.package+xml" : "irp",
+			"vnd.is-xpr" : "xpr",
+			"vnd.isac.fcs" : "fcs",
+			"vnd.jam" : "jam",
+			"vnd.jcp.javame.midlet-rms" : "rms",
+			"vnd.jisp" : "jisp",
+			"vnd.joost.joda-archive" : "joda",
+			"vnd.kahootz" : [ "ktz", "ktr" ],
+			"vnd.kde.karbon" : "karbon",
+			"vnd.kde.kchart" : "chrt",
+			"vnd.kde.kformula" : "kfo",
+			"vnd.kde.kivio" : "flw",
+			"vnd.kde.kontour" : "kon",
+			"vnd.kde.kpresenter" : [ "kpr", "kpt" ],
+			"vnd.kde.kspread" : "ksp",
+			"vnd.kde.kword" : [ "kwd", "kwt" ],
+			"vnd.kenameaapp" : "htke",
+			"vnd.kidspiration" : "kia",
+			"vnd.kinar" : [ "kne", "knp" ],
+			"vnd.koan" : [ "skp", "skd", "skt", "skm" ],
+			"vnd.kodak-descriptor" : "sse",
+			"vnd.las.las+xml" : "lasxml",
+			"vnd.llamagraphics.life-balance.desktop" : "lbd",
+			"vnd.llamagraphics.life-balance.exchange+xml" : "lbe",
+			"vnd.lotus-1-2-3" : "123",
+			"vnd.lotus-approach" : "apr",
+			"vnd.lotus-freelance" : "pre",
+			"vnd.lotus-notes" : "nsf",
+			"vnd.lotus-organizer" : "org",
+			"vnd.lotus-screencam" : "scm",
+			"vnd.lotus-wordpro" : "lwp",
+			"vnd.macports.portpkg" : "portpkg",
+			"vnd.mcd" : "mcd",
+			"vnd.medcalcdata" : "mc1",
+			"vnd.mediastation.cdkey" : "cdkey",
+			"vnd.mfer" : "mwf",
+			"vnd.mfmp" : "mfm",
+			"vnd.micrografx.flo" : "flo",
+			"vnd.micrografx.igx" : "igx",
+			"vnd.mif" : "mif",
+			"vnd.mobius.daf" : "daf",
+			"vnd.mobius.dis" : "dis",
+			"vnd.mobius.mbk" : "mbk",
+			"vnd.mobius.mqy" : "mqy",
+			"vnd.mobius.msl" : "msl",
+			"vnd.mobius.plc" : "plc",
+			"vnd.mobius.txf" : "txf",
+			"vnd.mophun.application" : "mpn",
+			"vnd.mophun.certificate" : "mpc",
+			"vnd.ms-artgalry" : "cil",
+			"vnd.ms-cab-compressed" : "cab",
+			"vnd.ms-excel.addin.macroenabled.12" : "xlam",
+			"vnd.ms-excel.sheet.binary.macroenabled.12" : "xlsb",
+			"vnd.ms-excel.sheet.macroenabled.12" : "xlsm",
+			"vnd.ms-excel.template.macroenabled.12" : "xltm",
+			"vnd.ms-fontobject" : "eot",
+			"vnd.ms-htmlhelp" : "chm",
+			"vnd.ms-ims" : "ims",
+			"vnd.ms-lrm" : "lrm",
+			"vnd.ms-officetheme" : "thmx",
+			"vnd.ms-powerpoint.addin.macroenabled.12" : "ppam",
+			"vnd.ms-powerpoint.presentation.macroenabled.12" : "pptm",
+			"vnd.ms-powerpoint.slide.macroenabled.12" : "sldm",
+			"vnd.ms-powerpoint.slideshow.macroenabled.12" : "ppsm",
+			"vnd.ms-powerpoint.template.macroenabled.12" : "potm",
+			"vnd.ms-project" : [ "mpp", "mpt" ],
+			"vnd.ms-word.document.macroenabled.12" : "docm",
+			"vnd.ms-word.template.macroenabled.12" : "dotm",
+			"vnd.ms-works" : [ "wps", "wks", "wcm", "wdb" ],
+			"vnd.ms-wpl" : "wpl",
+			"vnd.ms-xpsdocument" : "xps",
+			"vnd.mseq" : "mseq",
+			"vnd.musician" : "mus",
+			"vnd.muvee.style" : "msty",
+			"vnd.mynfc" : "taglet",
+			"vnd.neurolanguage.nlu" : "nlu",
+			"vnd.nitf" : [ "ntf", "nitf" ],
+			"vnd.noblenet-directory" : "nnd",
+			"vnd.noblenet-sealer" : "nns",
+			"vnd.noblenet-web" : "nnw",
+			"vnd.nokia.n-gage.data" : "ngdat",
+			"vnd.nokia.n-gage.symbian.install" : "n-gage",
+			"vnd.nokia.radio-preset" : "rpst",
+			"vnd.nokia.radio-presets" : "rpss",
+			"vnd.novadigm.edm" : "edm",
+			"vnd.novadigm.edx" : "edx",
+			"vnd.novadigm.ext" : "ext",
+			"vnd.oasis.opendocument.chart-template" : "otc",
+			"vnd.oasis.opendocument.formula-template" : "odft",
+			"vnd.oasis.opendocument.image-template" : "oti",
+			"vnd.olpc-sugar" : "xo",
+			"vnd.oma.dd2+xml" : "dd2",
+			"vnd.openofficeorg.extension" : "oxt",
+			"vnd.openxmlformats-officedocument.presentationml.slide" : "sldx",
+			"vnd.osgeo.mapguide.package" : "mgp",
+			"vnd.osgi.dp" : "dp",
+			"vnd.osgi.subsystem" : "esa",
+			"vnd.palm" : [ "pdb", "pqa", "oprc" ],
+			"vnd.pawaafile" : "paw",
+			"vnd.pg.format" : "str",
+			"vnd.pg.osasli" : "ei6",
+			"vnd.picsel" : "efif",
+			"vnd.pmi.widget" : "wg",
+			"vnd.pocketlearn" : "plf",
+			"vnd.powerbuilder6" : "pbd",
+			"vnd.previewsystems.box" : "box",
+			"vnd.proteus.magazine" : "mgz",
+			"vnd.publishare-delta-tree" : "qps",
+			"vnd.pvi.ptid1" : "ptid",
+			"vnd.quark.quarkxpress" : [ "qxd", "qxt", "qwd", "qwt", "qxl", "qxb" ],
+			"vnd.realvnc.bed" : "bed",
+			"vnd.recordare.musicxml" : "mxl",
+			"vnd.recordare.musicxml+xml" : "musicxml",
+			"vnd.rig.cryptonote" : "cryptonote",
+			"vnd.rn-realmedia" : "rm",
+			"vnd.rn-realmedia-vbr" : "rmvb",
+			"vnd.route66.link66+xml" : "link66",
+			"vnd.sailingtracker.track" : "st",
+			"vnd.seemail" : "see",
+			"vnd.sema" : "sema",
+			"vnd.semd" : "semd",
+			"vnd.semf" : "semf",
+			"vnd.shana.informed.formdata" : "ifm",
+			"vnd.shana.informed.formtemplate" : "itp",
+			"vnd.shana.informed.interchange" : "iif",
+			"vnd.shana.informed.package" : "ipk",
+			"vnd.simtech-mindmapper" : [ "twd", "twds" ],
+			"vnd.smart.teacher" : "teacher",
+			"vnd.solent.sdkm+xml" : [ "sdkm", "sdkd" ],
+			"vnd.spotfire.dxp" : "dxp",
+			"vnd.spotfire.sfs" : "sfs",
+			"vnd.stepmania.package" : "smzip",
+			"vnd.stepmania.stepchart" : "sm",
+			"vnd.sus-calendar" : [ "sus", "susp" ],
+			"vnd.svd" : "svd",
+			"vnd.syncml+xml" : "xsm",
+			"vnd.syncml.dm+wbxml" : "bdm",
+			"vnd.syncml.dm+xml" : "xdm",
+			"vnd.tao.intent-module-archive" : "tao",
+			"vnd.tcpdump.pcap" : [ "pcap", "cap", "dmp" ],
+			"vnd.tmobile-livetv" : "tmo",
+			"vnd.trid.tpt" : "tpt",
+			"vnd.triscape.mxs" : "mxs",
+			"vnd.trueapp" : "tra",
+			"vnd.ufdl" : [ "ufd", "ufdl" ],
+			"vnd.uiq.theme" : "utz",
+			"vnd.umajin" : "umj",
+			"vnd.unity" : "unityweb",
+			"vnd.uoml+xml" : "uoml",
+			"vnd.vcx" : "vcx",
+			"vnd.visionary" : "vis",
+			"vnd.vsf" : "vsf",
+			"vnd.webturbo" : "wtb",
+			"vnd.wolfram.player" : "nbp",
+			"vnd.wqd" : "wqd",
+			"vnd.wt.stf" : "stf",
+			"vnd.xara" : "xar",
+			"vnd.xfdl" : "xfdl",
+			"vnd.yamaha.hv-dic" : "hvd",
+			"vnd.yamaha.hv-script" : "hvs",
+			"vnd.yamaha.hv-voice" : "hvp",
+			"vnd.yamaha.openscoreformat" : "osf",
+			"vnd.yamaha.openscoreformat.osfpvg+xml" : "osfpvg",
+			"vnd.yamaha.smaf-audio" : "saf",
+			"vnd.yamaha.smaf-phrase" : "spf",
+			"vnd.yellowriver-custom-menu" : "cmp",
+			"vnd.zul" : [ "zir", "zirz" ],
+			"vnd.zzazz.deck+xml" : "zaz",
+			"voicexml+xml" : "vxml",
+			"widget" : "wgt",
+			"winhlp" : "hlp",
+			"wsdl+xml" : "wsdl",
+			"wspolicy+xml" : "wspolicy",
+			"x-ace-compressed" : "ace",
+			"x-authorware-bin" : [ "aab", "x32", "u32", "vox" ],
+			"x-authorware-map" : "aam",
+			"x-authorware-seg" : "aas",
+			"x-blorb" : [ "blb", "blorb" ],
+			"x-bzip" : "bz",
+			"x-bzip2" : [ "bz2", "boz" ],
+			"x-cfs-compressed" : "cfs",
+			"x-chat" : "chat",
+			"x-conference" : "nsc",
+			"x-dgc-compressed" : "dgc",
+			"x-dtbncx+xml" : "ncx",
+			"x-dtbook+xml" : "dtb",
+			"x-dtbresource+xml" : "res",
+			"x-eva" : "eva",
+			"x-font-bdf" : "bdf",
+			"x-font-ghostscript" : "gsf",
+			"x-font-linux-psf" : "psf",
+			"x-font-otf" : "otf",
+			"x-font-pcf" : "pcf",
+			"x-font-snf" : "snf",
+			"x-font-ttf" : [ "ttf", "ttc" ],
+			"x-font-type1" : [ "pfa", "pfb", "pfm", "afm" ],
+			"x-font-woff" : "woff",
+			"x-freearc" : "arc",
+			"x-gca-compressed" : "gca",
+			"x-glulx" : "ulx",
+			"x-gramps-xml" : "gramps",
+			"x-install-instructions" : "install",
+			"x-lzh-compressed" : [ "lzh", "lha" ],
+			"x-mie" : "mie",
+			"x-mobipocket-ebook" : [ "prc", "mobi" ],
+			"x-ms-application" : "application",
+			"x-ms-shortcut" : "lnk",
+			"x-ms-xbap" : "xbap",
+			"x-msbinder" : "obd",
+			"x-mscardfile" : "crd",
+			"x-msclip" : "clp",
+			"x-msdownload" : [ "exe", "dll", "com", "bat", "msi" ],
+			"x-msmediaview" : [ "mvb", "m13", "m14" ],
+			"x-msmetafile" : [ "wmf", "wmz", "emf", "emz" ],
+			"x-msmoney" : "mny",
+			"x-mspublisher" : "pub",
+			"x-msschedule" : "scd",
+			"x-msterminal" : "trm",
+			"x-mswrite" : "wri",
+			"x-nzb" : "nzb",
+			"x-pkcs12" : [ "p12", "pfx" ],
+			"x-pkcs7-certificates" : [ "p7b", "spc" ],
+			"x-research-info-systems" : "ris",
+			"x-silverlight-app" : "xap",
+			"x-sql" : "sql",
+			"x-stuffitx" : "sitx",
+			"x-subrip" : "srt",
+			"x-t3vm-image" : "t3",
+			"x-tads" : "gam",
+			"x-tex" : "tex",
+			"x-tex-tfm" : "tfm",
+			"x-tgif" : "obj",
+			"x-xliff+xml" : "xlf",
+			"x-xz" : "xz",
+			"x-zmachine" : [ "z1", "z2", "z3", "z4", "z5", "z6", "z7", "z8" ],
+			"xaml+xml" : "xaml",
+			"xcap-diff+xml" : "xdf",
+			"xenc+xml" : "xenc",
+			"xml-dtd" : "dtd",
+			"xop+xml" : "xop",
+			"xproc+xml" : "xpl",
+			"xslt+xml" : "xslt",
+			"xv+xml" : [ "mxml", "xhvml", "xvml", "xvm" ],
+			"yang" : "yang",
+			"yin+xml" : "yin",
+			"envoy" : "evy",
+			"fractals" : "fif",
+			"internet-property-stream" : "acx",
+			"olescript" : "axs",
+			"vnd.ms-outlook" : "msg",
+			"vnd.ms-pkicertstore" : "sst",
+			"x-compress" : "z",
+			"x-compressed" : "tgz",
+			"x-gzip" : "gz",
+			"x-perfmon" : [ "pma", "pmc", "pml", "pmr", "pmw" ],
+			"x-pkcs7-mime" : [ "p7c", "p7m" ],
+			"ynd.ms-pkipko" : "pko"
+		},
+		"audio" : {
+			"amr" : "amr",
+			"amr-wb" : "awb",
+			"annodex" : "axa",
+			"basic" : [ "au", "snd" ],
+			"flac" : "flac",
+			"midi" : [ "mid", "midi", "kar", "rmi" ],
+			"mpeg" : [ "mpga", "mpega", "mp2", "mp3", "m4a", "mp2a", "m2a", "m3a" ],
+			"mpegurl" : "m3u",
+			"ogg" : [ "oga", "ogg", "spx" ],
+			"prs.sid" : "sid",
+			"x-aiff" : [ "aif", "aiff", "aifc" ],
+			"x-gsm" : "gsm",
+			"x-ms-wma" : "wma",
+			"x-ms-wax" : "wax",
+			"x-pn-realaudio" : "ram",
+			"x-realaudio" : "ra",
+			"x-sd2" : "sd2",
+			"x-wav" : "wav",
+			"adpcm" : "adp",
+			"mp4" : "mp4a",
+			"s3m" : "s3m",
+			"silk" : "sil",
+			"vnd.dece.audio" : [ "uva", "uvva" ],
+			"vnd.digital-winds" : "eol",
+			"vnd.dra" : "dra",
+			"vnd.dts" : "dts",
+			"vnd.dts.hd" : "dtshd",
+			"vnd.lucent.voice" : "lvp",
+			"vnd.ms-playready.media.pya" : "pya",
+			"vnd.nuera.ecelp4800" : "ecelp4800",
+			"vnd.nuera.ecelp7470" : "ecelp7470",
+			"vnd.nuera.ecelp9600" : "ecelp9600",
+			"vnd.rip" : "rip",
+			"webm" : "weba",
+			"x-aac" : "aac",
+			"x-caf" : "caf",
+			"x-matroska" : "mka",
+			"x-pn-realaudio-plugin" : "rmp",
+			"xm" : "xm",
+			"mid" : [ "mid", "rmi" ]
+		},
+		"chemical" : {
+			"x-alchemy" : "alc",
+			"x-cache" : [ "cac", "cache" ],
+			"x-cache-csf" : "csf",
+			"x-cactvs-binary" : [ "cbin", "cascii", "ctab" ],
+			"x-cdx" : "cdx",
+			"x-chem3d" : "c3d",
+			"x-cif" : "cif",
+			"x-cmdf" : "cmdf",
+			"x-cml" : "cml",
+			"x-compass" : "cpa",
+			"x-crossfire" : "bsd",
+			"x-csml" : [ "csml", "csm" ],
+			"x-ctx" : "ctx",
+			"x-cxf" : [ "cxf", "cef" ],
+			"x-embl-dl-nucleotide" : [ "emb", "embl" ],
+			"x-gamess-input" : [ "inp", "gam", "gamin" ],
+			"x-gaussian-checkpoint" : [ "fch", "fchk" ],
+			"x-gaussian-cube" : "cub",
+			"x-gaussian-input" : [ "gau", "gjc", "gjf" ],
+			"x-gaussian-log" : "gal",
+			"x-gcg8-sequence" : "gcg",
+			"x-genbank" : "gen",
+			"x-hin" : "hin",
+			"x-isostar" : [ "istr", "ist" ],
+			"x-jcamp-dx" : [ "jdx", "dx" ],
+			"x-kinemage" : "kin",
+			"x-macmolecule" : "mcm",
+			"x-macromodel-input" : [ "mmd", "mmod" ],
+			"x-mdl-molfile" : "mol",
+			"x-mdl-rdfile" : "rd",
+			"x-mdl-rxnfile" : "rxn",
+			"x-mdl-sdfile" : [ "sd", "sdf" ],
+			"x-mdl-tgf" : "tgf",
+			"x-mmcif" : "mcif",
+			"x-mol2" : "mol2",
+			"x-molconn-Z" : "b",
+			"x-mopac-graph" : "gpt",
+			"x-mopac-input" : [ "mop", "mopcrt", "mpc", "zmt" ],
+			"x-mopac-out" : "moo",
+			"x-ncbi-asn1" : "asn",
+			"x-ncbi-asn1-ascii" : [ "prt", "ent" ],
+			"x-ncbi-asn1-binary" : [ "val", "aso" ],
+			"x-pdb" : [ "pdb", "ent" ],
+			"x-rosdal" : "ros",
+			"x-swissprot" : "sw",
+			"x-vamas-iso14976" : "vms",
+			"x-vmd" : "vmd",
+			"x-xtel" : "xtel",
+			"x-xyz" : "xyz"
+		},
+		"image" : {
+			"gif" : "gif",
+			"ief" : "ief",
+			"jpeg" : [ "jpeg", "jpg", "jpe" ],
+			"pcx" : "pcx",
+			"png" : "png",
+			"svg+xml" : [ "svg", "svgz" ],
+			"tiff" : [ "tiff", "tif" ],
+			"vnd.djvu" : [ "djvu", "djv" ],
+			"vnd.wap.wbmp" : "wbmp",
+			"x-canon-cr2" : "cr2",
+			"x-canon-crw" : "crw",
+			"x-cmu-raster" : "ras",
+			"x-coreldraw" : "cdr",
+			"x-coreldrawpattern" : "pat",
+			"x-coreldrawtemplate" : "cdt",
+			"x-corelphotopaint" : "cpt",
+			"x-epson-erf" : "erf",
+			"x-icon" : "ico",
+			"x-jg" : "art",
+			"x-jng" : "jng",
+			"x-nikon-nef" : "nef",
+			"x-olympus-orf" : "orf",
+			"x-photoshop" : "psd",
+			"x-portable-anymap" : "pnm",
+			"x-portable-bitmap" : "pbm",
+			"x-portable-graymap" : "pgm",
+			"x-portable-pixmap" : "ppm",
+			"x-rgb" : "rgb",
+			"x-xbitmap" : "xbm",
+			"x-xpixmap" : "xpm",
+			"x-xwindowdump" : "xwd",
+			"bmp" : "bmp",
+			"cgm" : "cgm",
+			"g3fax" : "g3",
+			"ktx" : "ktx",
+			"prs.btif" : "btif",
+			"sgi" : "sgi",
+			"vnd.dece.graphic" : [ "uvi", "uvvi", "uvg", "uvvg" ],
+			"vnd.dwg" : "dwg",
+			"vnd.dxf" : "dxf",
+			"vnd.fastbidsheet" : "fbs",
+			"vnd.fpx" : "fpx",
+			"vnd.fst" : "fst",
+			"vnd.fujixerox.edmics-mmr" : "mmr",
+			"vnd.fujixerox.edmics-rlc" : "rlc",
+			"vnd.ms-modi" : "mdi",
+			"vnd.ms-photo" : "wdp",
+			"vnd.net-fpx" : "npx",
+			"vnd.xiff" : "xif",
+			"webp" : "webp",
+			"x-3ds" : "3ds",
+			"x-cmx" : "cmx",
+			"x-freehand" : [ "fh", "fhc", "fh4", "fh5", "fh7" ],
+			"x-pict" : [ "pic", "pct" ],
+			"x-tga" : "tga",
+			"cis-cod" : "cod",
+			"pipeg" : "jfif"
+		},
+		"message" : {
+			"rfc822" : [ "eml", "mime", "mht", "mhtml", "nws" ]
+		},
+		"model" : {
+			"iges" : [ "igs", "iges" ],
+			"mesh" : [ "msh", "mesh", "silo" ],
+			"vrml" : [ "wrl", "vrml" ],
+			"x3d+vrml" : [ "x3dv", "x3dvz" ],
+			"x3d+xml" : [ "x3d", "x3dz" ],
+			"x3d+binary" : [ "x3db", "x3dbz" ],
+			"vnd.collada+xml" : "dae",
+			"vnd.dwf" : "dwf",
+			"vnd.gdl" : "gdl",
+			"vnd.gtw" : "gtw",
+			"vnd.mts" : "mts",
+			"vnd.vtu" : "vtu"
+		},
+		"text" : {
+			"cache-manifest" : [ "manifest", "appcache" ],
+			"calendar" : [ "ics", "icz", "ifb" ],
+			"css" : "css",
+			"csv" : "csv",
+			"h323" : "323",
+			"html" : [ "html", "htm", "shtml", "stm" ],
+			"iuls" : "uls",
+			"mathml" : "mml",
+			"plain" : [ "txt", "text", "brf", "conf", "def", "list", "log", "in", "bas" ],
+			"richtext" : "rtx",
+			"scriptlet" : [ "sct", "wsc" ],
+			"texmacs" : [ "tm", "ts" ],
+			"tab-separated-values" : "tsv",
+			"vnd.sun.j2me.app-descriptor" : "jad",
+			"vnd.wap.wml" : "wml",
+			"vnd.wap.wmlscript" : "wmls",
+			"x-bibtex" : "bib",
+			"x-boo" : "boo",
+			"x-c++hdr" : [ "h++", "hpp", "hxx", "hh" ],
+			"x-c++src" : [ "c++", "cpp", "cxx", "cc" ],
+			"x-component" : "htc",
+			"x-dsrc" : "d",
+			"x-diff" : [ "diff", "patch" ],
+			"x-haskell" : "hs",
+			"x-java" : "java",
+			"x-literate-haskell" : "lhs",
+			"x-moc" : "moc",
+			"x-pascal" : [ "p", "pas" ],
+			"x-pcs-gcd" : "gcd",
+			"x-perl" : [ "pl", "pm" ],
+			"x-python" : "py",
+			"x-scala" : "scala",
+			"x-setext" : "etx",
+			"x-tcl" : [ "tcl", "tk" ],
+			"x-tex" : [ "tex", "ltx", "sty", "cls" ],
+			"x-vcalendar" : "vcs",
+			"x-vcard" : "vcf",
+			"n3" : "n3",
+			"prs.lines.tag" : "dsc",
+			"sgml" : [ "sgml", "sgm" ],
+			"troff" : [ "t", "tr", "roff", "man", "me", "ms" ],
+			"turtle" : "ttl",
+			"uri-list" : [ "uri", "uris", "urls" ],
+			"vcard" : "vcard",
+			"vnd.curl" : "curl",
+			"vnd.curl.dcurl" : "dcurl",
+			"vnd.curl.scurl" : "scurl",
+			"vnd.curl.mcurl" : "mcurl",
+			"vnd.dvb.subtitle" : "sub",
+			"vnd.fly" : "fly",
+			"vnd.fmi.flexstor" : "flx",
+			"vnd.graphviz" : "gv",
+			"vnd.in3d.3dml" : "3dml",
+			"vnd.in3d.spot" : "spot",
+			"x-asm" : [ "s", "asm" ],
+			"x-c" : [ "c", "cc", "cxx", "cpp", "h", "hh", "dic" ],
+			"x-fortran" : [ "f", "for", "f77", "f90" ],
+			"x-opml" : "opml",
+			"x-nfo" : "nfo",
+			"x-sfv" : "sfv",
+			"x-uuencode" : "uu",
+			"webviewhtml" : "htt"
+		},
+		"video" : {
+			"3gpp" : "3gp",
+			"annodex" : "axv",
+			"dl" : "dl",
+			"dv" : [ "dif", "dv" ],
+			"fli" : "fli",
+			"gl" : "gl",
+			"mpeg" : [ "mpeg", "mpg", "mpe", "m1v", "m2v", "mp2", "mpa", "mpv2" ],
+			"mp4" : [ "mp4", "mp4v", "mpg4" ],
+			"quicktime" : [ "qt", "mov" ],
+			"ogg" : "ogv",
+			"vnd.mpegurl" : [ "mxu", "m4u" ],
+			"x-flv" : "flv",
+			"x-la-asf" : [ "lsf", "lsx" ],
+			"x-mng" : "mng",
+			"x-ms-asf" : [ "asf", "asx", "asr" ],
+			"x-ms-wm" : "wm",
+			"x-ms-wmv" : "wmv",
+			"x-ms-wmx" : "wmx",
+			"x-ms-wvx" : "wvx",
+			"x-msvideo" : "avi",
+			"x-sgi-movie" : "movie",
+			"x-matroska" : [ "mpv", "mkv", "mk3d", "mks" ],
+			"3gpp2" : "3g2",
+			"h261" : "h261",
+			"h263" : "h263",
+			"h264" : "h264",
+			"jpeg" : "jpgv",
+			"jpm" : [ "jpm", "jpgm" ],
+			"mj2" : [ "mj2", "mjp2" ],
+			"vnd.dece.hd" : [ "uvh", "uvvh" ],
+			"vnd.dece.mobile" : [ "uvm", "uvvm" ],
+			"vnd.dece.pd" : [ "uvp", "uvvp" ],
+			"vnd.dece.sd" : [ "uvs", "uvvs" ],
+			"vnd.dece.video" : [ "uvv", "uvvv" ],
+			"vnd.dvb.file" : "dvb",
+			"vnd.fvt" : "fvt",
+			"vnd.ms-playready.media.pyv" : "pyv",
+			"vnd.uvvu.mp4" : [ "uvu", "uvvu" ],
+			"vnd.vivo" : "viv",
+			"webm" : "webm",
+			"x-f4v" : "f4v",
+			"x-m4v" : "m4v",
+			"x-ms-vob" : "vob",
+			"x-smv" : "smv"
+		},
+		"x-conference" : {
+			"x-cooltalk" : "ice"
+		},
+		"x-world" : {
+			"x-vrml" : [ "vrm", "vrml", "wrl", "flr", "wrz", "xaf", "xof" ]
+		}
+	};
+
+	var mimeTypes = (function() {
+		var type, subtype, val, index, mimeTypes = {};
+		for (type in table) {
+			if (table.hasOwnProperty(type)) {
+				for (subtype in table[type]) {
+					if (table[type].hasOwnProperty(subtype)) {
+						val = table[type][subtype];
+						if (typeof val == "string") {
+							mimeTypes[val] = type + "/" + subtype;
+						} else {
+							for (index = 0; index < val.length; index++) {
+								mimeTypes[val[index]] = type + "/" + subtype;
+							}
+						}
+					}
+				}
+			}
+		}
+		return mimeTypes;
+	})();
+
+	zip.getMimeType = function(filename) {
+		var defaultValue = "application/octet-stream";
+		return filename && mimeTypes[filename.split(".").pop().toLowerCase()] || defaultValue;
+	};
+
+})();
diff --git a/zip.js/WebContent/tests/arraybuffer.js b/zip.js/WebContent/tests/arraybuffer.js
new file mode 100644
index 0000000..395c739
--- /dev/null
+++ b/zip.js/WebContent/tests/arraybuffer.js
@@ -0,0 +1,760 @@
+// Code can be found at: http://www.calormen.com/polyfill/typedarray.js
+
+/*
+ $LicenseInfo:firstyear=2010&license=mit$
+
+ Copyright (c) 2010, Linden Research, Inc.
+
+ 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.
+ $/LicenseInfo$
+ */
+
+// Original can be found at:  https://bitbucket.org/lindenlab/llsd
+// Modifications by Joshua Bell inexorabletash at hotmail.com
+//  * Restructure the creation of types and exporting to global namespace
+//  * Allow no arguments to DataView constructor
+//  * Work cross-frame with native arrays/shimmed DataView
+//  * Corrected Object.defineProperty shim for IE8
+// ES3/ES5 implementation of the Krhonos TypedArray Working Draft (work in progress):
+//   Ref: https://cvs.khronos.org/svn/repos/registry/trunk/public/webgl/doc/spec/TypedArray-spec.html
+//   Date: 2011-02-01
+//
+// Variations:
+//  * Float/Double -> Float32/Float64, per WebGL-Public mailing list conversations (post 5/17)
+//  * Allows typed_array.get/set() as alias for subscripts (typed_array[])
+(function(global) {
+	"use strict";
+
+	var USE_NATIVE_IF_AVAILABLE = true;
+
+	// Approximations of internal ECMAScript conversion functions
+	var ECMAScript = (function() {
+		// Stash a copy in case other scripts modify these
+		var opts = Object.prototype.toString, ophop = Object.prototype.hasOwnProperty;
+
+		return {
+			// Class returns internal [[Class]] property, used to avoid cross-frame instanceof issues:
+			Class : function(v) {
+				return opts.call(v).replace(/^\[object *|\]$/g, '');
+			},
+			HasProperty : function(o, p) {
+				return p in o;
+			},
+			HasOwnProperty : function(o, p) {
+				return ophop.call(o, p);
+			},
+			IsCallable : function(o) {
+				return typeof o === 'function';
+			},
+			ToInt32 : function(v) {
+				return v >> 0;
+			},
+			ToUint32 : function(v) {
+				return v >>> 0;
+			}
+		};
+	}());
+
+	// Create an INDEX_SIZE_ERR event - intentionally induces a DOM error if possible
+
+	function new_INDEX_SIZE_ERR() {
+		try {
+			if (document) {
+				// raises DOMException(INDEX_SIZE_ERR)
+				document.createTextNode("").splitText(1);
+			}
+			return new RangeError("INDEX_SIZE_ERR");
+		} catch (e) {
+			return e;
+		}
+	}
+
+	// ES5: lock down object properties
+
+	function configureProperties(obj) {
+		if (Object.getOwnPropertyNames && Object.defineProperty) {
+			var props = Object.getOwnPropertyNames(obj), i;
+			for (i = 0; i < props.length; i += 1) {
+				Object.defineProperty(obj, props[i], {
+					value : obj[props[i]],
+					writable : false,
+					enumerable : false,
+					configurable : false
+				});
+			}
+		}
+	}
+
+	// emulate ES5 getter/setter API using legacy APIs
+	// http://blogs.msdn.com/b/ie/archive/2010/09/07/transitioning-existing-code-to-the-es5-getter-setter-apis.aspx
+	// (second clause tests for Object.defineProperty() in IE<9 that only supports extending DOM prototypes, but
+	// note that IE<9 does not support __defineGetter__ or __defineSetter__ so it just renders the method harmless)
+	if (!Object.defineProperty || !(function() {
+		try {
+			Object.defineProperty({}, 'x', {});
+			return true;
+		} catch (e) {
+			return false;
+		}
+	}())) {
+		Object.defineProperty = function(o, p, desc) {
+			if (!o === Object(o)) {
+				throw new TypeError("Object.defineProperty called on non-object");
+			}
+			if (ECMAScript.HasProperty(desc, 'get') && Object.prototype.__defineGetter__) {
+				Object.prototype.__defineGetter__.call(o, p, desc.get);
+			}
+			if (ECMAScript.HasProperty(desc, 'set') && Object.prototype.__defineSetter__) {
+				Object.prototype.__defineSetter__.call(o, p, desc.set);
+			}
+			if (ECMAScript.HasProperty(desc, 'value')) {
+				o[p] = desc.value;
+			}
+			return o;
+		};
+	}
+
+	if (!Object.getOwnPropertyNames) {
+		Object.getOwnPropertyNames = function getOwnPropertyNames(o) {
+			if (o !== Object(o)) {
+				throw new TypeError("Object.getOwnPropertyNames called on non-object");
+			}
+			var props = [], p;
+			for (p in o) {
+				if (ECMAScript.HasOwnProperty(o, p)) {
+					props.push(p);
+				}
+			}
+			return props;
+		};
+	}
+
+	// ES5: Make obj[index] an alias for obj._getter(index)/obj._setter(index, value)
+	// for index in 0 ... obj.length
+
+	function makeArrayAccessors(obj) {
+		if (!Object.defineProperty) {
+			return;
+		}
+
+		function makeArrayAccessor(index) {
+			Object.defineProperty(obj, index, {
+				'get' : function() {
+					return obj._getter(index);
+				},
+				'set' : function(v) {
+					obj._setter(index, v);
+				},
+				enumerable : true,
+				configurable : false
+			});
+		}
+
+		var i;
+		for (i = 0; i < obj.length; i += 1) {
+			makeArrayAccessor(i);
+		}
+	}
+
+	// Internal conversion functions:
+	// pack<Type>() - take a number (interpreted as Type), output a byte array
+	// unpack<Type>() - take a byte array, output a Type-like number
+
+	function as_signed(value, bits) {
+		var s = 32 - bits;
+		return (value << s) >> s;
+	}
+
+	function as_unsigned(value, bits) {
+		var s = 32 - bits;
+		return (value << s) >>> s;
+	}
+
+	function packInt8(n) {
+		return [ n & 0xff ];
+	}
+
+	function unpackInt8(bytes) {
+		return as_signed(bytes[0], 8);
+	}
+
+	function packUint8(n) {
+		return [ n & 0xff ];
+	}
+
+	function unpackUint8(bytes) {
+		return as_unsigned(bytes[0], 8);
+	}
+
+	function packInt16(n) {
+		return [ (n >> 8) & 0xff, n & 0xff ];
+	}
+
+	function unpackInt16(bytes) {
+		return as_signed(bytes[0] << 8 | bytes[1], 16);
+	}
+
+	function packUint16(n) {
+		return [ (n >> 8) & 0xff, n & 0xff ];
+	}
+
+	function unpackUint16(bytes) {
+		return as_unsigned(bytes[0] << 8 | bytes[1], 16);
+	}
+
+	function packInt32(n) {
+		return [ (n >> 24) & 0xff, (n >> 16) & 0xff, (n >> 8) & 0xff, n & 0xff ];
+	}
+
+	function unpackInt32(bytes) {
+		return as_signed(bytes[0] << 24 | bytes[1] << 16 | bytes[2] << 8 | bytes[3], 32);
+	}
+
+	function packUint32(n) {
+		return [ (n >> 24) & 0xff, (n >> 16) & 0xff, (n >> 8) & 0xff, n & 0xff ];
+	}
+
+	function unpackUint32(bytes) {
+		return as_unsigned(bytes[0] << 24 | bytes[1] << 16 | bytes[2] << 8 | bytes[3], 32);
+	}
+
+	function packIEEE754(v, ebits, fbits) {
+
+		var bias = (1 << (ebits - 1)) - 1, s, e, f, ln, i, bits, str, bytes;
+
+		// Compute sign, exponent, fraction
+		if (v !== v) {
+			// NaN
+			// http://dev.w3.org/2006/webapi/WebIDL/#es-type-mapping
+			e = (1 << bias) - 1;
+			f = Math.pow(2, fbits - 1);
+			s = 0;
+		} else if (v === Infinity || v === -Infinity) {
+			e = (1 << bias) - 1;
+			f = 0;
+			s = (v < 0) ? 1 : 0;
+		} else if (v === 0) {
+			e = 0;
+			f = 0;
+			s = (1 / v === -Infinity) ? 1 : 0;
+		} else {
+			s = v < 0;
+			v = Math.abs(v);
+
+			if (v >= Math.pow(2, 1 - bias)) {
+				// Normalized
+				ln = Math.min(Math.floor(Math.log(v) / Math.LN2), bias);
+				e = ln + bias;
+				f = Math.round(v * Math.pow(2, fbits - ln) - Math.pow(2, fbits));
+			} else {
+				// Denormalized
+				e = 0;
+				f = Math.round(v / Math.pow(2, 1 - bias - fbits));
+			}
+		}
+
+		// Pack sign, exponent, fraction
+		bits = [];
+		for (i = fbits; i; i -= 1) {
+			bits.push(f % 2 ? 1 : 0);
+			f = Math.floor(f / 2);
+		}
+		for (i = ebits; i; i -= 1) {
+			bits.push(e % 2 ? 1 : 0);
+			e = Math.floor(e / 2);
+		}
+		bits.push(s ? 1 : 0);
+		bits.reverse();
+		str = bits.join('');
+
+		// Bits to bytes
+		bytes = [];
+		while (str.length) {
+			bytes.push(parseInt(str.substring(0, 8), 2));
+			str = str.substring(8);
+		}
+		return bytes;
+	}
+
+	function unpackIEEE754(bytes, ebits, fbits) {
+
+		// Bytes to bits
+		var bits = [], i, j, b, str, bias, s, e, f;
+
+		for (i = bytes.length; i; i -= 1) {
+			b = bytes[i - 1];
+			for (j = 8; j; j -= 1) {
+				bits.push(b % 2 ? 1 : 0);
+				b = b >> 1;
+			}
+		}
+		bits.reverse();
+		str = bits.join('');
+
+		// Unpack sign, exponent, fraction
+		bias = (1 << (ebits - 1)) - 1;
+		s = parseInt(str.substring(0, 1), 2) ? -1 : 1;
+		e = parseInt(str.substring(1, 1 + ebits), 2);
+		f = parseInt(str.substring(1 + ebits), 2);
+
+		// Produce number
+		if (e === (1 << ebits) - 1) {
+			return f !== 0 ? NaN : s * Infinity;
+		} else if (e > 0) {
+			// Normalized
+			return s * Math.pow(2, e - bias) * (1 + f / Math.pow(2, fbits));
+		} else if (f !== 0) {
+			// Denormalized
+			return s * Math.pow(2, -(bias - 1)) * (f / Math.pow(2, fbits));
+		} else {
+			return s < 0 ? -0 : 0;
+		}
+	}
+
+	function unpackFloat64(b) {
+		return unpackIEEE754(b, 11, 52);
+	}
+
+	function packFloat64(v) {
+		return packIEEE754(v, 11, 52);
+	}
+
+	function unpackFloat32(b) {
+		return unpackIEEE754(b, 8, 23);
+	}
+
+	function packFloat32(v) {
+		return packIEEE754(v, 8, 23);
+	}
+
+	//
+	// 3 The ArrayBuffer Type
+	//
+	(function() {
+
+		/** @constructor */
+		var ArrayBuffer = function ArrayBuffer(length) {
+			length = ECMAScript.ToInt32(length);
+			if (length < 0) {
+				throw new RangeError('ArrayBuffer size is not a small enough positive integer.');
+			}
+
+			this.byteLength = length;
+			this._bytes = [];
+			this._bytes.length = length;
+
+			var i;
+			for (i = 0; i < this.byteLength; i += 1) {
+				this._bytes[i] = 0;
+			}
+
+			configureProperties(this);
+		};
+
+		//
+		// 4 The ArrayBufferView Type
+		//
+		// NOTE: this constructor is not exported
+		/** @constructor */
+		var ArrayBufferView = function ArrayBufferView() {
+			// this.buffer = null;
+			// this.byteOffset = 0;
+			// this.byteLength = 0;
+		};
+
+		//
+		// 5 The Typed Array View Types
+		//
+
+		function makeTypedArrayConstructor(bytesPerElement, pack, unpack) {
+			// Each TypedArray type requires a distinct constructor instance with
+			// identical logic, which this produces.
+			var ctor;
+			ctor = function(buffer, byteOffset, length) {
+				var array, sequence, i, s;
+
+				if (!arguments.length || typeof arguments[0] === 'number') {
+					// Constructor(unsigned long length)
+					this.length = ECMAScript.ToInt32(arguments[0]);
+					if (length < 0) {
+						throw new RangeError('ArrayBufferView size is not a small enough positive integer.');
+					}
+
+					this.byteLength = this.length * this.BYTES_PER_ELEMENT;
+					this.buffer = new ArrayBuffer(this.byteLength);
+					this.byteOffset = 0;
+				} else if (typeof arguments[0] === 'object' && arguments[0].constructor === ctor) {
+					// Constructor(TypedArray array)
+					array = arguments[0];
+
+					this.length = array.length;
+					this.byteLength = this.length * this.BYTES_PER_ELEMENT;
+					this.buffer = new ArrayBuffer(this.byteLength);
+					this.byteOffset = 0;
+
+					for (i = 0; i < this.length; i += 1) {
+						this._setter(i, array._getter(i));
+					}
+				} else if (typeof arguments[0] === 'object' && !(arguments[0] instanceof ArrayBuffer || ECMAScript.Class(arguments[0]) === 'ArrayBuffer')) {
+					// Constructor(sequence<type> array)
+					sequence = arguments[0];
+
+					this.length = ECMAScript.ToUint32(sequence.length);
+					this.byteLength = this.length * this.BYTES_PER_ELEMENT;
+					this.buffer = new ArrayBuffer(this.byteLength);
+					this.byteOffset = 0;
+
+					for (i = 0; i < this.length; i += 1) {
+						s = sequence[i];
+						this._setter(i, Number(s));
+					}
+				} else if (typeof arguments[0] === 'object' && (arguments[0] instanceof ArrayBuffer || ECMAScript.Class(arguments[0]) === 'ArrayBuffer')) {
+					// Constructor(ArrayBuffer buffer,
+					// optional unsigned long byteOffset, optional unsigned long length)
+					this.buffer = buffer;
+
+					this.byteOffset = ECMAScript.ToUint32(byteOffset);
+					if (this.byteOffset > this.buffer.byteLength) {
+						throw new_INDEX_SIZE_ERR(); // byteOffset out of range
+					}
+
+					if (this.byteOffset % this.BYTES_PER_ELEMENT) {
+						// The given byteOffset must be a multiple of the element
+						// size of the specific type, otherwise an exception is raised.
+						// throw new_INDEX_SIZE_ERR();
+						throw new RangeError("ArrayBuffer length minus the byteOffset is not a multiple of the element size.");
+					}
+
+					if (arguments.length < 3) {
+						this.byteLength = this.buffer.byteLength - this.byteOffset;
+
+						if (this.byteLength % this.BYTES_PER_ELEMENT) {
+							throw new_INDEX_SIZE_ERR(); // length of buffer minus byteOffset not a multiple of the element size
+						}
+						this.length = this.byteLength / this.BYTES_PER_ELEMENT;
+					} else {
+						this.length = ECMAScript.ToUint32(length);
+						this.byteLength = this.length * this.BYTES_PER_ELEMENT;
+					}
+
+					if ((this.byteOffset + this.byteLength) > this.buffer.byteLength) {
+						throw new_INDEX_SIZE_ERR(); // byteOffset and length reference an area beyond the end of the buffer
+					}
+				} else {
+					throw new TypeError("Unexpected argument type(s)");
+				}
+
+				this.constructor = ctor;
+
+				configureProperties(this);
+				makeArrayAccessors(this);
+			};
+
+			ctor.prototype = new ArrayBufferView();
+			ctor.prototype.BYTES_PER_ELEMENT = bytesPerElement;
+			ctor.prototype._pack = pack;
+			ctor.prototype._unpack = unpack;
+			ctor.BYTES_PER_ELEMENT = bytesPerElement;
+
+			// getter type (unsigned long index);
+			ctor.prototype._getter = function(index) {
+				if (arguments.length < 1) {
+					throw new SyntaxError("Not enough arguments");
+				}
+
+				index = ECMAScript.ToUint32(index);
+				if (index >= this.length) {
+					// throw new_INDEX_SIZE_ERR(); // Array index out of range
+					return (void 0); // undefined
+				}
+
+				var bytes = [], i, o;
+				for (i = 0, o = this.byteOffset + index * this.BYTES_PER_ELEMENT; i < this.BYTES_PER_ELEMENT; i += 1, o += 1) {
+					bytes.push(this.buffer._bytes[o]);
+				}
+				return this._unpack(bytes);
+			};
+
+			// NONSTANDARD: convenience alias for getter: type get(unsigned long index);
+			ctor.prototype.get = ctor.prototype._getter;
+
+			// setter void (unsigned long index, type value);
+			ctor.prototype._setter = function(index, value) {
+				if (arguments.length < 2) {
+					throw new SyntaxError("Not enough arguments");
+				}
+
+				index = ECMAScript.ToUint32(index);
+				if (index >= this.length) {
+					// throw new_INDEX_SIZE_ERR(); // Array index out of range
+					return;
+				}
+
+				var bytes = this._pack(value), i, o;
+				for (i = 0, o = this.byteOffset + index * this.BYTES_PER_ELEMENT; i < this.BYTES_PER_ELEMENT; i += 1, o += 1) {
+					this.buffer._bytes[o] = bytes[i];
+				}
+			};
+
+			// void set(TypedArray array, optional unsigned long offset);
+			// void set(sequence<type> array, optional unsigned long offset);
+			ctor.prototype.set = function(index, value) {
+				if (arguments.length < 1) {
+					throw new SyntaxError("Not enough arguments");
+				}
+				var array, sequence, offset, len, i, s, d, byteOffset, byteLength, tmp;
+
+				if (typeof arguments[0] === 'object' && arguments[0].constructor === this.constructor) {
+					// void set(TypedArray array, optional unsigned long offset);
+					array = arguments[0];
+					offset = ECMAScript.ToUint32(arguments[1]);
+
+					if (offset + array.length > this.length) {
+						throw new_INDEX_SIZE_ERR(); // Offset plus length of array is out of range
+					}
+
+					byteOffset = this.byteOffset + offset * this.BYTES_PER_ELEMENT;
+					byteLength = array.length * this.BYTES_PER_ELEMENT;
+
+					if (array.buffer === this.buffer) {
+						tmp = [];
+						for (i = 0, s = array.byteOffset; i < byteLength; i += 1, s += 1) {
+							tmp[i] = array.buffer._bytes[s];
+						}
+						for (i = 0, d = byteOffset; i < byteLength; i += 1, d += 1) {
+							this.buffer._bytes[d] = tmp[i];
+						}
+					} else {
+						for (i = 0, s = array.byteOffset, d = byteOffset; i < byteLength; i += 1, s += 1, d += 1) {
+							this.buffer._bytes[d] = array.buffer._bytes[s];
+						}
+					}
+				} else if (typeof arguments[0] === 'object' && typeof arguments[0].length !== 'undefined') {
+					// void set(sequence<type> array, optional unsigned long offset);
+					sequence = arguments[0];
+					len = ECMAScript.ToUint32(sequence.length);
+					offset = ECMAScript.ToUint32(arguments[1]);
+
+					if (offset + len > this.length) {
+						throw new_INDEX_SIZE_ERR(); // Offset plus length of array is out of range
+					}
+
+					for (i = 0; i < len; i += 1) {
+						s = sequence[i];
+						this._setter(offset + i, Number(s));
+					}
+				} else {
+					throw new TypeError("Unexpected argument type(s)");
+				}
+			};
+
+			// TypedArray subarray(long begin, optional long end);
+			ctor.prototype.subarray = function(start, end) {
+				function clamp(v, min, max) {
+					return v < min ? min : v > max ? max : v;
+				}
+
+				start = ECMAScript.ToInt32(start);
+				end = ECMAScript.ToInt32(end);
+
+				if (arguments.length < 1) {
+					start = 0;
+				}
+				if (arguments.length < 2) {
+					end = this.length;
+				}
+
+				if (start < 0) {
+					start = this.length + start;
+				}
+				if (end < 0) {
+					end = this.length + end;
+				}
+
+				start = clamp(start, 0, this.length);
+				end = clamp(end, 0, this.length);
+
+				var len = end - start;
+				if (len < 0) {
+					len = 0;
+				}
+
+				return new this.constructor(this.buffer, start * this.BYTES_PER_ELEMENT, len);
+			};
+
+			return ctor;
+		}
+
+		var Int8Array = makeTypedArrayConstructor(1, packInt8, unpackInt8);
+		var Uint8Array = makeTypedArrayConstructor(1, packUint8, unpackUint8);
+		var Int16Array = makeTypedArrayConstructor(2, packInt16, unpackInt16);
+		var Uint16Array = makeTypedArrayConstructor(2, packUint16, unpackUint16);
+		var Int32Array = makeTypedArrayConstructor(4, packInt32, unpackInt32);
+		var Uint32Array = makeTypedArrayConstructor(4, packUint32, unpackUint32);
+		var Float32Array = makeTypedArrayConstructor(4, packFloat32, unpackFloat32);
+		var Float64Array = makeTypedArrayConstructor(8, packFloat64, unpackFloat64);
+
+		if (USE_NATIVE_IF_AVAILABLE) {
+			global.ArrayBuffer = global.ArrayBuffer || ArrayBuffer;
+			global.Int8Array = global.Int8Array || Int8Array;
+			global.Uint8Array = global.Uint8Array || Uint8Array;
+			global.Int16Array = global.Int16Array || Int16Array;
+			global.Uint16Array = global.Uint16Array || Uint16Array;
+			global.Int32Array = global.Int32Array || Int32Array;
+			global.Uint32Array = global.Uint32Array || Uint32Array;
+			global.Float32Array = global.Float32Array || Float32Array;
+			global.Float64Array = global.Float64Array || Float64Array;
+		} else {
+			global.ArrayBuffer = ArrayBuffer;
+			global.Int8Array = Int8Array;
+			global.Uint8Array = Uint8Array;
+			global.Int16Array = Int16Array;
+			global.Uint16Array = Uint16Array;
+			global.Int32Array = Int32Array;
+			global.Uint32Array = Uint32Array;
+			global.Float32Array = Float32Array;
+			global.Float64Array = Float64Array;
+		}
+	}());
+
+	//
+	// 6 The DataView View Type
+	//
+	(function() {
+		function r(array, index) {
+			return ECMAScript.IsCallable(array.get) ? array.get(index) : array[index];
+		}
+
+		var IS_BIG_ENDIAN = (function() {
+			var u16array = new Uint16Array([ 0x1234 ]), u8array = new Uint8Array(u16array.buffer);
+			return r(u8array, 0) === 0x12;
+		}());
+
+		// Constructor(ArrayBuffer buffer,
+		// optional unsigned long byteOffset,
+		// optional unsigned long byteLength)
+		/** @constructor */
+		var DataView = function DataView(buffer, byteOffset, byteLength) {
+			if (arguments.length === 0) {
+				buffer = new ArrayBuffer(0);
+			} else if (!(buffer instanceof ArrayBuffer || ECMAScript.Class(buffer) === 'ArrayBuffer')) {
+				throw new TypeError("TypeError");
+			}
+
+			this.buffer = buffer || new ArrayBuffer(0);
+
+			this.byteOffset = ECMAScript.ToUint32(byteOffset);
+			if (this.byteOffset > this.buffer.byteLength) {
+				throw new_INDEX_SIZE_ERR(); // byteOffset out of range
+			}
+
+			if (arguments.length < 3) {
+				this.byteLength = this.buffer.byteLength - this.byteOffset;
+			} else {
+				this.byteLength = ECMAScript.ToUint32(byteLength);
+			}
+
+			if ((this.byteOffset + this.byteLength) > this.buffer.byteLength) {
+				throw new_INDEX_SIZE_ERR(); // byteOffset and length reference an area beyond the end of the buffer
+			}
+
+			configureProperties(this);
+		};
+
+		// TODO: Reintroduce this to get correct hierarchy
+		// if (typeof ArrayBufferView === 'function') {
+		// DataView.prototype = new ArrayBufferView();
+		// }
+
+		function makeDataView_getter(arrayType) {
+			return function(byteOffset, littleEndian) {
+
+				byteOffset = ECMAScript.ToUint32(byteOffset);
+
+				if (byteOffset + arrayType.BYTES_PER_ELEMENT > this.byteLength) {
+					throw new_INDEX_SIZE_ERR(); // Array index out of range
+				}
+				byteOffset += this.byteOffset;
+
+				var uint8Array = new Uint8Array(this.buffer, byteOffset, arrayType.BYTES_PER_ELEMENT), bytes = [], i;
+				for (i = 0; i < arrayType.BYTES_PER_ELEMENT; i += 1) {
+					bytes.push(r(uint8Array, i));
+				}
+
+				if (Boolean(littleEndian) === Boolean(IS_BIG_ENDIAN)) {
+					bytes.reverse();
+				}
+
+				return r(new arrayType(new Uint8Array(bytes).buffer), 0);
+			};
+		}
+
+		DataView.prototype.getUint8 = makeDataView_getter(Uint8Array);
+		DataView.prototype.getInt8 = makeDataView_getter(Int8Array);
+		DataView.prototype.getUint16 = makeDataView_getter(Uint16Array);
+		DataView.prototype.getInt16 = makeDataView_getter(Int16Array);
+		DataView.prototype.getUint32 = makeDataView_getter(Uint32Array);
+		DataView.prototype.getInt32 = makeDataView_getter(Int32Array);
+		DataView.prototype.getFloat32 = makeDataView_getter(Float32Array);
+		DataView.prototype.getFloat64 = makeDataView_getter(Float64Array);
+
+		function makeDataView_setter(arrayType) {
+			return function(byteOffset, value, littleEndian) {
+
+				byteOffset = ECMAScript.ToUint32(byteOffset);
+				if (byteOffset + arrayType.BYTES_PER_ELEMENT > this.byteLength) {
+					throw new_INDEX_SIZE_ERR(); // Array index out of range
+				}
+
+				// Get bytes
+				var typeArray = new arrayType([ value ]), byteArray = new Uint8Array(typeArray.buffer), bytes = [], i, byteView;
+
+				for (i = 0; i < arrayType.BYTES_PER_ELEMENT; i += 1) {
+					bytes.push(r(byteArray, i));
+				}
+
+				// Flip if necessary
+				if (Boolean(littleEndian) === Boolean(IS_BIG_ENDIAN)) {
+					bytes.reverse();
+				}
+
+				// Write them
+				byteView = new Uint8Array(this.buffer, byteOffset, arrayType.BYTES_PER_ELEMENT);
+				byteView.set(bytes);
+			};
+		}
+
+		DataView.prototype.setUint8 = makeDataView_setter(Uint8Array);
+		DataView.prototype.setInt8 = makeDataView_setter(Int8Array);
+		DataView.prototype.setUint16 = makeDataView_setter(Uint16Array);
+		DataView.prototype.setInt16 = makeDataView_setter(Int16Array);
+		DataView.prototype.setUint32 = makeDataView_setter(Uint32Array);
+		DataView.prototype.setInt32 = makeDataView_setter(Int32Array);
+		DataView.prototype.setFloat32 = makeDataView_setter(Float32Array);
+		DataView.prototype.setFloat64 = makeDataView_setter(Float64Array);
+
+		if (USE_NATIVE_IF_AVAILABLE) {
+			global.DataView = global.DataView || DataView;
+		} else {
+			global.DataView = DataView;
+		}
+
+	}());
+
+}(this));
diff --git a/zip.js/WebContent/tests/base64.js b/zip.js/WebContent/tests/base64.js
new file mode 100644
index 0000000..ae1a02d
--- /dev/null
+++ b/zip.js/WebContent/tests/base64.js
@@ -0,0 +1,58 @@
+/// Code can be found at: https://gist.github.com/1284012
+
+(function() {
+
+	var a64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/', a256 = {
+		indexOf : function(c) {
+			return c.charCodeAt(0);
+		},
+		charAt : String.fromCharCode
+	};
+
+	function code(s, discard, alpha, beta, w1, w2) {
+		s = String(s);
+		var b = 0, x = '', i, c, bs = 1, sb = 1, length = s.length, tmp;
+		for (i = 0; i < length || (!discard && sb > 1); i += 1) {
+			b *= w1;
+			bs *= w1;
+			if (i < length) {
+				c = alpha.indexOf(s.charAt(i));
+				if (c <= -1 || c >= w1) {
+					throw new RangeError();
+				}
+				sb *= w1;
+				b += c;
+			}
+			while (bs >= w2) {
+				bs /= w2;
+				if (sb > 1) {
+					tmp = b;
+					b %= bs;
+					x += beta.charAt((tmp - b) / bs);
+					sb /= w2;
+				}
+			}
+		}
+		return x;
+	}
+
+	if (!("btoa" in window))
+		window.btoa = function(s) {
+			s = code(s, false, a256, a64, 256, 64);
+			return s + '===='.slice((s.length % 4) || 4);
+		};
+
+	if (!("atob" in window))
+		window.atob = function(s) {
+			var i;
+			s = String(s).split('=');
+			for (i = s.length - 1; i >= 0; i -= 1) {
+				if (s[i].length % 4 === 1) {
+					throw new RangeError();
+				}
+				s[i] = code(s[i], true, a64, a256, 64, 256);
+			}
+			return s.join('');
+		};
+
+})();
diff --git a/zip.js/WebContent/tests/dataview.js b/zip.js/WebContent/tests/dataview.js
new file mode 100644
index 0000000..ce2557a
--- /dev/null
+++ b/zip.js/WebContent/tests/dataview.js
@@ -0,0 +1,212 @@
+
+/* 
+ * DataView.js:
+ * An implementation of the DataView class on top of typed arrays.
+ * Useful for Firefox 4 which implements TypedArrays but not DataView.
+ *
+ * Copyright 2011, David Flanagan
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, 
+ * are permitted provided that the following conditions are met:
+ *
+ *   Redistributions of source code must retain the above copyright notice, 
+ *   this list of conditions and the following disclaimer.
+ *
+ *   Redistributions in binary form must reproduce the above copyright notice, 
+ *   this list of conditions and the following disclaimer in the documentation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+"use strict";
+
+(function(global) {
+    // If DataView already exists, do nothing
+    if (global.DataView) return;
+
+    // If ArrayBuffer is not supported, fail with an error
+    if (!global.ArrayBuffer) fail("ArrayBuffer not supported");
+
+    // If ES5 is not supported, fail
+    if (!Object.defineProperties) fail("This module requires ECMAScript 5");
+
+    // Figure if the platform is natively little-endian.
+    // If the integer 0x00000001 is arranged in memory as 01 00 00 00 then
+    // we're on a little endian platform. On a big-endian platform we'd get
+    // get bytes 00 00 00 01 instead.
+    var nativele = new Int8Array(new Int32Array([1]).buffer)[0] === 1;
+
+    // A temporary array for copying or reversing bytes into.
+    // Since js is single-threaded, we only need this one static copy
+    var temp = new Uint8Array(8);
+
+    // The DataView() constructor
+    global.DataView = function DataView(buffer, offset, length) {
+        if (!(buffer instanceof ArrayBuffer)) fail("Bad ArrayBuffer");
+
+        // Default values for omitted arguments
+        offset = offset || 0;
+        length = length || (buffer.byteLength - offset);
+
+        if (offset < 0 || length < 0 || offset + length > buffer.byteLength) fail("Illegal offset and/or length");
+
+        // Define the 3 read-only, non-enumerable ArrayBufferView properties
+        Object.defineProperties(this, {
+            buffer: {
+                value: buffer,
+                enumerable: false,
+                writable: false,
+                configurable: false
+            },
+            byteOffset: {
+                value: offset,
+                enumerable: false,
+                writable: false,
+                configurable: false
+            },
+            byteLength: {
+                value: length,
+                enumerable: false,
+                writable: false,
+                configurable: false
+            },
+            _bytes: {
+                value: new Uint8Array(buffer, offset, length),
+                enumerable: false,
+                writable: false,
+                configurable: false
+            }
+        });
+    }
+
+    // The DataView prototype object
+    global.DataView.prototype = {
+        constructor: DataView,
+
+        getInt8: function getInt8(offset) {
+            return get(this, Int8Array, 1, offset);
+        },
+        getUint8: function getUint8(offset) {
+            return get(this, Uint8Array, 1, offset);
+        },
+        getInt16: function getInt16(offset, le) {
+            return get(this, Int16Array, 2, offset, le);
+        },
+        getUint16: function getUint16(offset, le) {
+            return get(this, Uint16Array, 2, offset, le);
+        },
+        getInt32: function getInt32(offset, le) {
+            return get(this, Int32Array, 4, offset, le);
+        },
+        getUint32: function getUint32(offset, le) {
+            return get(this, Uint32Array, 4, offset, le);
+        },
+        getFloat32: function getFloat32(offset, le) {
+            return get(this, Float32Array, 4, offset, le);
+        },
+        getFloat64: function getFloat32(offset, le) {
+            return get(this, Float64Array, 8, offset, le);
+        },
+
+
+        setInt8: function setInt8(offset, value) {
+            set(this, Int8Array, 1, offset, value);
+        },
+        setUint8: function setUint8(offset, value) {
+            set(this, Uint8Array, 1, offset, value);
+        },
+        setInt16: function setInt16(offset, value, le) {
+            set(this, Int16Array, 2, offset, value, le);
+        },
+        setUint16: function setUint16(offset, value, le) {
+            set(this, Uint16Array, 2, offset, value, le);
+        },
+        setInt32: function setInt32(offset, value, le) {
+            set(this, Int32Array, 4, offset, value, le);
+        },
+        setUint32: function setUint32(offset, value, le) {
+            set(this, Uint32Array, 4, offset, value, le);
+        },
+        setFloat32: function setFloat32(offset, value, le) {
+            set(this, Float32Array, 4, offset, value, le);
+        },
+        setFloat64: function setFloat64(offset, value, le) {
+            set(this, Float64Array, 8, offset, value, le);
+        }
+    };
+
+    // The get() utility function used by the get methods
+
+
+    function get(view, type, size, offset, le) {
+        if (offset === undefined) fail("Missing required offset argument");
+
+        if (offset < 0 || offset + size > view.byteLength) fail("Invalid index: " + offset);
+
+        if (size === 1 || !! le === nativele) {
+            // This is the easy case: the desired endianness 
+            // matches the native endianness.
+            // Typed arrays require proper alignment.  DataView does not.
+            if ((view.byteOffset + offset) % size === 0) return (new type(view.buffer, view.byteOffset + offset, 1))[0];
+            else {
+                // Copy bytes into the temp array, to fix alignment
+                for (var i = 0; i < size; i++)
+                temp[i] = view._bytes[offset + i];
+                // Now wrap that buffer with an array of the desired type
+                return (new type(temp.buffer))[0];
+            }
+        } else {
+            // If the native endianness doesn't match the desired, then
+            // we have to reverse the bytes
+            for (var i = 0; i < size; i++)
+            temp[size - i - 1] = view._bytes[offset + i];
+            return (new type(temp.buffer))[0];
+        }
+    }
+
+    // The set() utility function used by the set methods
+
+
+    function set(view, type, size, offset, value, le) {
+        if (offset === undefined) fail("Missing required offset argument");
+        if (value === undefined) fail("Missing required value argument");
+
+        if (offset < 0 || offset + size > view.byteLength) fail("Invalid index: " + offset);
+
+        if (size === 1 || !! le === nativele) {
+            // This is the easy case: the desired endianness 
+            // matches the native endianness.
+            if ((view.byteOffset + offset) % size === 0) {
+                (new type(view.buffer, view.byteOffset + offset, 1))[0] = value;
+            } else {
+                (new type(temp.buffer))[0] = value;
+                // Now copy the bytes into the view's buffer
+                for (var i = 0; i < size; i++)
+                view._bytes[i + offset] = temp[i];
+            }
+        } else {
+            // If the native endianness doesn't match the desired, then
+            // we have to reverse the bytes
+            // Store the value into our temporary buffer
+            (new type(temp.buffer))[0] = value;
+
+            // Now copy the bytes, in reverse order, into the view's buffer
+            for (var i = 0; i < size; i++)
+            view._bytes[offset + i] = temp[size - 1 - i];
+        }
+    }
+
+    function fail(msg) {
+        throw new Error(msg);
+    }
+}(this)); 
\ No newline at end of file
diff --git a/zip.js/WebContent/tests/lorem.txt b/zip.js/WebContent/tests/lorem.txt
new file mode 100644
index 0000000..e0a150b
--- /dev/null
+++ b/zip.js/WebContent/tests/lorem.txt
@@ -0,0 +1 @@
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Typi non habent claritatem insitam; est usus legentis in iis qui facit eorum claritatem. Investigationes demonstraverunt lectores legere me lius quod ii legunt saepius. Claritas est etiam processus dynamicus, qui sequitur mutationem consuetudium lectorum. Mirum est notare quam littera gothica, quam nunc putamus parum claram, anteposuerit litterarum formas humanitatis per seacula quarta decima et quinta decima. Eodem modo typi, qui nunc nobis videntur parum clari, fiant sollemnes in futurum.
\ No newline at end of file
diff --git a/zip.js/WebContent/tests/lorem.zip b/zip.js/WebContent/tests/lorem.zip
new file mode 100644
index 0000000..7794582
Binary files /dev/null and b/zip.js/WebContent/tests/lorem.zip differ
diff --git a/zip.js/WebContent/tests/lorem2.zip b/zip.js/WebContent/tests/lorem2.zip
new file mode 100644
index 0000000..0a02e32
Binary files /dev/null and b/zip.js/WebContent/tests/lorem2.zip differ
diff --git a/zip.js/WebContent/tests/lorem_store.zip b/zip.js/WebContent/tests/lorem_store.zip
new file mode 100644
index 0000000..cff4206
Binary files /dev/null and b/zip.js/WebContent/tests/lorem_store.zip differ
diff --git a/zip.js/WebContent/tests/test1.html b/zip.js/WebContent/tests/test1.html
new file mode 100644
index 0000000..e982c6f
--- /dev/null
+++ b/zip.js/WebContent/tests/test1.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset='utf-8'>
+<title>Demo Blob</title>
+</head>
+<body>
+	<script type="text/javascript" src="../zip.js"></script>
+	<script type="text/javascript" src="../mime-types.js"></script>
+	<script type="text/javascript" src="dataview.js"></script>
+	<script type="text/javascript" src="test1.js"></script>
+</body>
+</html>
\ No newline at end of file
diff --git a/zip.js/WebContent/tests/test1.js b/zip.js/WebContent/tests/test1.js
new file mode 100644
index 0000000..e17aab0
--- /dev/null
+++ b/zip.js/WebContent/tests/test1.js
@@ -0,0 +1,46 @@
+var TEXT_CONTENT = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Typi non habent claritatem insitam; est usus legentis in iis qui facit eorum claritatem. Investigationes demonstraverunt lectores legere me lius quod ii legunt saepius. Claritas est etiam processus dynamicus, qui sequitur mutationem consuetudium lectorum. Mirum est notare quam littera gothica, quam nunc putamus parum claram, anteposuerit litterarum formas humanitatis per seacula quarta decima et quinta decima. Eodem modo typi, qui nunc nobis videntur parum clari, fiant sollemnes in futurum.";
+var FILENAME = "lorem.txt";
+var blob;
+
+function onerror(message) {
+	console.error(message);
+}
+
+function zipBlob(blob, callback) {
+	zip.createWriter(new zip.BlobWriter("application/zip"), function(zipWriter) {
+		zipWriter.add(FILENAME, new zip.BlobReader(blob), function() {
+			zipWriter.close(callback);
+		});
+	}, onerror);
+}
+
+function unzipBlob(blob, callback) {
+	zip.createReader(new zip.BlobReader(blob), function(zipReader) {
+		zipReader.getEntries(function(entries) {
+			entries[0].getData(new zip.BlobWriter(zip.getMimeType(entries[0].filename)), function(data) {
+				zipReader.close();
+				callback(data);
+			});
+		});
+	}, onerror);
+}
+
+function logBlobText(blob) {
+	var reader = new FileReader();
+	reader.onload = function(e) {
+		console.log(e.target.result);
+		console.log("--------------");
+	};
+	reader.readAsText(blob);
+}
+
+zip.workerScriptsPath = "../";
+blob = new Blob([ TEXT_CONTENT ], {
+	type : zip.getMimeType(FILENAME)
+});
+logBlobText(blob);
+zipBlob(blob, function(zippedBlob) {
+	unzipBlob(zippedBlob, function(unzippedBlob) {
+		logBlobText(unzippedBlob);
+	});
+});
diff --git a/zip.js/WebContent/tests/test10.html b/zip.js/WebContent/tests/test10.html
new file mode 100644
index 0000000..b5706b8
--- /dev/null
+++ b/zip.js/WebContent/tests/test10.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset='utf-8'>
+<title>Demo STORE unzip</title>
+</head>
+<body>
+	<script type="text/javascript" src="../zip.js"></script>
+	<script type="text/javascript" src="../zip-fs.js"></script>
+	<script type="text/javascript" src="../zip-ext.js"></script>
+	<script type="text/javascript" src="dataview.js"></script>
+	<script type="text/javascript" src="test10.js"></script>
+</body>
+</html>
\ No newline at end of file
diff --git a/zip.js/WebContent/tests/test10.js b/zip.js/WebContent/tests/test10.js
new file mode 100644
index 0000000..6517243
--- /dev/null
+++ b/zip.js/WebContent/tests/test10.js
@@ -0,0 +1,34 @@
+var URL = "lorem_store.zip";
+
+var zipFs = new zip.fs.FS();
+
+function onerror(message) {
+	console.error(message);
+}
+
+function zipImportedZip(callback) {
+	var directory = zipFs.root.addDirectory("import");
+	directory.importHttpContent(URL, false, function() {
+		zipFs.exportBlob(callback);
+	}, onerror);
+}
+
+function unzipBlob(blob, callback) {
+	zipFs.importBlob(blob, function() {
+		var directory = zipFs.root.getChildByName("import");
+		var firstEntry = directory.children[0];
+		firstEntry.getText(callback);
+	}, onerror);
+}
+
+function logText(text) {
+	console.log(text);
+	console.log("--------------");
+}
+
+zip.workerScriptsPath = "../";
+zipImportedZip(function(zippedBlob) {
+	unzipBlob(zippedBlob, function(unzippedText) {
+		logText(unzippedText);
+	});
+});
diff --git a/zip.js/WebContent/tests/test11.html b/zip.js/WebContent/tests/test11.html
new file mode 100644
index 0000000..96a1d64
--- /dev/null
+++ b/zip.js/WebContent/tests/test11.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset='utf-8'>
+<title>Demo ZipEntry.prototype.getFileEntry (File)</title>
+</head>
+<body>
+	<script type="text/javascript" src="../zip.js"></script>
+	<script type="text/javascript" src="../zip-fs.js"></script>
+	<script type="text/javascript" src="../zip-ext.js"></script>
+	<script type="text/javascript" src="dataview.js"></script>
+	<script type="text/javascript" src="test11.js"></script>
+</body>
+</html>
\ No newline at end of file
diff --git a/zip.js/WebContent/tests/test11.js b/zip.js/WebContent/tests/test11.js
new file mode 100644
index 0000000..0ea2780
--- /dev/null
+++ b/zip.js/WebContent/tests/test11.js
@@ -0,0 +1,67 @@
+var requestFileSystem = window.webkitRequestFileSystem || window.mozRequestFileSystem || window.msRequestFileSystem || window.requestFileSystem;
+var URL = "lorem.zip", FILENAME = "lorem.txt";
+var filesystem, zipFs = new zip.fs.FS();
+
+function onerror(message) {
+	console.error(message);
+}
+
+function removeRecursively(entry, onend, onerror) {
+	var rootReader = entry.createReader();
+	rootReader.readEntries(function(entries) {
+		var i = 0;
+
+		function next() {
+			i++;
+			removeNextEntry();
+		}
+
+		function removeNextEntry() {
+			var entry = entries[i];
+			if (entry) {
+				if (entry.isDirectory)
+					removeRecursively(entry, next, onerror);
+				if (entry.isFile)
+					entry.remove(next, onerror);
+			} else
+				onend();
+		}
+
+		removeNextEntry();
+	}, onerror);
+}
+
+function importZipToFilesystem(callback) {
+	zipFs.importHttpContent(URL, false, function() {
+		filesystem.root.getFile(FILENAME, {
+			create : true
+		}, function(fileEntry) {
+			var zippedFile = zipFs.root.getChildByName(FILENAME);
+			zippedFile.getFileEntry(fileEntry, callback, null, onerror);
+		}, onerror);
+	}, onerror);
+}
+
+function logFile(file) {
+	var reader = new FileReader();
+	reader.onload = function(event) {
+		console.log(event.target.result);
+		console.log("--------------");
+	};
+	reader.onerror = onerror;
+	reader.readAsText(file);
+}
+
+function test() {
+	importZipToFilesystem(function() {
+		filesystem.root.getFile(FILENAME, null, function(fileEntry) {
+			fileEntry.file(logFile, onerror);
+		}, onerror);
+	}, onerror);
+}
+
+zip.workerScriptsPath = "../";
+requestFileSystem(TEMPORARY, 4 * 1024 * 1024 * 1024, function(fs) {
+	filesystem = fs;
+	removeRecursively(filesystem.root, test, onerror);
+}, onerror);
diff --git a/zip.js/WebContent/tests/test12.html b/zip.js/WebContent/tests/test12.html
new file mode 100644
index 0000000..738408b
--- /dev/null
+++ b/zip.js/WebContent/tests/test12.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset='utf-8'>
+<title>Demo ZipEntry.prototype.getFileEntry (Directory)</title>
+</head>
+<body>
+	<script type="text/javascript" src="../zip.js"></script>
+	<script type="text/javascript" src="../zip-fs.js"></script>
+	<script type="text/javascript" src="../zip-ext.js"></script>
+	<script type="text/javascript" src="dataview.js"></script>
+	<script type="text/javascript" src="test12.js"></script>
+</body>
+</html>
\ No newline at end of file
diff --git a/zip.js/WebContent/tests/test12.js b/zip.js/WebContent/tests/test12.js
new file mode 100644
index 0000000..6c57057
--- /dev/null
+++ b/zip.js/WebContent/tests/test12.js
@@ -0,0 +1,66 @@
+var requestFileSystem = window.webkitRequestFileSystem || window.mozRequestFileSystem || window.msRequestFileSystem || window.requestFileSystem;
+var URL = "lorem2.zip";
+var filesystem, zipFs = new zip.fs.FS();
+
+function onerror(message) {
+	console.error(message);
+}
+
+function removeRecursively(entry, onend, onerror) {
+	var rootReader = entry.createReader();
+	rootReader.readEntries(function(entries) {
+		var i = 0;
+
+		function next() {
+			i++;
+			removeNextEntry();
+		}
+
+		function removeNextEntry() {
+			var entry = entries[i];
+			if (entry) {
+				if (entry.isDirectory)
+					removeRecursively(entry, next, onerror);
+				if (entry.isFile)
+					entry.remove(next, onerror);
+			} else
+				onend();
+		}
+
+		removeNextEntry();
+	}, onerror);
+}
+
+function importZipToFilesystem(callback) {
+	zipFs.importHttpContent(URL, false, function() {
+		zipFs.root.getFileEntry(filesystem.root, callback, null, onerror);
+	}, onerror);
+}
+
+function logFile(file) {
+	var reader = new FileReader();
+	reader.onload = function(event) {
+		console.log(event.target.result);
+		console.log("--------------");
+	};
+	reader.onerror = onerror;
+	reader.readAsText(file);
+}
+
+function test() {
+	importZipToFilesystem(function() {
+		filesystem.root.getDirectory("aaa", null, function(directoryEntry) {
+			directoryEntry.getDirectory("ccc", null, function(directoryEntry) {
+				directoryEntry.getFile("lorem.txt", null, function(fileEntry) {
+					fileEntry.file(logFile, onerror);
+				}, onerror);
+			}, onerror);
+		}, onerror);
+	}, onerror);
+}
+
+zip.workerScriptsPath = "../";
+requestFileSystem(TEMPORARY, 4 * 1024 * 1024 * 1024, function(fs) {
+	filesystem = fs;
+	removeRecursively(filesystem.root, test, test);
+}, onerror);
diff --git a/zip.js/WebContent/tests/test13.html b/zip.js/WebContent/tests/test13.html
new file mode 100644
index 0000000..a680a01
--- /dev/null
+++ b/zip.js/WebContent/tests/test13.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset='utf-8'>
+<title>Demo ZipEntry.prototype.addFileEntry (File)</title>
+</head>
+<body>
+	<script type="text/javascript" src="../zip.js"></script>
+	<script type="text/javascript" src="../zip-fs.js"></script>
+	<script type="text/javascript" src="dataview.js"></script>
+	<script type="text/javascript" src="test13.js"></script>
+</body>
+</html>
\ No newline at end of file
diff --git a/zip.js/WebContent/tests/test13.js b/zip.js/WebContent/tests/test13.js
new file mode 100644
index 0000000..ce8cb32
--- /dev/null
+++ b/zip.js/WebContent/tests/test13.js
@@ -0,0 +1,74 @@
+var TEXT_CONTENT = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Typi non habent claritatem insitam; est usus legentis in iis qui facit eorum claritatem. Investigationes demonstraverunt lectores legere me lius quod ii legunt saepius. Claritas est etiam processus dynamicus, qui sequitur mutationem consuetudium lectorum. Mirum est notare quam littera gothica, quam nunc putamus parum claram, anteposuerit litterarum formas humanitatis per seacula quarta decima et quinta decima. Eodem modo typi, qui nunc nobis videntur parum clari, fiant sollemnes in futurum.";
+var requestFileSystem = window.webkitRequestFileSystem || window.mozRequestFileSystem || window.msRequestFileSystem || window.requestFileSystem;
+var filesystem, zipFs = new zip.fs.FS();
+
+function onerror(message) {
+	console.error(message);
+}
+
+function removeRecursively(entry, onend, onerror) {
+	var rootReader = entry.createReader();
+	rootReader.readEntries(function(entries) {
+		var i = 0;
+
+		function next() {
+			i++;
+			removeNextEntry();
+		}
+
+		function removeNextEntry() {
+			var entry = entries[i];
+			if (entry) {
+				if (entry.isDirectory)
+					removeRecursively(entry, next, onerror);
+				if (entry.isFile)
+					entry.remove(next, onerror);
+			} else
+				onend();
+		}
+
+		removeNextEntry();
+	}, onerror);
+}
+
+function addFileEntryAndReadFile(fileEntry, callback) {
+	zipFs.root.addFileEntry(fileEntry, function() {
+		var zipEntry = zipFs.root.getChildByName("lorem.txt");
+		zipEntry.getText(callback);
+	}, onerror);
+}
+
+function logText(text) {
+	console.log(text);
+	console.log("--------------");
+}
+
+function initFileSystem(callback) {
+	filesystem.root.getFile("lorem.txt", {
+		create : true
+	}, function(fileEntry) {
+		fileEntry.createWriter(function(writer) {
+			writer.onwrite = function() {
+				callback(fileEntry);
+			};
+			writer.onerror = onerror;
+			writer.write(new Blob([ TEXT_CONTENT ], {
+				type : "text/plain"
+			}));
+		}, onerror);
+	}, onerror);
+}
+
+function test() {
+	initFileSystem(function(fileEntry) {
+		addFileEntryAndReadFile(fileEntry, function(text) {
+			logText(text);
+		}, onerror);
+	});
+}
+
+zip.workerScriptsPath = "../";
+requestFileSystem(TEMPORARY, 4 * 1024 * 1024 * 1024, function(fs) {
+	filesystem = fs;
+	removeRecursively(filesystem.root, test, onerror);
+}, onerror);
diff --git a/zip.js/WebContent/tests/test14.html b/zip.js/WebContent/tests/test14.html
new file mode 100644
index 0000000..45e5f44
--- /dev/null
+++ b/zip.js/WebContent/tests/test14.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset='utf-8'>
+<title>Demo ZipEntry.prototype.addFileEntry (Directory)</title>
+</head>
+<body>
+	<script type="text/javascript" src="../zip.js"></script>
+	<script type="text/javascript" src="../zip-fs.js"></script>
+	<script type="text/javascript" src="dataview.js"></script>
+	<script type="text/javascript" src="test14.js"></script>
+</body>
+</html>
\ No newline at end of file
diff --git a/zip.js/WebContent/tests/test14.js b/zip.js/WebContent/tests/test14.js
new file mode 100644
index 0000000..8d90dc7
--- /dev/null
+++ b/zip.js/WebContent/tests/test14.js
@@ -0,0 +1,80 @@
+var TEXT_CONTENT = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Typi non habent claritatem insitam; est usus legentis in iis qui facit eorum claritatem. Investigationes demonstraverunt lectores legere me lius quod ii legunt saepius. Claritas est etiam processus dynamicus, qui sequitur mutationem consuetudium lectorum. Mirum est notare quam littera gothica, quam nunc putamus parum claram, anteposuerit litterarum formas humanitatis per seacula quarta decima et quinta decima. Eodem modo typi, qui nunc nobis videntur parum clari, fiant sollemnes in futurum.";
+var requestFileSystem = window.webkitRequestFileSystem || window.mozRequestFileSystem || window.msRequestFileSystem || window.requestFileSystem;
+var filesystem, zipFs = new zip.fs.FS();
+
+function onerror(message) {
+	console.error(message);
+}
+
+function removeRecursively(entry, onend, onerror) {
+	var rootReader = entry.createReader();
+	rootReader.readEntries(function(entries) {
+		var i = 0;
+
+		function next() {
+			i++;
+			removeNextEntry();
+		}
+
+		function removeNextEntry() {
+			var entry = entries[i];
+			if (entry) {
+				if (entry.isDirectory)
+					removeRecursively(entry, next, onerror);
+				if (entry.isFile)
+					entry.remove(next, onerror);
+			} else
+				onend();
+		}
+
+		removeNextEntry();
+	}, onerror);
+}
+
+function addDirectoryAndReadFile(callback) {
+	zipFs.root.addFileEntry(filesystem.root, function() {
+		var zipEntry = zipFs.root.getChildByName("aaa").getChildByName("ccc").getChildByName("lorem.txt");
+		zipEntry.getText(callback);
+	}, onerror);
+}
+
+function logText(text) {
+	console.log(text);
+	console.log("--------------");
+}
+
+function initFileSystem(callback) {
+	filesystem.root.getDirectory("aaa", {
+		create : true
+	}, function(directoryEntry) {
+		directoryEntry.getDirectory("ccc", {
+			create : true
+		}, function(directoryEntry) {
+			directoryEntry.getFile("lorem.txt", {
+				create : true
+			}, function(fileEntry) {
+				fileEntry.createWriter(function(writer) {
+					writer.onwrite = callback;
+					writer.onerror = onerror;
+					writer.write(new Blob([ TEXT_CONTENT ], {
+						type : "text/plain"
+					}));
+				}, onerror);
+			}, onerror);
+		}, onerror);
+	}, onerror);
+}
+
+function test() {
+	initFileSystem(function() {
+		addDirectoryAndReadFile(function(text) {
+			logText(text);
+		}, onerror);
+	});
+}
+
+zip.workerScriptsPath = "../";
+requestFileSystem(TEMPORARY, 4 * 1024 * 1024 * 1024, function(fs) {
+	filesystem = fs;
+	removeRecursively(filesystem.root, test, onerror);
+}, onerror);
diff --git a/zip.js/WebContent/tests/test15.html b/zip.js/WebContent/tests/test15.html
new file mode 100644
index 0000000..548427c
--- /dev/null
+++ b/zip.js/WebContent/tests/test15.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset='utf-8'>
+<title>Demo parallel reads</title>
+</head>
+<body>
+	<script type="text/javascript" src="../zip.js"></script>
+	<script type="text/javascript" src="dataview.js"></script>
+	<script type="text/javascript" src="test15.js"></script>
+</body>
+</html>
\ No newline at end of file
diff --git a/zip.js/WebContent/tests/test15.js b/zip.js/WebContent/tests/test15.js
new file mode 100644
index 0000000..6fca5d2
--- /dev/null
+++ b/zip.js/WebContent/tests/test15.js
@@ -0,0 +1,60 @@
+var TEXT_CONTENT = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Typi non habent claritatem insitam; est usus legentis in iis qui facit eorum claritatem. Investigationes demonstraverunt lectores legere me lius quod ii legunt saepius. Claritas est etiam processus dynamicus, qui sequitur mutationem consuetudium lectorum. Mirum est notare quam littera gothica, quam nunc putamus parum claram, anteposuerit litterarum formas humanitatis per seacula quarta decima et quinta decima. Eodem modo typi, qui nunc nobis videntur parum clari, fiant sollemnes in futurum.";
+
+function onerror(message) {
+	console.error(message);
+}
+
+function zipBlobs(blobs, callback) {
+	zip.createWriter(new zip.BlobWriter("application/zip"), function(zipWriter) {
+		var index = 0;
+
+		function next() {
+			if (index < blobs.length)
+				zipWriter.add(blobs[index].name, new zip.BlobReader(blobs[index].blob), function() {
+					index++;
+					next();
+				});
+			else
+				zipWriter.close(callback);
+		}
+
+		next();
+	}, onerror);
+}
+
+function unzipBlob(blob) {
+	zip.createReader(new zip.BlobReader(blob), function(zipReader) {
+		zipReader.getEntries(function(entries) {
+			var i;
+			for (i = 0; i < entries.length; i++)
+				entries[i].getData(new zip.TextWriter(), function(text) {
+					logText(text);
+				});
+		});
+	}, onerror);
+}
+
+function getBlob() {
+	return new Blob([ TEXT_CONTENT ], {
+		type : "text/plain"
+	});
+}
+
+function logText(text) {
+	console.log(text);
+	console.log("--------------");
+}
+
+zip.workerScriptsPath = "../";
+
+var blobs = [ {
+	name : "lorem1.txt",
+	blob : getBlob()
+}, {
+	name : "lorem2.txt",
+	blob : getBlob()
+} ];
+
+zipBlobs(blobs, function(zippedBlob) {
+	unzipBlob(zippedBlob);
+});
diff --git a/zip.js/WebContent/tests/test16.html b/zip.js/WebContent/tests/test16.html
new file mode 100644
index 0000000..e7d3acc
--- /dev/null
+++ b/zip.js/WebContent/tests/test16.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset='utf-8'>
+<title>Demo without web workers</title>
+</head>
+<body>
+	<script type="text/javascript" src="../zip.js"></script>
+	<script type="text/javascript" src="../deflate.js"></script>
+	<script type="text/javascript" src="../inflate.js"></script>
+	<script type="text/javascript" src="dataview.js"></script>
+	<script type="text/javascript" src="test16.js"></script>
+</body>
+</html>
\ No newline at end of file
diff --git a/zip.js/WebContent/tests/test16.js b/zip.js/WebContent/tests/test16.js
new file mode 100644
index 0000000..40c2c20
--- /dev/null
+++ b/zip.js/WebContent/tests/test16.js
@@ -0,0 +1,46 @@
+var TEXT_CONTENT = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Typi non habent claritatem insitam; est usus legentis in iis qui facit eorum claritatem. Investigationes demonstraverunt lectores legere me lius quod ii legunt saepius. Claritas est etiam processus dynamicus, qui sequitur mutationem consuetudium lectorum. Mirum est notare quam littera gothica, quam nunc putamus parum claram, anteposuerit litterarum formas humanitatis per seacula quarta decima et quinta decima. Eodem modo typi, qui nunc nobis videntur parum clari, fiant sollemnes in futurum.";
+var FILENAME = "lorem.txt";
+var blob;
+
+function onerror(message) {
+	console.error(message);
+}
+
+function zipBlob(blob, callback) {
+	zip.createWriter(new zip.BlobWriter("application/zip"), function(zipWriter) {
+		zipWriter.add(FILENAME, new zip.BlobReader(blob), function() {
+			zipWriter.close(callback);
+		});
+	}, onerror);
+}
+
+function unzipBlob(blob, callback) {
+	zip.createReader(new zip.BlobReader(blob), function(zipReader) {
+		zipReader.getEntries(function(entries) {
+			entries[0].getData(new zip.BlobWriter("text/plain"), function(data) {
+				zipReader.close();
+				callback(data);
+			});
+		});
+	}, onerror);
+}
+
+function logBlobText(blob) {
+	var reader = new FileReader();
+	reader.onload = function(e) {
+		console.log(e.target.result);
+		console.log("--------------");
+	};
+	reader.readAsText(blob);
+}
+
+zip.useWebWorkers = false;
+blob = new Blob([ TEXT_CONTENT ], {
+	type : "text/plain"
+});
+logBlobText(blob);
+zipBlob(blob, function(zippedBlob) {
+	unzipBlob(zippedBlob, function(unzippedBlob) {
+		logBlobText(unzippedBlob);
+	});
+});
diff --git a/zip.js/WebContent/tests/test17.html b/zip.js/WebContent/tests/test17.html
new file mode 100644
index 0000000..81464f3
--- /dev/null
+++ b/zip.js/WebContent/tests/test17.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset='utf-8'>
+<title>Demo base 64 (compatible with IE, Firefox, Chrome, Safari)</title>
+</head>
+<body>
+	<script type="text/javascript" src="../zip.js"></script>
+	<script type="text/javascript" src="../deflate.js"></script>
+	<script type="text/javascript" src="../inflate.js"></script>
+	<script type="text/javascript" src="arraybuffer.js"></script>
+	<script type="text/javascript" src="base64.js"></script>
+	<script type="text/javascript" src="test17.js"></script>
+</body>
+</html>
\ No newline at end of file
diff --git a/zip.js/WebContent/tests/test17.js b/zip.js/WebContent/tests/test17.js
new file mode 100644
index 0000000..6e6e4f0
--- /dev/null
+++ b/zip.js/WebContent/tests/test17.js
@@ -0,0 +1,41 @@
+var TEXT_CONTENT = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Typi non habent claritatem insitam; est usus legentis in iis qui facit eorum claritatem. Investigationes demonstraverunt lectores legere me lius quod ii legunt saepius. Claritas est etiam processus dynamicus, qui sequitur mutationem consuetudium lectorum. Mirum est notare quam littera gothica, quam nunc putamus parum claram, anteposuerit litterarum formas humanitatis per seacula quarta decima et quinta decima. Eodem modo typi, qui nunc nobis videntur parum clari, fiant sollemnes in futurum.";
+var FILENAME = "lorem.txt";
+
+var dataURI = "data:text/plain;base64," + btoa(TEXT_CONTENT);
+
+function onerror(message) {
+	console.error(message);
+}
+
+function zipDataURI(dataURI, callback) {
+	zip.createWriter(new zip.Data64URIWriter("application/zip"), function(zipWriter) {
+		zipWriter.add(FILENAME, new zip.Data64URIReader(dataURI), function() {
+			zipWriter.close(callback);
+		});
+	}, onerror);
+}
+
+function unzipDataURI(dataURI, callback) {
+	zip.createReader(new zip.Data64URIReader(dataURI), function(zipReader) {
+		zipReader.getEntries(function(entries) {
+			entries[0].getData(new zip.Data64URIWriter("text/plain"), function(data) {
+				zipReader.close();
+				callback(data);
+			});
+		});
+	}, onerror);
+}
+
+function logDataURI(dataURI) {
+	console.log(dataURI);
+	console.log("--------------");
+}
+
+zip.useWebWorkers = false;
+logDataURI(dataURI);
+zipDataURI(dataURI, function(zippedData64) {
+	logDataURI(zippedData64);
+	unzipDataURI(zippedData64, function(unzippedDataURI) {
+		logDataURI(unzippedDataURI);
+	});
+});
diff --git a/zip.js/WebContent/tests/test18.html b/zip.js/WebContent/tests/test18.html
new file mode 100644
index 0000000..ef786c6
--- /dev/null
+++ b/zip.js/WebContent/tests/test18.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset='utf-8'>
+<title>Demo ArrayBuffer</title>
+</head>
+<body>
+	<script type="text/javascript" src="../zip.js"></script>
+	<script type="text/javascript" src="../zip-ext.js"></script>
+	<script type="text/javascript" src="../deflate.js"></script>
+	<script type="text/javascript" src="../inflate.js"></script>
+	<script type="text/javascript" src="arraybuffer.js"></script>
+	<script type="text/javascript" src="base64.js"></script>
+	<script type="text/javascript" src="test18.js"></script>
+</body>
+</html>
\ No newline at end of file
diff --git a/zip.js/WebContent/tests/test18.js b/zip.js/WebContent/tests/test18.js
new file mode 100644
index 0000000..3bce9b0
--- /dev/null
+++ b/zip.js/WebContent/tests/test18.js
@@ -0,0 +1,46 @@
+var TEXT_CONTENT = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Typi non habent claritatem insitam; est usus legentis in iis qui facit eorum claritatem. Investigationes demonstraverunt lectores legere me lius quod ii legunt saepius. Claritas est etiam processus dynamicus, qui sequitur mutationem consuetudium lectorum. Mirum est notare quam littera gothica, quam nunc putamus parum claram, anteposuerit litterarum formas humanitatis per seacula quarta decima et quinta decima. Eodem modo typi, qui nunc nobis videntur parum clari, fiant sollemnes in futurum.";
+var FILENAME = "lorem.txt";
+var arrayBuffer;
+
+function onerror(message) {
+	console.error(message);
+}
+
+function zipArrayBuffer(arrayBuffer, callback) {
+	zip.createWriter(new zip.ArrayBufferWriter(), function(zipWriter) {
+		zipWriter.add(FILENAME, new zip.ArrayBufferReader(arrayBuffer), function() {
+			zipWriter.close(callback);
+		});
+	}, onerror);
+}
+
+function unzipArrayBuffer(arrayBuffer, callback) {
+	zip.createReader(new zip.ArrayBufferReader(arrayBuffer), function(zipReader) {
+		zipReader.getEntries(function(entries) {
+			entries[0].getData(new zip.ArrayBufferWriter(), function(data) {
+				zipReader.close();
+				callback(data);
+			});
+		});
+	}, onerror);
+}
+
+function logArrayBufferText(arrayBuffer) {
+	var array = new Uint8Array(arrayBuffer);
+	var str = "";
+	Array.prototype.forEach.call(array, function(code) {
+		str += String.fromCharCode(code);
+	});
+	console.log(str);
+}
+
+zip.workerScriptsPath = "../";
+arrayBuffer = new Uint8Array(Array.prototype.map.call(TEXT_CONTENT, function(c) {
+	return c.charCodeAt(0);
+})).buffer;
+logArrayBufferText(arrayBuffer);
+zipArrayBuffer(arrayBuffer, function(zippedArrayBuffer) {
+	unzipArrayBuffer(zippedArrayBuffer, function(unzippedArrayBuffer) {
+		logArrayBufferText(unzippedArrayBuffer);
+	});
+});
diff --git a/zip.js/WebContent/tests/test2.html b/zip.js/WebContent/tests/test2.html
new file mode 100644
index 0000000..857bdb9
--- /dev/null
+++ b/zip.js/WebContent/tests/test2.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset='utf-8'>
+<title>Demo File</title>
+</head>
+<body>
+	<script type="text/javascript" src="../zip.js"></script>
+	<script type="text/javascript" src="../zip-ext.js"></script>
+	<script type="text/javascript" src="dataview.js"></script>
+	<script type="text/javascript" src="util.js"></script>
+	<script type="text/javascript" src="test2.js"></script>
+</body>
+</html>
\ No newline at end of file
diff --git a/zip.js/WebContent/tests/test2.js b/zip.js/WebContent/tests/test2.js
new file mode 100644
index 0000000..157b5eb
--- /dev/null
+++ b/zip.js/WebContent/tests/test2.js
@@ -0,0 +1,49 @@
+var TEXT_CONTENT = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Typi non habent claritatem insitam; est usus legentis in iis qui facit eorum claritatem. Investigationes demonstraverunt lectores legere me lius quod ii legunt saepius. Claritas est etiam processus dynamicus, qui sequitur mutationem consuetudium lectorum. Mirum est notare quam littera gothica, quam nunc putamus parum claram, anteposuerit litterarum formas humanitatis per seacula quarta decima et quinta decima. Eodem modo typi, qui nunc nobis videntur parum clari, fiant sollemnes in futurum.";
+var FILENAME = "lorem.txt";
+
+var blob, requestFileSystem = this.webkitRequestFileSystem || this.mozRequestFileSystem || this.requestFileSystem;
+
+function onerror(message) {
+	console.error(message);
+}
+
+function zipBlob(blob, callback) {
+	createTempFile(function(fileEntry) {
+		zip.createWriter(new zip.FileWriter(fileEntry, "application/zip"), function(zipWriter) {
+			zipWriter.add(FILENAME, new zip.BlobReader(blob), function() {
+				zipWriter.close(callback);
+			});
+		}, onerror);
+	});
+}
+
+function unzipBlob(blob, callback) {
+	zip.createReader(new zip.BlobReader(blob), function(zipReader) {
+		zipReader.getEntries(function(entries) {
+			entries[0].getData(new zip.BlobWriter("text/plain"), function(data) {
+				zipReader.close();
+				callback(data);
+			});
+		});
+	}, onerror);
+}
+
+function logBlobText(blob) {
+	var reader = new FileReader();
+	reader.onload = function(e) {
+		console.log(e.target.result);
+		console.log("--------------");
+	};
+	reader.readAsText(blob);
+}
+
+zip.workerScriptsPath = "../";
+blob = new Blob([TEXT_CONTENT], {
+	type: "text/plain"
+});
+logBlobText(blob);
+zipBlob(blob, function(zippedBlob) {
+	unzipBlob(zippedBlob, function(unzippedBlob) {
+		logBlobText(unzippedBlob);
+	});
+});
diff --git a/zip.js/WebContent/tests/test3.html b/zip.js/WebContent/tests/test3.html
new file mode 100644
index 0000000..98dd6b1
--- /dev/null
+++ b/zip.js/WebContent/tests/test3.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset='utf-8'>
+<title>Demo filesystem API</title>
+</head>
+<body>
+	<script type="text/javascript" src="../zip.js"></script>
+	<script type="text/javascript" src="../zip-fs.js"></script>
+	<script type="text/javascript" src="../mime-types.js"></script>
+	<script type="text/javascript" src="dataview.js"></script>
+	<script type="text/javascript" src="test3.js"></script>
+</body>
+</html>
\ No newline at end of file
diff --git a/zip.js/WebContent/tests/test3.js b/zip.js/WebContent/tests/test3.js
new file mode 100644
index 0000000..836ade3
--- /dev/null
+++ b/zip.js/WebContent/tests/test3.js
@@ -0,0 +1,40 @@
+var TEXT_CONTENT = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Typi non habent claritatem insitam; est usus legentis in iis qui facit eorum claritatem. Investigationes demonstraverunt lectores legere me lius quod ii legunt saepius. Claritas est etiam processus dynamicus, qui sequitur mutationem consuetudium lectorum. Mirum est notare quam littera gothica, quam nunc putamus parum claram, anteposuerit litterarum formas humanitatis per seacula quarta decima et quinta decima. Eodem modo typi, qui nunc nobis videntur parum clari, fiant sollemnes in futurum.";
+var FILENAME = "lorem.txt";
+
+var blob, zipFs = new zip.fs.FS();
+
+function onerror(message) {
+	console.error(message);
+}
+
+function zipBlob(blob, callback) {
+	zipFs.root.addBlob(FILENAME, blob);
+	zipFs.exportBlob(callback);
+}
+
+function unzipBlob(blob, callback) {
+	zipFs.importBlob(blob, function() {
+		var firstEntry = zipFs.root.children[0];
+		firstEntry.getBlob(zip.getMimeType(firstEntry.name), callback);
+	}, onerror);
+}
+
+function logBlobText(blob) {
+	var reader = new FileReader();
+	reader.onload = function(e) {
+		console.log(e.target.result);
+		console.log("--------------");
+	};
+	reader.readAsText(blob);
+}
+
+zip.workerScriptsPath = "../";
+blob = new Blob([TEXT_CONTENT], {
+	type : zip.getMimeType(FILENAME)
+});
+logBlobText(blob);
+zipBlob(blob, function(zippedBlob) {
+	unzipBlob(zippedBlob, function(unzippedBlob) {
+		logBlobText(unzippedBlob);
+	});
+});
diff --git a/zip.js/WebContent/tests/test4.html b/zip.js/WebContent/tests/test4.html
new file mode 100644
index 0000000..939c051
--- /dev/null
+++ b/zip.js/WebContent/tests/test4.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset='utf-8'>
+<title>Demo base 64</title>
+</head>
+<body>
+	<script type="text/javascript" src="../zip.js"></script>
+	<script type="text/javascript" src="dataview.js"></script>
+	<script type="text/javascript" src="test4.js"></script>
+</body>
+</html>
\ No newline at end of file
diff --git a/zip.js/WebContent/tests/test4.js b/zip.js/WebContent/tests/test4.js
new file mode 100644
index 0000000..38b3274
--- /dev/null
+++ b/zip.js/WebContent/tests/test4.js
@@ -0,0 +1,40 @@
+var TEXT_CONTENT = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Typi non habent claritatem insitam; est usus legentis in iis qui facit eorum claritatem. Investigationes demonstraverunt lectores legere me lius quod ii legunt saepius. Claritas est etiam processus dynamicus, qui sequitur mutationem consuetudium lectorum. Mirum est notare quam littera gothica, quam nunc putamus parum claram, anteposuerit litterarum formas humanitatis per seacula quarta decima et quinta decima. Eodem modo typi, qui nunc nobis videntur parum clari, fiant sollemnes in futurum.";
+var FILENAME = "lorem.txt";
+
+var dataURI = "data:text/plain;base64," + btoa(TEXT_CONTENT);
+
+function onerror(message) {
+	console.error(message);
+}
+
+function zipDataURI(dataURI, callback) {
+	zip.createWriter(new zip.BlobWriter("application/zip"), function(zipWriter) {
+		zipWriter.add(FILENAME, new zip.Data64URIReader(dataURI), function() {
+			zipWriter.close(callback);
+		});
+	}, onerror);
+}
+
+function unzipBlob(blob, callback) {
+	zip.createReader(new zip.BlobReader(blob), function(zipReader) {
+		zipReader.getEntries(function(entries) {
+			entries[0].getData(new zip.Data64URIWriter("text/plain"), function(data) {
+				zipReader.close();
+				callback(data);
+			});
+		});
+	}, onerror);
+}
+
+function logDataURI(dataURI) {
+	console.log(dataURI);
+	console.log("--------------");
+}
+
+zip.workerScriptsPath = "../";
+logDataURI(dataURI);
+zipDataURI(dataURI, function(zippedBlob) {
+	unzipBlob(zippedBlob, function(unzippedDataURI) {
+		logDataURI(unzippedDataURI);
+	});
+});
diff --git a/zip.js/WebContent/tests/test5.html b/zip.js/WebContent/tests/test5.html
new file mode 100644
index 0000000..33f492a
--- /dev/null
+++ b/zip.js/WebContent/tests/test5.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset='utf-8'>
+<title>Demo filesystem API with base64</title>
+</head>
+<body>
+	<script type="text/javascript" src="../zip.js"></script>
+	<script type="text/javascript" src="../zip-fs.js"></script>
+	<script type="text/javascript" src="dataview.js"></script>
+	<script type="text/javascript" src="test5.js"></script>
+</body>
+</html>
\ No newline at end of file
diff --git a/zip.js/WebContent/tests/test5.js b/zip.js/WebContent/tests/test5.js
new file mode 100644
index 0000000..5897ef5
--- /dev/null
+++ b/zip.js/WebContent/tests/test5.js
@@ -0,0 +1,33 @@
+var TEXT_CONTENT = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Typi non habent claritatem insitam; est usus legentis in iis qui facit eorum claritatem. Investigationes demonstraverunt lectores legere me lius quod ii legunt saepius. Claritas est etiam processus dynamicus, qui sequitur mutationem consuetudium lectorum. Mirum est notare quam littera gothica, quam nunc putamus parum claram, anteposuerit litterarum formas humanitatis per seacula quarta decima et quinta decima. Eodem modo typi, qui nunc nobis videntur parum clari, fiant sollemnes in futurum.";
+var FILENAME = "lorem.txt";
+
+var dataURI = "data:text/plain;base64," + btoa(TEXT_CONTENT), zipFs = new zip.fs.FS();
+
+function onerror(message) {
+	console.error(message);
+}
+
+function zipDataURI(dataURI, callback) {
+	zipFs.root.addData64URI(FILENAME, dataURI);
+	zipFs.exportData64URI(callback);
+}
+
+function unzipDataURI(dataURI, callback) {
+	zipFs.importData64URI(dataURI, function() {
+		var firstEntry = zipFs.root.children[0];
+		firstEntry.getData64URI("text/plain", callback, null, true);
+	}, onerror);
+}
+
+function logDataURI(dataURI) {
+	console.log(dataURI);
+	console.log("--------------");
+}
+
+zip.workerScriptsPath = "../";
+logDataURI(dataURI);
+zipDataURI(dataURI, function(zippedDataURI) {
+	unzipDataURI(zippedDataURI, function(unzippedDataURI) {
+		logDataURI(unzippedDataURI);
+	});
+});
diff --git a/zip.js/WebContent/tests/test6.html b/zip.js/WebContent/tests/test6.html
new file mode 100644
index 0000000..4542a03
--- /dev/null
+++ b/zip.js/WebContent/tests/test6.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset='utf-8'>
+<title>Demo filesystem API with base64</title>
+</head>
+<body>
+	<script type="text/javascript" src="../zip.js"></script>
+	<script type="text/javascript" src="../zip-fs.js"></script>
+	<script type="text/javascript" src="dataview.js"></script>
+	<script type="text/javascript" src="test6.js"></script>
+</body>
+</html>
\ No newline at end of file
diff --git a/zip.js/WebContent/tests/test6.js b/zip.js/WebContent/tests/test6.js
new file mode 100644
index 0000000..eef9efc
--- /dev/null
+++ b/zip.js/WebContent/tests/test6.js
@@ -0,0 +1,33 @@
+var TEXT_CONTENT = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Typi non habent claritatem insitam; est usus legentis in iis qui facit eorum claritatem. Investigationes demonstraverunt lectores legere me lius quod ii legunt saepius. Claritas est etiam processus dynamicus, qui sequitur mutationem consuetudium lectorum. Mirum est notare quam littera gothica, quam nunc putamus parum claram, anteposuerit litterarum formas humanitatis per seacula quarta decima et quinta decima. Eodem modo typi, qui nunc nobis videntur parum clari, fiant sollemnes in futurum.";
+var FILENAME = "lorem.txt";
+
+var zipFs = new zip.fs.FS();
+
+function onerror(message) {
+	console.error(message);
+}
+
+function zipText(text, callback) {
+	zipFs.root.addText(FILENAME, text);
+	zipFs.exportBlob(callback);
+}
+
+function unzipBlob(blob, callback) {
+	zipFs.importBlob(blob, function() {
+		var firstEntry = zipFs.root.children[0];
+		firstEntry.getText(callback);
+	}, onerror);
+}
+
+function logText(text) {
+	console.log(text);
+	console.log("--------------");
+}
+
+zip.workerScriptsPath = "../";
+logText(TEXT_CONTENT);
+zipText(TEXT_CONTENT, function(zippedBlob) {
+	unzipBlob(zippedBlob, function(unzippedText) {
+		logText(unzippedText);
+	});
+});
diff --git a/zip.js/WebContent/tests/test7.html b/zip.js/WebContent/tests/test7.html
new file mode 100644
index 0000000..9582594
--- /dev/null
+++ b/zip.js/WebContent/tests/test7.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset='utf-8'>
+<title>Demo HttpReader</title>
+</head>
+<body>
+	<script type="text/javascript" src="../zip.js"></script>
+	<script type="text/javascript" src="../zip-fs.js"></script>
+	<script type="text/javascript" src="../zip-ext.js"></script>
+	<script type="text/javascript" src="dataview.js"></script>
+	<script type="text/javascript" src="test7.js"></script>
+</body>
+</html>
\ No newline at end of file
diff --git a/zip.js/WebContent/tests/test7.js b/zip.js/WebContent/tests/test7.js
new file mode 100644
index 0000000..abd601f
--- /dev/null
+++ b/zip.js/WebContent/tests/test7.js
@@ -0,0 +1,18 @@
+var zipFs = new zip.fs.FS();
+
+function onerror(message) {
+	console.error(message);
+}
+
+function logText(text) {
+	console.log(text);
+	console.log("--------------");
+}
+
+zip.workerScriptsPath = "../";
+zipFs.importHttpContent("lorem.zip", false, function() {
+	var firstEntry = zipFs.root.children[0];
+	firstEntry.getText(function(data) {
+		logText(data);
+	});
+}, onerror);
diff --git a/zip.js/WebContent/tests/test8.html b/zip.js/WebContent/tests/test8.html
new file mode 100644
index 0000000..ebfc984
--- /dev/null
+++ b/zip.js/WebContent/tests/test8.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset='utf-8'>
+<title>Demo FileHTTP</title>
+</head>
+<body>
+	<script type="text/javascript" src="../zip.js"></script>
+	<script type="text/javascript" src="../zip-fs.js"></script>
+	<script type="text/javascript" src="../zip-ext.js"></script>
+	<script type="text/javascript" src="dataview.js"></script>
+	<script type="text/javascript" src="test8.js"></script>
+</body>
+</html>
\ No newline at end of file
diff --git a/zip.js/WebContent/tests/test8.js b/zip.js/WebContent/tests/test8.js
new file mode 100644
index 0000000..7c34ec0
--- /dev/null
+++ b/zip.js/WebContent/tests/test8.js
@@ -0,0 +1,31 @@
+var FILENAME = "lorem.txt", URL = "lorem.txt";
+
+var zipFs = new zip.fs.FS();
+
+function onerror(message) {
+	console.error(message);
+}
+
+function zipText(callback) {
+	zipFs.root.addHttpContent(FILENAME, URL);
+	zipFs.exportBlob(callback);
+}
+
+function unzipBlob(blob, callback) {
+	zipFs.importBlob(blob, function() {
+		var firstEntry = zipFs.root.children[0];
+		firstEntry.getText(callback);
+	}, onerror);
+}
+
+function logText(text) {
+	console.log(text);
+	console.log("--------------");
+}
+
+zip.workerScriptsPath = "../";
+zipText(function(zippedBlob) {
+	unzipBlob(zippedBlob, function(unzippedText) {
+		logText(unzippedText);
+	});
+});
diff --git a/zip.js/WebContent/tests/test9.html b/zip.js/WebContent/tests/test9.html
new file mode 100644
index 0000000..309530c
--- /dev/null
+++ b/zip.js/WebContent/tests/test9.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset='utf-8'>
+<title>Demo FileHTTP import</title>
+</head>
+<body>
+	<script type="text/javascript" src="../zip.js"></script>
+	<script type="text/javascript" src="../zip-fs.js"></script>
+	<script type="text/javascript" src="../zip-ext.js"></script>
+	<script type="text/javascript" src="dataview.js"></script>
+	<script type="text/javascript" src="test9.js"></script>
+</body>
+</html>
\ No newline at end of file
diff --git a/zip.js/WebContent/tests/test9.js b/zip.js/WebContent/tests/test9.js
new file mode 100644
index 0000000..ac44f40
--- /dev/null
+++ b/zip.js/WebContent/tests/test9.js
@@ -0,0 +1,34 @@
+var URL = "lorem.zip";
+
+var zipFs = new zip.fs.FS();
+
+function onerror(message) {
+	console.error(message);
+}
+
+function zipImportedZip(callback) {
+	var directory = zipFs.root.addDirectory("import");
+	directory.importHttpContent(URL, false, function() {
+		zipFs.exportBlob(callback);
+	}, onerror);
+}
+
+function unzipBlob(blob, callback) {
+	zipFs.importBlob(blob, function() {
+		var directory = zipFs.root.getChildByName("import");
+		var firstEntry = directory.children[0];
+		firstEntry.getText(callback);
+	}, onerror);
+}
+
+function logText(text) {
+	console.log(text);
+	console.log("--------------");
+}
+
+zip.workerScriptsPath = "../";
+zipImportedZip(function(zippedBlob) {
+	unzipBlob(zippedBlob, function(unzippedText) {
+		logText(unzippedText);
+	});
+});
diff --git a/zip.js/WebContent/tests/util.js b/zip.js/WebContent/tests/util.js
new file mode 100644
index 0000000..e0f2c41
--- /dev/null
+++ b/zip.js/WebContent/tests/util.js
@@ -0,0 +1,16 @@
+function createTempFile(callback) {
+	var TMP_FILENAME = "file.tmp";
+	requestFileSystem(TEMPORARY, 4 * 1024 * 1024 * 1024, function(filesystem) {
+		function create() {
+			filesystem.root.getFile(TMP_FILENAME, {
+				create : true
+			}, function(entry) {
+				callback(entry);
+			}, onerror);
+		}
+
+		filesystem.root.getFile(TMP_FILENAME, null, function(entry) {
+			entry.remove(create, create);
+		}, create);
+	});
+}
diff --git a/zip.js/WebContent/zip-ext.js b/zip.js/WebContent/zip-ext.js
new file mode 100644
index 0000000..f0bacac
--- /dev/null
+++ b/zip.js/WebContent/zip-ext.js
@@ -0,0 +1,241 @@
+/*
+ Copyright (c) 2013 Gildas Lormeau. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+
+ 3. The names of the authors may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
+ INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+(function() {
+
+	var ERR_HTTP_RANGE = "HTTP Range not supported.";
+
+	var Reader = zip.Reader;
+	var Writer = zip.Writer;
+	
+	var ZipDirectoryEntry;
+
+	var appendABViewSupported;
+	try {
+		appendABViewSupported = new Blob([ new DataView(new ArrayBuffer(0)) ]).size === 0;
+	} catch (e) {
+	}
+
+	function HttpReader(url) {
+		var that = this;
+
+		function getData(callback, onerror) {
+			var request;
+			if (!that.data) {
+				request = new XMLHttpRequest();
+				request.addEventListener("load", function() {
+					if (!that.size)
+						that.size = Number(request.getResponseHeader("Content-Length"));
+					that.data = new Uint8Array(request.response);
+					callback();
+				}, false);
+				request.addEventListener("error", onerror, false);
+				request.open("GET", url);
+				request.responseType = "arraybuffer";
+				request.send();
+			} else
+				callback();
+		}
+
+		function init(callback, onerror) {
+			var request = new XMLHttpRequest();
+			request.addEventListener("load", function() {
+				that.size = Number(request.getResponseHeader("Content-Length"));
+				callback();
+			}, false);
+			request.addEventListener("error", onerror, false);
+			request.open("HEAD", url);
+			request.send();
+		}
+
+		function readUint8Array(index, length, callback, onerror) {
+			getData(function() {
+				callback(new Uint8Array(that.data.subarray(index, index + length)));
+			}, onerror);
+		}
+
+		that.size = 0;
+		that.init = init;
+		that.readUint8Array = readUint8Array;
+	}
+	HttpReader.prototype = new Reader();
+	HttpReader.prototype.constructor = HttpReader;
+
+	function HttpRangeReader(url) {
+		var that = this;
+
+		function init(callback, onerror) {
+			var request = new XMLHttpRequest();
+			request.addEventListener("load", function() {
+				that.size = Number(request.getResponseHeader("Content-Length"));
+				if (request.getResponseHeader("Accept-Ranges") == "bytes")
+					callback();
+				else
+					onerror(ERR_HTTP_RANGE);
+			}, false);
+			request.addEventListener("error", onerror, false);
+			request.open("HEAD", url);
+			request.send();
+		}
+
+		function readArrayBuffer(index, length, callback, onerror) {
+			var request = new XMLHttpRequest();
+			request.open("GET", url);
+			request.responseType = "arraybuffer";
+			request.setRequestHeader("Range", "bytes=" + index + "-" + (index + length - 1));
+			request.addEventListener("load", function() {
+				callback(request.response);
+			}, false);
+			request.addEventListener("error", onerror, false);
+			request.send();
+		}
+
+		function readUint8Array(index, length, callback, onerror) {
+			readArrayBuffer(index, length, function(arraybuffer) {
+				callback(new Uint8Array(arraybuffer));
+			}, onerror);
+		}
+
+		that.size = 0;
+		that.init = init;
+		that.readUint8Array = readUint8Array;
+	}
+	HttpRangeReader.prototype = new Reader();
+	HttpRangeReader.prototype.constructor = HttpRangeReader;
+
+	function ArrayBufferReader(arrayBuffer) {
+		var that = this;
+
+		function init(callback, onerror) {
+			that.size = arrayBuffer.byteLength;
+			callback();
+		}
+
+		function readUint8Array(index, length, callback, onerror) {
+			callback(new Uint8Array(arrayBuffer.slice(index, index + length)));
+		}
+
+		that.size = 0;
+		that.init = init;
+		that.readUint8Array = readUint8Array;
+	}
+	ArrayBufferReader.prototype = new Reader();
+	ArrayBufferReader.prototype.constructor = ArrayBufferReader;
+
+	function ArrayBufferWriter() {
+		var array, that = this;
+
+		function init(callback, onerror) {
+			array = new Uint8Array();
+			callback();
+		}
+
+		function writeUint8Array(arr, callback, onerror) {
+			var tmpArray = new Uint8Array(array.length + arr.length);
+			tmpArray.set(array);
+			tmpArray.set(arr, array.length);
+			array = tmpArray;
+			callback();
+		}
+
+		function getData(callback) {
+			callback(array.buffer);
+		}
+
+		that.init = init;
+		that.writeUint8Array = writeUint8Array;
+		that.getData = getData;
+	}
+	ArrayBufferWriter.prototype = new Writer();
+	ArrayBufferWriter.prototype.constructor = ArrayBufferWriter;
+
+	function FileWriter(fileEntry, contentType) {
+		var writer, that = this;
+
+		function init(callback, onerror) {
+			fileEntry.createWriter(function(fileWriter) {
+				writer = fileWriter;
+				callback();
+			}, onerror);
+		}
+
+		function writeUint8Array(array, callback, onerror) {
+			var blob = new Blob([ appendABViewSupported ? array : array.buffer ], {
+				type : contentType
+			});
+			writer.onwrite = function() {
+				writer.onwrite = null;
+				callback();
+			};
+			writer.onerror = onerror;
+			writer.write(blob);
+		}
+
+		function getData(callback) {
+			fileEntry.file(callback);
+		}
+
+		that.init = init;
+		that.writeUint8Array = writeUint8Array;
+		that.getData = getData;
+	}
+	FileWriter.prototype = new Writer();
+	FileWriter.prototype.constructor = FileWriter;
+
+	zip.FileWriter = FileWriter;
+	zip.HttpReader = HttpReader;
+	zip.HttpRangeReader = HttpRangeReader;
+	zip.ArrayBufferReader = ArrayBufferReader;
+	zip.ArrayBufferWriter = ArrayBufferWriter;
+
+	if (zip.fs) {
+		ZipDirectoryEntry = zip.fs.ZipDirectoryEntry;
+		ZipDirectoryEntry.prototype.addHttpContent = function(name, URL, useRangeHeader) {
+			function addChild(parent, name, params, directory) {
+				if (parent.directory)
+					return directory ? new ZipDirectoryEntry(parent.fs, name, params, parent) : new zip.fs.ZipFileEntry(parent.fs, name, params, parent);
+				else
+					throw "Parent entry is not a directory.";
+			}
+
+			return addChild(this, name, {
+				data : URL,
+				Reader : useRangeHeader ? HttpRangeReader : HttpReader
+			});
+		};
+		ZipDirectoryEntry.prototype.importHttpContent = function(URL, useRangeHeader, onend, onerror) {
+			this.importZip(useRangeHeader ? new HttpRangeReader(URL) : new HttpReader(URL), onend, onerror);
+		};
+		zip.fs.FS.prototype.importHttpContent = function(URL, useRangeHeader, onend, onerror) {
+			this.entries = [];
+			this.root = new ZipDirectoryEntry(this);
+			this.root.importHttpContent(URL, useRangeHeader, onend, onerror);
+		};
+	}
+
+})();
diff --git a/zip.js/WebContent/zip-fs.js b/zip.js/WebContent/zip-fs.js
new file mode 100644
index 0000000..339bf66
--- /dev/null
+++ b/zip.js/WebContent/zip-fs.js
@@ -0,0 +1,538 @@
+/*
+ Copyright (c) 2013 Gildas Lormeau. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright 
+ notice, this list of conditions and the following disclaimer in 
+ the documentation and/or other materials provided with the distribution.
+
+ 3. The names of the authors may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
+ INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+(function() {
+
+	var CHUNK_SIZE = 512 * 1024;
+
+	var TextWriter = zip.TextWriter, //
+	BlobWriter = zip.BlobWriter, //
+	Data64URIWriter = zip.Data64URIWriter, //
+	Reader = zip.Reader, //
+	TextReader = zip.TextReader, //
+	BlobReader = zip.BlobReader, //
+	Data64URIReader = zip.Data64URIReader, //
+	createReader = zip.createReader, //
+	createWriter = zip.createWriter;
+
+	function ZipBlobReader(entry) {
+		var that = this, blobReader;
+
+		function init(callback) {
+			this.size = entry.uncompressedSize;
+			callback();
+		}
+
+		function getData(callback) {
+			if (that.data)
+				callback();
+			else
+				entry.getData(new BlobWriter(), function(data) {
+					that.data = data;
+					blobReader = new BlobReader(data);
+					callback();
+				}, null, that.checkCrc32);
+		}
+
+		function readUint8Array(index, length, callback, onerror) {
+			getData(function() {
+				blobReader.readUint8Array(index, length, callback, onerror);
+			}, onerror);
+		}
+
+		that.size = 0;
+		that.init = init;
+		that.readUint8Array = readUint8Array;
+	}
+	ZipBlobReader.prototype = new Reader();
+	ZipBlobReader.prototype.constructor = ZipBlobReader;
+	ZipBlobReader.prototype.checkCrc32 = false;
+
+	function getTotalSize(entry) {
+		var size = 0;
+
+		function process(entry) {
+			size += entry.uncompressedSize || 0;
+			entry.children.forEach(process);
+		}
+
+		process(entry);
+		return size;
+	}
+
+	function initReaders(entry, onend, onerror) {
+		var index = 0;
+
+		function next() {
+			index++;
+			if (index < entry.children.length)
+				process(entry.children[index]);
+			else
+				onend();
+		}
+
+		function process(child) {
+			if (child.directory)
+				initReaders(child, next, onerror);
+			else {
+				child.reader = new child.Reader(child.data, onerror);
+				child.reader.init(function() {
+					child.uncompressedSize = child.reader.size;
+					next();
+				});
+			}
+		}
+
+		if (entry.children.length)
+			process(entry.children[index]);
+		else
+			onend();
+	}
+
+	function detach(entry) {
+		var children = entry.parent.children;
+		children.forEach(function(child, index) {
+			if (child.id == entry.id)
+				children.splice(index, 1);
+		});
+	}
+
+	function exportZip(zipWriter, entry, onend, onprogress, totalSize) {
+		var currentIndex = 0;
+
+		function process(zipWriter, entry, onend, onprogress, totalSize) {
+			var childIndex = 0;
+
+			function exportChild() {
+				var child = entry.children[childIndex];
+				if (child)
+					zipWriter.add(child.getFullname(), child.reader, function() {
+						currentIndex += child.uncompressedSize || 0;
+						process(zipWriter, child, function() {
+							childIndex++;
+							exportChild();
+						}, onprogress, totalSize);
+					}, function(index) {
+						if (onprogress)
+							onprogress(currentIndex + index, totalSize);
+					}, {
+						directory : child.directory,
+						version : child.zipVersion
+					});
+				else
+					onend();
+			}
+
+			exportChild();
+		}
+
+		process(zipWriter, entry, onend, onprogress, totalSize);
+	}
+
+	function addFileEntry(zipEntry, fileEntry, onend, onerror) {
+		function getChildren(fileEntry, callback) {
+			if (fileEntry.isDirectory)
+				fileEntry.createReader().readEntries(callback);
+			if (fileEntry.isFile)
+				callback([]);
+		}
+
+		function process(zipEntry, fileEntry, onend) {
+			getChildren(fileEntry, function(children) {
+				var childIndex = 0;
+
+				function addChild(child) {
+					function nextChild(childFileEntry) {
+						process(childFileEntry, child, function() {
+							childIndex++;
+							processChild();
+						});
+					}
+
+					if (child.isDirectory)
+						nextChild(zipEntry.addDirectory(child.name));
+					if (child.isFile)
+						child.file(function(file) {
+							var childZipEntry = zipEntry.addBlob(child.name, file);
+							childZipEntry.uncompressedSize = file.size;
+							nextChild(childZipEntry);
+						}, onerror);
+				}
+
+				function processChild() {
+					var child = children[childIndex];
+					if (child)
+						addChild(child);
+					else
+						onend();
+				}
+
+				processChild();
+			});
+		}
+
+		if (fileEntry.isDirectory)
+			process(zipEntry, fileEntry, onend);
+		else
+			fileEntry.file(function(file) {
+				zipEntry.addBlob(fileEntry.name, file);
+				onend();
+			}, onerror);
+	}
+
+	function getFileEntry(fileEntry, entry, onend, onprogress, onerror, totalSize, checkCrc32) {
+		var currentIndex = 0;
+
+		function process(fileEntry, entry, onend, onprogress, onerror, totalSize) {
+			var childIndex = 0;
+
+			function addChild(child) {
+				function nextChild(childFileEntry) {
+					currentIndex += child.uncompressedSize || 0;
+					process(childFileEntry, child, function() {
+						childIndex++;
+						processChild();
+					}, onprogress, onerror, totalSize);
+				}
+
+				if (child.directory)
+					fileEntry.getDirectory(child.name, {
+						create : true
+					}, nextChild, onerror);
+				else
+					fileEntry.getFile(child.name, {
+						create : true
+					}, function(file) {
+						child.getData(new zip.FileWriter(file, zip.getMimeType(child.name)), nextChild, function(index) {
+							if (onprogress)
+								onprogress(currentIndex + index, totalSize);
+						}, checkCrc32);
+					}, onerror);
+			}
+
+			function processChild() {
+				var child = entry.children[childIndex];
+				if (child)
+					addChild(child);
+				else
+					onend();
+			}
+
+			processChild();
+		}
+
+		if (entry.directory)
+			process(fileEntry, entry, onend, onprogress, onerror, totalSize);
+		else
+			entry.getData(new zip.FileWriter(fileEntry, zip.getMimeType(entry.name)), onend, onprogress, checkCrc32);
+	}
+
+	function resetFS(fs) {
+		fs.entries = [];
+		fs.root = new ZipDirectoryEntry(fs);
+	}
+
+	function bufferedCopy(reader, writer, onend, onprogress, onerror) {
+		var chunkIndex = 0;
+
+		function stepCopy() {
+			var index = chunkIndex * CHUNK_SIZE;
+			if (onprogress)
+				onprogress(index, reader.size);
+			if (index < reader.size)
+				reader.readUint8Array(index, Math.min(CHUNK_SIZE, reader.size - index), function(array) {
+					writer.writeUint8Array(new Uint8Array(array), function() {
+						chunkIndex++;
+						stepCopy();
+					});
+				}, onerror);
+			else
+				writer.getData(onend);
+		}
+
+		stepCopy();
+	}
+
+	function getEntryData(writer, onend, onprogress, onerror) {
+		var that = this;
+		if (!writer || (writer.constructor == that.Writer && that.data))
+			onend(that.data);
+		else {
+			if (!that.reader)
+				that.reader = new that.Reader(that.data, onerror);
+			that.reader.init(function() {
+				writer.init(function() {
+					bufferedCopy(that.reader, writer, onend, onprogress, onerror);
+				}, onerror);
+			});
+		}
+	}
+
+	function addChild(parent, name, params, directory) {
+		if (parent.directory)
+			return directory ? new ZipDirectoryEntry(parent.fs, name, params, parent) : new ZipFileEntry(parent.fs, name, params, parent);
+		else
+			throw "Parent entry is not a directory.";
+	}
+
+	function ZipEntry() {
+	}
+
+	ZipEntry.prototype = {
+		init : function(fs, name, params, parent) {
+			var that = this;
+			if (fs.root && parent && parent.getChildByName(name))
+				throw "Entry filename already exists.";
+			if (!params)
+				params = {};
+			that.fs = fs;
+			that.name = name;
+			that.id = fs.entries.length;
+			that.parent = parent;
+			that.children = [];
+			that.zipVersion = params.zipVersion || 0x14;
+			that.uncompressedSize = 0;
+			fs.entries.push(that);
+			if (parent)
+				that.parent.children.push(that);
+		},
+		getFileEntry : function(fileEntry, onend, onprogress, onerror, checkCrc32) {
+			var that = this;
+			initReaders(that, function() {
+				getFileEntry(fileEntry, that, onend, onprogress, onerror, getTotalSize(that), checkCrc32);
+			}, onerror);
+		},
+		moveTo : function(target) {
+			var that = this;
+			if (target.directory) {
+				if (!target.isDescendantOf(that)) {
+					if (that != target) {
+						if (target.getChildByName(that.name))
+							throw "Entry filename already exists.";
+						detach(that);
+						that.parent = target;
+						target.children.push(that);
+					}
+				} else
+					throw "Entry is a ancestor of target entry.";
+			} else
+				throw "Target entry is not a directory.";
+		},
+		getFullname : function() {
+			var that = this, fullname = that.name, entry = that.parent;
+			while (entry) {
+				fullname = (entry.name ? entry.name + "/" : "") + fullname;
+				entry = entry.parent;
+			}
+			return fullname;
+		},
+		isDescendantOf : function(ancestor) {
+			var entry = this.parent;
+			while (entry && entry.id != ancestor.id)
+				entry = entry.parent;
+			return !!entry;
+		}
+	};
+	ZipEntry.prototype.constructor = ZipEntry;
+
+	var ZipFileEntryProto;
+
+	function ZipFileEntry(fs, name, params, parent) {
+		var that = this;
+		ZipEntry.prototype.init.call(that, fs, name, params, parent);
+		that.Reader = params.Reader;
+		that.Writer = params.Writer;
+		that.data = params.data;
+		that.getData = params.getData || getEntryData;
+	}
+
+	ZipFileEntry.prototype = ZipFileEntryProto = new ZipEntry();
+	ZipFileEntryProto.constructor = ZipFileEntry;
+	ZipFileEntryProto.getText = function(onend, onprogress, checkCrc32, encoding) {
+		this.getData(new TextWriter(encoding), onend, onprogress, checkCrc32);
+	};
+	ZipFileEntryProto.getBlob = function(mimeType, onend, onprogress, checkCrc32) {
+		this.getData(new BlobWriter(mimeType), onend, onprogress, checkCrc32);
+	};
+	ZipFileEntryProto.getData64URI = function(mimeType, onend, onprogress, checkCrc32) {
+		this.getData(new Data64URIWriter(mimeType), onend, onprogress, checkCrc32);
+	};
+
+	var ZipDirectoryEntryProto;
+
+	function ZipDirectoryEntry(fs, name, params, parent) {
+		var that = this;
+		ZipEntry.prototype.init.call(that, fs, name, params, parent);
+		that.directory = true;
+	}
+
+	ZipDirectoryEntry.prototype = ZipDirectoryEntryProto = new ZipEntry();
+	ZipDirectoryEntryProto.constructor = ZipDirectoryEntry;
+	ZipDirectoryEntryProto.addDirectory = function(name) {
+		return addChild(this, name, null, true);
+	};
+	ZipDirectoryEntryProto.addText = function(name, text) {
+		return addChild(this, name, {
+			data : text,
+			Reader : TextReader,
+			Writer : TextWriter
+		});
+	};
+	ZipDirectoryEntryProto.addBlob = function(name, blob) {
+		return addChild(this, name, {
+			data : blob,
+			Reader : BlobReader,
+			Writer : BlobWriter
+		});
+	};
+	ZipDirectoryEntryProto.addData64URI = function(name, dataURI) {
+		return addChild(this, name, {
+			data : dataURI,
+			Reader : Data64URIReader,
+			Writer : Data64URIWriter
+		});
+	};
+	ZipDirectoryEntryProto.addFileEntry = function(fileEntry, onend, onerror) {
+		addFileEntry(this, fileEntry, onend, onerror);
+	};
+	ZipDirectoryEntryProto.addData = function(name, params) {
+		return addChild(this, name, params);
+	};
+	ZipDirectoryEntryProto.importBlob = function(blob, onend, onerror) {
+		this.importZip(new BlobReader(blob), onend, onerror);
+	};
+	ZipDirectoryEntryProto.importText = function(text, onend, onerror) {
+		this.importZip(new TextReader(text), onend, onerror);
+	};
+	ZipDirectoryEntryProto.importData64URI = function(dataURI, onend, onerror) {
+		this.importZip(new Data64URIReader(dataURI), onend, onerror);
+	};
+	ZipDirectoryEntryProto.exportBlob = function(onend, onprogress, onerror) {
+		this.exportZip(new BlobWriter("application/zip"), onend, onprogress, onerror);
+	};
+	ZipDirectoryEntryProto.exportText = function(onend, onprogress, onerror) {
+		this.exportZip(new TextWriter(), onend, onprogress, onerror);
+	};
+	ZipDirectoryEntryProto.exportFileEntry = function(fileEntry, onend, onprogress, onerror) {
+		this.exportZip(new zip.FileWriter(fileEntry, "application/zip"), onend, onprogress, onerror);
+	};
+	ZipDirectoryEntryProto.exportData64URI = function(onend, onprogress, onerror) {
+		this.exportZip(new Data64URIWriter("application/zip"), onend, onprogress, onerror);
+	};
+	ZipDirectoryEntryProto.importZip = function(reader, onend, onerror) {
+		var that = this;
+		createReader(reader, function(zipReader) {
+			zipReader.getEntries(function(entries) {
+				entries.forEach(function(entry) {
+					var parent = that, path = entry.filename.split("/"), name = path.pop();
+					path.forEach(function(pathPart) {
+						parent = parent.getChildByName(pathPart) || new ZipDirectoryEntry(that.fs, pathPart, null, parent);
+					});
+					if (!entry.directory)
+						addChild(parent, name, {
+							data : entry,
+							Reader : ZipBlobReader
+						});
+				});
+				onend();
+			});
+		}, onerror);
+	};
+	ZipDirectoryEntryProto.exportZip = function(writer, onend, onprogress, onerror) {
+		var that = this;
+		initReaders(that, function() {
+			createWriter(writer, function(zipWriter) {
+				exportZip(zipWriter, that, function() {
+					zipWriter.close(onend);
+				}, onprogress, getTotalSize(that));
+			}, onerror);
+		}, onerror);
+	};
+	ZipDirectoryEntryProto.getChildByName = function(name) {
+		var childIndex, child, that = this;
+		for (childIndex = 0; childIndex < that.children.length; childIndex++) {
+			child = that.children[childIndex];
+			if (child.name == name)
+				return child;
+		}
+	};
+
+	function FS() {
+		resetFS(this);
+	}
+	FS.prototype = {
+		remove : function(entry) {
+			detach(entry);
+			this.entries[entry.id] = null;
+		},
+		find : function(fullname) {
+			var index, path = fullname.split("/"), node = this.root;
+			for (index = 0; node && index < path.length; index++)
+				node = node.getChildByName(path[index]);
+			return node;
+		},
+		getById : function(id) {
+			return this.entries[id];
+		},
+		importBlob : function(blob, onend, onerror) {
+			resetFS(this);
+			this.root.importBlob(blob, onend, onerror);
+		},
+		importText : function(text, onend, onerror) {
+			resetFS(this);
+			this.root.importText(text, onend, onerror);
+		},
+		importData64URI : function(dataURI, onend, onerror) {
+			resetFS(this);
+			this.root.importData64URI(dataURI, onend, onerror);
+		},
+		exportBlob : function(onend, onprogress, onerror) {
+			this.root.exportBlob(onend, onprogress, onerror);
+		},
+		exportText : function(onend, onprogress, onerror) {
+			this.root.exportText(onend, onprogress, onerror);
+		},
+		exportFileEntry : function(fileEntry, onend, onprogress, onerror) {
+			this.root.exportFileEntry(fileEntry, onend, onprogress, onerror);
+		},
+		exportData64URI : function(onend, onprogress, onerror) {
+			this.root.exportData64URI(onend, onprogress, onerror);
+		}
+	};
+
+	zip.fs = {
+		FS : FS,
+		ZipDirectoryEntry : ZipDirectoryEntry,
+		ZipFileEntry : ZipFileEntry
+	};
+
+	zip.getMimeType = function() {
+		return "application/octet-stream";
+	};
+
+})();
diff --git a/zip.js/WebContent/zip.js b/zip.js/WebContent/zip.js
new file mode 100644
index 0000000..655b0b9
--- /dev/null
+++ b/zip.js/WebContent/zip.js
@@ -0,0 +1,801 @@
+/*
+ Copyright (c) 2013 Gildas Lormeau. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+
+ 3. The names of the authors may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
+ INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+(function(obj) {
+
+	var ERR_BAD_FORMAT = "File format is not recognized.";
+	var ERR_ENCRYPTED = "File contains encrypted entry.";
+	var ERR_ZIP64 = "File is using Zip64 (4gb+ file size).";
+	var ERR_READ = "Error while reading zip file.";
+	var ERR_WRITE = "Error while writing zip file.";
+	var ERR_WRITE_DATA = "Error while writing file data.";
+	var ERR_READ_DATA = "Error while reading file data.";
+	var ERR_DUPLICATED_NAME = "File already exists.";
+	var CHUNK_SIZE = 512 * 1024;
+
+	var INFLATE_JS = "inflate.js";
+	var DEFLATE_JS = "deflate.js";
+	
+	var TEXT_PLAIN = "text/plain";
+	
+	var MESSAGE_EVENT = "message";
+
+	var appendABViewSupported;
+	try {
+		appendABViewSupported = new Blob([ new DataView(new ArrayBuffer(0)) ]).size === 0;
+	} catch (e) {
+	}
+
+	function Crc32() {
+		var crc = -1, that = this;
+		that.append = function(data) {
+			var offset, table = that.table;
+			for (offset = 0; offset < data.length; offset++)
+				crc = (crc >>> 8) ^ table[(crc ^ data[offset]) & 0xFF];
+		};
+		that.get = function() {
+			return ~crc;
+		};
+	}
+	Crc32.prototype.table = (function() {
+		var i, j, t, table = [];
+		for (i = 0; i < 256; i++) {
+			t = i;
+			for (j = 0; j < 8; j++)
+				if (t & 1)
+					t = (t >>> 1) ^ 0xEDB88320;
+				else
+					t = t >>> 1;
+			table[i] = t;
+		}
+		return table;
+	})();
+
+	function blobSlice(blob, index, length) {
+		if (blob.slice)
+			return blob.slice(index, index + length);
+		else if (blob.webkitSlice)
+			return blob.webkitSlice(index, index + length);
+		else if (blob.mozSlice)
+			return blob.mozSlice(index, index + length);
+		else if (blob.msSlice)
+			return blob.msSlice(index, index + length);
+	}
+
+	function getDataHelper(byteLength, bytes) {
+		var dataBuffer, dataArray;
+		dataBuffer = new ArrayBuffer(byteLength);
+		dataArray = new Uint8Array(dataBuffer);
+		if (bytes)
+			dataArray.set(bytes, 0);
+		return {
+			buffer : dataBuffer,
+			array : dataArray,
+			view : new DataView(dataBuffer)
+		};
+	}
+
+	// Readers
+	function Reader() {
+	}
+
+	function TextReader(text) {
+		var that = this, blobReader;
+
+		function init(callback, onerror) {
+			var blob = new Blob([ text ], {
+				type : TEXT_PLAIN
+			});
+			blobReader = new BlobReader(blob);
+			blobReader.init(function() {
+				that.size = blobReader.size;
+				callback();
+			}, onerror);
+		}
+
+		function readUint8Array(index, length, callback, onerror) {
+			blobReader.readUint8Array(index, length, callback, onerror);
+		}
+
+		that.size = 0;
+		that.init = init;
+		that.readUint8Array = readUint8Array;
+	}
+	TextReader.prototype = new Reader();
+	TextReader.prototype.constructor = TextReader;
+
+	function Data64URIReader(dataURI) {
+		var that = this, dataStart;
+
+		function init(callback) {
+			var dataEnd = dataURI.length;
+			while (dataURI.charAt(dataEnd - 1) == "=")
+				dataEnd--;
+			dataStart = dataURI.indexOf(",") + 1;
+			that.size = Math.floor((dataEnd - dataStart) * 0.75);
+			callback();
+		}
+
+		function readUint8Array(index, length, callback) {
+			var i, data = getDataHelper(length);
+			var start = Math.floor(index / 3) * 4;
+			var end = Math.ceil((index + length) / 3) * 4;
+			var bytes = obj.atob(dataURI.substring(start + dataStart, end + dataStart));
+			var delta = index - Math.floor(start / 4) * 3;
+			for (i = delta; i < delta + length; i++)
+				data.array[i - delta] = bytes.charCodeAt(i);
+			callback(data.array);
+		}
+
+		that.size = 0;
+		that.init = init;
+		that.readUint8Array = readUint8Array;
+	}
+	Data64URIReader.prototype = new Reader();
+	Data64URIReader.prototype.constructor = Data64URIReader;
+
+	function BlobReader(blob) {
+		var that = this;
+
+		function init(callback) {
+			this.size = blob.size;
+			callback();
+		}
+
+		function readUint8Array(index, length, callback, onerror) {
+			var reader = new FileReader();
+			reader.onload = function(e) {
+				callback(new Uint8Array(e.target.result));
+			};
+			reader.onerror = onerror;
+			reader.readAsArrayBuffer(blobSlice(blob, index, length));
+		}
+
+		that.size = 0;
+		that.init = init;
+		that.readUint8Array = readUint8Array;
+	}
+	BlobReader.prototype = new Reader();
+	BlobReader.prototype.constructor = BlobReader;
+
+	// Writers
+
+	function Writer() {
+	}
+	Writer.prototype.getData = function(callback) {
+		callback(this.data);
+	};
+
+	function TextWriter(encoding) {
+		var that = this, blob;
+
+		function init(callback) {
+			blob = new Blob([], {
+				type : TEXT_PLAIN
+			});
+			callback();
+		}
+
+		function writeUint8Array(array, callback) {
+			blob = new Blob([ blob, appendABViewSupported ? array : array.buffer ], {
+				type : TEXT_PLAIN
+			});
+			callback();
+		}
+
+		function getData(callback, onerror) {
+			var reader = new FileReader();
+			reader.onload = function(e) {
+				callback(e.target.result);
+			};
+			reader.onerror = onerror;
+			reader.readAsText(blob, encoding);
+		}
+
+		that.init = init;
+		that.writeUint8Array = writeUint8Array;
+		that.getData = getData;
+	}
+	TextWriter.prototype = new Writer();
+	TextWriter.prototype.constructor = TextWriter;
+
+	function Data64URIWriter(contentType) {
+		var that = this, data = "", pending = "";
+
+		function init(callback) {
+			data += "data:" + (contentType || "") + ";base64,";
+			callback();
+		}
+
+		function writeUint8Array(array, callback) {
+			var i, delta = pending.length, dataString = pending;
+			pending = "";
+			for (i = 0; i < (Math.floor((delta + array.length) / 3) * 3) - delta; i++)
+				dataString += String.fromCharCode(array[i]);
+			for (; i < array.length; i++)
+				pending += String.fromCharCode(array[i]);
+			if (dataString.length > 2)
+				data += obj.btoa(dataString);
+			else
+				pending = dataString;
+			callback();
+		}
+
+		function getData(callback) {
+			callback(data + obj.btoa(pending));
+		}
+
+		that.init = init;
+		that.writeUint8Array = writeUint8Array;
+		that.getData = getData;
+	}
+	Data64URIWriter.prototype = new Writer();
+	Data64URIWriter.prototype.constructor = Data64URIWriter;
+
+	function BlobWriter(contentType) {
+		var blob, that = this;
+
+		function init(callback) {
+			blob = new Blob([], {
+				type : contentType
+			});
+			callback();
+		}
+
+		function writeUint8Array(array, callback) {
+			blob = new Blob([ blob, appendABViewSupported ? array : array.buffer ], {
+				type : contentType
+			});
+			callback();
+		}
+
+		function getData(callback) {
+			callback(blob);
+		}
+
+		that.init = init;
+		that.writeUint8Array = writeUint8Array;
+		that.getData = getData;
+	}
+	BlobWriter.prototype = new Writer();
+	BlobWriter.prototype.constructor = BlobWriter;
+
+	// inflate/deflate core functions
+
+	function launchWorkerProcess(worker, reader, writer, offset, size, onappend, onprogress, onend, onreaderror, onwriteerror) {
+		var chunkIndex = 0, index, outputSize;
+
+		function onflush() {
+			worker.removeEventListener(MESSAGE_EVENT, onmessage, false);
+			onend(outputSize);
+		}
+
+		function onmessage(event) {
+			var message = event.data, data = message.data;
+
+			if (message.onappend) {
+				outputSize += data.length;
+				writer.writeUint8Array(data, function() {
+					onappend(false, data);
+					step();
+				}, onwriteerror);
+			}
+			if (message.onflush)
+				if (data) {
+					outputSize += data.length;
+					writer.writeUint8Array(data, function() {
+						onappend(false, data);
+						onflush();
+					}, onwriteerror);
+				} else
+					onflush();
+			if (message.progress && onprogress)
+				onprogress(index + message.current, size);
+		}
+
+		function step() {
+			index = chunkIndex * CHUNK_SIZE;
+			if (index < size)
+				reader.readUint8Array(offset + index, Math.min(CHUNK_SIZE, size - index), function(array) {
+					worker.postMessage({
+						append : true,
+						data : array
+					});
+					chunkIndex++;
+					if (onprogress)
+						onprogress(index, size);
+					onappend(true, array);
+				}, onreaderror);
+			else
+				worker.postMessage({
+					flush : true
+				});
+		}
+
+		outputSize = 0;
+		worker.addEventListener(MESSAGE_EVENT, onmessage, false);
+		step();
+	}
+
+	function launchProcess(process, reader, writer, offset, size, onappend, onprogress, onend, onreaderror, onwriteerror) {
+		var chunkIndex = 0, index, outputSize = 0;
+
+		function step() {
+			var outputData;
+			index = chunkIndex * CHUNK_SIZE;
+			if (index < size)
+				reader.readUint8Array(offset + index, Math.min(CHUNK_SIZE, size - index), function(inputData) {
+					var outputData = process.append(inputData, function() {
+						if (onprogress)
+							onprogress(offset + index, size);
+					});
+					outputSize += outputData.length;
+					onappend(true, inputData);
+					writer.writeUint8Array(outputData, function() {
+						onappend(false, outputData);
+						chunkIndex++;
+						setTimeout(step, 1);
+					}, onwriteerror);
+					if (onprogress)
+						onprogress(index, size);
+				}, onreaderror);
+			else {
+				outputData = process.flush();
+				if (outputData) {
+					outputSize += outputData.length;
+					writer.writeUint8Array(outputData, function() {
+						onappend(false, outputData);
+						onend(outputSize);
+					}, onwriteerror);
+				} else
+					onend(outputSize);
+			}
+		}
+
+		step();
+	}
+
+	function inflate(reader, writer, offset, size, computeCrc32, onend, onprogress, onreaderror, onwriteerror) {
+		var worker, crc32 = new Crc32();
+
+		function oninflateappend(sending, array) {
+			if (computeCrc32 && !sending)
+				crc32.append(array);
+		}
+
+		function oninflateend(outputSize) {
+			onend(outputSize, crc32.get());
+		}
+
+		if (obj.zip.useWebWorkers) {
+			worker = new Worker(obj.zip.workerScriptsPath + INFLATE_JS);
+			launchWorkerProcess(worker, reader, writer, offset, size, oninflateappend, onprogress, oninflateend, onreaderror, onwriteerror);
+		} else
+			launchProcess(new obj.zip.Inflater(), reader, writer, offset, size, oninflateappend, onprogress, oninflateend, onreaderror, onwriteerror);
+		return worker;
+	}
+
+	function deflate(reader, writer, level, onend, onprogress, onreaderror, onwriteerror) {
+		var worker, crc32 = new Crc32();
+
+		function ondeflateappend(sending, array) {
+			if (sending)
+				crc32.append(array);
+		}
+
+		function ondeflateend(outputSize) {
+			onend(outputSize, crc32.get());
+		}
+
+		function onmessage() {
+			worker.removeEventListener(MESSAGE_EVENT, onmessage, false);
+			launchWorkerProcess(worker, reader, writer, 0, reader.size, ondeflateappend, onprogress, ondeflateend, onreaderror, onwriteerror);
+		}
+
+		if (obj.zip.useWebWorkers) {
+			worker = new Worker(obj.zip.workerScriptsPath + DEFLATE_JS);
+			worker.addEventListener(MESSAGE_EVENT, onmessage, false);
+			worker.postMessage({
+				init : true,
+				level : level
+			});
+		} else
+			launchProcess(new obj.zip.Deflater(), reader, writer, 0, reader.size, ondeflateappend, onprogress, ondeflateend, onreaderror, onwriteerror);
+		return worker;
+	}
+
+	function copy(reader, writer, offset, size, computeCrc32, onend, onprogress, onreaderror, onwriteerror) {
+		var chunkIndex = 0, crc32 = new Crc32();
+
+		function step() {
+			var index = chunkIndex * CHUNK_SIZE;
+			if (index < size)
+				reader.readUint8Array(offset + index, Math.min(CHUNK_SIZE, size - index), function(array) {
+					if (computeCrc32)
+						crc32.append(array);
+					if (onprogress)
+						onprogress(index, size, array);
+					writer.writeUint8Array(array, function() {
+						chunkIndex++;
+						step();
+					}, onwriteerror);
+				}, onreaderror);
+			else
+				onend(size, crc32.get());
+		}
+
+		step();
+	}
+
+	// ZipReader
+
+	function decodeASCII(str) {
+		var i, out = "", charCode, extendedASCII = [ '\u00C7', '\u00FC', '\u00E9', '\u00E2', '\u00E4', '\u00E0', '\u00E5', '\u00E7', '\u00EA', '\u00EB',
+				'\u00E8', '\u00EF', '\u00EE', '\u00EC', '\u00C4', '\u00C5', '\u00C9', '\u00E6', '\u00C6', '\u00F4', '\u00F6', '\u00F2', '\u00FB', '\u00F9',
+				'\u00FF', '\u00D6', '\u00DC', '\u00F8', '\u00A3', '\u00D8', '\u00D7', '\u0192', '\u00E1', '\u00ED', '\u00F3', '\u00FA', '\u00F1', '\u00D1',
+				'\u00AA', '\u00BA', '\u00BF', '\u00AE', '\u00AC', '\u00BD', '\u00BC', '\u00A1', '\u00AB', '\u00BB', '_', '_', '_', '\u00A6', '\u00A6',
+				'\u00C1', '\u00C2', '\u00C0', '\u00A9', '\u00A6', '\u00A6', '+', '+', '\u00A2', '\u00A5', '+', '+', '-', '-', '+', '-', '+', '\u00E3',
+				'\u00C3', '+', '+', '-', '-', '\u00A6', '-', '+', '\u00A4', '\u00F0', '\u00D0', '\u00CA', '\u00CB', '\u00C8', 'i', '\u00CD', '\u00CE',
+				'\u00CF', '+', '+', '_', '_', '\u00A6', '\u00CC', '_', '\u00D3', '\u00DF', '\u00D4', '\u00D2', '\u00F5', '\u00D5', '\u00B5', '\u00FE',
+				'\u00DE', '\u00DA', '\u00DB', '\u00D9', '\u00FD', '\u00DD', '\u00AF', '\u00B4', '\u00AD', '\u00B1', '_', '\u00BE', '\u00B6', '\u00A7',
+				'\u00F7', '\u00B8', '\u00B0', '\u00A8', '\u00B7', '\u00B9', '\u00B3', '\u00B2', '_', ' ' ];
+		for (i = 0; i < str.length; i++) {
+			charCode = str.charCodeAt(i) & 0xFF;
+			if (charCode > 127)
+				out += extendedASCII[charCode - 128];
+			else
+				out += String.fromCharCode(charCode);
+		}
+		return out;
+	}
+
+	function decodeUTF8(string) {
+		return decodeURIComponent(escape(string));
+	}
+
+	function getString(bytes) {
+		var i, str = "";
+		for (i = 0; i < bytes.length; i++)
+			str += String.fromCharCode(bytes[i]);
+		return str;
+	}
+
+	function getDate(timeRaw) {
+		var date = (timeRaw & 0xffff0000) >> 16, time = timeRaw & 0x0000ffff;
+		try {
+			return new Date(1980 + ((date & 0xFE00) >> 9), ((date & 0x01E0) >> 5) - 1, date & 0x001F, (time & 0xF800) >> 11, (time & 0x07E0) >> 5,
+					(time & 0x001F) * 2, 0);
+		} catch (e) {
+		}
+	}
+
+	function readCommonHeader(entry, data, index, centralDirectory, onerror) {
+		entry.version = data.view.getUint16(index, true);
+		entry.bitFlag = data.view.getUint16(index + 2, true);
+		entry.compressionMethod = data.view.getUint16(index + 4, true);
+		entry.lastModDateRaw = data.view.getUint32(index + 6, true);
+		entry.lastModDate = getDate(entry.lastModDateRaw);
+		if ((entry.bitFlag & 0x01) === 0x01) {
+			onerror(ERR_ENCRYPTED);
+			return;
+		}
+		if (centralDirectory || (entry.bitFlag & 0x0008) != 0x0008) {
+			entry.crc32 = data.view.getUint32(index + 10, true);
+			entry.compressedSize = data.view.getUint32(index + 14, true);
+			entry.uncompressedSize = data.view.getUint32(index + 18, true);
+		}
+		if (entry.compressedSize === 0xFFFFFFFF || entry.uncompressedSize === 0xFFFFFFFF) {
+			onerror(ERR_ZIP64);
+			return;
+		}
+		entry.filenameLength = data.view.getUint16(index + 22, true);
+		entry.extraFieldLength = data.view.getUint16(index + 24, true);
+	}
+
+	function createZipReader(reader, onerror) {
+		function Entry() {
+		}
+
+		Entry.prototype.getData = function(writer, onend, onprogress, checkCrc32) {
+			var that = this, worker;
+
+			function terminate(callback, param) {
+				if (worker)
+					worker.terminate();
+				worker = null;
+				if (callback)
+					callback(param);
+			}
+
+			function testCrc32(crc32) {
+				var dataCrc32 = getDataHelper(4);
+				dataCrc32.view.setUint32(0, crc32);
+				return that.crc32 == dataCrc32.view.getUint32(0);
+			}
+
+			function getWriterData(uncompressedSize, crc32) {
+				if (checkCrc32 && !testCrc32(crc32))
+					onreaderror();
+				else
+					writer.getData(function(data) {
+						terminate(onend, data);
+					});
+			}
+
+			function onreaderror() {
+				terminate(onerror, ERR_READ_DATA);
+			}
+
+			function onwriteerror() {
+				terminate(onerror, ERR_WRITE_DATA);
+			}
+
+			reader.readUint8Array(that.offset, 30, function(bytes) {
+				var data = getDataHelper(bytes.length, bytes), dataOffset;
+				if (data.view.getUint32(0) != 0x504b0304) {
+					onerror(ERR_BAD_FORMAT);
+					return;
+				}
+				readCommonHeader(that, data, 4, false, onerror);
+				dataOffset = that.offset + 30 + that.filenameLength + that.extraFieldLength;
+				writer.init(function() {
+					if (that.compressionMethod === 0)
+						copy(reader, writer, dataOffset, that.compressedSize, checkCrc32, getWriterData, onprogress, onreaderror, onwriteerror);
+					else
+						worker = inflate(reader, writer, dataOffset, that.compressedSize, checkCrc32, getWriterData, onprogress, onreaderror, onwriteerror);
+				}, onwriteerror);
+			}, onreaderror);
+		};
+
+		function seekEOCDR(offset, entriesCallback) {
+			reader.readUint8Array(reader.size - offset, offset, function(bytes) {
+				var dataView = getDataHelper(bytes.length, bytes).view;
+				if (dataView.getUint32(0) != 0x504b0506) {
+					seekEOCDR(offset + 1, entriesCallback);
+				} else {
+					entriesCallback(dataView);
+				}
+			}, function() {
+				onerror(ERR_READ);
+			});
+		}
+
+		return {
+			getEntries : function(callback) {
+				if (reader.size < 22) {
+					onerror(ERR_BAD_FORMAT);
+					return;
+				}
+				// look for End of central directory record
+				seekEOCDR(22, function(dataView) {
+					var datalength, fileslength;
+					datalength = dataView.getUint32(16, true);
+					fileslength = dataView.getUint16(8, true);
+					reader.readUint8Array(datalength, reader.size - datalength, function(bytes) {
+						var i, index = 0, entries = [], entry, filename, comment, data = getDataHelper(bytes.length, bytes);
+						for (i = 0; i < fileslength; i++) {
+							entry = new Entry();
+							if (data.view.getUint32(index) != 0x504b0102) {
+								onerror(ERR_BAD_FORMAT);
+								return;
+							}
+							readCommonHeader(entry, data, index + 6, true, onerror);
+							entry.commentLength = data.view.getUint16(index + 32, true);
+							entry.directory = ((data.view.getUint8(index + 38) & 0x10) == 0x10);
+							entry.offset = data.view.getUint32(index + 42, true);
+							filename = getString(data.array.subarray(index + 46, index + 46 + entry.filenameLength));
+							entry.filename = ((entry.bitFlag & 0x0800) === 0x0800) ? decodeUTF8(filename) : decodeASCII(filename);
+							if (!entry.directory && entry.filename.charAt(entry.filename.length - 1) == "/")
+								entry.directory = true;
+							comment = getString(data.array.subarray(index + 46 + entry.filenameLength + entry.extraFieldLength, index + 46
+									+ entry.filenameLength + entry.extraFieldLength + entry.commentLength));
+							entry.comment = ((entry.bitFlag & 0x0800) === 0x0800) ? decodeUTF8(comment) : decodeASCII(comment);
+							entries.push(entry);
+							index += 46 + entry.filenameLength + entry.extraFieldLength + entry.commentLength;
+						}
+						callback(entries);
+					}, function() {
+						onerror(ERR_READ);
+					});
+				});
+			},
+			close : function(callback) {
+				if (callback)
+					callback();
+			}
+		};
+	}
+
+	// ZipWriter
+
+	function encodeUTF8(string) {
+		return unescape(encodeURIComponent(string));
+	}
+
+	function getBytes(str) {
+		var i, array = [];
+		for (i = 0; i < str.length; i++)
+			array.push(str.charCodeAt(i));
+		return array;
+	}
+
+	function createZipWriter(writer, onerror, dontDeflate) {
+		var worker, files = {}, filenames = [], datalength = 0;
+
+		function terminate(callback, message) {
+			if (worker)
+				worker.terminate();
+			worker = null;
+			if (callback)
+				callback(message);
+		}
+
+		function onwriteerror() {
+			terminate(onerror, ERR_WRITE);
+		}
+
+		function onreaderror() {
+			terminate(onerror, ERR_READ_DATA);
+		}
+
+		return {
+			add : function(name, reader, onend, onprogress, options) {
+				var header, filename, date;
+
+				function writeHeader(callback) {
+					var data;
+					date = options.lastModDate || new Date();
+					header = getDataHelper(26);
+					files[name] = {
+						headerArray : header.array,
+						directory : options.directory,
+						filename : filename,
+						offset : datalength,
+						comment : getBytes(encodeUTF8(options.comment || ""))
+					};
+					header.view.setUint32(0, 0x14000808);
+					if (options.version)
+						header.view.setUint8(0, options.version);
+					if (!dontDeflate && options.level !== 0 && !options.directory)
+						header.view.setUint16(4, 0x0800);
+					header.view.setUint16(6, (((date.getHours() << 6) | date.getMinutes()) << 5) | date.getSeconds() / 2, true);
+					header.view.setUint16(8, ((((date.getFullYear() - 1980) << 4) | (date.getMonth() + 1)) << 5) | date.getDate(), true);
+					header.view.setUint16(22, filename.length, true);
+					data = getDataHelper(30 + filename.length);
+					data.view.setUint32(0, 0x504b0304);
+					data.array.set(header.array, 4);
+					data.array.set(filename, 30);
+					datalength += data.array.length;
+					writer.writeUint8Array(data.array, callback, onwriteerror);
+				}
+
+				function writeFooter(compressedLength, crc32) {
+					var footer = getDataHelper(16);
+					datalength += compressedLength || 0;
+					footer.view.setUint32(0, 0x504b0708);
+					if (typeof crc32 != "undefined") {
+						header.view.setUint32(10, crc32, true);
+						footer.view.setUint32(4, crc32, true);
+					}
+					if (reader) {
+						footer.view.setUint32(8, compressedLength, true);
+						header.view.setUint32(14, compressedLength, true);
+						footer.view.setUint32(12, reader.size, true);
+						header.view.setUint32(18, reader.size, true);
+					}
+					writer.writeUint8Array(footer.array, function() {
+						datalength += 16;
+						terminate(onend);
+					}, onwriteerror);
+				}
+
+				function writeFile() {
+					options = options || {};
+					name = name.trim();
+					if (options.directory && name.charAt(name.length - 1) != "/")
+						name += "/";
+					if (files.hasOwnProperty(name)) {
+						onerror(ERR_DUPLICATED_NAME);
+						return;
+					}
+					filename = getBytes(encodeUTF8(name));
+					filenames.push(name);
+					writeHeader(function() {
+						if (reader)
+							if (dontDeflate || options.level === 0)
+								copy(reader, writer, 0, reader.size, true, writeFooter, onprogress, onreaderror, onwriteerror);
+							else
+								worker = deflate(reader, writer, options.level, writeFooter, onprogress, onreaderror, onwriteerror);
+						else
+							writeFooter();
+					}, onwriteerror);
+				}
+
+				if (reader)
+					reader.init(writeFile, onreaderror);
+				else
+					writeFile();
+			},
+			close : function(callback) {
+				var data, length = 0, index = 0, indexFilename, file;
+				for (indexFilename = 0; indexFilename < filenames.length; indexFilename++) {
+					file = files[filenames[indexFilename]];
+					length += 46 + file.filename.length + file.comment.length;
+				}
+				data = getDataHelper(length + 22);
+				for (indexFilename = 0; indexFilename < filenames.length; indexFilename++) {
+					file = files[filenames[indexFilename]];
+					data.view.setUint32(index, 0x504b0102);
+					data.view.setUint16(index + 4, 0x1400);
+					data.array.set(file.headerArray, index + 6);
+					data.view.setUint16(index + 32, file.comment.length, true);
+					if (file.directory)
+						data.view.setUint8(index + 38, 0x10);
+					data.view.setUint32(index + 42, file.offset, true);
+					data.array.set(file.filename, index + 46);
+					data.array.set(file.comment, index + 46 + file.filename.length);
+					index += 46 + file.filename.length + file.comment.length;
+				}
+				data.view.setUint32(index, 0x504b0506);
+				data.view.setUint16(index + 8, filenames.length, true);
+				data.view.setUint16(index + 10, filenames.length, true);
+				data.view.setUint32(index + 12, length, true);
+				data.view.setUint32(index + 16, datalength, true);
+				writer.writeUint8Array(data.array, function() {
+					terminate(function() {
+						writer.getData(callback);
+					});
+				}, onwriteerror);
+			}
+		};
+	}
+
+	obj.zip = {
+		Reader : Reader,
+		Writer : Writer,
+		BlobReader : BlobReader,
+		Data64URIReader : Data64URIReader,
+		TextReader : TextReader,
+		BlobWriter : BlobWriter,
+		Data64URIWriter : Data64URIWriter,
+		TextWriter : TextWriter,
+		createReader : function(reader, callback, onerror) {
+			reader.init(function() {
+				callback(createZipReader(reader, onerror));
+			}, onerror);
+		},
+		createWriter : function(writer, callback, onerror, dontDeflate) {
+			writer.init(function() {
+				callback(createZipWriter(writer, onerror, dontDeflate));
+			}, onerror);
+		},
+		workerScriptsPath : "",
+		useWebWorkers : true
+	};
+
+})(this);


hooks/post-receive
-- 
Supplemental git repository mirkarte for Evolvis project useful-scripts
(Evolvis project useful-scripts repository mirkarte)


More information about the useful-scripts-commits mailing list